diff options
author | Taco Hoekwater <taco@elvenkind.com> | 2010-04-04 13:55:46 +0000 |
---|---|---|
committer | Taco Hoekwater <taco@elvenkind.com> | 2010-04-04 13:55:46 +0000 |
commit | f372862c42d234710b6057449b46818e63181c90 (patch) | |
tree | a9ebec66dd31ac37aed442502ebd1b9fe76245ec /Build/source/texk/web2c/luatexdir/pdf | |
parent | 2dad291ab056f30816e0aea61970f38033c2f6a5 (diff) |
import luatex 0.60.0 (with small local changes, see luatexdir/ChangeLog)
and do an autoreconf
git-svn-id: svn://tug.org/texlive/trunk@17680 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/web2c/luatexdir/pdf')
46 files changed, 9853 insertions, 693 deletions
diff --git a/Build/source/texk/web2c/luatexdir/pdf/pagetree.h b/Build/source/texk/web2c/luatexdir/pdf/pagetree.h index 488c0cd129b..d4b8a11c134 100644 --- a/Build/source/texk/web2c/luatexdir/pdf/pagetree.h +++ b/Build/source/texk/web2c/luatexdir/pdf/pagetree.h @@ -17,13 +17,13 @@ You should have received a copy of the GNU General Public License along with LuaTeX; if not, see <http://www.gnu.org/licenses/>. */ -/* $Id: pagetree.h 2325 2009-04-18 11:24:38Z hhenkel $ */ +/* $Id: pagetree.h 3261 2009-12-18 11:38:21Z taco $ */ #ifndef PAGETREE_H # define PAGETREE_H -integer output_pages_tree(void); -integer pdf_do_page_divert(integer, integer); -void pdf_do_page_undivert(integer, integer); +int output_pages_tree(PDF); +int pdf_do_page_divert(PDF, int, int); +void pdf_do_page_undivert(int, int); #endif diff --git a/Build/source/texk/web2c/luatexdir/pdf/pagetree.c b/Build/source/texk/web2c/luatexdir/pdf/pagetree.w index 5e738695043..0a24b56ec97 100644 --- a/Build/source/texk/web2c/luatexdir/pdf/pagetree.c +++ b/Build/source/texk/web2c/luatexdir/pdf/pagetree.w @@ -1,40 +1,32 @@ -/* pagetree.c - - Copyright 2006-2009 Taco Hoekwater <taco@luatex.org> +% pagetree.w +% +% Copyright 2006-2010 Taco Hoekwater <taco@@luatex.org> - This file is part of LuaTeX. +% 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 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. +% 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 <http://www.gnu.org/licenses/>. */ +% You should have received a copy of the GNU General Public License along +% with LuaTeX; if not, see <http://www.gnu.org/licenses/>. +@ @c #include "ptexlib.h" -#include "openbsd-compat.h" +static const char _svn_version[] = + "$Id: pagetree.w 3573 2010-04-02 14:10:54Z hhenkel $ " + "$URL: http://foundry.supelec.fr/svn/luatex/tags/beta-0.60.0/source/texk/web2c/luatexdir/pdf/pagetree.w $"; -#include "sys/types.h" -#ifndef __MINGW32__ -# include "sysexits.h" -#else -# define EX_SOFTWARE 70 -#endif - -static const char __svn_version[] = - "$Id: pagetree.c 2448 2009-06-08 07:43:50Z taco $ " - "$URL: http://foundry.supelec.fr/svn/luatex/tags/beta-0.40.6/source/texk/web2c/luatexdir/pdf/pagetree.c $"; - -/**********************************************************************/ -/* Page diversions */ +@* Page diversions. +@ @c #ifdef DEBUG # define PAGES_TREE_KIDSMAX 3 #else @@ -44,15 +36,15 @@ static const char __svn_version[] = static struct avl_table *divert_list_tree = NULL; typedef struct pages_entry_ { - integer objnum; /* object number of this /Pages object */ - integer number_of_pages; /* total number of all pages below */ - integer number_of_kids; /* number of direct kid objects */ - integer kids[PAGES_TREE_KIDSMAX]; /* array of kid object numbers */ + int objnum; /* object number of this /Pages object */ + int number_of_pages; /* total number of all pages below */ + int number_of_kids; /* number of direct kid objects */ + int kids[PAGES_TREE_KIDSMAX]; /* array of kid object numbers */ struct pages_entry_ *next; } pages_entry; typedef struct divert_list_entry_ { - integer divnum; + int divnum; pages_entry *first; pages_entry *last; } divert_list_entry; @@ -69,7 +61,8 @@ static int comp_divert_list_entry(const void *pa, const void *pb, void *p) return 0; } -static pages_entry *new_pages_entry(void) +@ @c +static pages_entry *new_pages_entry(PDF pdf) { pages_entry *p; int i; @@ -78,11 +71,12 @@ static pages_entry *new_pages_entry(void) for (i = 0; i < PAGES_TREE_KIDSMAX; i++) p->kids[i] = 0; p->next = NULL; - pdf_create_obj(0, 0); - p->objnum = obj_ptr; + pdf_create_obj(pdf, obj_type_pages, 0); + p->objnum = pdf->obj_ptr; return p; } +@ @c static divert_list_entry *new_divert_list_entry(void) { divert_list_entry *d; @@ -91,6 +85,7 @@ static divert_list_entry *new_divert_list_entry(void) return d; } +@ @c static void ensure_list_tree(void) { if (divert_list_tree == NULL) { @@ -100,7 +95,8 @@ static void ensure_list_tree(void) } } -static divert_list_entry *get_divert_list(integer divnum) +@ @c +static divert_list_entry *get_divert_list(int divnum) { divert_list_entry *d, tmp; void **aa; @@ -115,9 +111,9 @@ static divert_list_entry *get_divert_list(integer divnum) return d; } -/* pdf_do_page_divert() returns the current /Parent object number */ - -integer pdf_do_page_divert(integer objnum, integer divnum) +@ |pdf_do_page_divert()| returns the current /Parent object number +@c +int pdf_do_page_divert(PDF pdf, int objnum, int divnum) { divert_list_entry *d; pages_entry *p; @@ -126,13 +122,13 @@ integer pdf_do_page_divert(integer objnum, integer divnum) struct avl_traverser t; int i; #endif - // initialize the tree + /* initialize the tree */ ensure_list_tree(); - // make sure we have a list for this diversion + /* make sure we have a list for this diversion */ d = get_divert_list(divnum); if (d->first == NULL || d->last->number_of_kids == PAGES_TREE_KIDSMAX) { - // append a new pages_entry - p = new_pages_entry(); + /* append a new |pages_entry| */ + p = new_pages_entry(pdf); if (d->first == NULL) d->first = p; else @@ -160,6 +156,7 @@ integer pdf_do_page_divert(integer objnum, integer divnum) return p->objnum; } +@ @c static void movelist(divert_list_entry * d, divert_list_entry * dto) { if (d != NULL && d->first != NULL && d->divnum != dto->divnum) { /* no undivert of empty list or into self */ @@ -168,13 +165,13 @@ static void movelist(divert_list_entry * d, divert_list_entry * dto) else dto->last->next = d->first; dto->last = d->last; - d->first = d->last = NULL; /* one could as well remove this divert_list_entry */ + d->first = d->last = NULL; /* one could as well remove this |divert_list_entry| */ } } -/* undivert from diversion <divnum> into diversion <curdivnum> */ - -void pdf_do_page_undivert(integer divnum, integer curdivnum) +@ undivert from diversion |divnum| into diversion |curdivnum| +@c +void pdf_do_page_undivert(int divnum, int curdivnum) { divert_list_entry *d, *dto, tmp; struct avl_traverser t; @@ -182,11 +179,11 @@ void pdf_do_page_undivert(integer divnum, integer curdivnum) pages_entry *p; int i; #endif - // initialize the tree + /* initialize the tree */ ensure_list_tree(); - // find the diversion <curdivnum> list where diversion <divnum> should go + /* find the diversion |curdivnum| list where diversion |divnum| should go */ dto = get_divert_list(curdivnum); - if (divnum == 0) { /* 0 = special case: undivert _all_ lists */ + if (divnum == 0) { /* 0 = special case: undivert {\it all\/} lists */ avl_t_init(&t, divert_list_tree); for (d = avl_t_first(&t, divert_list_tree); d != NULL; d = avl_t_next(&t)) @@ -213,54 +210,60 @@ void pdf_do_page_undivert(integer divnum, integer curdivnum) #endif } -/* write a /Pages object */ +@ write a /Pages object +@c +#define pdf_pages_attr equiv(pdf_pages_attr_loc) -static void write_pages(pages_entry * p, int parent) +static void write_pages(PDF pdf, pages_entry * p, int parent) { int i; assert(p != NULL); - pdf_begin_dict(p->objnum, 1); - pdf_printf("/Type /Pages\n"); - if (parent == 0) /* it's root */ - print_pdf_pages_attr(); - else - pdf_printf("/Parent %d 0 R\n", parent); - pdf_printf("/Count %d\n/Kids [", (int) p->number_of_pages); + pdf_begin_dict(pdf, p->objnum, 1); + pdf_printf(pdf, "/Type /Pages\n"); + if (parent == 0) { /* it's root */ + if (pdf_pages_attr != null) + pdf_print_toks_ln(pdf, pdf_pages_attr); + if (pdf_pagesattributes_toks != null) /* from Lua */ + pdf_print_toks_ln(pdf, pdf_pagesattributes_toks); + } else + pdf_printf(pdf, "/Parent %d 0 R\n", parent); + pdf_printf(pdf, "/Count %d\n/Kids [", (int) p->number_of_pages); for (i = 0; i < p->number_of_kids; i++) - pdf_printf("%d 0 R ", (int) p->kids[i]); - remove_last_space(); - pdf_printf("]\n"); - pdf_end_dict(); + pdf_printf(pdf, "%d 0 R ", (int) p->kids[i]); + pdf_remove_last_space(pdf); + pdf_printf(pdf, "]\n"); + pdf_end_dict(pdf); } -/* loop over all /Pages objects, output them, create their parents, - * recursing bottom up, return the /Pages root object number */ - -static integer output_pages_list(pages_entry * pe) +@ loop over all /Pages objects, output them, create their parents, +recursing bottom up, return the /Pages root object number +@c +static int output_pages_list(PDF pdf, pages_entry * pe) { pages_entry *p, *q, *r; assert(pe != NULL); - if (pe->next == NULL) { /* everything fits into one pages_entry */ - write_pages(pe, 0); /* --> /Pages root found */ + if (pe->next == NULL) { /* everything fits into one |pages_entry| */ + write_pages(pdf, pe, 0); /* --> /Pages root found */ return pe->objnum; } - q = r = new_pages_entry(); /* one level higher needed */ + q = r = new_pages_entry(pdf); /* one level higher needed */ for (p = pe; p != NULL; p = p->next) { if (q->number_of_kids == PAGES_TREE_KIDSMAX) { - q->next = new_pages_entry(); + q->next = new_pages_entry(pdf); q = q->next; } q->kids[q->number_of_kids++] = p->objnum; q->number_of_pages += p->number_of_pages; - write_pages(p, q->objnum); + write_pages(pdf, p, q->objnum); } - return output_pages_list(r); /* recurse through next higher level */ + return output_pages_list(pdf, r); /* recurse through next higher level */ } -integer output_pages_tree(void) +@ @c +int output_pages_tree(PDF pdf) { divert_list_entry *d; pdf_do_page_undivert(0, 0); /* concatenate all diversions into diversion 0 */ d = get_divert_list(0); /* get diversion 0 */ - return output_pages_list(d->first); + return output_pages_list(pdf, d->first); } diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfaction.h b/Build/source/texk/web2c/luatexdir/pdf/pdfaction.h new file mode 100644 index 00000000000..77944dd3f5b --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdfaction.h @@ -0,0 +1,78 @@ +/* pdfaction.h + + Copyright 2009 Taco Hoekwater <taco@luatex.org> + + 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 <http://www.gnu.org/licenses/>. */ + +/* $Id: pdfaction.h 2801 2009-07-10 13:12:59Z taco $ */ + +#ifndef PDFACTION_H +# define PDFACTION_H + +/* pdf action spec */ + +# define pdf_action_size 4 + +typedef enum { + pdf_action_page = 0, + pdf_action_goto, + pdf_action_thread, + pdf_action_user +} pdf_action_type; + +typedef enum { + pdf_window_notset, + pdf_window_new, + pdf_window_nonew, +} pdf_window_type; + + +# define pdf_action_type(a) type((a) + 1) /* enum pdf_action_type */ +# define pdf_action_named_id(a) subtype((a) + 1) /* boolean */ +# define pdf_action_id(a) vlink((a) + 1) /* number or toks */ +# define pdf_action_file(a) vinfo((a) + 2) /* toks */ +# define pdf_action_new_window(a) vlink((a) + 2) /* enum pdf_window_type */ +# define pdf_action_tokens(a) vinfo((a) + 3) /* toks */ +# define pdf_action_refcount(a) vlink((a) + 3) /* number */ + +/* increase count of references to this action. this is used to speed up copy_node() */ + +# define add_action_ref(a) pdf_action_refcount((a))++ + +/* decrease count of references to this + action; free it if there is no reference to this action*/ + +# define delete_action_ref(a) { \ + if (pdf_action_refcount(a) == null) { \ + delete_action_node(a); \ + } else { \ + decr(pdf_action_refcount(a)); \ + } \ + } + + +# define set_pdf_action_type(A,B) pdf_action_type(A)=B +# define set_pdf_action_tokens(A,B) pdf_action_tokens(A)=B +# define set_pdf_action_file(A,B) pdf_action_file(A)=B +# define set_pdf_action_id(A,B) pdf_action_id(A)=B +# define set_pdf_action_named_id(A,B) pdf_action_named_id(A)=B +# define set_pdf_action_new_window(A,B) pdf_action_new_window(A)=B + +extern halfword scan_action(PDF pdf); +extern void write_action(PDF pdf, halfword p); +extern void delete_action_node(halfword a); + +#endif diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfaction.w b/Build/source/texk/web2c/luatexdir/pdf/pdfaction.w new file mode 100644 index 00000000000..b6d06ebea9b --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdfaction.w @@ -0,0 +1,207 @@ +% pdfaction.w +% +% Copyright 2009-2010 Taco Hoekwater <taco@@luatex.org> + +% 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 <http://www.gnu.org/licenses/>. + +@ @c +#include "ptexlib.h" + +static const char _svn_version[] = + "$Id: pdfaction.w 3571 2010-04-02 13:50:45Z taco $" + "$URL: http://foundry.supelec.fr/svn/luatex/tags/beta-0.60.0/source/texk/web2c/luatexdir/pdf/pdfaction.w $"; + + +@ @c +halfword new_action_node(void) +{ + return new_node(action_node, 0); +} + +@ @c +void delete_action_node(halfword a) +{ + if (pdf_action_type(a) == pdf_action_user) { + delete_token_ref(pdf_action_tokens(a)); + } else { + if (pdf_action_file(a) != null) + delete_token_ref(pdf_action_file(a)); + if (pdf_action_type(a) == pdf_action_page) + delete_token_ref(pdf_action_tokens(a)); + else if (pdf_action_named_id(a) > 0) + delete_token_ref(pdf_action_id(a)); + } + free_node(a, pdf_action_size); +} + +@ read an action specification +@c +halfword scan_action(PDF pdf) +{ + int p; + (void) pdf; + p = new_action_node(); + if (scan_keyword("user")) + set_pdf_action_type(p, pdf_action_user); + else if (scan_keyword("goto")) + set_pdf_action_type(p, pdf_action_goto); + else if (scan_keyword("thread")) + set_pdf_action_type(p, pdf_action_thread); + else + pdf_error("ext1", "action type missing"); + if (pdf_action_type(p) == pdf_action_user) { + scan_pdf_ext_toks(); + set_pdf_action_tokens(p, def_ref); + return p; + } + if (scan_keyword("file")) { + scan_pdf_ext_toks(); + set_pdf_action_file(p, def_ref); + } + if (scan_keyword("page")) { + if (pdf_action_type(p) != pdf_action_goto) + pdf_error("ext1", "only GoTo action can be used with `page'"); + set_pdf_action_type(p, pdf_action_page); + scan_int(); + if (cur_val <= 0) + pdf_error("ext1", "page number must be positive"); + set_pdf_action_id(p, cur_val); + set_pdf_action_named_id(p, 0); + scan_pdf_ext_toks(); + set_pdf_action_tokens(p, def_ref); + } else if (scan_keyword("name")) { + scan_pdf_ext_toks(); + set_pdf_action_named_id(p, 1); + set_pdf_action_id(p, def_ref); + } else if (scan_keyword("num")) { + if ((pdf_action_type(p) == pdf_action_goto) && + (pdf_action_file(p) != null)) + pdf_error("ext1", + "`goto' option cannot be used with both `file' and `num'"); + scan_int(); + if (cur_val <= 0) + pdf_error("ext1", "num identifier must be positive"); + set_pdf_action_named_id(p, 0); + set_pdf_action_id(p, cur_val); + } else { + pdf_error("ext1", "identifier type missing"); + } + if (scan_keyword("newwindow")) { + set_pdf_action_new_window(p, pdf_window_new); + /* Scan an optional space */ + get_x_token(); + if (cur_cmd != spacer_cmd) + back_input(); + } else if (scan_keyword("nonewwindow")) { + set_pdf_action_new_window(p, pdf_window_nonew); + /* Scan an optional space */ + get_x_token(); + if (cur_cmd != spacer_cmd) + back_input(); + } else { + set_pdf_action_new_window(p, pdf_window_notset); + } + if ((pdf_action_new_window(p) > pdf_window_notset) && + (((pdf_action_type(p) != pdf_action_goto) && + (pdf_action_type(p) != pdf_action_page)) || + (pdf_action_file(p) == null))) + pdf_error("ext1", + "`newwindow'/`nonewwindow' must be used with `goto' and `file' option"); + return p; +} + +@ write an action specification +@c +void write_action(PDF pdf, halfword p) +{ + char *s; + int d = 0; + if (pdf_action_type(p) == pdf_action_user) { + pdf_print_toks_ln(pdf, pdf_action_tokens(p)); + return; + } + pdf_printf(pdf, "<< "); + if (pdf_action_file(p) != null) { + pdf_printf(pdf, "/F "); + s = tokenlist_to_cstring(pdf_action_file(p), true, NULL); + pdf_print_str(pdf, s); + xfree(s); + pdf_printf(pdf, " "); + if (pdf_action_new_window(p) > pdf_window_notset) { + pdf_printf(pdf, "/NewWindow "); + if (pdf_action_new_window(p) == pdf_window_new) + pdf_printf(pdf, "true "); + else + pdf_printf(pdf, "false "); + } + } + switch (pdf_action_type(p)) { + case pdf_action_page: + if (pdf_action_file(p) == null) { + pdf_printf(pdf, "/S /GoTo /D ["); + pdf_print_int(pdf, + get_obj(pdf, obj_type_page, pdf_action_id(p), false)); + pdf_printf(pdf, " 0 R"); + } else { + pdf_printf(pdf, "/S /GoToR /D ["); + pdf_print_int(pdf, pdf_action_id(p) - 1); + } + { + char *tokstr = + tokenlist_to_cstring(pdf_action_tokens(p), true, NULL); + pdf_printf(pdf, " %s]", tokstr); + xfree(tokstr); + } + break; + case pdf_action_goto: + if (pdf_action_file(p) == null) { + pdf_printf(pdf, "/S /GoTo "); + d = get_obj(pdf, obj_type_dest, pdf_action_id(p), + pdf_action_named_id(p)); + } else { + pdf_printf(pdf, "/S /GoToR "); + } + if (pdf_action_named_id(p) > 0) { + char *tokstr = tokenlist_to_cstring(pdf_action_id(p), true, NULL); + pdf_str_entry(pdf, "D", tokstr); + xfree(tokstr); + } else if (pdf_action_file(p) == null) { + pdf_indirect(pdf, "D", d); + } else { + pdf_error("ext4", + "`goto' option cannot be used with both `file' and `num'"); + } + break; + case pdf_action_thread: + pdf_printf(pdf, "/S /Thread "); + if (pdf_action_file(p) == null) { + d = get_obj(pdf, obj_type_thread, pdf_action_id(p), + pdf_action_named_id(p)); + if (pdf_action_named_id(p) > 0) { + char *tokstr = + tokenlist_to_cstring(pdf_action_id(p), true, NULL); + pdf_str_entry(pdf, "D", tokstr); + xfree(tokstr); + } else if (pdf_action_file(p) == null) { + pdf_indirect(pdf, "D", d); + } else { + pdf_int_entry(pdf, "D", pdf_action_id(p)); + } + } + break; + } + pdf_printf(pdf, " >>\n"); +} diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfannot.h b/Build/source/texk/web2c/luatexdir/pdf/pdfannot.h new file mode 100644 index 00000000000..6372195d16b --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdfannot.h @@ -0,0 +1,37 @@ +/* pdfannot.h + + Copyright 2009 Taco Hoekwater <taco@luatex.org> + + 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 <http://www.gnu.org/licenses/>. */ + +/* $Id: pdfannot.h 2772 2009-07-07 22:16:42Z hhenkel $ */ + +#ifndef PDFANNOT_H +# define PDFANNOT_H + +/* data structure of annotations; words 1..4 represent the coordinates of the annotation */ + +# define obj_annot_ptr obj_aux /* pointer to corresponding whatsit node */ + +# define set_pdf_annot_objnum(A,B) pdf_annot_objnum(A)=B +# define set_pdf_annot_data(A,B) pdf_annot_data(A)=B + +extern void do_annot(PDF pdf, halfword p, halfword parent_box, scaledpos cur); +extern void new_annot_whatsit(small_number w); + +extern void scan_annot(PDF pdf); + +#endif diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfannot.w b/Build/source/texk/web2c/luatexdir/pdf/pdfannot.w new file mode 100644 index 00000000000..25830556762 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdfannot.w @@ -0,0 +1,99 @@ +% pdfannot.w + +% Copyright 2009-2010 Taco Hoekwater <taco@@luatex.org> + +% 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 <http://www.gnu.org/licenses/>. + +@ @c +static const char _svn_version[] = + "$Id: pdfannot.w 3571 2010-04-02 13:50:45Z taco $" + "$URL: http://foundry.supelec.fr/svn/luatex/tags/beta-0.60.0/source/texk/web2c/luatexdir/pdf/pdfannot.w $"; + +#include "ptexlib.h" + +@ @c +#define tail cur_list.tail_field + +void do_annot(PDF pdf, halfword p, halfword parent_box, scaledpos cur) +{ + scaled_whd alt_rule; + if (!is_shipping_page) + pdf_error("ext4", "annotations cannot be inside an XForm"); + if (doing_leaders) + return; + if (is_obj_scheduled(pdf, pdf_annot_objnum(p))) { + pdf_create_obj(pdf, obj_type_annot, pdf->sys_obj_ptr + 1); + obj_annot_ptr(pdf, pdf_annot_objnum(p)) = p; + pdf_annot_objnum(p) = pdf->sys_obj_ptr; + } + alt_rule.wd = width(p); + alt_rule.ht = height(p); + alt_rule.dp = depth(p); + set_rect_dimens(pdf, p, parent_box, cur, alt_rule, 0); + obj_annot_ptr(pdf, pdf_annot_objnum(p)) = p; + addto_page_resources(pdf, obj_type_annot, pdf_annot_objnum(p)); +} + +@ create a new whatsit node for annotation +@c +void new_annot_whatsit(small_number w) +{ + scaled_whd alt_rule; + new_whatsit(w); + alt_rule = scan_alt_rule(); /* scans |<rule spec>| to |alt_rule| */ + set_width(tail, alt_rule.wd); + set_height(tail, alt_rule.ht); + set_depth(tail, alt_rule.dp); + if ((w == pdf_thread_node) || (w == pdf_start_thread_node)) { + if (scan_keyword("attr")) { + scan_pdf_ext_toks(); + set_pdf_thread_attr(tail, def_ref); + } else { + set_pdf_thread_attr(tail, null); + } + } +} + +@ @c +void scan_annot(PDF pdf) +{ + int k; + if (scan_keyword("reserveobjnum")) { + pdf_create_obj(pdf, obj_type_annot, pdf->sys_obj_ptr + 1); + k = pdf->sys_obj_ptr; + /* Scan an optional space */ + get_x_token(); + if (cur_cmd != spacer_cmd) + back_input(); + } else { + if (scan_keyword("useobjnum")) { + scan_int(); + k = cur_val; + check_obj_exists(pdf, obj_type_annot, k); + if (obj_annot_ptr(pdf, k) != 0) + pdf_error("ext1", "annot object in use"); + } else { + pdf_create_obj(pdf, obj_type_annot, pdf->sys_obj_ptr + 1); + k = pdf->sys_obj_ptr; + } + new_annot_whatsit(pdf_annot_node); + obj_annot_ptr(pdf, k) = tail; + set_pdf_annot_objnum(tail, k); + scan_pdf_ext_toks(); + set_pdf_annot_data(tail, def_ref); + } + pdf_last_annot = k; +} diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfcolorstack.h b/Build/source/texk/web2c/luatexdir/pdf/pdfcolorstack.h new file mode 100644 index 00000000000..20d8e436146 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdfcolorstack.h @@ -0,0 +1,44 @@ +/* pdfcolorstack.h + + Copyright 2009 Taco Hoekwater <taco@luatex.org> + + 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 <http://www.gnu.org/licenses/>. */ + +/* $Id: pdfcolorstack.h 3261 2009-12-18 11:38:21Z taco $ */ + +#ifndef PDFCOLORSTACK_H +# define PDFCOLORSTACK_H + +# define set_pdf_colorstack_stack(A,B) pdf_colorstack_stack(A)=B +# define set_pdf_colorstack_cmd(A,B) pdf_colorstack_cmd(A)=B +# define set_pdf_colorstack_data(A,B) pdf_colorstack_data(A)=B + +/* remember shipout mode: page/form */ +extern boolean page_mode; + +# define STACK_INCREMENT 8 + +int newcolorstack(int s, int literal_mode, boolean pagestart); +int colorstackused(void); +int colorstackpop(int colstack_no); +int colorstackcurrent(int colstack_no); +int colorstackskippagestart(int colstack_no); +void colorstackpagestart(void); + +extern void pdf_out_colorstack(PDF pdf, halfword p); +extern void pdf_out_colorstack_startpage(PDF pdf); + +#endif diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfcolorstack.w b/Build/source/texk/web2c/luatexdir/pdf/pdfcolorstack.w new file mode 100644 index 00000000000..1e472c7f713 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdfcolorstack.w @@ -0,0 +1,386 @@ +% pdfcolorstack.w +% +% Copyright 2009-2010 Taco Hoekwater <taco@@luatex.org> + +% 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 <http://www.gnu.org/licenses/>. + +@ @c +#include "ptexlib.h" + +static const char _svn_version[] = + "$Id: pdfcolorstack.w 3571 2010-04-02 13:50:45Z taco $" + "$URL: http://foundry.supelec.fr/svn/luatex/tags/beta-0.60.0/source/texk/web2c/luatexdir/pdf/pdfcolorstack.w $"; + + +@* Color Stack and Matrix Transformation Support. + + +@ In the following array and especially stack data structures are used. + +They have the following properties: + + \item{-} They automatically grow dynamically. + \item{-} The size never decreases. + \item{-} The variable with name ending in "size" contains the number how many + entries the data structure can hold. + \item{-} The variable with name ending in "used" contains the number of + actually used entries. + \item{-} Memory of strings in stack entries must be allocated and + freed if the stack is cleared. + + +@ Color Stack +@c +#define MAX_COLORSTACKS 32768 +/* The colorstack number is stored in two bytes (info field of the node) */ +/* Condition (newcolorstack): |MAX_COLORSTACKS mod STACK_INCREMENT = 0| */ + +#define COLOR_DEFAULT "0 g 0 G" +/* |literal_mode|s, see pdftex.web */ +#define SET_ORIGIN 0 +#define DIRECT_PAGE 1 +#define DIRECT_ALWAYS 2 + +/* remember shipout mode: page/form */ +boolean page_mode; + +typedef struct { + char **page_stack; + char **form_stack; + char *page_current; + char *form_current; + char *form_init; + int page_size; + int form_size; + int page_used; + int form_used; + int literal_mode; + boolean page_start; +} colstack_type; + +static colstack_type *colstacks = NULL; +static int colstacks_size = 0; +static int colstacks_used = 0; + +@ Initialization is done, if the color stacks are used, + |init_colorstacks()| is defined as macro to avoid unnecessary + procedure calls. +@c +#define init_colorstacks() if (colstacks_size == 0) colstacks_first_init(); + +void colstacks_first_init(void) +{ + colstacks_size = STACK_INCREMENT; + colstacks = xtalloc((unsigned) colstacks_size, colstack_type); + colstacks_used = 1; + colstacks[0].page_stack = NULL; + colstacks[0].form_stack = NULL; + colstacks[0].page_size = 0; + colstacks[0].form_size = 0; + colstacks[0].page_used = 0; + colstacks[0].form_used = 0; + colstacks[0].page_current = xstrdup(COLOR_DEFAULT); + colstacks[0].form_current = xstrdup(COLOR_DEFAULT); + colstacks[0].form_init = xstrdup(COLOR_DEFAULT); + colstacks[0].literal_mode = DIRECT_ALWAYS; + colstacks[0].page_start = true; +} + +@ @c +int colorstackused(void) +{ + init_colorstacks(); + return colstacks_used; +} + +@ |newcolorstack()| + A new color stack is setup with the given parameters. + The stack number is returned or -1 in case of error (no room). +@c +int newcolorstack(int s, int literal_mode, boolean page_start) +{ + colstack_type *colstack; + int colstack_num; + char *str; + + init_colorstacks(); + + /* make room */ + if (colstacks_used == MAX_COLORSTACKS) { + return -1; + } + if (colstacks_used == colstacks_size) { + colstacks_size += STACK_INCREMENT; + /* If |(MAX_COLORSTACKS mod STACK_INCREMENT = 0)| then we don't + need to check the case that size overruns |MAX_COLORSTACKS|. */ + colstacks = + xreallocarray(colstacks, colstack_type, (unsigned) colstacks_size); + } + /* claim new color stack */ + colstack_num = colstacks_used++; + colstack = &colstacks[colstack_num]; + /* configure the new color stack */ + colstack->page_stack = NULL; + colstack->form_stack = NULL; + colstack->page_size = 0; + colstack->page_used = 0; + colstack->form_size = 0; + colstack->form_used = 0; + colstack->literal_mode = literal_mode; + colstack->page_start = page_start; + str = makecstring(s); + if (*str == 0) { + colstack->page_current = NULL; + colstack->form_current = NULL; + colstack->form_init = NULL; + } else { + colstack->page_current = xstrdup(str); + colstack->form_current = xstrdup(str); + colstack->form_init = xstrdup(str); + } + free(str); + return colstack_num; +} + +@ @c +#define get_colstack(n) (&colstacks[n]) + +@ Puts a string on top of the string pool and updates |pool_ptr|. +@c +static void put_cstring_on_str_pool(char *str) +{ + int save_selector = selector; + selector = new_string; + if (str == NULL || *str == 0) { + return; + } + tprint(str); + selector = save_selector; +} + +@ @c +int colorstackset(int colstack_no, str_number s) +{ + colstack_type *colstack = get_colstack(colstack_no); + + if (page_mode) { + xfree(colstack->page_current); + colstack->page_current = makecstring(s); + } else { + xfree(colstack->form_current); + colstack->form_current = makecstring(s); + } + return colstack->literal_mode; +} + +@ @c +int colorstackcurrent(int colstack_no) +{ + colstack_type *colstack = get_colstack(colstack_no); + + if (page_mode) { + put_cstring_on_str_pool(colstack->page_current); + } else { + put_cstring_on_str_pool(colstack->form_current); + } + return colstack->literal_mode; +} + +@ @c +static int colorstackpush(int colstack_no, str_number s) +{ + colstack_type *colstack = get_colstack(colstack_no); + char *str; + if (page_mode) { + if (colstack->page_used == colstack->page_size) { + colstack->page_size += STACK_INCREMENT; + colstack->page_stack = xretalloc(colstack->page_stack, + (unsigned) colstack->page_size, + char *); + } + colstack->page_stack[colstack->page_used++] = colstack->page_current; + str = makecstring(s); + if (*str == 0) { + colstack->page_current = NULL; + } else { + colstack->page_current = xstrdup(str); + } + free(str); + } else { + if (colstack->form_used == colstack->form_size) { + colstack->form_size += STACK_INCREMENT; + colstack->form_stack = xretalloc(colstack->form_stack, + (unsigned) colstack->form_size, + char *); + } + colstack->form_stack[colstack->form_used++] = colstack->form_current; + str = makecstring(s); + if (*str == 0) { + colstack->form_current = NULL; + } else { + colstack->form_current = xstrdup(str); + } + free(str); + } + return colstack->literal_mode; +} + +@ @c +int colorstackpop(int colstack_no) +{ + colstack_type *colstack = get_colstack(colstack_no); + + if (page_mode) { + if (colstack->page_used == 0) { + pdftex_warn("pop empty color page stack %u", + (unsigned int) colstack_no); + return colstack->literal_mode; + } + xfree(colstack->page_current); + colstack->page_current = colstack->page_stack[--colstack->page_used]; + put_cstring_on_str_pool(colstack->page_current); + } else { + if (colstack->form_used == 0) { + pdftex_warn("pop empty color form stack %u", + (unsigned int) colstack_no); + return colstack->literal_mode; + } + xfree(colstack->form_current); + colstack->form_current = colstack->form_stack[--colstack->form_used]; + put_cstring_on_str_pool(colstack->form_current); + } + return colstack->literal_mode; +} + +@ @c +void colorstackpagestart(void) +{ + int i, j; + colstack_type *colstack; + + if (page_mode) { + /* see procedure |pdf_out_colorstack_startpage| */ + return; + } + + for (i = 0; i < colstacks_used; i++) { + colstack = &colstacks[i]; + for (j = 0; j < colstack->form_used; j++) { + xfree(colstack->form_stack[j]); + } + colstack->form_used = 0; + xfree(colstack->form_current); + if (colstack->form_init == NULL) { + colstack->form_current = NULL; + } else { + colstack->form_current = xstrdup(colstack->form_init); + } + } +} + +@ @c +int colorstackskippagestart(int colstack_no) +{ + colstack_type *colstack = get_colstack(colstack_no); + + if (!colstack->page_start) { + return 1; + } + if (colstack->page_current == NULL) { + return 0; + } + if (strcmp(COLOR_DEFAULT, colstack->page_current) == 0) { + return 2; + } + return 0; +} + + +@ @c +void pdf_out_colorstack(PDF pdf, halfword p) +{ + int old_setting; + str_number s; + int cmd; + int stack_no; + int literal_mode; + cmd = pdf_colorstack_cmd(p); + stack_no = pdf_colorstack_stack(p); + literal_mode = 0; + if (stack_no >= colorstackused()) { + tprint_nl(""); + tprint("Color stack "); + print_int(stack_no); + tprint(" is not initialized for use!"); + tprint_nl(""); + return; + } + switch (cmd) { + case colorstack_set: + case colorstack_push: + old_setting = selector; + selector = new_string; + show_token_list(token_link(pdf_colorstack_data(p)), null, -1); + selector = old_setting; + s = make_string(); + if (cmd == colorstack_set) + literal_mode = colorstackset(stack_no, s); + else + literal_mode = colorstackpush(stack_no, s); + if (str_length(s) > 0) + pdf_literal(pdf, s, literal_mode, false); + flush_str(s); + return; + break; + case colorstack_pop: + literal_mode = colorstackpop(stack_no); + break; + case colorstack_current: + literal_mode = colorstackcurrent(stack_no); + break; + default: + break; + } + if (cur_length > 0) { + s = make_string(); + pdf_literal(pdf, s, literal_mode, false); + flush_str(s); + } +} + +@ @c +void pdf_out_colorstack_startpage(PDF pdf) +{ + int i; + int max; + int start_status; + int literal_mode; + str_number s; + i = 0; + max = colorstackused(); + while (i < max) { + start_status = colorstackskippagestart(i); + if (start_status == 0) { + literal_mode = colorstackcurrent(i); + if (cur_length > 0) { + s = make_string(); + pdf_literal(pdf, s, literal_mode, false); + flush_str(s); + } + } + incr(i); + } +} diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfdest.h b/Build/source/texk/web2c/luatexdir/pdf/pdfdest.h new file mode 100644 index 00000000000..0e5d9dca457 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdfdest.h @@ -0,0 +1,66 @@ +/* pdfdest.h + + Copyright 2009 Taco Hoekwater <taco@luatex.org> + + 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 <http://www.gnu.org/licenses/>. */ + +/* $Id: pdfdest.h 3386 2010-01-26 06:41:37Z taco $ */ + +#ifndef PDFDEST_H +# define PDFDEST_H + +/* types of destinations */ + +typedef enum { + pdf_dest_xyz = 0, + pdf_dest_fit = 1, + pdf_dest_fith = 2, + pdf_dest_fitv = 3, + pdf_dest_fitb = 4, + pdf_dest_fitbh = 5, + pdf_dest_fitbv = 6, + pdf_dest_fitr = 7 +} pdf_destination_types; + +/* max number of kids for balanced trees */ +# define name_tree_kids_max 32 /* max number of kids of node of name tree for name destinations */ + +/* data structure of destinations */ + +# define obj_dest_ptr obj_aux /* pointer to |pdf_dest_node| */ +# define set_obj_dest_ptr(pdf,A,B) obj_dest_ptr(pdf,A)=B + +# define set_pdf_dest_id(A,B) pdf_dest_id(A)=B +# define set_pdf_dest_named_id(A,B) pdf_dest_named_id(A)=B +# define set_pdf_dest_type(A,B) pdf_dest_type(A)=B +# define set_pdf_dest_xyz_zoom(A,B) pdf_dest_xyz_zoom(A)=B + +# define inf_dest_names_size 1000 /* min size of the destination names table for PDF output */ +# define sup_dest_names_size 131072 /* max size of the destination names table for PDF output */ + +extern void append_dest_name(PDF, char *, int); +extern void do_dest(PDF pdf, halfword p, halfword parent_box, scaledpos cur); +extern void warn_dest_dup(int id, small_number byname, const char *s1, + const char *s2); + +extern void write_out_pdf_mark_destinations(PDF); +extern void scan_pdfdest(PDF); +extern void init_dest_names(PDF); +extern void sort_dest_names(PDF); +extern int output_name_tree(PDF); + + +#endif diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfdest.w b/Build/source/texk/web2c/luatexdir/pdf/pdfdest.w new file mode 100644 index 00000000000..2f53f77dca5 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdfdest.w @@ -0,0 +1,417 @@ +% pdfdest.w + +% Copyright 2009-2010 Taco Hoekwater <taco@@luatex.org> + +% 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 <http://www.gnu.org/licenses/>. + +@ @c +static const char _svn_version[] = + "$Id: pdfdest.w 3571 2010-04-02 13:50:45Z taco $" + "$URL: http://foundry.supelec.fr/svn/luatex/tags/beta-0.60.0/source/texk/web2c/luatexdir/pdf/pdfdest.w $"; + +#include "ptexlib.h" + +@ @c +#define pdf_dest_margin dimen_par(pdf_dest_margin_code) + +@ Here we implement subroutines for work with objects and related things. +Some of them are used in former parts too, so we need to declare them +forward. + +@c +void init_dest_names(PDF pdf) +{ + pdf->dest_names_size = inf_dest_names_size; + pdf->dest_names = xmallocarray(dest_name_entry, inf_dest_names_size); /* will grow dynamically */ +} + +@ @c +void append_dest_name(PDF pdf, char *s, int n) +{ + int a; + if (pdf->dest_names_ptr == sup_dest_names_size) + overflow("number of destination names (dest_names_size)", + (unsigned) pdf->dest_names_size); + if (pdf->dest_names_ptr == pdf->dest_names_size) { + a = pdf->dest_names_size / 5; + if (pdf->dest_names_size < sup_dest_names_size - a) + pdf->dest_names_size = pdf->dest_names_size + a; + else + pdf->dest_names_size = sup_dest_names_size; + pdf->dest_names = + xreallocarray(pdf->dest_names, dest_name_entry, + (unsigned) pdf->dest_names_size); + } + pdf->dest_names[pdf->dest_names_ptr].objname = xstrdup(s); + pdf->dest_names[pdf->dest_names_ptr].objnum = n; + pdf->dest_names_ptr++; +} + + +@ When a destination is created we need to check whether another destination +with the same identifier already exists and give a warning if needed. + +@c +void warn_dest_dup(int id, small_number byname, const char *s1, const char *s2) +{ + pdf_warning(s1, "destination with the same identifier (", false, false); + if (byname > 0) { + tprint("name"); + print_mark(id); + } else { + tprint("num"); + print_int(id); + } + tprint(") "); + tprint(s2); + print_ln(); + show_context(); +} + + +@ @c +void do_dest(PDF pdf, halfword p, halfword parent_box, scaledpos cur) +{ + scaledpos pos = pdf->posstruct->pos; + scaled_whd alt_rule; + int k; + if (!is_shipping_page) + pdf_error("ext4", "destinations cannot be inside an XForm"); + if (doing_leaders) + return; + k = get_obj(pdf, obj_type_dest, pdf_dest_id(p), pdf_dest_named_id(p)); + if (obj_dest_ptr(pdf, k) != null) { + warn_dest_dup(pdf_dest_id(p), (small_number) pdf_dest_named_id(p), + "ext4", "has been already used, duplicate ignored"); + return; + } + obj_dest_ptr(pdf, k) = p; + addto_page_resources(pdf, obj_type_dest, k); + alt_rule.wd = width(p); + alt_rule.ht = height(p); + alt_rule.dp = depth(p); + switch (pdf_dest_type(p)) { + case pdf_dest_xyz: + if (matrixused()) + set_rect_dimens(pdf, p, parent_box, cur, alt_rule, pdf_dest_margin); + else { + pdf_ann_left(p) = pos.h; + pdf_ann_top(p) = pos.v; + } + break; + case pdf_dest_fith: + case pdf_dest_fitbh: + if (matrixused()) + set_rect_dimens(pdf, p, parent_box, cur, alt_rule, pdf_dest_margin); + else + pdf_ann_top(p) = pos.v; + break; + case pdf_dest_fitv: + case pdf_dest_fitbv: + if (matrixused()) + set_rect_dimens(pdf, p, parent_box, cur, alt_rule, pdf_dest_margin); + else + pdf_ann_left(p) = pos.h; + break; + case pdf_dest_fit: + case pdf_dest_fitb: + break; + case pdf_dest_fitr: + set_rect_dimens(pdf, p, parent_box, cur, alt_rule, pdf_dest_margin); + } +} + +@ @c +void write_out_pdf_mark_destinations(PDF pdf) +{ + pdf_object_list *k; + if ((k = get_page_resources_list(pdf, obj_type_dest)) != NULL) { + while (k != NULL) { + if (is_obj_written(pdf, k->info)) { + pdf_error("ext5", + "destination has been already written (this shouldn't happen)"); + } else { + int i; + i = obj_dest_ptr(pdf, k->info); + if (pdf_dest_named_id(i) > 0) { + pdf_begin_dict(pdf, k->info, 1); + pdf_printf(pdf, "/D "); + } else { + pdf_begin_obj(pdf, k->info, 1); + } + pdf_out(pdf, '['); + pdf_print_int(pdf, pdf->last_page); + pdf_printf(pdf, " 0 R "); + switch (pdf_dest_type(i)) { + case pdf_dest_xyz: + pdf_printf(pdf, "/XYZ "); + pdf_print_mag_bp(pdf, pdf_ann_left(i)); + pdf_out(pdf, ' '); + pdf_print_mag_bp(pdf, pdf_ann_top(i)); + pdf_out(pdf, ' '); + if (pdf_dest_xyz_zoom(i) == null) { + pdf_printf(pdf, "null"); + } else { + pdf_print_int(pdf, pdf_dest_xyz_zoom(i) / 1000); + pdf_out(pdf, '.'); + pdf_print_int(pdf, (pdf_dest_xyz_zoom(i) % 1000)); + } + break; + case pdf_dest_fit: + pdf_printf(pdf, "/Fit"); + break; + case pdf_dest_fith: + pdf_printf(pdf, "/FitH "); + pdf_print_mag_bp(pdf, pdf_ann_top(i)); + break; + case pdf_dest_fitv: + pdf_printf(pdf, "/FitV "); + pdf_print_mag_bp(pdf, pdf_ann_left(i)); + break; + case pdf_dest_fitb: + pdf_printf(pdf, "/FitB"); + break; + case pdf_dest_fitbh: + pdf_printf(pdf, "/FitBH "); + pdf_print_mag_bp(pdf, pdf_ann_top(i)); + break; + case pdf_dest_fitbv: + pdf_printf(pdf, "/FitBV "); + pdf_print_mag_bp(pdf, pdf_ann_left(i)); + break; + case pdf_dest_fitr: + pdf_printf(pdf, "/FitR "); + pdf_print_rect_spec(pdf, i); + break; + default: + pdf_error("ext5", "unknown dest type"); + break; + } + pdf_printf(pdf, "]\n"); + if (pdf_dest_named_id(i) > 0) + pdf_end_dict(pdf); + else + pdf_end_obj(pdf); + } + k = k->link; + } + } +} + +@ @c +void scan_pdfdest(PDF pdf) +{ + halfword q; + int k; + str_number i; + scaled_whd alt_rule; + q = cur_list.tail_field; + new_whatsit(pdf_dest_node); + if (scan_keyword("num")) { + scan_int(); + if (cur_val <= 0) + pdf_error("ext1", "num identifier must be positive"); + if (cur_val > max_halfword) + pdf_error("ext1", "number too big"); + set_pdf_dest_id(cur_list.tail_field, cur_val); + set_pdf_dest_named_id(cur_list.tail_field, 0); + } else if (scan_keyword("name")) { + scan_pdf_ext_toks(); + set_pdf_dest_id(cur_list.tail_field, def_ref); + set_pdf_dest_named_id(cur_list.tail_field, 1); + } else { + pdf_error("ext1", "identifier type missing"); + } + if (scan_keyword("xyz")) { + set_pdf_dest_type(cur_list.tail_field, pdf_dest_xyz); + if (scan_keyword("zoom")) { + scan_int(); + if (cur_val > max_halfword) + pdf_error("ext1", "number too big"); + set_pdf_dest_xyz_zoom(cur_list.tail_field, cur_val); + } else { + set_pdf_dest_xyz_zoom(cur_list.tail_field, null); + } + } else if (scan_keyword("fitbh")) { + set_pdf_dest_type(cur_list.tail_field, pdf_dest_fitbh); + } else if (scan_keyword("fitbv")) { + set_pdf_dest_type(cur_list.tail_field, pdf_dest_fitbv); + } else if (scan_keyword("fitb")) { + set_pdf_dest_type(cur_list.tail_field, pdf_dest_fitb); + } else if (scan_keyword("fith")) { + set_pdf_dest_type(cur_list.tail_field, pdf_dest_fith); + } else if (scan_keyword("fitv")) { + set_pdf_dest_type(cur_list.tail_field, pdf_dest_fitv); + } else if (scan_keyword("fitr")) { + set_pdf_dest_type(cur_list.tail_field, pdf_dest_fitr); + } else if (scan_keyword("fit")) { + set_pdf_dest_type(cur_list.tail_field, pdf_dest_fit); + } else { + pdf_error("ext1", "destination type missing"); + } + /* Scan an optional space */ + get_x_token(); + if (cur_cmd != spacer_cmd) + back_input(); + + if (pdf_dest_type(cur_list.tail_field) == pdf_dest_fitr) { + alt_rule = scan_alt_rule(); /* scans |<rule spec>| to |alt_rule| */ + set_width(cur_list.tail_field, alt_rule.wd); + set_height(cur_list.tail_field, alt_rule.ht); + set_depth(cur_list.tail_field, alt_rule.dp); + } + if (pdf_dest_named_id(cur_list.tail_field) != 0) { + i = tokens_to_string(pdf_dest_id(cur_list.tail_field)); + k = find_obj(pdf, obj_type_dest, i, true); + flush_str(i); + } else { + k = find_obj(pdf, obj_type_dest, pdf_dest_id(cur_list.tail_field), + false); + } + if ((k != 0) && (obj_dest_ptr(pdf, k) != null)) { + warn_dest_dup(pdf_dest_id(cur_list.tail_field), + (small_number) pdf_dest_named_id(cur_list.tail_field), + "ext4", "has been already used, duplicate ignored"); + flush_node_list(cur_list.tail_field); + cur_list.tail_field = q; + vlink(q) = null; + } +} + +@ sorts |dest_names| by names +@c +static int dest_cmp(const void *a, const void *b) +{ + dest_name_entry aa = *(const dest_name_entry *) a; + dest_name_entry bb = *(const dest_name_entry *) b; + return strcmp(aa.objname, bb.objname); +} + +@ @c +void sort_dest_names(PDF pdf) +{ + qsort(pdf->dest_names, (size_t) pdf->dest_names_ptr, + sizeof(dest_name_entry), dest_cmp); +} + + +@ Output the name tree. The tree nature of the destination list forces the +storing of intermediate data in |obj_info| and |obj_aux| fields, which +is further uglified by the fact that |obj_tab| entries do not accept char +pointers. + +@c +int output_name_tree(PDF pdf) +{ + boolean is_names = true; /* flag for name tree output: is it Names or Kids? */ + int b = 0, j, l; + int k = 0; /* index of current child of |l|; if |k < pdf_dest_names_ptr| + then this is pointer to |dest_names| array; + otherwise it is the pointer to |obj_tab| (object number) */ + int dests = 0; + int names_head = 0, names_tail = 0; + if (pdf->dest_names_ptr == 0) { + goto DONE; + } + sort_dest_names(pdf); + + while (true) { + + do { + pdf_create_obj(pdf, obj_type_others, 0); /* create a new node */ + l = pdf->obj_ptr; + if (b == 0) + b = l; /* first in this level */ + if (names_head == 0) { + names_head = l; + names_tail = l; + } else { + set_obj_link(pdf, names_tail, l); + names_tail = l; + } + set_obj_link(pdf, names_tail, 0); + /* Output the current node in this level */ + pdf_begin_dict(pdf, l, 1); + j = 0; + if (is_names) { + set_obj_start(pdf, l, pdf->dest_names[k].objname); + pdf_printf(pdf, "/Names ["); + do { + pdf_print_str(pdf, pdf->dest_names[k].objname); + pdf_out(pdf, ' '); + pdf_print_int(pdf, pdf->dest_names[k].objnum); + pdf_printf(pdf, " 0 R "); + j++; + k++; + } while (j != name_tree_kids_max && k != pdf->dest_names_ptr); + pdf_remove_last_space(pdf); + pdf_printf(pdf, "]\n"); + set_obj_stop(pdf, l, pdf->dest_names[k - 1].objname); /* for later */ + if (k == pdf->dest_names_ptr) { + is_names = false; + k = names_head; + b = 0; + } + + } else { + set_obj_start(pdf, l, obj_start(pdf, k)); + pdf_printf(pdf, "/Kids ["); + do { + pdf_print_int(pdf, k); + pdf_printf(pdf, " 0 R "); + set_obj_stop(pdf, l, obj_stop(pdf, k)); + k = obj_link(pdf, k); + j++; + } while (j != name_tree_kids_max && k != b + && obj_link(pdf, k) != 0); + pdf_remove_last_space(pdf); + pdf_printf(pdf, "]\n"); + if (k == b) + b = 0; + } + pdf_printf(pdf, "/Limits ["); + pdf_print_str(pdf, obj_start(pdf, l)); + pdf_out(pdf, ' '); + pdf_print_str(pdf, obj_stop(pdf, l)); + pdf_printf(pdf, "]\n"); + pdf_end_dict(pdf); + + + } while (b != 0); + + if (k == l) { + dests = l; + goto DONE; + } + + } + + DONE: + if ((dests != 0) || (pdf_names_toks != null)) { + pdf_new_dict(pdf, obj_type_others, 0, 1); + if (dests != 0) + pdf_indirect_ln(pdf, "Dests", dests); + if (pdf_names_toks != null) { + pdf_print_toks_ln(pdf, pdf_names_toks); + delete_token_ref(pdf_names_toks); + pdf_names_toks = null; + } + pdf_end_dict(pdf); + return pdf->obj_ptr; + } else { + return 0; + } +} diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdffont.h b/Build/source/texk/web2c/luatexdir/pdf/pdffont.h new file mode 100644 index 00000000000..aabe66a4792 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdffont.h @@ -0,0 +1,48 @@ +/* pdffont.h + + Copyright 2010 Taco Hoekwater <taco@luatex.org> + + 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 <http://www.gnu.org/licenses/>. */ + +/* $Id: pdffont.h 3430 2010-02-11 21:42:02Z hhenkel $ */ + +#ifndef PDFFONT_H +# define PDFFONT_H + +extern void output_one_char(PDF pdf, internal_font_number ffi, int c); + +extern void pdf_init_font(PDF pdf, internal_font_number f); +extern internal_font_number pdf_set_font(PDF pdf, internal_font_number f); + +extern int pk_dpi; /* PK pixel density value from \.{texmf.cnf} */ + +extern void copy_expand_params(internal_font_number k, internal_font_number f, + int e); +extern internal_font_number tfm_lookup(char *s, scaled fs, int e); +extern internal_font_number expand_font(internal_font_number f, int e); + +extern void set_expand_params(internal_font_number f, boolean auto_expand, + int stretch_limit, int shrink_limit, + int font_step, int expand_ratio); + +extern void read_expand_font(void); +extern void new_letterspaced_font(small_number a); +extern void make_font_copy(small_number a); + +extern void pdf_include_chars(PDF); +extern void glyph_to_unicode(void); + +#endif diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdffont.w b/Build/source/texk/web2c/luatexdir/pdf/pdffont.w new file mode 100644 index 00000000000..77b817bb61a --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdffont.w @@ -0,0 +1,495 @@ +% pdffont.w + +% Copyright 2009-2010 Taco Hoekwater <taco@@luatex.org> + +% 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 <http://www.gnu.org/licenses/>. + +\def\pdfTeX{pdf\TeX} + +@ @c +static const char _svn_version[] = + "$Id: pdffont.w 3571 2010-04-02 13:50:45Z taco $" + "$URL: http://foundry.supelec.fr/svn/luatex/tags/beta-0.60.0/source/texk/web2c/luatexdir/pdf/pdffont.w $"; + +#include "ptexlib.h" + +@ @c +#define font_id_text(A) cs_text(font_id_base+(A)) /* a frozen font identifier's name */ + +int pk_dpi; /* PK pixel density value from \.{texmf.cnf} */ + + +@ As \pdfTeX{} should also act as a back-end driver, it needs to support virtual +fonts too. Information about virtual fonts can be found in the source of some +\.{DVI}-related programs. + +Whenever we want to write out a character in a font to PDF output, we +should check whether the used character is a virtual or read character. +The |has_packet()| C macro checks for this condition. + + +@ The following code typesets a character to PDF output + +@c +void output_one_char(PDF pdf, internal_font_number ffi, int c) +{ + scaled_whd ci; /* the real width, height and depth of the character */ + ci = get_charinfo_whd(ffi, c); + switch (pdf->posstruct->dir) { + case dir_TLT: + break; + case dir_TRT: + pos_left(ci.wd); + break; + case dir_LTL: + pos_down(ci.ht); + pos_left(ci.wd); + break; + case dir_RTT: + pos_down(ci.ht); + pos_left(ci.wd / 2); + break; + } + if (has_packet(ffi, c)) { + assert(pdf->o_mode == OMODE_PDF); + do_vf_packet(pdf, ffi, c); + } else + backend_out[glyph_node] (pdf, ffi, c); /* |pdf_place_glyph(pdf, ffi, c);| */ +} + +@ Mark |f| as a used font; set |font_used(f)|, |font_size(f)| and |pdf_font_num(f)| +@c +static void pdf_use_font(internal_font_number f, int fontnum) +{ + set_font_used(f, true); + assert((fontnum > 0) || ((fontnum < 0) && (pdf_font_num(-fontnum) > 0))); + set_pdf_font_num(f, fontnum); +} + +@ To set PDF font we need to find out fonts with the same name, because \TeX\ +can load the same font several times for various sizes. For such fonts we +define only one font resource. The array |pdf_font_num| holds the object +number of font resource. A negative value of an entry of |pdf_font_num| +indicates that the corresponding font shares the font resource with the font + +@c +#define same(n,f,k) (n(f) != NULL && n(k) != NULL && strcmp(n(f), n(k)) == 0) + +static boolean font_shareable(internal_font_number f, internal_font_number k) +{ + int ret = 0; + internal_font_number b; + /* For some lua-loaded (for instance AFM) fonts, it is normal to have + a zero cidregistry, and such fonts do not have a fontmap entry yet + at this point, so the test should use the other branch */ + if (font_cidregistry(f) == NULL && font_cidregistry(k) == NULL && + font_encodingbytes(f) != 2 && font_encodingbytes(k) != 2) { + if (font_map(k) != NULL && + font_map(f) != NULL && + (same(font_name, k, f) || + (font_auto_expand(f) && + (b = pdf_font_blink(f)) != 0 && same(font_name, k, b)))) { + ret = 1; + } +#ifdef DEBUG + printf("\nfont_shareable(%d:%d, %d:%d): => %d\n", f, pdf_font_blink(f), + k, pdf_font_blink(k), ret); +#endif + } else { + if ((same(font_filename, k, f) && same(font_fullname, k, f)) + || (font_auto_expand(f) + && (b = pdf_font_blink(f)) != 0 && same(font_name, k, b))) { + ret = 1; + } +#ifdef DEBUG + printf("\nfont_shareable(%d:%s:%s,%d:%s:%s): => %d\n", + f, font_filename(f), font_fullname(f), + k, font_filename(k), font_fullname(k), ret); +#endif + } + return ret; +} + +@ create a font object +@c +void pdf_init_font(PDF pdf, internal_font_number f) +{ + internal_font_number k, b; + fm_entry *fm; + int i; + assert(!font_used(f)); + + /* if |f| is auto expanded then ensure the base font is initialized */ + + if (font_auto_expand(f) && ((b = pdf_font_blink(f)) != 0)) { + if (!font_used(b)) + pdf_init_font(pdf, b); + set_font_map(f, font_map(b)); + /* propagate slant and extend from unexpanded base font */ + set_font_slant(f, font_slant(b)); + set_font_extend(f, font_extend(b)); + } + /* check whether |f| can share the font object with some |k|: we have 2 cases + here: 1) |f| and |k| have the same tfm name (so they have been loaded at + different sizes, eg 'cmr10' and 'cmr10 at 11pt'); 2) |f| has been auto + expanded from |k| + */ + + /* take over slant and extend from map entry, if not already set; + this should also be the only place where getfontmap() may be called. */ + + fm = getfontmap(font_name(f)); + if (font_map(f) == NULL && fm != NULL) { + font_map(f) = fm; + if (is_slantset(fm)) + font_slant(f) = fm->slant; + if (is_extendset(fm)) + font_extend(f) = fm->extend; + } + i = pdf->head_tab[obj_type_font]; + while (i != 0) { + k = obj_info(pdf, i); + if (font_shareable(f, k)) { + assert(pdf_font_num(k) != 0); + if (pdf_font_num(k) < 0) + pdf_use_font(f, pdf_font_num(k)); + else + pdf_use_font(f, -k); + return; + } + i = obj_link(pdf, i); + } + /* create a new font object for |f| */ + pdf_create_obj(pdf, obj_type_font, f); + pdf_use_font(f, pdf->obj_ptr); +} + +@ set the actual font on PDF page +@c +internal_font_number pdf_set_font(PDF pdf, internal_font_number f) +{ + int ff; /* for use with |set_ff| */ + if (!font_used(f)) + pdf_init_font(pdf, f); + /* + set |ff| to the tfm number of the base font sharing the font object with |f|; + |ff| is either |f| itself (then it is its own base font), + or some font with the same tfm name at different size and/or expansion. + */ + ff = pdf_font_num(f) < 0 ? -pdf_font_num(f) : f; /* aka |set_ff(f)| */ + addto_page_resources(pdf, obj_type_font, ff); + return ff; +} + +@ Here come some subroutines to deal with expanded fonts for HZ-algorithm. +@c +void copy_expand_params(internal_font_number k, internal_font_number f, int e) +{ /* set expansion-related parameters for an expanded font |k|, based on the base + font |f| and the expansion amount |e| */ + set_font_expand_ratio(k, e); + set_font_step(k, font_step(f)); + set_font_auto_expand(k, font_auto_expand(f)); + set_pdf_font_blink(k, f); +} + +@ return 1 == identical +@c +static boolean cmp_font_name(int id, char *tt) +{ + char *tid; + if (!is_valid_font(id)) + return 0; + tid = font_name(id); + if (tt == NULL && tid == NULL) + return 1; + if (tt == NULL || tid == NULL || strcmp(tid, tt) != 0) + return 0; + return 1; +} + +@ @c +internal_font_number tfm_lookup(char *s, scaled fs, int e) +{ /* looks up for a TFM with name |s| loaded at |fs| size; if found then flushes |s| */ + internal_font_number k; + if (fs != 0) { + for (k = 1; k <= max_font_id(); k++) { + if (cmp_font_name(k, s) && font_size(k) == fs + && font_expand_ratio(k) == e) { + return k; + } + } + } else { + for (k = 1; k <= max_font_id(); k++) { + if (cmp_font_name(k, s) && font_expand_ratio(k) == e) { + return k; + } + } + } + return null_font; +} + +@ @c +static internal_font_number load_expand_font(internal_font_number f, int e) +{ /* loads font |f| expanded by |e| thousandths into font memory; |e| is nonzero + and is a multiple of |font_step(f)| */ + internal_font_number k; + k = tfm_lookup(font_name(f), font_size(f), e); + if (k == null_font) { + if (font_auto_expand(f)) { + k = auto_expand_font(f, e); + font_id_text(k) = font_id_text(f); + } else { + k = read_font_info(null_cs, font_name(f), font_size(f), + font_natural_dir(f)); + } + } + copy_expand_params(k, f, e); + return k; +} + +@ @c +static int fix_expand_value(internal_font_number f, int e) +{ /* return the multiple of |font_step(f)| that is nearest to |e| */ + int step; + int max_expand; + boolean neg; + if (e == 0) + return 0; + if (e < 0) { + e = -e; + neg = true; + max_expand = -font_expand_ratio(font_shrink(f)); + } else { + neg = false; + max_expand = font_expand_ratio(font_stretch(f)); + } + if (e > max_expand) { + e = max_expand; + } else { + step = font_step(f); + if (e % step > 0) + e = step * round_xn_over_d(e, 1, step); + } + if (neg) + e = -e; + return e; +} + +@ @c +static internal_font_number get_expand_font(internal_font_number f, int e) +{ /* look up and create if not found an expanded version of |f|; |f| is an + expandable font; |e| is nonzero and is a multiple of |font_step(f)| */ + internal_font_number k; + k = pdf_font_elink(f); + while (k != null_font) { + if (font_expand_ratio(k) == e) + return k; + k = pdf_font_elink(k); + } + k = load_expand_font(f, e); + set_pdf_font_elink(k, pdf_font_elink(f)); + set_pdf_font_elink(f, k); + return k; +} + +@ @c +internal_font_number expand_font(internal_font_number f, int e) +{ /* looks up for font |f| expanded by |e| thousandths, |e| is an arbitrary value + between max stretch and max shrink of |f|; if not found then creates it */ + if (e == 0) + return f; + e = fix_expand_value(f, e); + if (e == 0) + return f; + if (pdf_font_elink(f) == null_font) + pdf_error("font expansion", "uninitialized pdf_font_elink"); + return get_expand_font(f, e); +} + +@ @c +void set_expand_params(internal_font_number f, boolean auto_expand, + int stretch_limit, int shrink_limit, + int font_step, int expand_ratio) +{ /* expand a font with given parameters */ + set_font_step(f, font_step); + set_font_auto_expand(f, auto_expand); + if (stretch_limit > 0) + set_font_stretch(f, get_expand_font(f, stretch_limit)); + if (shrink_limit > 0) + set_font_shrink(f, get_expand_font(f, -shrink_limit)); + if (expand_ratio != 0) + set_font_expand_ratio(f, expand_ratio); +} + +@ @c +void read_expand_font(void) +{ /* read font expansion spec and load expanded font */ + int shrink_limit, stretch_limit, font_step; + internal_font_number f; + boolean auto_expand; + /* read font expansion parameters */ + scan_font_ident(); + f = cur_val; + if (f == null_font) + pdf_error("font expansion", "invalid font identifier"); + if (pdf_font_blink(f) != null_font) + pdf_error("font expansion", + "\\pdffontexpand cannot be used this way (the base font has been expanded)"); + scan_optional_equals(); + scan_int(); + stretch_limit = fix_int(cur_val, 0, 1000); + scan_int(); + shrink_limit = fix_int(cur_val, 0, 500); + scan_int(); + font_step = fix_int(cur_val, 0, 100); + if (font_step == 0) + pdf_error("font expansion", "invalid step"); + stretch_limit = stretch_limit - stretch_limit % font_step; + if (stretch_limit < 0) + stretch_limit = 0; + shrink_limit = shrink_limit - shrink_limit % font_step; + if (shrink_limit < 0) + shrink_limit = 0; + if ((stretch_limit == 0) && (shrink_limit == 0)) + pdf_error("font expansion", "invalid limit(s)"); + auto_expand = false; + if (scan_keyword("autoexpand")) { + auto_expand = true; + /* Scan an optional space */ + get_x_token(); + if (cur_cmd != spacer_cmd) + back_input(); + } + + /* check if the font can be expanded */ + if (font_expand_ratio(f) != 0) + pdf_error("font expansion", + "this font has been expanded by another font so it cannot be used now"); + if (font_step(f) != 0) { + /* this font has been expanded, ensure the expansion parameters are identical */ + if (font_step(f) != font_step) + pdf_error("font expansion", + "font has been expanded with different expansion step"); + + if (((font_stretch(f) == null_font) && (stretch_limit != 0)) || + ((font_stretch(f) != null_font) + && (font_expand_ratio(font_stretch(f)) != stretch_limit))) + pdf_error("font expansion", + "font has been expanded with different stretch limit"); + + if (((font_shrink(f) == null_font) && (shrink_limit != 0)) || + ((font_shrink(f) != null_font) + && (-font_expand_ratio(font_shrink(f)) != shrink_limit))) + pdf_error("font expansion", + "font has been expanded with different shrink limit"); + + if (font_auto_expand(f) != auto_expand) + pdf_error("font expansion", + "font has been expanded with different auto expansion value"); + } else { + if (font_used(f)) + pdf_warning("font expansion", + "font should be expanded before its first use", true, + true); + set_expand_params(f, auto_expand, stretch_limit, shrink_limit, + font_step, 0); + if (font_type(f) == virtual_font_type) + vf_expand_local_fonts(f); + } +} + +@ @c +void new_letterspaced_font(small_number a) +{ /* letter-space a font by creating a virtual font */ + pointer u; /* user's font identifier */ + str_number t; /* name for the frozen font identifier */ + internal_font_number f, k; + get_r_token(); + u = cur_cs; + if (u >= hash_base) + t = cs_text(u); + else + t = maketexstring("FONT"); + define(u, set_font_cmd, null_font); + scan_optional_equals(); + scan_font_ident(); + k = cur_val; + scan_int(); + f = letter_space_font(u, k, fix_int(cur_val, -1000, 1000)); + equiv(u) = f; + eqtb[font_id_base + f] = eqtb[u]; + font_id_text(f) = t; +} + +@ @c +void make_font_copy(small_number a) +{ /* make a font copy for further use with font expansion */ + pointer u; /* user's font identifier */ + str_number t; /* name for the frozen font identifier */ + internal_font_number f, k; + get_r_token(); + u = cur_cs; + if (u >= hash_base) + t = cs_text(u); + else + t = maketexstring("FONT"); + define(u, set_font_cmd, null_font); + scan_optional_equals(); + scan_font_ident(); + k = cur_val; + f = copy_font_info(k); + equiv(u) = f; + eqtb[font_id_base + f] = eqtb[u]; + font_id_text(f) = t; +} + +@ @c +void pdf_include_chars(PDF pdf) +{ + str_number s; + unsigned char *k, *j; /* running index */ + internal_font_number f; + scan_font_ident(); + f = cur_val; + if (f == null_font) + pdf_error("font", "invalid font identifier"); + pdf_check_vf(cur_val); + if (!font_used(f)) + pdf_init_font(pdf, f); + scan_pdf_ext_toks(); + s = tokens_to_string(def_ref); + delete_token_ref(def_ref); + j = str_string(s) + str_length(s); + for (k = str_string(s); k < j; k++) { + pdf_mark_char(f, *k); + } + flush_str(s); +} + +@ @c +void glyph_to_unicode(void) +{ + str_number s1, s2; + scan_pdf_ext_toks(); + s1 = tokens_to_string(def_ref); + delete_token_ref(def_ref); + scan_pdf_ext_toks(); + s2 = tokens_to_string(def_ref); + delete_token_ref(def_ref); + def_tounicode(s1, s2); + flush_str(s2); + flush_str(s1); +} diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfgen.h b/Build/source/texk/web2c/luatexdir/pdf/pdfgen.h new file mode 100644 index 00000000000..f5840e715db --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdfgen.h @@ -0,0 +1,239 @@ +/* pdfgen.h + + Copyright 2009-2010 Taco Hoekwater <taco@luatex.org> + + 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 <http://www.gnu.org/licenses/>. */ + +/* $Id: pdfgen.h 3573 2010-04-02 14:10:54Z hhenkel $ */ + +#ifndef PDFGEN_H +# define PDFGEN_H + +# define PROCSET_PDF (1 << 0) +# define PROCSET_TEXT (1 << 1) +# define PROCSET_IMAGE_B (1 << 2) +# define PROCSET_IMAGE_C (1 << 3) +# define PROCSET_IMAGE_I (1 << 4) + +# define inf_pdf_mem_size 10000 /* min size of the |mem| array */ +# define sup_pdf_mem_size 10000000 /* max size of the |mem| array */ + +extern PDF static_pdf; + +extern int pdf_get_mem(PDF pdf, int s); + +/* +We use the similiar subroutines to handle the output buffer for +PDF output. When compress is used, the state of writing to buffer +is held in |zip_write_state|. We must write the header of PDF +output file in initialization to ensure that it will be the first +written bytes. +*/ + +# define inf_pdf_op_buf_size 16384 /* size of the PDF output buffer */ +# define sup_pdf_op_buf_size 16384 /* size of the PDF output buffer */ +# define inf_pdf_os_buf_size 1 /* initial value of |pdf_os_buf_size| */ +# define sup_pdf_os_buf_size 5000000 /* arbitrary upper hard limit of |pdf_os_buf_size| */ +# define max_single_pdf_print 8192 /* Max size that can be get from pdf_room() at once. + the value is on the conservative side, but should be + large enough to cover most uses */ +# define pdf_os_max_objs 100 /* maximum number of objects in object stream */ + +# define inf_obj_tab_size 1000 /* min size of the cross-reference table for PDF output */ +# define sup_obj_tab_size 8388607 /* max size of the cross-reference table for PDF output */ + +/* The following macros are similar as for \.{DVI} buffer handling */ + +# define pdf_offset(pdf) (pdf->gone + pdf->ptr) + /* the file offset of last byte in PDF + buffer that |pdf_ptr| points to */ +# define pdf_save_offset(pdf) pdf->save_offset=(pdf->gone + pdf->ptr) +# define pdf_saved_offset(pdf) pdf->save_offset + +# define set_ff(A) do { \ + if (pdf_font_num(A) < 0) \ + ff = -pdf_font_num(A); \ + else \ + ff = A; \ + } while (0) + +typedef enum { + no_zip = 0, /* no \.{ZIP} compression */ + zip_writing = 1, /* \.{ZIP} compression being used */ + zip_finish = 2 /* finish \.{ZIP} compression */ +} zip_write_states; + +extern int pdf_output_option; +extern int pdf_output_value; +extern int pdf_draftmode_option; +extern int pdf_draftmode_value; + +extern scaled one_hundred_inch; +extern scaled one_inch; +extern scaled one_true_inch; +extern scaled one_hundred_bp; +extern scaled one_bp; +extern int ten_pow[10]; + +extern void pdf_flush(PDF); +extern void pdf_room(PDF, int); + +extern void fix_pdf_minorversion(PDF); + + /* output a byte to PDF buffer without checking of overflow */ +# define pdf_quick_out(pdf,A) pdf->buf[pdf->ptr++]=(unsigned char)A + +/* do the same as |pdf_quick_out| and flush the PDF buffer if necessary */ +# define pdf_out(pdf,A) do { pdf_room(pdf,1); pdf_quick_out(pdf,A); } while (0) + +# define pdf_out_block(pdf,A,n) do { \ + pdf_room(pdf,(int)(n)); \ + (void)memcpy((pdf->buf+pdf->ptr),(A),(size_t)(n)); \ + pdf->ptr+=(int)(n); \ + } while (0) + +/* +Basic printing procedures for PDF output are very similiar to \TeX\ basic +printing ones but the output is going to PDF buffer. Subroutines with +suffix |_ln| append a new-line character to the PDF output. +*/ + +# define pdf_new_line_char 10 /* new-line character for UNIX platforms */ + +/* output a new-line character to PDF buffer */ +# define pdf_print_nl(pdf) pdf_out(pdf,pdf_new_line_char) + +/* print out a string to PDF buffer followed by a new-line character */ +# define pdf_print_ln(pdf,A) do { \ + pdf_print(pdf,A); \ + pdf_print_nl(pdf); \ + } while (0) + +/* print out an integer to PDF buffer followed by a new-line character */ +# define pdf_print_int_ln(pdf,A) do { \ + pdf_print_int(pdf,A); \ + pdf_print_nl(pdf); \ + } while (0) + +extern void pdf_puts(PDF, const char *); +extern __attribute__ ((format(printf, 2, 3))) +void pdf_printf(PDF, const char *, ...); + +extern void pdf_print_char(PDF, int); +extern void pdf_print_wide_char(PDF, int); +extern void pdf_print(PDF, str_number); +extern void pdf_print_int(PDF, longinteger); +extern void pdf_print_real(PDF, int, int); +extern void pdf_print_str(PDF, const char *); + +extern void pdf_begin_stream(PDF); +extern void pdf_end_stream(PDF); +extern void pdf_remove_last_space(PDF); + +extern void pdf_print_bp(PDF, scaled); +extern void pdf_print_mag_bp(PDF, scaled); + +/* This is for the resource lists */ + +extern void addto_page_resources(PDF pdf, pdf_obj_type t, int k); +extern pdf_object_list *get_page_resources_list(PDF pdf, pdf_obj_type t); + +# define pdf_print_resname_prefix(pdf) do { \ + if (pdf->resname_prefix != NULL) \ + pdf_puts(pdf,pdf->resname_prefix); \ + } while (0) + +extern void pdf_print_fw_int(PDF, longinteger, int); +extern void pdf_out_bytes(PDF, longinteger, int); +extern void pdf_int_entry(PDF, const char *, int); +extern void pdf_int_entry_ln(PDF, const char *, int); +extern void pdf_indirect(PDF, const char *, int); +extern void pdf_indirect_ln(PDF, const char *, int); +extern void pdf_print_str_ln(PDF, const char *); +extern void pdf_str_entry(PDF, const char *, const char *); +extern void pdf_str_entry_ln(PDF, const char *, const char *); + +extern void pdf_print_toks(PDF, halfword); +extern void pdf_print_toks_ln(PDF, halfword); + +extern void pdf_print_rect_spec(PDF, halfword); +extern void pdf_rectangle(PDF, halfword); + +extern void pdf_begin_obj(PDF, int, int); +extern void pdf_new_obj(PDF, int, int, int); +extern void pdf_end_obj(PDF); + +extern void pdf_begin_dict(PDF, int, int); +extern void pdf_new_dict(PDF, int, int, int); +extern void pdf_end_dict(PDF); + +extern void pdf_os_switch(PDF pdf, boolean pdf_os); +extern void pdf_os_prepare_obj(PDF pdf, int i, int pdf_os_level); +extern void pdf_os_write_objstream(PDF); + +extern void write_stream_length(PDF, int, longinteger); + +extern void print_creation_date(PDF); +extern void print_mod_date(PDF); +extern void print_ID(PDF, const char *); + +extern void remove_pdffile(PDF); + +extern int fb_offset(PDF); +extern void fb_flush(PDF); +extern void fb_putchar(PDF, eight_bits); +extern void fb_seek(PDF, int); +extern void fb_free(PDF); + +extern void write_zip(PDF, boolean); +extern void zip_free(PDF); + +/* functions that do not output stuff */ + +extern scaled round_xn_over_d(scaled x, int n, int d); +extern char *convertStringToPDFString(const char *in, int len); + +extern void init_start_time(PDF); +extern char *getcreationdate(PDF); + +extern void pdf_error(const char *t, const char *p); +extern void pdf_warning(const char *t, const char *p, boolean pr, boolean ap); +extern void check_o_mode(PDF pdf, const char *s, int o_mode, boolean errorflag); + +extern void set_job_id(PDF, int, int, int, int); +extern char *get_resname_prefix(PDF); +extern void pdf_begin_page(PDF pdf, boolean shipping_page); +extern void pdf_end_page(PDF pdf, boolean shipping_page); + +extern void fix_o_mode(PDF pdf); +extern void ensure_output_state(PDF pdf, output_state s); +extern PDF init_pdf_struct(PDF pdf); + +extern halfword pdf_info_toks; /* additional keys of Info dictionary */ +extern halfword pdf_catalog_toks; /* additional keys of Catalog dictionary */ +extern halfword pdf_catalog_openaction; +extern halfword pdf_names_toks; /* additional keys of Names dictionary */ +extern halfword pdf_trailer_toks; /* additional keys of Trailer dictionary */ +extern halfword pdf_pageattributes_toks; /* additional keys of Page dictionary */ +extern halfword pdf_pageresources_toks; /* additional keys of Resources dictionary */ +extern halfword pdf_pagesattributes_toks; /* additional keys of Pages dictionary */ +extern void scan_pdfcatalog(PDF pdf); +extern void finish_pdf_file(PDF pdf, int luatex_version, + str_number luatex_revision); + +extern boolean is_shipping_page; + +#endif /* PDFGEN_H */ diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfgen.w b/Build/source/texk/web2c/luatexdir/pdf/pdfgen.w new file mode 100644 index 00000000000..cbb7ccf8b89 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdfgen.w @@ -0,0 +1,2479 @@ +% pdfgen.w + +% Copyright 2009-2010 Taco Hoekwater <taco@@luatex.org> + +% 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 <http://www.gnu.org/licenses/>. + +@ @c +static const char _svn_version[] = + "$Id: pdfgen.w 3573 2010-04-02 14:10:54Z hhenkel $" + "$URL: http://foundry.supelec.fr/svn/luatex/tags/beta-0.60.0/source/texk/web2c/luatexdir/pdf/pdfgen.w $"; + +#include "ptexlib.h" + +@ @c +#include <kpathsea/c-dir.h> +#include <kpathsea/c-ctype.h> +#include "md5.h" + +#define is_hex_char isxdigit + +#define check_nprintf(size_get, size_want) \ + if ((unsigned)(size_get) >= (unsigned)(size_want)) \ + pdftex_fail ("snprintf failed: file %s, line %d", __FILE__, __LINE__); + +PDF static_pdf = NULL; + +static char *jobname_cstr = NULL; + +@ commandline interface +@c +int pdf_output_option; +int pdf_output_value; +int pdf_draftmode_option; +int pdf_draftmode_value; + +halfword pdf_info_toks; /* additional keys of Info dictionary */ +halfword pdf_catalog_toks; /* additional keys of Catalog dictionary */ +halfword pdf_catalog_openaction; +halfword pdf_names_toks; /* additional keys of Names dictionary */ +halfword pdf_trailer_toks; /* additional keys of Trailer dictionary */ +halfword pdf_pageattributes_toks; /* additional keys of Page dictionary */ +halfword pdf_pageresources_toks; /* additional keys of Resources dictionary */ +halfword pdf_pagesattributes_toks; /* additional keys of Pages dictionary */ +boolean is_shipping_page; /* set to |shipping_page| when |ship_out| starts */ + +@ |init_pdf_struct()| is called early, only once, from maincontrol.w + +@c +PDF init_pdf_struct(PDF pdf) +{ + assert(pdf == NULL); + pdf = xmalloc(sizeof(pdf_output_file)); + memset(pdf, 0, sizeof(pdf_output_file)); + + pdf->o_mode = OMODE_NONE; /* will be set by |fix_o_mode()| */ + pdf->o_state = ST_INITIAL; + + pdf->os_obj = xmalloc(pdf_os_max_objs * sizeof(os_obj_data)); + pdf->os_buf_size = inf_pdf_os_buf_size; + pdf->os_buf = xmalloc((unsigned) pdf->os_buf_size * sizeof(unsigned char)); + pdf->op_buf_size = inf_pdf_op_buf_size; + pdf->op_buf = xmalloc((unsigned) pdf->op_buf_size * sizeof(unsigned char)); + + pdf->buf_size = pdf->op_buf_size; + pdf->buf = pdf->op_buf; + + /* Sometimes it is neccesary to allocate memory for PDF output that cannot + be deallocated then, so we use |mem| for this purpose. */ + pdf->mem_size = inf_pdf_mem_size; /* allocated size of |mem| array */ + pdf->mem = xmalloc((unsigned) ((unsigned) pdf->mem_size * sizeof(int))); + pdf->mem_ptr = 1; /* the first word is not used so we can use zero as a value for testing + whether a pointer to |mem| is valid */ + pdf->pstruct = NULL; + + pdf->posstruct = xmalloc(sizeof(posstructure)); + pdf->posstruct->pos.h = 0; + pdf->posstruct->pos.v = 0; + pdf->posstruct->dir = dir_TLT; + + pdf->obj_tab_size = (unsigned) inf_obj_tab_size; /* allocated size of |obj_tab| array */ + pdf->obj_tab = xmalloc((unsigned) + ((unsigned) (pdf->obj_tab_size + 1) * + sizeof(obj_entry))); + memset(pdf->obj_tab, 0, sizeof(obj_entry)); + + pdf->minor_version = -1; /* unset */ + pdf->decimal_digits = 4; + pdf->gamma = 65536; + pdf->image_gamma = 65536; + pdf->image_hicolor = 1; + pdf->image_apply_gamma = 0; + pdf->objcompresslevel = 0; + pdf->compress_level = 0; + pdf->draftmode = 0; + pdf->inclusion_copy_font = 1; + pdf->replace_font = 0; + pdf->pk_resolution = 0; + pdf->pk_scale_factor = 0; + + init_dest_names(pdf); + pdf->page_resources = NULL; + + init_pdf_pagecalculations(pdf); + + return pdf; +} + +@ @c +static void pdf_shipout_begin(boolean shipping_page) +{ + pos_stack_used = 0; /* start with empty stack */ + + page_mode = shipping_page; + if (shipping_page) { + colorstackpagestart(); + } +} + +static void pdf_shipout_end(boolean shipping_page) +{ + if (pos_stack_used > 0) { + pdftex_fail("%u unmatched \\pdfsave after %s shipout", + (unsigned int) pos_stack_used, + ((shipping_page) ? "page" : "form")); + } +} + +@ We use |pdf_get_mem| to allocate memory in |mem|. + +@c +int pdf_get_mem(PDF pdf, int s) +{ /* allocate |s| words in |mem| */ + int a; + int ret; + if (s > sup_pdf_mem_size - pdf->mem_ptr) + overflow("PDF memory size (pdf_mem_size)", (unsigned) pdf->mem_size); + if (pdf->mem_ptr + s > pdf->mem_size) { + a = pdf->mem_size / 5; + if (pdf->mem_ptr + s > pdf->mem_size + a) { + pdf->mem_size = pdf->mem_ptr + s; + } else if (pdf->mem_size < sup_pdf_mem_size - a) { + pdf->mem_size = pdf->mem_size + a; + } else { + pdf->mem_size = sup_pdf_mem_size; + } + pdf->mem = xreallocarray(pdf->mem, int, (unsigned) pdf->mem_size); + } + ret = pdf->mem_ptr; + pdf->mem_ptr = pdf->mem_ptr + s; + return ret; +} + + +@ |fix_o_mode| freezes |pdf->o_mode| as soon as anything goes through +the backend, be it \.{PDF}, \.{DVI}, or \.{Lua}. + +@c +#define pdf_output int_par(pdf_output_code) + +void fix_o_mode(PDF pdf) +{ + static int fixed_pdf_output = 0; + if (pdf->o_mode == OMODE_NONE) { + if (pdf_output > 0) { + if (pdf_output == 2009) + pdf->o_mode = OMODE_LUA; + else + pdf->o_mode = OMODE_PDF; + } else + pdf->o_mode = OMODE_DVI; + fixed_pdf_output = pdf_output; + pdf_output_value = pdf_output; + } else if (pdf_output != fixed_pdf_output) { + pdf_error("setup", + "\\pdfoutput can only be changed before anything is written to the output"); + } +} + + +@ This ensures that |pdfminorversion| is set only before any bytes have +been written to the generated \.{PDF} file. Here also all variables for +\.{PDF} output are initialized, the \.{PDF} file is opened by |ensure_pdf_open|, +and the \.{PDF} header is written. + +@c +void fix_pdf_minorversion(PDF pdf) +{ + if (pdf->minor_version < 0) { /* unset */ + if ((pdf_minor_version < 0) || (pdf_minor_version > 9)) { + const char *hlp[] = + { "The pdfminorversion must be between 0 and 9.", + "I changed this to 4.", NULL + }; + char msg[256]; + (void) snprintf(msg, 255, + "LuaTeX error (illegal pdfminorversion %d)", + (int) pdf_minor_version); + tex_error(msg, hlp); + pdf_minor_version = 4; + } + pdf->minor_version = pdf_minor_version; + } else { + /* Check that variables for \.{PDF} output are unchanged */ + if (pdf->minor_version != int_par(pdf_minor_version_code)) + pdf_error("setup", + "\\pdfminorversion cannot be changed after data is written to the PDF file"); + if (pdf->draftmode != int_par(pdf_draftmode_code)) + pdf_error("setup", + "\\pdfdraftmode cannot be changed after data is written to the PDF file"); + } + if (pdf->draftmode != 0) { + pdf->compress_level = 0; /* re-fix it, might have been changed inbetween */ + pdf->objcompresslevel = 0; + } +} + +@ The PDF buffer is flushed by calling |pdf_flush|, which checks the +variable |zip_write_state| and will compress the buffer before flushing if +neccesary. We call |pdf_begin_stream| to begin a stream and |pdf_end_stream| +to finish it. The stream contents will be compressed if compression is turn on. + +@c +static void write_pdf(PDF pdf, int a, int b) +{ + (void) fwrite((char *) &pdf->buf[a], sizeof(pdf->buf[a]), + (size_t) ((b) - (a) + 1), pdf->file); +} + +@ @c +void pdf_flush(PDF pdf) +{ /* flush out the |pdf_buf| */ + + off_t saved_pdf_gone; + if (!pdf->os_mode) { + saved_pdf_gone = pdf->gone; + switch (pdf->zip_write_state) { + case no_zip: + if (pdf->ptr > 0) { + if (pdf->draftmode == 0) + write_pdf(pdf, 0, pdf->ptr - 1); + pdf->gone += pdf->ptr; + pdf->last_byte = pdf->buf[pdf->ptr - 1]; + } + break; + case zip_writing: + if (pdf->draftmode == 0) + write_zip(pdf, false); + break; + case zip_finish: + if (pdf->draftmode == 0) + write_zip(pdf, true); + pdf->zip_write_state = no_zip; + break; + } + pdf->ptr = 0; + if (saved_pdf_gone > pdf->gone) + pdf_error("file size", + "File size exceeds architectural limits (pdf_gone wraps around)"); + } +} + +@ switch between PDF stream and object stream mode + +@c +void pdf_os_switch(PDF pdf, boolean pdf_os) +{ + if (pdf_os && pdf->os_enable) { + if (!pdf->os_mode) { /* back up PDF stream variables */ + pdf->op_ptr = pdf->ptr; + pdf->ptr = pdf->os_ptr; + pdf->buf = pdf->os_buf; + pdf->buf_size = pdf->os_buf_size; + pdf->os_mode = true; /* switch to object stream */ + } + } else { + if (pdf->os_mode) { /* back up object stream variables */ + pdf->os_ptr = pdf->ptr; + pdf->ptr = pdf->op_ptr; + pdf->buf = pdf->op_buf; + pdf->buf_size = pdf->op_buf_size; + pdf->os_mode = false; /* switch to PDF stream */ + } + } +} + +@ create new \.{/ObjStm} object if required, and set up cross reference info + +@c +void pdf_os_prepare_obj(PDF pdf, int i, int pdf_os_level) +{ + pdf_os_switch(pdf, ((pdf_os_level > 0) + && (pdf->objcompresslevel >= pdf_os_level))); + if (pdf->os_mode) { + if (pdf->os_cur_objnum == 0) { + pdf_create_obj(pdf, obj_type_objstm, pdf->sys_obj_ptr + 1); + pdf->os_cur_objnum = pdf->sys_obj_ptr; + pdf->obj_ptr--; /* object stream is not accessible to user */ + pdf->os_cntr++; /* only for statistics */ + pdf->os_idx = 0; + pdf->ptr = 0; /* start fresh object stream */ + } else { + pdf->os_idx++; + } + obj_os_idx(pdf, i) = pdf->os_idx; + obj_offset(pdf, i) = pdf->os_cur_objnum; + pdf->os_obj[pdf->os_idx].num = i; + pdf->os_obj[pdf->os_idx].off = pdf->ptr; + } else { + obj_offset(pdf, i) = pdf_offset(pdf); + obj_os_idx(pdf, i) = -1; /* mark it as not included in object stream */ + } +} + +@* low-level buffer checkers. + +@ check that |s| bytes more fit into |pdf_os_buf|; increase it if required +@c +static void pdf_os_get_os_buf(PDF pdf, int s) +{ + int a; + if (s > sup_pdf_os_buf_size - pdf->ptr) + overflow("PDF object stream buffer", (unsigned) pdf->os_buf_size); + if (pdf->ptr + s > pdf->os_buf_size) { + a = pdf->os_buf_size / 5; + if (pdf->ptr + s > pdf->os_buf_size + a) + pdf->os_buf_size = pdf->ptr + s; + else if (pdf->os_buf_size < sup_pdf_os_buf_size - a) + pdf->os_buf_size = pdf->os_buf_size + a; + else + pdf->os_buf_size = sup_pdf_os_buf_size; + pdf->os_buf = + xreallocarray(pdf->os_buf, unsigned char, + (unsigned) pdf->os_buf_size); + pdf->buf = pdf->os_buf; + pdf->buf_size = pdf->os_buf_size; + } +} + +@ make sure that there are at least |n| bytes free in PDF buffer +@c +void pdf_room(PDF pdf, int n) +{ + if (pdf->os_mode && (n + pdf->ptr > pdf->buf_size)) + pdf_os_get_os_buf(pdf, n); + else if ((!pdf->os_mode) && (n > pdf->buf_size)) + overflow("PDF output buffer", (unsigned) pdf->op_buf_size); + else if ((!pdf->os_mode) && (n + pdf->ptr > pdf->buf_size)) + pdf_flush(pdf); +} + + +@ print out a character to PDF buffer; the character will be printed in octal + form in the following cases: chars <= 32, backslash (92), left parenthesis + (40) and right parenthesis (41) + +@c +#define pdf_print_escaped(c) \ + if ((c)<=32||(c)=='\\'||(c)=='('||(c)==')'||(c)>127) { \ + pdf_room(pdf,4); \ + pdf_quick_out(pdf,'\\'); \ + pdf_quick_out(pdf,(unsigned char)('0' + (((c)>>6) & 0x3))); \ + pdf_quick_out(pdf,(unsigned char)('0' + (((c)>>3) & 0x7))); \ + pdf_quick_out(pdf,(unsigned char)('0' + ( (c) & 0x7))); \ + } else { \ + pdf_out(pdf,(c)); \ + } + +void pdf_print_char(PDF pdf, int c) +{ + if (c > 255) + return; + pdf_print_escaped(c); +} + +void pdf_print_wide_char(PDF pdf, int c) +{ + char hex[5]; + snprintf(hex, 5, "%04X", c); + pdf_room(pdf, 4); + pdf_quick_out(pdf, (unsigned char) hex[0]); + pdf_quick_out(pdf, (unsigned char) hex[1]); + pdf_quick_out(pdf, (unsigned char) hex[2]); + pdf_quick_out(pdf, (unsigned char) hex[3]); +} + +@ @c +void pdf_puts(PDF pdf, const char *s) +{ + + size_t l = strlen(s); + if (l < (size_t) pdf->buf_size) { + pdf_room(pdf, (int) l); + while (*s != '\0') + pdf_quick_out(pdf, *s++); + } else { + while (*s != '\0') + pdf_out(pdf, *s++); + } +} + +@ @c +__attribute__ ((format(printf, 2, 3))) +void pdf_printf(PDF pdf, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + if (pdf->printf_buf == NULL) { + pdf->printf_buf = xtalloc(PRINTF_BUF_SIZE, char); + } + (void) vsnprintf(pdf->printf_buf, PRINTF_BUF_SIZE, fmt, args); + pdf_puts(pdf, pdf->printf_buf); + va_end(args); +} + +@ print out a string to PDF buffer +@c +void pdf_print(PDF pdf, str_number s) +{ + if (s < number_chars) { + assert(s < 256); + pdf_out(pdf, s); + } else { + unsigned char *k, *j; + j = str_string(s) + str_length(s); + for (k = str_string(s); k < j; k++) { + pdf_out(pdf, *k); + } + } +} + +@ print out a integer to PDF buffer +@c +void pdf_print_int(PDF pdf, longinteger n) +{ + register int k = 0; /* current digit; we assume that $|n|<10^{23}$ */ + int dig[24]; + if (n < 0) { + pdf_out(pdf, '-'); + if (n < -0x7FFFFFFF) { /* need to negate |n| more carefully */ + register longinteger m; + k++; + m = -1 - n; + n = m / 10; + m = (m % 10) + 1; + if (m < 10) { + dig[0] = (int) m; + } else { + dig[0] = 0; + n++; + } + } else { + n = -n; + } + } + do { + dig[k++] = (int) (n % 10); + n = n / 10; + } while (n != 0); + pdf_room(pdf, k); + while (k-- > 0) { + pdf_quick_out(pdf, (unsigned char) ('0' + dig[k])); + } +} + +@ print $m/10^d$ as real +@c +void pdf_print_real(PDF pdf, int m, int d) +{ + if (m < 0) { + pdf_out(pdf, '-'); + m = -m; + }; + pdf_print_int(pdf, m / ten_pow[d]); + m = m % ten_pow[d]; + if (m > 0) { + pdf_out(pdf, '.'); + d--; + while (m < ten_pow[d]) { + pdf_out(pdf, '0'); + d--; + } + while (m % 10 == 0) + m = m / 10; + pdf_print_int(pdf, m); + } +} + +@ print out |s| as string in PDF output +@c +void pdf_print_str(PDF pdf, const char *s) +{ + const char *orig = s; + int l = (int) strlen(s) - 1; /* last string index */ + if (l < 0) { + pdf_puts(pdf, "()"); + return; + } + /* the next is not really safe, the string could be "(a)xx(b)" */ + if ((s[0] == '(') && (s[l] == ')')) { + pdf_puts(pdf, s); + return; + } + if ((s[0] != '<') || (s[l] != '>') || odd((l + 1))) { + pdf_out(pdf, '('); + pdf_puts(pdf, s); + pdf_out(pdf, ')'); + return; + } + s++; + while (is_hex_char(*s)) + s++; + if (s != orig + l) { + pdf_out(pdf, '('); + pdf_puts(pdf, orig); + pdf_out(pdf, ')'); + return; + } + pdf_puts(pdf, orig); /* it was a hex string after all */ +} + +@ begin a stream +@c +void pdf_begin_stream(PDF pdf) +{ + assert(pdf->os_mode == false); + pdf_puts(pdf, "/Length \n"); + pdf->seek_write_length = true; /* fill in length at |pdf_end_stream| call */ + pdf->stream_length_offset = pdf_offset(pdf) - 11; + pdf->stream_length = 0; + pdf->last_byte = 0; + if (pdf->compress_level > 0) { + pdf_puts(pdf, "/Filter /FlateDecode\n"); + pdf_puts(pdf, ">>\n"); + pdf_puts(pdf, "stream\n"); + pdf_flush(pdf); + pdf->zip_write_state = zip_writing; + } else { + pdf_puts(pdf, ">>\n"); + pdf_puts(pdf, "stream\n"); + pdf_save_offset(pdf); + } +} + +@ end a stream +@c +void pdf_end_stream(PDF pdf) +{ + if (pdf->zip_write_state == zip_writing) + pdf->zip_write_state = zip_finish; + else + pdf->stream_length = pdf_offset(pdf) - pdf_saved_offset(pdf); + pdf_flush(pdf); + if (pdf->seek_write_length) + write_stream_length(pdf, (int) pdf->stream_length, + pdf->stream_length_offset); + pdf->seek_write_length = false; + if (pdf->last_byte != pdf_new_line_char) + pdf_out(pdf, pdf_new_line_char); + pdf_puts(pdf, "endstream\n"); + pdf_end_obj(pdf); +} + +void pdf_remove_last_space(PDF pdf) +{ + if ((pdf->ptr > 0) && (pdf->buf[pdf->ptr - 1] == ' ')) + pdf->ptr--; +} + + +@ To print |scaled| value to PDF output we need some subroutines to ensure +accurary. + +@c +#define max_integer 0x7FFFFFFF /* $2^{31}-1$ */ + +/* scaled value corresponds to 100in, exact, 473628672 */ +scaled one_hundred_inch = 7227 * 65536; + +/* scaled value corresponds to 1in (rounded to 4736287) */ +scaled one_inch = (7227 * 65536 + 50) / 100; + + /* scaled value corresponds to 1truein (rounded!) */ +scaled one_true_inch = (7227 * 65536 + 50) / 100; + +/* scaled value corresponds to 100bp */ +scaled one_hundred_bp = (7227 * 65536) / 72; + +/* scaled value corresponds to 1bp (rounded to 65782) */ +scaled one_bp = ((7227 * 65536) / 72 + 50) / 100; + +/* $10^0..10^9$ */ +int ten_pow[10] = { + 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 +}; + + +@ The function |divide_scaled| divides |s| by |m| using |dd| decimal +digits of precision. It is defined in C because it is a good candidate +for optimizations that are not possible in pascal. + +@c +scaled round_xn_over_d(scaled x, int n, int d) +{ + boolean positive; /* was |x>=0|? */ + unsigned t, u, v; /* intermediate quantities */ + if (x >= 0) { + positive = true; + } else { + x = -(x); + positive = false; + } + t = (unsigned) ((x % 0100000) * n); + u = (unsigned) (((unsigned) (x) / 0100000) * (unsigned) n + (t / 0100000)); + v = (u % d) * 0100000 + (t % 0100000); + if (u / d >= 0100000) + arith_error = true; + else + u = 0100000 * (u / d) + (v / d); + v = v % d; + if (2 * v >= (unsigned) d) + u++; + if (positive) + return (scaled) u; + else + return (-(scaled) u); +} + +@ @c +#define lround(a) (long) floor((a) + 0.5) + +void pdf_print_bp(PDF pdf, scaled s) +{ /* print scaled as |bp| */ + pdffloat a; + pdfstructure *p = pdf->pstruct; + assert(p != NULL); + a.m = lround(s * p->k1); + a.e = pdf->decimal_digits; + print_pdffloat(pdf, a); +} + +void pdf_print_mag_bp(PDF pdf, scaled s) +{ /* take |mag| into account */ + pdffloat a; + pdfstructure *p = pdf->pstruct; + prepare_mag(); + if (int_par(mag_code) != 1000) + a.m = lround(s * (double) int_par(mag_code) / 1000.0 * p->k1); + else + a.m = lround(s * p->k1); + a.e = pdf->decimal_digits; + print_pdffloat(pdf, a); +} + +#define set_p_or_return(a) do { \ + p = a; \ + if (p==NULL) { \ + a = item; \ + return; \ + } \ + } while (0) + + +@* handling page resources. + +@c +typedef struct { + int obj_type; + pdf_object_list *list; +} pr_entry; + +@ @c +static int comp_page_resources(const void *pa, const void *pb, void *p) +{ + int a, b; + (void) p; + a = ((const pr_entry *) pa)->obj_type; + b = ((const pr_entry *) pb)->obj_type; + if (a > b) + return 1; + if (a < b) + return -1; + return 0; +} + +@ @c +void addto_page_resources(PDF pdf, pdf_obj_type t, int k) +{ + pdf_resource_struct *re; + pr_entry *pr, tmp; + void **pp; + pdf_object_list *p, *item = NULL; + assert(pdf != NULL); + re = pdf->page_resources; + assert(re != NULL); + assert(t <= PDF_OBJ_TYPE_MAX); + if (re->resources_tree == NULL) { + re->resources_tree = + avl_create(comp_page_resources, NULL, &avl_xallocator); + if (re->resources_tree == NULL) + pdftex_fail + ("addto_page_resources(): avl_create() page_resource_tree failed"); + } + tmp.obj_type = t; + pr = (pr_entry *) avl_find(re->resources_tree, &tmp); + if (pr == NULL) { + pr = xtalloc(1, pr_entry); + pr->obj_type = t; + pr->list = NULL; + pp = avl_probe(re->resources_tree, pr); + if (pp == NULL) + pdftex_fail + ("addto_page_resources(): avl_probe() out of memory in insertion"); + } + if (pr->list == NULL) { + item = xmalloc(sizeof(pdf_object_list)); + item->link = NULL; + item->info = k; + pr->list = item; + set_obj_scheduled(pdf, k); + } else { + for (p = pr->list; p->info != k && p->link != NULL; p = p->link); + if (p->info != k) { + item = xmalloc(sizeof(pdf_object_list)); + item->link = NULL; + item->info = k; + p->link = item; + set_obj_scheduled(pdf, k); + } + } +} + +@ @c +pdf_object_list *get_page_resources_list(PDF pdf, pdf_obj_type t) +{ + pdf_resource_struct *re = pdf->page_resources; + pr_entry *pr, tmp; + if (re == NULL || re->resources_tree == NULL) + return NULL; + tmp.obj_type = t; + pr = (pr_entry *) avl_find(re->resources_tree, &tmp); + if (pr == NULL) + return NULL; + return pr->list; +} + +@ @c +static void reset_page_resources(PDF pdf) +{ + pdf_resource_struct *re = pdf->page_resources; + pr_entry *p; + struct avl_traverser t; + pdf_object_list *l1, *l2; + if (re == NULL || re->resources_tree == NULL) + return; + avl_t_init(&t, re->resources_tree); + for (p = avl_t_first(&t, re->resources_tree); p != NULL; p = avl_t_next(&t)) { + if (p->list != NULL) { + for (l1 = p->list; l1 != NULL; l1 = l2) { + l2 = l1->link; + free(l1); + } + p->list = NULL; /* but the AVL tree remains */ + } + } +} + +@ @c +static void destroy_pg_res_tree(void *pa, void *param) +{ + (void) param; + xfree(pa); +} + +@ @c +static void destroy_page_resources_tree(PDF pdf) +{ + pdf_resource_struct *re = pdf->page_resources; + reset_page_resources(pdf); + if (re->resources_tree != NULL) + avl_destroy(re->resources_tree, destroy_pg_res_tree); + re->resources_tree = NULL; +} + +@* Subroutines to print out various PDF objects. + +@ print out an integer with fixed width; used for outputting cross-reference table +@c +void pdf_print_fw_int(PDF pdf, longinteger n, int w) +{ + int k; /* $0\le k\le23$ */ + int dig[24]; + k = 0; + do { + dig[k] = (int) (n % 10); + n = n / 10; + k++; + } while (k != w); + pdf_room(pdf, k); + while (k-- > 0) + pdf_quick_out(pdf, (unsigned char) ('0' + dig[k])); +} + +@ print out an integer as a number of bytes; used for outputting \.{/XRef} cross-reference stream +@c +void pdf_out_bytes(PDF pdf, longinteger n, int w) +{ + int k; + int bytes[8]; /* digits in a number being output */ + k = 0; + do { + bytes[k] = (int) (n % 256); + n = n / 256; + k++; + } while (k != w); + pdf_room(pdf, k); + while (k-- > 0) + pdf_quick_out(pdf, bytes[k]); +} + +@ print out an entry in dictionary with integer value to PDF buffer +@c +void pdf_int_entry(PDF pdf, const char *s, int v) +{ + pdf_printf(pdf, "/%s ", s); + pdf_print_int(pdf, v); +} + +void pdf_int_entry_ln(PDF pdf, const char *s, int v) +{ + + pdf_int_entry(pdf, s, v); + pdf_print_nl(pdf); +} + +@ print out an indirect entry in dictionary +@c +void pdf_indirect(PDF pdf, const char *s, int o) +{ + pdf_printf(pdf, "/%s %d 0 R", s, (int) o); +} + +void pdf_indirect_ln(PDF pdf, const char *s, int o) +{ + + pdf_indirect(pdf, s, o); + pdf_print_nl(pdf); +} + +@ print out |s| as string in PDF output +@c +void pdf_print_str_ln(PDF pdf, const char *s) +{ + pdf_print_str(pdf, s); + pdf_print_nl(pdf); +} + +@ print out an entry in dictionary with string value to PDF buffer +@c +void pdf_str_entry(PDF pdf, const char *s, const char *v) +{ + if (v == 0) + return; + pdf_printf(pdf, "/%s ", s); + pdf_print_str(pdf, v); +} + +void pdf_str_entry_ln(PDF pdf, const char *s, const char *v) +{ + if (v == 0) + return; + pdf_str_entry(pdf, s, v); + pdf_print_nl(pdf); +} + +@ @c +void pdf_print_toks(PDF pdf, halfword p) +{ + int len = 0; + char *s = tokenlist_to_cstring(p, true, &len); + if (len > 0) + pdf_puts(pdf, s); + xfree(s); +} + +void pdf_print_toks_ln(PDF pdf, halfword p) +{ + int len = 0; + char *s = tokenlist_to_cstring(p, true, &len); + if (len > 0) { + pdf_puts(pdf, s); + pdf_print_nl(pdf); + } + xfree(s); +} + +@ prints a rect spec +@c +void pdf_print_rect_spec(PDF pdf, halfword r) +{ + pdf_print_mag_bp(pdf, pdf_ann_left(r)); + pdf_out(pdf, ' '); + pdf_print_mag_bp(pdf, pdf_ann_bottom(r)); + pdf_out(pdf, ' '); + pdf_print_mag_bp(pdf, pdf_ann_right(r)); + pdf_out(pdf, ' '); + pdf_print_mag_bp(pdf, pdf_ann_top(r)); +} + +@ output a rectangle specification to PDF file +@c +void pdf_rectangle(PDF pdf, halfword r) +{ + prepare_mag(); + pdf_puts(pdf, "/Rect ["); + pdf_print_rect_spec(pdf, r); + pdf_puts(pdf, "]\n"); +} + +@ @c +static void init_pdf_outputparameters(PDF pdf) +{ + assert(pdf->o_mode == OMODE_PDF); + pdf->draftmode = fix_int(pdf_draftmode, 0, 1); + pdf->compress_level = fix_int(pdf_compress_level, 0, 9); + pdf->decimal_digits = fix_int(pdf_decimal_digits, 0, 4); + pdf->gamma = fix_int(pdf_gamma, 0, 1000000); + pdf->image_gamma = fix_int(pdf_image_gamma, 0, 1000000); + pdf->image_hicolor = fix_int(pdf_image_hicolor, 0, 1); + pdf->image_apply_gamma = fix_int(pdf_image_apply_gamma, 0, 1); + pdf->objcompresslevel = fix_int(pdf_objcompresslevel, 0, 3); + pdf->inclusion_copy_font = fix_int(pdf_inclusion_copy_font, 0, 1); + pdf->replace_font = fix_int(pdf_replace_font, 0, 1); + pdf->pk_resolution = fix_int(pdf_pk_resolution, 72, 8000); + if ((pdf->minor_version >= 5) && (pdf->objcompresslevel > 0)) { + pdf->os_enable = true; + } else { + if (pdf->objcompresslevel > 0) { + pdf_warning("Object streams", + "\\pdfobjcompresslevel > 0 requires \\pdfminorversion > 4. Object streams disabled now.", + true, true); + pdf->objcompresslevel = 0; + } + pdf->os_enable = false; + } + if (pdf->pk_resolution == 0) /* if not set from format file or by user */ + pdf->pk_resolution = pk_dpi; /* take it from \.{texmf.cnf} */ + pdf->pk_scale_factor = + divide_scaled(72, pdf->pk_resolution, 5 + pdf->decimal_digits); + if (!callback_defined(read_pk_file_callback)) { + if (pdf_pk_mode != null) { + char *s = tokenlist_to_cstring(pdf_pk_mode, true, NULL); + kpseinitprog("PDFTEX", (unsigned) pdf->pk_resolution, s, nil); + xfree(s); + } else { + kpseinitprog("PDFTEX", (unsigned) pdf->pk_resolution, nil, nil); + } + if (!kpsevarvalue("MKTEXPK")) + kpsesetprogramenabled(kpsepkformat, 1, kpsesrccmdline); + } + set_job_id(pdf, int_par(year_code), + int_par(month_code), int_par(day_code), int_par(time_code)); + if ((pdf_unique_resname > 0) && (pdf->resname_prefix == NULL)) + pdf->resname_prefix = get_resname_prefix(pdf); +} + +@ Checks that we have a name for the generated PDF file and that it's open. + +@c +static void ensure_output_file_open(PDF pdf, const char *ext) +{ + char *fn; + if (pdf->file_name != NULL) + return; + if (job_name == 0) + open_log_file(); + fn = pack_job_name(ext); + if (pdf->draftmode == 0 || pdf->o_mode == OMODE_DVI) { + while (!lua_b_open_out(&pdf->file, fn)) + fn = prompt_file_name("file name for output", ext); + } + pdf->file_name = fn; +} + +@ @c +static void ensure_pdf_header_written(PDF pdf) +{ + assert(pdf->o_state == ST_FILE_OPEN); + assert(pdf->o_mode == OMODE_PDF); + /* Initialize variables for \.{PDF} output */ + fix_pdf_minorversion(pdf); + init_pdf_outputparameters(pdf); + /* Write \.{PDF} header */ + pdf_printf(pdf, "%%PDF-1.%d\n", pdf->minor_version); + pdf_out(pdf, '%'); + pdf_out(pdf, 'P' + 128); + pdf_out(pdf, 'T' + 128); + pdf_out(pdf, 'E' + 128); + pdf_out(pdf, 'X' + 128); + pdf_print_nl(pdf); +} + +@ @c +void ensure_output_state(PDF pdf, output_state s) +{ + if (pdf->o_state < s) { + if (s > ST_INITIAL) + ensure_output_state(pdf, s - 1); + switch (s - 1) { + case ST_INITIAL: + fix_o_mode(pdf); + break; + case ST_OMODE_FIX: + switch (pdf->o_mode) { + case OMODE_DVI: + ensure_output_file_open(pdf, ".dvi"); + break; + case OMODE_PDF: + ensure_output_file_open(pdf, ".pdf"); + break; + case OMODE_LUA: + break; + default: + assert(0); + } + break; + case ST_FILE_OPEN: + switch (pdf->o_mode) { + case OMODE_DVI: + ensure_dvi_header_written(pdf); + break; + case OMODE_PDF: + ensure_pdf_header_written(pdf); + break; + case OMODE_LUA: + break; + default: + assert(0); + } + break; + case ST_HEADER_WRITTEN: + break; + case ST_FILE_CLOSED: + break; + default: + assert(0); + } + pdf->o_state++; + } +} + +@ begin a PDF dictionary object +@c +void pdf_begin_dict(PDF pdf, int i, int pdf_os_level) +{ + ensure_output_state(pdf, ST_HEADER_WRITTEN); + pdf_os_prepare_obj(pdf, i, pdf_os_level); + if (!pdf->os_mode) { + pdf_printf(pdf, "%d 0 obj <<\n", (int) i); + } else { + if (pdf->compress_level == 0) + pdf_printf(pdf, "%% %d 0 obj\n", (int) i); /* debugging help */ + pdf_puts(pdf, "<<\n"); + } +} + +@ begin a new PDF dictionary object +@c +void pdf_new_dict(PDF pdf, int t, int i, int pdf_os) +{ + pdf_create_obj(pdf, t, i); + pdf_begin_dict(pdf, pdf->obj_ptr, pdf_os); +} + +@ end a PDF dictionary object +@c +void pdf_end_dict(PDF pdf) +{ + if (pdf->os_mode) { + pdf_puts(pdf, ">>\n"); + if (pdf->os_idx == pdf_os_max_objs - 1) + pdf_os_write_objstream(pdf); + } else { + pdf_puts(pdf, ">> endobj\n"); + } +} + +@ Write out an accumulated object stream. + +First the object number and byte offset pairs are generated +and appended to the ready buffered object stream. +By this the value of \.{/First} can be calculated. +Then a new \.{/ObjStm} object is generated, and everything is +copied to the PDF output buffer, where also compression is done. +When calling this procedure, |pdf_os_mode| must be |true|. + +@c +void pdf_os_write_objstream(PDF pdf) +{ + halfword i, j, p, q; + if (pdf->os_cur_objnum == 0) /* no object stream started */ + return; + p = pdf->ptr; + i = 0; + j = 0; + while (i <= pdf->os_idx) { /* assemble object number and byte offset pairs */ + pdf_printf(pdf, "%d %d", (int) pdf->os_obj[i].num, + (int) pdf->os_obj[i].off); + if (j == 9) { /* print out in groups of ten for better readability */ + pdf_out(pdf, pdf_new_line_char); + j = 0; + } else { + pdf_out(pdf, ' '); + j++; + } + i++; + } + pdf->buf[pdf->ptr - 1] = pdf_new_line_char; /* no risk of flush, as we are in |pdf_os_mode| */ + q = pdf->ptr; + pdf_begin_dict(pdf, pdf->os_cur_objnum, 0); /* switch to PDF stream writing */ + pdf_puts(pdf, "/Type /ObjStm\n"); + pdf_printf(pdf, "/N %d\n", (int) (pdf->os_idx + 1)); + pdf_printf(pdf, "/First %d\n", (int) (q - p)); + pdf_begin_stream(pdf); + pdf_room(pdf, q - p); /* should always fit into the PDF output buffer */ + i = p; + while (i < q) { /* write object number and byte offset pairs */ + pdf_quick_out(pdf, pdf->os_buf[i]); + i++; + } + i = 0; + while (i < p) { + q = i + pdf->buf_size; + if (q > p) + q = p; + pdf_room(pdf, q - i); + while (i < q) { /* write the buffered objects */ + pdf_quick_out(pdf, pdf->os_buf[i]); + i++; + } + } + pdf_end_stream(pdf); + pdf->os_cur_objnum = 0; /* to force object stream generation next time */ +} + +@ begin a PDF object +@c +void pdf_begin_obj(PDF pdf, int i, int pdf_os_level) +{ + ensure_output_state(pdf, ST_HEADER_WRITTEN); + pdf_os_prepare_obj(pdf, i, pdf_os_level); + if (!pdf->os_mode) { + pdf_printf(pdf, "%d 0 obj\n", (int) i); + } else if (pdf->compress_level == 0) { + pdf_printf(pdf, "%% %d 0 obj\n", (int) i); /* debugging help */ + } +} + +@ begin a new PDF object +@c +void pdf_new_obj(PDF pdf, int t, int i, int pdf_os) +{ + pdf_create_obj(pdf, t, i); + pdf_begin_obj(pdf, pdf->obj_ptr, pdf_os); +} + +@ end a PDF object +@c +void pdf_end_obj(PDF pdf) +{ + if (pdf->os_mode) { + if (pdf->os_idx == pdf_os_max_objs - 1) + pdf_os_write_objstream(pdf); + } else { + pdf_puts(pdf, "endobj\n"); /* end a PDF object */ + } +} + +@ @c +void write_stream_length(PDF pdf, int length, longinteger offset) +{ + if (jobname_cstr == NULL) + jobname_cstr = makecstring(job_name); + if (pdf->draftmode == 0) { + xfseeko(pdf->file, (off_t) offset, SEEK_SET, jobname_cstr); + fprintf(pdf->file, "%li", (long int) length); + xfseeko(pdf->file, pdf_offset(pdf), SEEK_SET, jobname_cstr); + } +} + +@ Converts any string given in in in an allowed PDF string which can be + handled by printf et.al.: \.{\\} is escaped to \.{\\\\}, parenthesis are escaped and + control characters are octal encoded. + This assumes that the string does not contain any already escaped + characters! + +@c +char *convertStringToPDFString(const char *in, int len) +{ + static char pstrbuf[MAX_PSTRING_LEN]; + char *out = pstrbuf; + int i, j, k; + char buf[5]; + j = 0; + for (i = 0; i < len; i++) { + check_buf((unsigned) j + sizeof(buf), MAX_PSTRING_LEN); + if (((unsigned char) in[i] < '!') || ((unsigned char) in[i] > '~')) { + /* convert control characters into oct */ + k = snprintf(buf, sizeof(buf), + "\\%03o", (unsigned int) (unsigned char) in[i]); + check_nprintf(k, sizeof(buf)); + out[j++] = buf[0]; + out[j++] = buf[1]; + out[j++] = buf[2]; + out[j++] = buf[3]; + } else if ((in[i] == '(') || (in[i] == ')')) { + /* escape paranthesis */ + out[j++] = '\\'; + out[j++] = in[i]; + } else if (in[i] == '\\') { + /* escape backslash */ + out[j++] = '\\'; + out[j++] = '\\'; + } else { + /* copy char :-) */ + out[j++] = in[i]; + } + } + out[j] = '\0'; + return pstrbuf; +} + +@ Converts any string given in in in an allowed PDF string which is + hexadecimal encoded; + |sizeof(out)| should be at least $|lin|*2+1$. + +@c +static void convertStringToHexString(const char *in, char *out, int lin) +{ + int i, j, k; + char buf[3]; + j = 0; + for (i = 0; i < lin; i++) { + k = snprintf(buf, sizeof(buf), + "%02X", (unsigned int) (unsigned char) in[i]); + check_nprintf(k, sizeof(buf)); + out[j++] = buf[0]; + out[j++] = buf[1]; + } + out[j] = '\0'; +} + +@ Compute the ID string as per PDF1.4 9.3: +\medskip +{\obeylines\obeyspaces + File identifers are defined by the optional ID entry in a PDF file's + trailer dictionary (see Section 3.4.4, "File Trailer"; see also + implementation note 105 in Appendix H). The value of this entry is an + array of two strings. The first string is a permanent identifier based + on the contents of the file at the time it was originally created, and + does not change when the file is incrementally updated. The second + string is a changing identifier based on the file's contents at the + time it was last updated. When a file is first written, both + identifiers are set to the same value. If both identifiers match when a + file reference is resolved, it is very likely that the correct file has + been found; if only the first identifier matches, then a different + version of the correct file has been found. + To help ensure the uniqueness of file identifiers, it is recommend + that they be computed using a message digest algorithm such as MD5 + (described in Internet RFC 1321, The MD5 Message-Digest Algorithm; see + the Bibliography), using the following information (see implementation + note 106 in Appendix H): + - The current time + - A string representation of the file's location, usually a pathname + - The size of the file in bytes + - The values of all entries in the file's document information + dictionary (see Section 9.2.1, Document Information Dictionary ) +} +\medskip + This stipulates only that the two IDs must be identical when the file is + created and that they should be reasonably unique. Since it's difficult + to get the file size at this point in the execution of pdfTeX and + scanning the info dict is also difficult, we start with a simpler + implementation using just the first two items. + +@c +void print_ID(PDF pdf, const char *file_name) +{ + time_t t; + size_t size; + char time_str[32]; + md5_state_t state; + md5_byte_t digest[16]; + char id[64]; + char pwd[4096]; + /* start md5 */ + md5_init(&state); + /* get the time */ + t = time(NULL); + size = strftime(time_str, sizeof(time_str), "%Y%m%dT%H%M%SZ", gmtime(&t)); + md5_append(&state, (const md5_byte_t *) time_str, (int) size); + /* get the file name */ + if (getcwd(pwd, sizeof(pwd)) == NULL) + pdftex_fail("getcwd() failed (%s), (path too long?)", strerror(errno)); + md5_append(&state, (const md5_byte_t *) pwd, (int) strlen(pwd)); + md5_append(&state, (const md5_byte_t *) "/", 1); + md5_append(&state, (const md5_byte_t *) file_name, (int) strlen(file_name)); + /* finish md5 */ + md5_finish(&state, digest); + /* write the IDs */ + convertStringToHexString((char *) digest, id, 16); + pdf_printf(pdf, "/ID [<%s> <%s>]", id, id); +} + +@ Print the /CreationDate entry. + + PDF Reference, third edition says about the expected date format: +\medskip +{\obeylines\obeyspaces + 3.8.2 Dates + + PDF defines a standard date format, which closely follows that of + the international standard ASN.1 (Abstract Syntax Notation One), + defined in ISO/IEC 8824 (see the Bibliography). A date is a string + of the form + + (D:YYYYMMDDHHmmSSOHH'mm') + + where + + YYYY is the year + MM is the month + DD is the day (01-31) + HH is the hour (00-23) + mm is the minute (00-59) + SS is the second (00-59) + O is the relationship of local time to Universal Time (UT), + denoted by one of the characters +, -, or Z (see below) + HH followed by ' is the absolute value of the offset from UT + in hours (00-23) + mm followed by ' is the absolute value of the offset from UT + in minutes (00-59) + + The apostrophe character (') after HH and mm is part of the syntax. + All fields after the year are optional. (The prefix D:, although also + optional, is strongly recommended.) The default values for MM and DD + are both 01; all other numerical fields default to zero values. A plus + sign (+) as the value of the O field signifies that local time is + later than UT, a minus sign (-) that local time is earlier than UT, + and the letter Z that local time is equal to UT. If no UT information + is specified, the relationship of the specified time to UT is + considered to be unknown. Whether or not the time zone is known, the + rest of the date should be specified in local time. + + For example, December 23, 1998, at 7:52 PM, U.S. Pacific Standard + Time, is represented by the string + + D:199812231952-08'00' +} + + The main difficulty is get the time zone offset. |strftime()| does this in ISO + C99 (e.g. newer glibc) with \%z, but we have to work with other systems (e.g. + Solaris 2.5). + +@c +#define TIME_STR_SIZE 30 /* minimum size for |time_str| is 24: |"D:YYYYmmddHHMMSS+HH'MM'"| */ + +static void makepdftime(PDF pdf) +{ + struct tm lt, gmt; + size_t size; + int i, off, off_hours, off_mins; + time_t t = pdf->start_time; + char *time_str = pdf->start_time_str; + + /* get the time */ + lt = *localtime(&t); + size = strftime(time_str, TIME_STR_SIZE, "D:%Y%m%d%H%M%S", <); + /* expected format: "YYYYmmddHHMMSS" */ + if (size == 0) { + /* unexpected, contents of |time_str| is undefined */ + time_str[0] = '\0'; + return; + } + + /* correction for seconds: \%S can be in range 00..61, + the PDF reference expects 00..59, + therefore we map "60" and "61" to "59" */ + if (time_str[14] == '6') { + time_str[14] = '5'; + time_str[15] = '9'; + time_str[16] = '\0'; /* for safety */ + } + + /* get the time zone offset */ + gmt = *gmtime(&t); + + /* this calculation method was found in exim's tod.c */ + off = 60 * (lt.tm_hour - gmt.tm_hour) + lt.tm_min - gmt.tm_min; + if (lt.tm_year != gmt.tm_year) { + off += (lt.tm_year > gmt.tm_year) ? 1440 : -1440; + } else if (lt.tm_yday != gmt.tm_yday) { + off += (lt.tm_yday > gmt.tm_yday) ? 1440 : -1440; + } + + if (off == 0) { + time_str[size++] = 'Z'; + time_str[size] = 0; + } else { + off_hours = off / 60; + off_mins = abs(off - off_hours * 60); + i = snprintf(&time_str[size], 9, "%+03d'%02d'", off_hours, off_mins); + check_nprintf(i, 9); + } + pdf->start_time = t; +} + +@ @c +void init_start_time(PDF pdf) +{ + assert(pdf); + if (pdf->start_time == 0) { + pdf->start_time = time((time_t *) NULL); + pdf->start_time_str = xtalloc(TIME_STR_SIZE, char); + makepdftime(pdf); + } +} + +@ @c +void print_creation_date(PDF pdf) +{ + init_start_time(pdf); + pdf_printf(pdf, "/CreationDate (%s)\n", pdf->start_time_str); +} + +@ @c +void print_mod_date(PDF pdf) +{ + init_start_time(pdf); + pdf_printf(pdf, "/ModDate (%s)\n", pdf->start_time_str); +} + +@ @c +char *getcreationdate(PDF pdf) +{ + assert(pdf); + init_start_time(pdf); + return pdf->start_time_str; +} + +@ @c +void remove_pdffile(PDF pdf) +{ + if (pdf != NULL) { + if (!kpathsea_debug && pdf->file_name && (pdf->draftmode != 0)) { + xfclose(pdf->file, pdf->file_name); + remove(pdf->file_name); + } + } +} + +@ @c +static void realloc_fb(PDF pdf) +{ + if (pdf->fb_array == NULL) { + pdf->fb_limit = SMALL_ARRAY_SIZE; + pdf->fb_array = xtalloc(pdf->fb_limit, char); + pdf->fb_ptr = pdf->fb_array; + } else if ((size_t) (pdf->fb_ptr - pdf->fb_array + 1) > pdf->fb_limit) { + size_t last_ptr_index = (size_t) (pdf->fb_ptr - pdf->fb_array); + pdf->fb_limit *= 2; + if ((size_t) (pdf->fb_ptr - pdf->fb_array + 1) > pdf->fb_limit) + pdf->fb_limit = (size_t) (pdf->fb_ptr - pdf->fb_array + 1); + xretalloc(pdf->fb_array, pdf->fb_limit, char); + pdf->fb_ptr = pdf->fb_array + last_ptr_index; + } +} + +@ @c +int fb_offset(PDF pdf) +{ + return (int) (pdf->fb_ptr - pdf->fb_array); +} + +@ @c +void fb_seek(PDF pdf, int offset) +{ + pdf->fb_ptr = pdf->fb_array + offset; +} + +@ @c +void fb_putchar(PDF pdf, eight_bits b) +{ + if ((size_t) (pdf->fb_ptr - pdf->fb_array + 1) > pdf->fb_limit) + realloc_fb(pdf); + *(pdf->fb_ptr)++ = (char) b; +} + +@ @c +void fb_flush(PDF pdf) +{ + char *p; + int n; + for (p = pdf->fb_array; p < pdf->fb_ptr;) { + n = pdf->buf_size - pdf->ptr; + if (pdf->fb_ptr - p < n) + n = (int) (pdf->fb_ptr - p); + memcpy(pdf->buf + pdf->ptr, p, (unsigned) n); + pdf->ptr += n; + if (pdf->ptr == pdf->buf_size) + pdf_flush(pdf); + p += n; + } + pdf->fb_ptr = pdf->fb_array; +} + +@ @c +void fb_free(PDF pdf) +{ + xfree(pdf->fb_array); +} + +@ @c +#define ZIP_BUF_SIZE 32768 + +#define check_err(f, fn) \ + if (f != Z_OK) \ + pdftex_fail("zlib: %s() failed (error code %d)", fn, f) + +@ @c +void write_zip(PDF pdf, boolean finish) +{ + int err; + int level = pdf->compress_level; + assert(level > 0); + /* This was just to suppress the filename report in |pdftex_fail| + but zlib errors are rare enough (especially now that the + compress level is fixed) that I don't care about the slightly + ugly error message that could result. + */ +#if 0 + cur_file_name = NULL; +#endif + if (pdf->stream_length == 0) { + if (pdf->zipbuf == NULL) { + pdf->zipbuf = xtalloc(ZIP_BUF_SIZE, char); + pdf->c_stream.zalloc = (alloc_func) 0; + pdf->c_stream.zfree = (free_func) 0; + pdf->c_stream.opaque = (voidpf) 0; + check_err(deflateInit(&pdf->c_stream, level), "deflateInit"); + } else { + check_err(deflateReset(&pdf->c_stream), "deflateReset"); + } + pdf->c_stream.next_out = (Bytef *) pdf->zipbuf; + pdf->c_stream.avail_out = ZIP_BUF_SIZE; + } + assert(pdf->zipbuf != NULL); + pdf->c_stream.next_in = pdf->buf; + pdf->c_stream.avail_in = (uInt) pdf->ptr; + for (;;) { + if (pdf->c_stream.avail_out == 0) { + pdf->gone = + pdf->gone + (off_t) xfwrite(pdf->zipbuf, 1, ZIP_BUF_SIZE, + pdf->file); + pdf->last_byte = pdf->zipbuf[ZIP_BUF_SIZE - 1]; /* not needed */ + pdf->c_stream.next_out = (Bytef *) pdf->zipbuf; + pdf->c_stream.avail_out = ZIP_BUF_SIZE; + } + err = deflate(&pdf->c_stream, finish ? Z_FINISH : Z_NO_FLUSH); + if (finish && err == Z_STREAM_END) + break; + check_err(err, "deflate"); + if (!finish && pdf->c_stream.avail_in == 0) + break; + } + if (finish) { + if (pdf->c_stream.avail_out < ZIP_BUF_SIZE) { /* at least one byte has been output */ + pdf->gone = pdf->gone + + (off_t) xfwrite(pdf->zipbuf, 1, + (size_t) (ZIP_BUF_SIZE - + pdf->c_stream.avail_out), pdf->file); + pdf->last_byte = + pdf->zipbuf[ZIP_BUF_SIZE - pdf->c_stream.avail_out - 1]; + } + xfflush(pdf->file); + } + pdf->stream_length = (off_t) pdf->c_stream.total_out; +} + +@ @c +void zip_free(PDF pdf) +{ + if (pdf->zipbuf != NULL) { + check_err(deflateEnd(&pdf->c_stream), "deflateEnd"); + free(pdf->zipbuf); + } +} + +@ @c +void pdf_error(const char *t, const char *p) +{ + normalize_selector(); + print_err("LuaTeX error"); + if (t != NULL) { + tprint(" ("); + tprint(t); + tprint(")"); + } + tprint(": "); + if (p != NULL) + tprint(p); + succumb(); +} + +@ @c +void pdf_warning(const char *t, const char *p, boolean prepend_nl, + boolean append_nl) +{ + if (prepend_nl) + print_ln(); + tprint("LuaTeX warning"); + if (t != NULL) { + tprint(" ("); + tprint(t); + tprint(")"); + } + tprint(": "); + if (p != NULL) + tprint(p); + if (append_nl) + print_ln(); + if (history == spotless) + history = warning_issued; +} + +@ Use |check_o_mode()| in the backend-specific "Implement..." chunks + +@c +void check_o_mode(PDF pdf, const char *s, int o_mode_bitpattern, boolean strict) +{ + + char warn_string[100]; + output_mode o_mode; + const char *m = NULL; + + /* in warn mode (strict == false): + only check, don't do |fix_o_mode()| here! |pdf->o_mode| is left + in possibly wrong state until real output, ok. + */ + + if (pdf->o_mode == OMODE_NONE) { + if (pdf_output > 0) { + if (pdf_output == 2009) + o_mode = OMODE_LUA; + else + o_mode = OMODE_PDF; + } else + o_mode = OMODE_DVI; + } else + o_mode = pdf->o_mode; + if (!((1 << o_mode) & o_mode_bitpattern)) { /* warning or error */ + switch (o_mode) { + case OMODE_DVI: + m = "DVI"; + break; + case OMODE_PDF: + m = "PDF"; + break; + case OMODE_LUA: + m = "Lua"; + break; + default: + assert(0); + } + snprintf(warn_string, 99, "not allowed in %s mode (\\pdfpoutput = %d)", + m, (int) pdf_output); + if (strict) + pdf_error(s, warn_string); + else + pdf_warning(s, warn_string, true, true); + } else if (strict) + ensure_output_state(pdf, ST_HEADER_WRITTEN); +} + +@ @c +void set_job_id(PDF pdf, int year, int month, int day, int time) +{ + char *name_string, *format_string, *s; + size_t slen; + int i; + + if (pdf->job_id_string != NULL) + return; + + name_string = makecstring(job_name); + format_string = makecstring(format_ident); + make_pdftex_banner(); + slen = SMALL_BUF_SIZE + + strlen(name_string) + strlen(format_string) + strlen(pdftex_banner); + s = xtalloc(slen, char); + /* The Web2c version string starts with a space. */ + i = snprintf(s, slen, + "%.4d/%.2d/%.2d %.2d:%.2d %s %s %s", + year, month, day, time / 60, time % 60, + name_string, format_string, pdftex_banner); + check_nprintf(i, slen); + pdf->job_id_string = xstrdup(s); + xfree(s); + xfree(name_string); + xfree(format_string); +} + +@ @c +char *get_resname_prefix(PDF pdf) +{ + static char name_str[] = + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + static char prefix[7]; /* make a tag of 6 chars long */ + unsigned long crc; + short i; + size_t base = strlen(name_str); + crc = crc32(0L, Z_NULL, 0); + crc = + crc32(crc, (Bytef *) pdf->job_id_string, + (uInt) strlen(pdf->job_id_string)); + for (i = 0; i < 6; i++) { + prefix[i] = name_str[crc % base]; + crc /= base; + } + prefix[6] = '\0'; + return prefix; +} + +@ @c +#define mag int_par(mag_code) + +#define pdf_xform_attr equiv(pdf_xform_attr_loc) +#define pdf_xform_resources equiv(pdf_xform_resources_loc) + +void pdf_begin_page(PDF pdf, boolean shipping_page) +{ + scaled form_margin = one_bp; + ensure_output_state(pdf, ST_HEADER_WRITTEN); + init_pdf_pagecalculations(pdf); + + if (pdf->page_resources == NULL) { + pdf->page_resources = xmalloc(sizeof(pdf_resource_struct)); + pdf->page_resources->resources_tree = NULL; + } + pdf->page_resources->last_resources = pdf_new_objnum(pdf); + reset_page_resources(pdf); + + if (shipping_page) { + pdf->last_page = get_obj(pdf, obj_type_page, total_pages + 1, 0); + set_obj_aux(pdf, pdf->last_page, 1); /* mark that this page has been created */ + pdf_new_dict(pdf, obj_type_pagestream, 0, 0); + pdf->last_stream = pdf->obj_ptr; + pdf->last_thread = null; + } else { + pdf_begin_dict(pdf, pdf_cur_form, 0); + pdf->last_stream = pdf_cur_form; + + /* Write out Form stream header */ + pdf_puts(pdf, "/Type /XObject\n"); + pdf_puts(pdf, "/Subtype /Form\n"); + if (pdf_xform_attr != null) + pdf_print_toks_ln(pdf, pdf_xform_attr); + if (obj_xform_attr(pdf, pdf_cur_form) != null) { + pdf_print_toks_ln(pdf, obj_xform_attr(pdf, pdf_cur_form)); + delete_token_ref(obj_xform_attr(pdf, pdf_cur_form)); + set_obj_xform_attr(pdf, pdf_cur_form, null); + } + pdf_puts(pdf, "/BBox ["); + pdf_print_bp(pdf, -form_margin); + pdf_out(pdf, ' '); + pdf_print_bp(pdf, -form_margin); + pdf_out(pdf, ' '); + pdf_print_bp(pdf, cur_page_size.h + form_margin); + pdf_out(pdf, ' '); + pdf_print_bp(pdf, cur_page_size.v + form_margin); + pdf_puts(pdf, "]\n"); + pdf_puts(pdf, "/FormType 1\n"); + pdf_puts(pdf, "/Matrix [1 0 0 1 0 0]\n"); + pdf_indirect_ln(pdf, "Resources", pdf->page_resources->last_resources); + } + /* Start stream of page/form contents */ + pdf_begin_stream(pdf); + if (shipping_page) { + /* Adjust transformation matrix for the magnification ratio */ + if (mag != 1000) { + pdf_print_real(pdf, mag, 3); + pdf_puts(pdf, " 0 0 "); + pdf_print_real(pdf, mag, 3); + pdf_puts(pdf, " 0 0 cm\n"); + } + } + pdf_shipout_begin(shipping_page); + + if (shipping_page) + pdf_out_colorstack_startpage(pdf); +} + +@ @c +#define pdf_page_attr equiv(pdf_page_attr_loc) +#define pdf_page_resources equiv(pdf_page_resources_loc) + +void pdf_end_page(PDF pdf, boolean shipping_page) +{ + int j; + pdf_resource_struct *res_p = pdf->page_resources; + pdf_resource_struct local_page_resources; + pdf_object_list *ol, *ol1; + scaledpos save_cur_page_size; /* to save |cur_page_size| during flushing pending forms */ + int procset = PROCSET_PDF; + + /* Finish stream of page/form contents */ + pdf_goto_pagemode(pdf); + pdf_shipout_end(shipping_page); + pdf_end_stream(pdf); + + if (shipping_page) { + /* Write out page object */ + + pdf_begin_dict(pdf, pdf->last_page, 1); + pdf->last_pages = pdf_do_page_divert(pdf, pdf->last_page, 0); + pdf_puts(pdf, "/Type /Page\n"); + pdf_indirect_ln(pdf, "Contents", pdf->last_stream); + pdf_indirect_ln(pdf, "Resources", res_p->last_resources); + pdf_puts(pdf, "/MediaBox [0 0 "); + pdf_print_mag_bp(pdf, cur_page_size.h); + pdf_out(pdf, ' '); + pdf_print_mag_bp(pdf, cur_page_size.v); + pdf_puts(pdf, "]\n"); + if (pdf_page_attr != null) + pdf_print_toks_ln(pdf, pdf_page_attr); + if (pdf_pageattributes_toks != null) /* from Lua */ + pdf_print_toks_ln(pdf, pdf_pageattributes_toks); + pdf_indirect_ln(pdf, "Parent", pdf->last_pages); + if (pdf->img_page_group_val > 0) { + pdf_printf(pdf, "/Group %d 0 R\n", pdf->img_page_group_val); + pdf->img_page_group_val = 0; + } + /* Generate array of annotations or beads in page */ + ol = get_page_resources_list(pdf, obj_type_annot); + ol1 = get_page_resources_list(pdf, obj_type_link); + if (ol != NULL || ol1 != NULL) { + pdf_puts(pdf, "/Annots [ "); + while (ol != NULL) { + assert(ol->info > 0); + pdf_print_int(pdf, ol->info); + pdf_puts(pdf, " 0 R "); + ol = ol->link; + } + while (ol1 != NULL) { + pdf_print_int(pdf, ol1->info); + pdf_puts(pdf, " 0 R "); + ol1 = ol1->link; + } + pdf_puts(pdf, "]\n"); + } + print_beads_list(pdf); + pdf_end_dict(pdf); + } + + /* Write out resource lists */ + /* Write out pending raw objects */ + ol = get_page_resources_list(pdf, obj_type_obj); + while (ol != NULL) { + if (!is_obj_written(pdf, ol->info)) + pdf_write_obj(pdf, ol->info); + ol = ol->link; + } + + /* Write out pending forms */ + /* When flushing pending forms we need to save and restore resource lists + which are also used by page shipping. + Saving and restoring |cur_page_size| is needed for proper + writing out pending PDF marks. */ + ol = get_page_resources_list(pdf, obj_type_xform); + while (ol != NULL) { + if (!is_obj_written(pdf, ol->info)) { + pdf_cur_form = ol->info; + save_cur_page_size = cur_page_size; + pdf->page_resources = &local_page_resources; + local_page_resources.resources_tree = NULL; + ship_out(pdf, obj_xform_box(pdf, pdf_cur_form), false); + /* Restore page size and page resources */ + cur_page_size = save_cur_page_size; + destroy_page_resources_tree(pdf); + pdf->page_resources = res_p; + } + ol = ol->link; + } + + /* Write out pending images */ + ol = get_page_resources_list(pdf, obj_type_ximage); + while (ol != NULL) { + if (!is_obj_written(pdf, ol->info)) + pdf_write_image(pdf, ol->info); + ol = ol->link; + } + + if (shipping_page) { + /* Write out pending PDF marks */ + /* Write out PDF annotations */ + ol = get_page_resources_list(pdf, obj_type_annot); + while (ol != NULL) { + if (ol->info > 0) { + j = obj_annot_ptr(pdf, ol->info); /* |j| points to |pdf_annot_node| */ + pdf_begin_dict(pdf, ol->info, 1); + pdf_puts(pdf, "/Type /Annot\n"); + pdf_print_toks_ln(pdf, pdf_annot_data(j)); + pdf_rectangle(pdf, j); + pdf_end_dict(pdf); + } + ol = ol->link; + } + + /* Write out PDF link annotations */ + if ((ol = get_page_resources_list(pdf, obj_type_link)) != NULL) { + while (ol != NULL) { + j = obj_annot_ptr(pdf, ol->info); + pdf_begin_dict(pdf, ol->info, 1); + pdf_puts(pdf, "/Type /Annot\n"); + if (pdf_action_type(pdf_link_action(j)) != pdf_action_user) + pdf_puts(pdf, "/Subtype /Link\n"); + if (pdf_link_attr(j) != null) + pdf_print_toks_ln(pdf, pdf_link_attr(j)); + pdf_rectangle(pdf, j); + if (pdf_action_type(pdf_link_action(j)) != pdf_action_user) + pdf_puts(pdf, "/A "); + write_action(pdf, pdf_link_action(j)); + pdf_end_dict(pdf); + ol = ol->link; + } + /* Flush |pdf_start_link_node|'s created by |append_link| */ + ol = get_page_resources_list(pdf, obj_type_link); + while (ol != NULL) { + j = obj_annot_ptr(pdf, ol->info); + /* nodes with |subtype = pdf_link_data_node| were created by |append_link| and + must be flushed here, as they are not linked in any list */ + if (subtype(j) == pdf_link_data_node) + flush_node(j); + ol = ol->link; + } + } + + /* Write out PDF mark destinations */ + write_out_pdf_mark_destinations(pdf); + /* Write out PDF bead rectangle specifications */ + print_bead_rectangles(pdf); + + } + /* Write out resources dictionary */ + pdf_begin_dict(pdf, res_p->last_resources, 1); + /* Print additional resources */ + if (shipping_page) { + if (pdf_page_resources != null) + pdf_print_toks_ln(pdf, pdf_page_resources); + if (pdf_pageresources_toks != null) /* from Lua */ + pdf_print_toks_ln(pdf, pdf_pageresources_toks); + } else { + if (pdf_xform_resources != null) + pdf_print_toks_ln(pdf, pdf_xform_resources); + if (obj_xform_resources(pdf, pdf_cur_form) != null) { + pdf_print_toks_ln(pdf, obj_xform_resources(pdf, pdf_cur_form)); + delete_token_ref(obj_xform_resources(pdf, pdf_cur_form)); + set_obj_xform_resources(pdf, pdf_cur_form, null); + } + } + + /* Generate font resources */ + if ((ol = get_page_resources_list(pdf, obj_type_font)) != NULL) { + pdf_puts(pdf, "/Font << "); + while (ol != NULL) { + assert(pdf_font_num(ol->info) > 0); /* always base font: an object number */ + pdf_puts(pdf, "/F"); + pdf_print_int(pdf, ol->info); + pdf_print_resname_prefix(pdf); + pdf_out(pdf, ' '); + pdf_print_int(pdf, pdf_font_num(ol->info)); + pdf_puts(pdf, " 0 R "); + ol = ol->link; + } + pdf_puts(pdf, ">>\n"); + procset |= PROCSET_TEXT; + } + + /* Generate XObject resources */ + ol = get_page_resources_list(pdf, obj_type_xform); + ol1 = get_page_resources_list(pdf, obj_type_ximage); + if (ol != NULL || ol1 != NULL) { + pdf_puts(pdf, "/XObject << "); + while (ol != NULL) { + pdf_printf(pdf, "/Fm"); + pdf_print_int(pdf, obj_info(pdf, ol->info)); + pdf_print_resname_prefix(pdf); + pdf_out(pdf, ' '); + pdf_print_int(pdf, ol->info); + pdf_puts(pdf, " 0 R "); + ol = ol->link; + } + while (ol1 != null) { + pdf_puts(pdf, "/Im"); + pdf_print_int(pdf, obj_data_ptr(pdf, ol1->info)); + pdf_print_resname_prefix(pdf); + pdf_out(pdf, ' '); + pdf_print_int(pdf, ol1->info); + pdf_puts(pdf, " 0 R "); + procset |= img_procset(idict_array[obj_data_ptr(pdf, ol1->info)]); + ol1 = ol1->link; + } + pdf_puts(pdf, ">>\n"); + } + + /* Generate ProcSet */ + pdf_puts(pdf, "/ProcSet ["); + if ((procset & PROCSET_PDF) != 0) + pdf_puts(pdf, " /PDF"); + if ((procset & PROCSET_TEXT) != 0) + pdf_puts(pdf, " /Text"); + if ((procset & PROCSET_IMAGE_B) != 0) + pdf_puts(pdf, " /ImageB"); + if ((procset & PROCSET_IMAGE_C) != 0) + pdf_puts(pdf, " /ImageC"); + if ((procset & PROCSET_IMAGE_I) != 0) + pdf_puts(pdf, " /ImageI"); + pdf_puts(pdf, " ]\n"); + + pdf_end_dict(pdf); +} + +@* Finishing the PDF output file. + +@ @c +#define pdf_gen_tounicode int_par(pdf_gen_tounicode_code) + +@ Destinations that have been referenced but don't exists have +|obj_dest_ptr=null|. Leaving them undefined might cause troubles for +PDF browsers, so we need to fix them; they point to the last page. + +@c +static void check_nonexisting_destinations(PDF pdf) +{ + int k; + for (k = pdf->head_tab[obj_type_dest]; k != 0; k = obj_link(pdf, k)) { + if (obj_dest_ptr(pdf, k) == null) { + pdf_warning("dest", NULL, false, false); + if (obj_info(pdf, k) < 0) { + tprint("name{"); + print(-obj_info(pdf, k)); + tprint("}"); + } else { + tprint("num"); + print_int(obj_info(pdf, k)); + } + tprint + (" has been referenced but does not exist, replaced by a fixed one"); + print_ln(); + print_ln(); + pdf_begin_obj(pdf, k, 1); + pdf_out(pdf, '['); + pdf_print_int(pdf, pdf->last_page); + pdf_puts(pdf, " 0 R /Fit]\n"); + pdf_end_obj(pdf); + } + } +} + +@ @c +static void check_nonexisting_pages(PDF pdf) +{ + struct avl_traverser t; + oentry *p; + struct avl_table *page_tree = pdf->obj_tree[obj_type_page]; + avl_t_init(&t, page_tree); + /* search from the end backward until the last real page is found */ + for (p = avl_t_last(&t, page_tree); + p != NULL && obj_aux(pdf, p->objptr) == 0; p = avl_t_prev(&t)) { + pdf_warning("dest", "Page ", false, false); + print_int(obj_info(pdf, p->objptr)); + tprint(" has been referenced but does not exist!"); + print_ln(); + print_ln(); + } +} + +@ If the same keys in a dictionary are given several times, then it is not +defined which value is choosen by an application. Therefore the keys +|/Producer| and |/Creator| are only set if the token list +|pdf_info_toks| converted to a string does not contain these key strings. + +@c +static boolean substr_of_str(const char *s, const char *t) +{ + if (strstr(t, s) == NULL) + return false; + return true; +} + +void pdf_print_info(PDF pdf, int luatex_version, str_number luatex_revision) +{ /* print info object */ + boolean creator_given, producer_given, creationdate_given, moddate_given, + trapped_given; + char *s = NULL; + int len = 0; + pdf_new_dict(pdf, obj_type_others, 0, 3); /* keep Info readable unless explicitely forced */ + creator_given = false; + producer_given = false; + creationdate_given = false; + moddate_given = false; + trapped_given = false; + if (pdf_info_toks != 0) { + s = tokenlist_to_cstring(pdf_info_toks, true, &len); + creator_given = substr_of_str("/Creator", s); + producer_given = substr_of_str("/Producer", s); + creationdate_given = substr_of_str("/CreationDate", s); + moddate_given = substr_of_str("/ModDate", s); + trapped_given = substr_of_str("/Trapped", s); + } + if (!producer_given) { + /* Print the Producer key */ + pdf_puts(pdf, "/Producer (LuaTeX-"); + pdf_print_int(pdf, luatex_version / 100); + pdf_out(pdf, '.'); + pdf_print_int(pdf, luatex_version % 100); + pdf_out(pdf, '.'); + pdf_print(pdf, luatex_revision); + pdf_puts(pdf, ")\n"); + + } + if (pdf_info_toks != null) { + if (len > 0) { + pdf_puts(pdf, s); + pdf_print_nl(pdf); + xfree(s); + } + delete_token_ref(pdf_info_toks); + pdf_info_toks = null; + } + if (!creator_given) + pdf_str_entry_ln(pdf, "Creator", "TeX"); + if (!creationdate_given) { + print_creation_date(pdf); + } + if (!moddate_given) { + print_mod_date(pdf); + } + if (!trapped_given) { + pdf_puts(pdf, "/Trapped /False\n"); + } + pdf_str_entry_ln(pdf, "PTEX.Fullbanner", pdftex_banner); + pdf_end_dict(pdf); +} + +void build_free_object_list(PDF pdf) +{ + int k, l; + l = 0; + set_obj_fresh(pdf, l); /* null object at begin of list of free objects */ + for (k = 1; k <= pdf->sys_obj_ptr; k++) { + if (!is_obj_written(pdf, k)) { + set_obj_link(pdf, l, k); + l = k; + } + } + set_obj_link(pdf, l, 0); +} + +@ Now the finish of PDF output file. At this moment all Page objects +are already written completely to PDF output file. + +@c +void finish_pdf_file(PDF pdf, int luatex_version, str_number luatex_revision) +{ + boolean res; + int i, j, k; + int root, outlines, threads, names_tree; + int xref_offset_width; + int callback_id = callback_defined(stop_run_callback); + + if (total_pages == 0) { + if (callback_id == 0) { + tprint_nl("No pages of output."); + } else if (callback_id > 0) { + res = run_callback(callback_id, "->"); + } + if (pdf->gone > 0) + garbage_warning(); + } else { + if (pdf->draftmode == 0) { + pdf_flush(pdf); /* to make sure that the output file name has been already created */ + flush_jbig2_page0_objects(pdf); /* flush page 0 objects from JBIG2 images, if any */ + + check_nonexisting_pages(pdf); + check_nonexisting_destinations(pdf); + + /* Output fonts definition */ + for (k = 1; k <= max_font_id(); k++) { + if (font_used(k) && (pdf_font_num(k) < 0)) { + i = -pdf_font_num(k); + assert(pdf_font_num(i) > 0); + for (j = font_bc(k); j <= font_ec(k); j++) + if (quick_char_exists(k, j) && pdf_char_marked(k, j)) + pdf_mark_char(i, j); + if ((pdf_font_attr(i) == 0) && (pdf_font_attr(k) != 0)) { + set_pdf_font_attr(i, pdf_font_attr(k)); + } else if ((pdf_font_attr(k) == 0) + && (pdf_font_attr(i) != 0)) { + set_pdf_font_attr(k, pdf_font_attr(i)); + } else if ((pdf_font_attr(i) != 0) + && (pdf_font_attr(k) != 0) + && + (!str_eq_str + (pdf_font_attr(i), pdf_font_attr(k)))) { + pdf_warning("\\pdffontattr", "fonts ", false, false); + print_font_identifier(i); + tprint(" and "); + print_font_identifier(k); + tprint + (" have conflicting attributes; I will ignore the attributes assigned to "); + print_font_identifier(i); + print_ln(); + print_ln(); + } + } + } + pdf->gen_tounicode = pdf_gen_tounicode; + k = pdf->head_tab[obj_type_font]; + while (k != 0) { + f = obj_info(pdf, k); + assert(pdf_font_num(f) > 0); + assert(pdf_font_num(f) == k); + do_pdf_font(pdf, f); + k = obj_link(pdf, k); + } + write_fontstuff(pdf); + + pdf->last_pages = output_pages_tree(pdf); + /* Output outlines */ + outlines = print_outlines(pdf); + + /* Output name tree */ + /* The name tree is very similiar to Pages tree so its construction should be + certain from Pages tree construction. For intermediate node |obj_info| will be + the first name and |obj_link| will be the last name in \.{\\Limits} array. + Note that |pdf_dest_names_ptr| will be less than |obj_ptr|, so we test if + |k < pdf_dest_names_ptr| then |k| is index of leaf in |dest_names|; else + |k| will be index in |obj_tab| of some intermediate node. + */ + names_tree = output_name_tree(pdf); + + /* Output article threads */ + if (pdf->head_tab[obj_type_thread] != 0) { + pdf_new_obj(pdf, obj_type_others, 0, 1); + threads = pdf->obj_ptr; + pdf_out(pdf, '['); + k = pdf->head_tab[obj_type_thread]; + while (k != 0) { + pdf_print_int(pdf, k); + pdf_puts(pdf, " 0 R "); + k = obj_link(pdf, k); + } + pdf_remove_last_space(pdf); + pdf_puts(pdf, "]\n"); + pdf_end_obj(pdf); + k = pdf->head_tab[obj_type_thread]; + while (k != 0) { + out_thread(pdf, k); + k = obj_link(pdf, k); + } + } else { + threads = 0; + } + + /* Output the catalog object */ + pdf_new_dict(pdf, obj_type_others, 0, 1); + root = pdf->obj_ptr; + pdf_puts(pdf, "/Type /Catalog\n"); + pdf_indirect_ln(pdf, "Pages", pdf->last_pages); + if (threads != 0) + pdf_indirect_ln(pdf, "Threads", threads); + if (outlines != 0) + pdf_indirect_ln(pdf, "Outlines", outlines); + if (names_tree != 0) + pdf_indirect_ln(pdf, "Names", names_tree); + if (pdf_catalog_toks != null) { + pdf_print_toks_ln(pdf, pdf_catalog_toks); + delete_token_ref(pdf_catalog_toks); + pdf_catalog_toks = null; + } + if (pdf_catalog_openaction != 0) + pdf_indirect_ln(pdf, "OpenAction", pdf_catalog_openaction); + pdf_end_dict(pdf); + + pdf_print_info(pdf, luatex_version, luatex_revision); /* last candidate for object stream */ + + if (pdf->os_enable) { + pdf_os_switch(pdf, true); + pdf_os_write_objstream(pdf); + pdf_flush(pdf); + pdf_os_switch(pdf, false); + /* Output the cross-reference stream dictionary */ + pdf_new_dict(pdf, obj_type_others, 0, 0); + if ((obj_offset(pdf, pdf->sys_obj_ptr) / 256) > 16777215) + xref_offset_width = 5; + else if (obj_offset(pdf, pdf->sys_obj_ptr) > 16777215) + xref_offset_width = 4; + else if (obj_offset(pdf, pdf->sys_obj_ptr) > 65535) + xref_offset_width = 3; + else + xref_offset_width = 2; + /* Build a linked list of free objects */ + build_free_object_list(pdf); + pdf_puts(pdf, "/Type /XRef\n"); + pdf_puts(pdf, "/Index [0 "); + pdf_print_int(pdf, pdf->obj_ptr + 1); + pdf_puts(pdf, "]\n"); + pdf_int_entry_ln(pdf, "Size", pdf->obj_ptr + 1); + pdf_puts(pdf, "/W [1 "); + pdf_print_int(pdf, xref_offset_width); + pdf_puts(pdf, " 1]\n"); + pdf_indirect_ln(pdf, "Root", root); + pdf_indirect_ln(pdf, "Info", pdf->obj_ptr - 1); + if (pdf_trailer_toks != null) { + pdf_print_toks_ln(pdf, pdf_trailer_toks); + delete_token_ref(pdf_trailer_toks); + pdf_trailer_toks = null; + } + print_ID(pdf, pdf->file_name); + pdf_print_nl(pdf); + pdf_begin_stream(pdf); + for (k = 0; k <= pdf->sys_obj_ptr; k++) { + if (!is_obj_written(pdf, k)) { /* a free object */ + pdf_out(pdf, 0); + pdf_out_bytes(pdf, obj_link(pdf, k), xref_offset_width); + pdf_out(pdf, 255); + } else if (obj_os_idx(pdf, k) == -1) { /* object not in object stream */ + pdf_out(pdf, 1); + pdf_out_bytes(pdf, obj_offset(pdf, k), + xref_offset_width); + pdf_out(pdf, 0); + } else { /* object in object stream */ + pdf_out(pdf, 2); + pdf_out_bytes(pdf, obj_offset(pdf, k), + xref_offset_width); + pdf_out(pdf, obj_os_idx(pdf, k)); + } + } + pdf_end_stream(pdf); + /* TODO: generate a debug version of the crossref */ + + pdf_flush(pdf); + } else { + /* Output the |obj_tab| */ + /* Build a linked list of free objects */ + build_free_object_list(pdf); + + pdf_save_offset(pdf); + pdf_puts(pdf, "xref\n"); + pdf_puts(pdf, "0 "); + pdf_print_int_ln(pdf, pdf->obj_ptr + 1); + pdf_print_fw_int(pdf, obj_link(pdf, 0), 10); + pdf_puts(pdf, " 65535 f \n"); + for (k = 1; k <= pdf->obj_ptr; k++) { + if (!is_obj_written(pdf, k)) { + pdf_print_fw_int(pdf, obj_link(pdf, k), 10); + pdf_puts(pdf, " 00000 f \n"); + } else { + pdf_print_fw_int(pdf, obj_offset(pdf, k), 10); + pdf_puts(pdf, " 00000 n \n"); + } + } + + } + + /* Output the trailer */ + if (!pdf->os_enable) { + pdf_puts(pdf, "trailer\n"); + pdf_puts(pdf, "<< "); + pdf_int_entry_ln(pdf, "Size", pdf->sys_obj_ptr + 1); + pdf_indirect_ln(pdf, "Root", root); + pdf_indirect_ln(pdf, "Info", pdf->sys_obj_ptr); + if (pdf_trailer_toks != null) { + pdf_print_toks_ln(pdf, pdf_trailer_toks); + delete_token_ref(pdf_trailer_toks); + pdf_trailer_toks = null; + } + print_ID(pdf, pdf->file_name); + pdf_puts(pdf, " >>\n"); + } + pdf_puts(pdf, "startxref\n"); + if (pdf->os_enable) + pdf_print_int_ln(pdf, obj_offset(pdf, pdf->sys_obj_ptr)); + else + pdf_print_int_ln(pdf, pdf_saved_offset(pdf)); + pdf_puts(pdf, "%%EOF\n"); + + pdf_flush(pdf); + if (callback_id == 0) { + tprint_nl("Output written on "); + tprint(pdf->file_name); + tprint(" ("); + print_int(total_pages); + tprint(" page"); + if (total_pages != 1) + print_char('s'); + tprint(", "); + print_int(pdf_offset(pdf)); + tprint(" bytes)."); + } else if (callback_id > 0) { + res = run_callback(callback_id, "->"); + } + } + libpdffinish(pdf); + if (pdf->draftmode == 0) + close_file(pdf->file); + else + pdf_warning(NULL, + "\\pdfdraftmode enabled, not changing output pdf", + true, true); + } + + if (callback_id == 0) { + if (log_opened) { + fprintf(log_file, + "\nPDF statistics: %d PDF objects out of %d (max. %d)\n", + (int) pdf->obj_ptr, (int) pdf->obj_tab_size, + (int) sup_obj_tab_size); + if (pdf->os_cntr > 0) { + fprintf(log_file, + " %d compressed objects within %d object stream%s\n", + (int) ((pdf->os_cntr - 1) * pdf_os_max_objs + + pdf->os_idx + 1), (int) pdf->os_cntr, + (pdf->os_cntr > 1 ? "s" : "")); + } + fprintf(log_file, " %d named destinations out of %d (max. %d)\n", + (int) pdf->dest_names_ptr, (int) pdf->dest_names_size, + (int) sup_dest_names_size); + fprintf(log_file, + " %d words of extra memory for PDF output out of %d (max. %d)\n", + (int) pdf->mem_ptr, (int) pdf->mem_size, + (int) sup_pdf_mem_size); + } + } +} + +@ @c +void scan_pdfcatalog(PDF pdf) +{ + halfword p; + scan_pdf_ext_toks(); + pdf_catalog_toks = concat_tokens(pdf_catalog_toks, def_ref); + if (scan_keyword("openaction")) { + if (pdf_catalog_openaction != 0) { + pdf_error("ext1", "duplicate of openaction"); + } else { + check_o_mode(pdf, "\\pdfcatalog", 1 << OMODE_PDF, true); + p = scan_action(pdf); + pdf_new_obj(pdf, obj_type_others, 0, 1); + pdf_catalog_openaction = pdf->obj_ptr; + write_action(pdf, p); + pdf_end_obj(pdf); + delete_action_ref(p); + } + } +} diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfglyph.h b/Build/source/texk/web2c/luatexdir/pdf/pdfglyph.h new file mode 100644 index 00000000000..6a19556a0f3 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdfglyph.h @@ -0,0 +1,30 @@ +/* pdfglyph.h + + Copyright 2009 Taco Hoekwater <taco@luatex.org> + + 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 <http://www.gnu.org/licenses/>. */ + +/* $Id: pdfglyph.h 3261 2009-12-18 11:38:21Z taco $ */ + +#ifndef PDFGLYPH_H +# define PDFGLYPH_H + +void end_chararray(PDF pdf); +void end_charmode(PDF pdf); +void pdf_place_glyph(PDF pdf, internal_font_number f, int c); +void pdf_print_charwidth(PDF pdf, internal_font_number f, int i); + +#endif diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfglyph.w b/Build/source/texk/web2c/luatexdir/pdf/pdfglyph.w new file mode 100644 index 00000000000..ba4911a3698 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdfglyph.w @@ -0,0 +1,222 @@ +% pdfglyph.w + +% Copyright 2009-2010 Taco Hoekwater <taco@@luatex.org> + +% 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 <http://www.gnu.org/licenses/>. + +@ @c +static const char _svn_version[] = + "$Id: pdfglyph.w 3584 2010-04-02 17:45:55Z hhenkel $" + "$URL: http://foundry.supelec.fr/svn/luatex/tags/beta-0.60.0/source/texk/web2c/luatexdir/pdf/pdfglyph.w $"; + +#include "ptexlib.h" + +@ @c +#include "pdf/pdfpage.h" + +#define lround(a) (long) floor((a) + 0.5) +#define pdf2double(a) ((double) (a).m / ten_pow[(a).e]) + +@ eternal constants +@c +#define one_bp ((double) 65536 * (double) 72.27 / 72) /* number of sp per 1bp */ +#define e_tj 3 /* must be 3; movements in []TJ are in fontsize/$10^3$ units */ + +@ @c +static long pdf_char_width(pdfstructure * p, internal_font_number f, int i) +{ + /* use exactly this formula also for calculating the /Width array values */ + return + lround((double) char_width(f, i) / font_size(f) * + ten_pow[e_tj + p->cw.e]); +} + +@ @c +void pdf_print_charwidth(PDF pdf, internal_font_number f, int i) +{ + pdffloat cw; + pdfstructure *p = pdf->pstruct; + assert(pdf_font_blink(f) == null_font); /* must use unexpanded font! */ + cw.m = pdf_char_width(p, f, i); + cw.e = p->cw.e; + print_pdffloat(pdf, cw); +} + +@ @c +static void setup_fontparameters(PDF pdf, internal_font_number f) +{ + float slant, extend, expand; + float u = 1.0; + pdfstructure *p = pdf->pstruct; + /* fix mantis bug \# 0000200 (acroread "feature") */ + if ((font_format(f) == opentype_format || + (font_format(f) == type1_format && font_encodingbytes(f) == 2)) + && font_units_per_em(f) > 0) + u = (float) (font_units_per_em(f) / 1000.0); + pdf->f_cur = f; + p->f_pdf = pdf_set_font(pdf, f); + p->fs.m = lround((float) font_size(f) / u / one_bp * ten_pow[p->fs.e]); + slant = (float) font_slant(f) / (float) 1000.0; + extend = (float) font_extend(f) / (float) 1000.0; + expand = (float) 1.0 + (float) font_expand_ratio(f) / (float) 1000.0; + p->tj_delta.e = p->cw.e - 1; /* "- 1" makes less corrections inside []TJ */ + /* no need to be more precise than TeX (1sp) */ + while (p->tj_delta.e > 0 + && (double) font_size(f) / ten_pow[p->tj_delta.e + e_tj] < 0.5) + p->tj_delta.e--; /* happens for very tiny fonts */ + assert(p->cw.e >= p->tj_delta.e); /* else we would need, e. g., |ten_pow[-1]| */ + p->tm[0].m = lround(expand * extend * (float) ten_pow[p->tm[0].e]); + p->tm[2].m = lround(slant * (float) ten_pow[p->tm[2].e]); + p->k2 = + ten_pow[e_tj + + p->cw.e] / (ten_pow[p->pdf.h.e] * pdf2double(p->fs) * + pdf2double(p->tm[0])); +} + +@ @c +static void set_font(PDF pdf) +{ + pdfstructure *p = pdf->pstruct; + pdf_printf(pdf, "/F%d", (int) p->f_pdf); + pdf_print_resname_prefix(pdf); + pdf_printf(pdf, " "); + print_pdffloat(pdf, p->fs); + pdf_printf(pdf, " Tf "); + p->f_pdf_cur = p->f_pdf; + p->fs_cur.m = p->fs.m; +} + +@ @c +static void print_tm(PDF pdf, pdffloat * tm) +{ + print_pdf_matrix(pdf, tm); + pdf_printf(pdf, " Tm "); +} + +@ @c +static void set_textmatrix(PDF pdf, scaledpos pos) +{ + boolean move; + pdfstructure *p = pdf->pstruct; + assert(is_textmode(p)); + move = calc_pdfpos(p, pos); + if (move == TRUE) { + print_tm(pdf, p->tm); + p->pdf.h.m = p->pdf_bt_pos.h.m + p->tm[4].m; /* Tm replaces */ + p->pdf.v.m = p->pdf_bt_pos.v.m + p->tm[5].m; + } +} + +@ @c +static void begin_charmode(PDF pdf, internal_font_number f, pdfstructure * p) +{ + assert(is_chararraymode(p)); + if (font_encodingbytes(f) == 2) { + p->ishex = 1; + pdf_printf(pdf, "<"); + } else { + p->ishex = 0; + pdf_printf(pdf, "("); + } + p->mode = PMODE_CHAR; +} + +@ @c +void end_charmode(PDF pdf) +{ + pdfstructure *p = pdf->pstruct; + assert(is_charmode(p)); + if (p->ishex == 1) { + p->ishex = 0; + pdf_printf(pdf, ">"); + } else { + pdf_printf(pdf, ")"); + } + p->mode = PMODE_CHARARRAY; +} + +@ @c +static void begin_chararray(PDF pdf) +{ + pdfstructure *p = pdf->pstruct; + assert(is_textmode(p)); + p->pdf_tj_pos = p->pdf; + p->cw.m = 0; + pdf_printf(pdf, "["); + p->mode = PMODE_CHARARRAY; +} + +@ @c +void end_chararray(PDF pdf) +{ + pdfstructure *p = pdf->pstruct; + assert(is_chararraymode(p)); + pdf_printf(pdf, "]TJ\n"); + p->pdf = p->pdf_tj_pos; + p->mode = PMODE_TEXT; +} + +@ @c +void pdf_place_glyph(PDF pdf, internal_font_number f, int c) +{ + boolean move; + pdfstructure *p = pdf->pstruct; + scaledpos pos = pdf->posstruct->pos; + if (!char_exists(f, c)) + return; + if (f != pdf->f_cur || is_textmode(p) || is_pagemode(p)) { + pdf_goto_textmode(pdf); + if (f != pdf->f_cur) + setup_fontparameters(pdf, f); + if (p->f_pdf != p->f_pdf_cur || p->fs.m != p->fs_cur.m) + set_font(pdf); + set_textmatrix(pdf, pos); + begin_chararray(pdf); + } + assert(is_charmode(p) || is_chararraymode(p)); + move = calc_pdfpos(p, pos); + if (move == TRUE) { + if ((p->wmode == WMODE_H + && (p->pdf_bt_pos.v.m + p->tm[5].m) != p->pdf.v.m) + || (p->wmode == WMODE_V + && (p->pdf_bt_pos.h.m + p->tm[4].m) != p->pdf.h.m) + || abs(p->tj_delta.m) >= 1000000) { + pdf_goto_textmode(pdf); + set_textmatrix(pdf, pos); + begin_chararray(pdf); + move = calc_pdfpos(p, pos); + } + if (move == TRUE) { + assert((p->wmode == WMODE_H + && (p->pdf_bt_pos.v.m + p->tm[5].m) == p->pdf.v.m) + || (p->wmode == WMODE_V + && (p->pdf_bt_pos.h.m + p->tm[4].m) == p->pdf.h.m)); + if (is_charmode(p)) + end_charmode(pdf); + assert(p->tj_delta.m != 0); + print_pdffloat(pdf, p->tj_delta); + p->cw.m -= p->tj_delta.m * ten_pow[p->cw.e - p->tj_delta.e]; + } + } + if (is_chararraymode(p)) + begin_charmode(pdf, f, p); + pdf_mark_char(f, c); + if (font_encodingbytes(f) == 2) + pdf_print_wide_char(pdf, char_index(f, c)); + else + pdf_print_char(pdf, c); + p->cw.m += pdf_char_width(p, p->f_pdf, c); /* aka |adv_char_width()| */ +} diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfimage.h b/Build/source/texk/web2c/luatexdir/pdf/pdfimage.h new file mode 100644 index 00000000000..86b5752bc42 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdfimage.h @@ -0,0 +1,28 @@ +/* pdfimage.h + + Copyright 2009 Taco Hoekwater <taco@luatex.org> + + 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 <http://www.gnu.org/licenses/>. */ + +/* $Id: pdfimage.h 3160 2009-11-16 16:29:11Z hhenkel $ */ + +#ifndef PDFIMAGE_H +# define PDFIMAGE_H + +void place_img(PDF pdf, image_dict * idict, scaled_whd dim, int transform); +void pdf_place_image(PDF pdf, halfword p); + +#endif diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfimage.w b/Build/source/texk/web2c/luatexdir/pdf/pdfimage.w new file mode 100644 index 00000000000..be343b37676 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdfimage.w @@ -0,0 +1,156 @@ +% pdfimage.w + +% Copyright 2009-2010 Taco Hoekwater <taco@@luatex.org> + +% 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 <http://www.gnu.org/licenses/>. + +@ @c +static const char _svn_version[] = + "$Id: pdfimage.w 3571 2010-04-02 13:50:45Z taco $" + "$URL: http://foundry.supelec.fr/svn/luatex/tags/beta-0.60.0/source/texk/web2c/luatexdir/pdf/pdfimage.w $"; + +#include "ptexlib.h" + +@ @c +void place_img(PDF pdf, image_dict * idict, scaled_whd dim, int transform) +{ + float a[6]; /* transformation matrix */ + float xoff, yoff, tmp; + pdfstructure *p = pdf->pstruct; + scaledpos pos = pdf->posstruct->pos; + int r; /* number of digits after the decimal point */ + int k; + scaledpos tmppos; + pdffloat cm[6]; + int groupref; /* added from web for 1.40.8 */ + assert(idict != 0); + assert(p != NULL); + a[0] = a[3] = 1.0e6; + a[1] = a[2] = 0; + if (img_type(idict) == IMG_TYPE_PDF + || img_type(idict) == IMG_TYPE_PDFSTREAM) { + a[0] /= (float) img_xsize(idict); + a[3] /= (float) img_ysize(idict); + xoff = (float) img_xorig(idict) / (float) img_xsize(idict); + yoff = (float) img_yorig(idict) / (float) img_ysize(idict); + r = 6; + } else { + /* added from web for 1.40.8 */ + if (img_type(idict) == IMG_TYPE_PNG) { + groupref = img_group_ref(idict); + if ((groupref > 0) && (pdf->img_page_group_val == 0)) + pdf->img_page_group_val = groupref; + } + /* /added from web */ + a[0] /= (float) one_hundred_bp; + a[3] = a[0]; + xoff = yoff = 0; + r = 4; + } + if ((transform & 7) > 3) { // mirror cases + a[0] *= -1; + xoff *= -1; + } + switch ((transform + img_rotation(idict)) & 3) { + case 0: /* no transform */ + break; + case 1: /* rot. 90 deg. (counterclockwise) */ + a[1] = a[0]; + a[2] = -a[3]; + a[3] = a[0] = 0; + tmp = yoff; + yoff = xoff; + xoff = -tmp; + break; + case 2: /* rot. 180 deg. (counterclockwise) */ + a[0] *= -1; + a[3] *= -1; + xoff *= -1; + yoff *= -1; + break; + case 3: /* rot. 270 deg. (counterclockwise) */ + a[1] = -a[0]; + a[2] = a[3]; + a[3] = a[0] = 0; + tmp = yoff; + yoff = -xoff; + xoff = tmp; + break; + default:; + } + xoff *= (float) dim.wd; + yoff *= (float) (dim.ht + dim.dp); + a[0] *= (float) dim.wd; + a[1] *= (float) (dim.ht + dim.dp); + a[2] *= (float) dim.wd; + a[3] *= (float) (dim.ht + dim.dp); + a[4] = (float) pos.h - xoff; + a[5] = (float) pos.v - yoff; + k = transform + img_rotation(idict); + if ((transform & 7) > 3) + k++; + switch (k & 3) { + case 0: /* no transform */ + break; + case 1: /* rot. 90 deg. (counterclockwise) */ + a[4] += (float) dim.wd; + break; + case 2: /* rot. 180 deg. */ + a[4] += (float) dim.wd; + a[5] += (float) (dim.ht + dim.dp); + break; + case 3: /* rot. 270 deg. */ + a[5] += (float) (dim.ht + dim.dp); + break; + default:; + } + /* the following is a kludge, TODO: use pdfpage.c functions */ + setpdffloat(cm[0], round(a[0]), r); + setpdffloat(cm[1], round(a[1]), r); + setpdffloat(cm[2], round(a[2]), r); + setpdffloat(cm[3], round(a[3]), r); + tmppos.h = round(a[4]); + tmppos.v = round(a[5]); + pdf_goto_pagemode(pdf); + (void) calc_pdfpos(p, tmppos); + cm[4] = p->cm[4]; + cm[5] = p->cm[5]; + if (pdf->img_page_group_val == 0) + pdf->img_page_group_val = img_group_ref(idict); /* added from web for 1.40.8 */ + pdf_printf(pdf, "q\n"); + pdf_print_cm(pdf, cm); + pdf_printf(pdf, "/Im"); + pdf_print_int(pdf, img_index(idict)); + pdf_print_resname_prefix(pdf); + pdf_printf(pdf, " Do\nQ\n"); + addto_page_resources(pdf, obj_type_ximage, img_objnum(idict)); + if (img_state(idict) < DICT_OUTIMG) + img_state(idict) = DICT_OUTIMG; +} + +@ for normal output, see \.{pdflistout.w} + +@c +void pdf_place_image(PDF pdf, halfword p) +{ + scaled_whd dim; + image_dict *idict = idict_array[pdf_ximage_index(p)]; + assert(idict != NULL); + dim.wd = width(p); + dim.ht = height(p); + dim.dp = depth(p); + place_img(pdf, idict, dim, pdf_ximage_transform(p)); +} diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdflink.h b/Build/source/texk/web2c/luatexdir/pdf/pdflink.h new file mode 100644 index 00000000000..c804f038345 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdflink.h @@ -0,0 +1,39 @@ +/* pdflink.h + + Copyright 2009 Taco Hoekwater <taco@luatex.org> + + 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 <http://www.gnu.org/licenses/>. */ + +/* $Id: pdflink.h 2978 2009-08-09 09:03:39Z hhenkel $ */ + +#ifndef PDFLINK_H +# define PDFLINK_H + +# define set_pdf_link_attr(A,B) pdf_link_attr(A)=B +# define set_pdf_link_action(A,B) pdf_link_action(A)=B +# define set_pdf_link_objnum(A,B) pdf_link_objnum(A)=B + +extern void push_link_level(PDF pdf, halfword p); +extern void pop_link_level(PDF pdf); +extern void do_link(PDF pdf, halfword p, halfword parent_box, scaledpos cur); +extern void end_link(PDF pdf, halfword p); +extern void append_link(PDF pdf, halfword parent_box, scaledpos cur, + small_number i); + +extern void scan_startlink(PDF pdf); + + +#endif diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdflink.w b/Build/source/texk/web2c/luatexdir/pdf/pdflink.w new file mode 100644 index 00000000000..66b369d12bd --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdflink.w @@ -0,0 +1,166 @@ +% pdflink.w + +% Copyright 2009-2010 Taco Hoekwater <taco@@luatex.org> + +% 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 <http://www.gnu.org/licenses/>. + +@ @c +static const char _svn_version[] = + "$Id: pdflink.w 3571 2010-04-02 13:50:45Z taco $" + "$URL: http://foundry.supelec.fr/svn/luatex/tags/beta-0.60.0/source/texk/web2c/luatexdir/pdf/pdflink.w $"; + +#include "ptexlib.h" + +@ @c +#define pdf_link_margin dimen_par(pdf_link_margin_code) + +@ To implement nested link annotations, we need a stack to hold copy of +|pdf_start_link_node|'s that are being written out, together with their box +nesting level. + +@c +void push_link_level(PDF pdf, halfword p) +{ + if (pdf->link_stack_ptr >= pdf_max_link_level) + overflow("pdf link stack size", pdf_max_link_level); + assert(((type(p) == whatsit_node) && (subtype(p) == pdf_start_link_node))); + incr(pdf->link_stack_ptr); + pdf->link_stack[pdf->link_stack_ptr].nesting_level = cur_s; + pdf->link_stack[pdf->link_stack_ptr].link_node = copy_node_list(p); + pdf->link_stack[pdf->link_stack_ptr].ref_link_node = p; +} + +@ @c +void pop_link_level(PDF pdf) +{ + assert(pdf->link_stack_ptr > 0); + flush_node_list(pdf->link_stack[pdf->link_stack_ptr].link_node); + decr(pdf->link_stack_ptr); +} + +@ @c +void do_link(PDF pdf, halfword p, halfword parent_box, scaledpos cur) +{ + scaled_whd alt_rule; + if (type(p) == vlist_node) + pdf_error("ext4", "\\pdfstartlink ended up in vlist"); + if (!is_shipping_page) + pdf_error("ext4", "link annotations cannot be inside an XForm"); + assert(type(parent_box) == hlist_node); + if (is_obj_scheduled(pdf, pdf_link_objnum(p))) + pdf_link_objnum(p) = pdf_new_objnum(pdf); + push_link_level(pdf, p); + alt_rule.wd = width(p); + alt_rule.ht = height(p); + alt_rule.dp = depth(p); + set_rect_dimens(pdf, p, parent_box, cur, alt_rule, pdf_link_margin); + obj_annot_ptr(pdf, pdf_link_objnum(p)) = p; /* the reference for the pdf annot object must be set here */ + addto_page_resources(pdf, obj_type_link, pdf_link_objnum(p)); +} + +@ @c +void end_link(PDF pdf, halfword p) +{ + halfword q; + scaledpos pos = pdf->posstruct->pos; + if (type(p) == vlist_node) + pdf_error("ext4", "\\pdfendlink ended up in vlist"); + if (pdf->link_stack_ptr < 1) + pdf_error("ext4", + "pdf link_stack empty, \\pdfendlink used without \\pdfstartlink?"); + if (pdf->link_stack[pdf->link_stack_ptr].nesting_level != cur_s) + pdf_error("ext4", + "\\pdfendlink ended up in different nesting level than \\pdfstartlink"); + + /* N.B.: test for running link must be done on |link_node| and not |ref_link_node|, + as |ref_link_node| can be set by |do_link| or |append_link| already */ + + if (is_running(width(pdf->link_stack[pdf->link_stack_ptr].link_node))) { + q = pdf->link_stack[pdf->link_stack_ptr].ref_link_node; + if (is_shipping_page && matrixused()) { + matrixrecalculate(pos.h + pdf_link_margin); + pdf_ann_left(q) = getllx() - pdf_link_margin; + pdf_ann_top(q) = cur_page_size.v - getury() - pdf_link_margin; + pdf_ann_right(q) = geturx() + pdf_link_margin; + pdf_ann_bottom(q) = cur_page_size.v - getlly() + pdf_link_margin; + } else { + switch (pdf->posstruct->dir) { + case dir_TLT: + pdf_ann_right(q) = pos.h + pdf_link_margin; + break; + case dir_TRT: + pdf_ann_left(q) = pos.h - pdf_link_margin; + break; + case dir_LTL: + case dir_RTT: + pdf_ann_bottom(q) = pos.v - pdf_link_margin; + break; + } + } + } + pop_link_level(pdf); +} + + +@ For ``running'' annotations we must append a new node when the end of +annotation is in other box than its start. The new created node is identical to +corresponding whatsit node representing the start of annotation, but its +|info| field is |max_halfword|. We set |info| field just before destroying the +node, in order to use |flush_node_list| to do the job. + + +@ Append a new pdf annot to |pdf_link_list| + +@c +void append_link(PDF pdf, halfword parent_box, scaledpos cur, small_number i) +{ + halfword p; + scaled_whd alt_rule; + assert(type(parent_box) == hlist_node); + p = copy_node(pdf->link_stack[(int) i].link_node); + pdf->link_stack[(int) i].ref_link_node = p; + subtype(p) = pdf_link_data_node; /* this node is not a normal link node */ + alt_rule.wd = width(p); + alt_rule.ht = height(p); + alt_rule.dp = depth(p); + set_rect_dimens(pdf, p, parent_box, cur, alt_rule, pdf_link_margin); + pdf_create_obj(pdf, obj_type_others, 0); + obj_annot_ptr(pdf, pdf->obj_ptr) = p; + addto_page_resources(pdf, obj_type_link, pdf->obj_ptr); +} + +@ @c +void scan_startlink(PDF pdf) +{ + int k; + halfword r; + if (abs(cur_list.mode_field) == vmode) + pdf_error("ext1", "\\pdfstartlink cannot be used in vertical mode"); + k = pdf_new_objnum(pdf); + new_annot_whatsit(pdf_start_link_node); + set_pdf_link_attr(cur_list.tail_field, null); + if (scan_keyword("attr")) { + scan_pdf_ext_toks(); + set_pdf_link_attr(cur_list.tail_field, def_ref); + } + r = scan_action(pdf); + set_pdf_link_action(cur_list.tail_field, r); + set_pdf_link_objnum(cur_list.tail_field, k); + pdf_last_link = k; + /* N.B.: although it is possible to set |obj_annot_ptr(k) := tail| here, it + is not safe if nodes are later copied/destroyed/moved; a better place + to do this is inside |do_link|, when the whatsit node is written out */ +} diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdflistout.h b/Build/source/texk/web2c/luatexdir/pdf/pdflistout.h new file mode 100644 index 00000000000..41aff73357a --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdflistout.h @@ -0,0 +1,50 @@ +/* pdflistout.h + + Copyright 2009 Taco Hoekwater <taco@luatex.org> + + 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 <http://www.gnu.org/licenses/>. */ + +/* $Id: pdflistout.h 3386 2010-01-26 06:41:37Z taco $ */ + +#ifndef PDFLISTOUT_H +# define PDFLISTOUT_H + +/* a few small helpers */ +# define pos_right(A) pdf->posstruct->pos.h = pdf->posstruct->pos.h + (A) +# define pos_left(A) pdf->posstruct->pos.h = pdf->posstruct->pos.h - (A) +# define pos_up(A) pdf->posstruct->pos.v = pdf->posstruct->pos.v + (A) +# define pos_down(A) pdf->posstruct->pos.v = pdf->posstruct->pos.v - (A) + +typedef void (*backend_function) (); /* variadic arguments */ + +typedef struct { + char *name; /* name of the backend */ + backend_function *node_fu; /* array of node output functions */ + backend_function *whatsit_fu; /* array of whatsit output functions */ +} backend_struct; + +extern pos_info_structure pos_info; + +extern backend_function *backend_out; +extern backend_function *backend_out_whatsit; + +extern void init_backend_functionpointers(output_mode o_mode); + +extern void hlist_out(PDF pdf, halfword this_box); +extern void vlist_out(PDF pdf, halfword this_box); +extern void out_what(PDF pdf, halfword p); + +#endif diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdflistout.w b/Build/source/texk/web2c/luatexdir/pdf/pdflistout.w new file mode 100644 index 00000000000..2698c47fa32 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdflistout.w @@ -0,0 +1,1139 @@ +% pdflistout.w + +% Copyright 2009-2010 Taco Hoekwater <taco@@luatex.org> + +% 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 <http://www.gnu.org/licenses/>. + +\def\pdfTeX{pdf\TeX} + +@ @c +static const char _svn_version[] = + "$Id: pdflistout.w 3571 2010-04-02 13:50:45Z taco $" + "$URL: http://foundry.supelec.fr/svn/luatex/tags/beta-0.60.0/source/texk/web2c/luatexdir/pdf/pdflistout.w $"; + +#include "ptexlib.h" + +@ @c +pos_info_structure pos_info; /* to be accessed from Lua */ + +static backend_struct *backend = NULL; +backend_function *backend_out, *backend_out_whatsit; + +@ @c +static void missing_backend_function(PDF pdf, halfword p) +{ + char *b; + const char *s; + const char *n; + char backend_string[15]; + char err_string[60]; + assert(backend != NULL); + if (type(p) == whatsit_node) + s = "whatsit"; + else + s = "node"; + n = get_node_name(type(p), subtype(p)); + b = backend[pdf->o_mode].name; + snprintf(backend_string, strlen(b) + 10, "%s back-end", b); + snprintf(err_string, 59, "no output function for \"%s\" %s", n, s); + pdf_error(backend_string, err_string); +} + +@ @c +static void init_none_backend_functions() +{ + backend_struct *p = &backend[OMODE_NONE]; + p->name = strdup("(None)"); +} + +@ @c +static void init_pdf_backend_functions() +{ + backend_struct *p = &backend[OMODE_PDF]; + p->name = strdup("PDF"); + p->node_fu[rule_node] = &pdf_place_rule; /* 2 */ + p->node_fu[glyph_node] = &pdf_place_glyph; /* 37 */ + p->whatsit_fu[special_node] = &pdf_special; /* 3 */ + p->whatsit_fu[pdf_literal_node] = &pdf_out_literal; /* 8 */ + p->whatsit_fu[pdf_refobj_node] = &pdf_ref_obj; /* 10 */ + p->whatsit_fu[pdf_refxform_node] = &pdf_place_form; /* 12 */ + p->whatsit_fu[pdf_refximage_node] = &pdf_place_image; /* 14 */ + p->whatsit_fu[pdf_annot_node] = &do_annot; /* 15 */ + p->whatsit_fu[pdf_start_link_node] = &do_link; /* 16 */ + p->whatsit_fu[pdf_end_link_node] = &end_link; /* 17 */ + p->whatsit_fu[pdf_dest_node] = &do_dest; /* 19 */ + p->whatsit_fu[pdf_thread_node] = &do_thread; /* 20 */ + p->whatsit_fu[pdf_end_thread_node] = &end_thread; /* 22 */ + p->whatsit_fu[late_lua_node] = &late_lua; /* 35 */ + p->whatsit_fu[pdf_colorstack_node] = &pdf_out_colorstack; /* 39 */ + p->whatsit_fu[pdf_setmatrix_node] = &pdf_out_setmatrix; /* 40 */ + p->whatsit_fu[pdf_save_node] = &pdf_out_save; /* 41 */ + p->whatsit_fu[pdf_restore_node] = &pdf_out_restore; /* 42 */ +} + +@ @c +static void init_dvi_backend_functions() +{ + backend_struct *p = &backend[OMODE_DVI]; + p->name = strdup("DVI"); + p->node_fu[rule_node] = &dvi_place_rule; /* 2 */ + p->node_fu[glyph_node] = &dvi_place_glyph; /* 37 */ + p->whatsit_fu[special_node] = &dvi_special; /* 3 */ + p->whatsit_fu[late_lua_node] = &late_lua; /* 35 */ +} + +@ @c +static void init_lua_backend_functions() +{ + backend_struct *p = &backend[OMODE_LUA]; + p->name = strdup("Lua"); + p->node_fu[rule_node] = &lua_place_rule; /* 2 */ + p->node_fu[glyph_node] = &lua_place_glyph; /* 37 */ + p->whatsit_fu[late_lua_node] = &late_lua; /* 35 */ +} + +@ @c +void init_backend_functionpointers(output_mode o_mode) +{ + int i, j; + if (backend == NULL) { + backend = xmalloc((MAX_OMODE + 1) * sizeof(backend_struct)); + for (i = 0; i <= MAX_OMODE; i++) { + backend[i].node_fu = + xmalloc((MAX_NODE_TYPE + 1) * sizeof(backend_function)); + backend[i].whatsit_fu = + xmalloc((MAX_WHATSIT_TYPE + 1) * sizeof(backend_function)); + for (j = 0; j < MAX_NODE_TYPE + 1; j++) + backend[i].node_fu[j] = &missing_backend_function; + for (j = 0; j < MAX_WHATSIT_TYPE + 1; j++) + backend[i].whatsit_fu[j] = &missing_backend_function; + } + init_none_backend_functions(); + init_dvi_backend_functions(); + init_pdf_backend_functions(); + init_lua_backend_functions(); + } + backend_out = backend[o_mode].node_fu; + backend_out_whatsit = backend[o_mode].whatsit_fu; +} + +@ This code scans forward to the ending |dir_node| while keeping +track of the needed width in |w|. When it finds the node that will end +this segment, it stores the accumulated with in the |dir_dvi_h| field +of that end node, so that when that node is found later in the +processing, the correct glue correction can be applied. + +@c +static scaled simple_advance_width(halfword p) +{ + halfword q = p; + scaled w = 0; + while ((q != null) && (vlink(q) != null)) { + q = vlink(q); + if (is_char_node(q)) { + w += glyph_width(q); + } else { + switch (type(q)) { + case hlist_node: + case vlist_node: + case rule_node: + case margin_kern_node: + case kern_node: + w += width(q); + break; + case disc_node: + if (vlink(no_break(q)) != null) + w += simple_advance_width(no_break(q)); + default: + break; + } + } + } + return w; +} + +@ @c +static halfword calculate_width_to_enddir(halfword p, real cur_glue, + scaled cur_g, halfword this_box) +{ + int dir_nest = 1; + halfword q = p, enddir_ptr = p; + scaled w = 0; + halfword g; /* this is normally a global variable, but that is just too hideous */ + /* to me, it looks like the next is needed. but Aleph doesn't do that, so let us not do it either */ + real glue_temp; /* glue value before rounding */ + /* |w:=w-cur_g; cur_glue:=0;| */ + int g_sign = glue_sign(this_box); + int g_order = glue_order(this_box); + while ((q != null) && (vlink(q) != null)) { + q = vlink(q); + if (is_char_node(q)) + w += pack_width(box_dir(this_box), dir_TRT, q, true); + else { + switch (type(q)) { + case hlist_node: + case vlist_node: + w += pack_width(box_dir(this_box), box_dir(q), q, false); + break; + case rule_node: + case margin_kern_node: + case kern_node: + w += width(q); + break; + case glue_node: + g = glue_ptr(q); + w += width(g) - cur_g; + if (g_sign != normal) { + if (g_sign == stretching) { + if (stretch_order(g) == g_order) { + cur_glue = cur_glue + stretch(g); + vet_glue(float_cast(glue_set(this_box)) * cur_glue); + cur_g = float_round(glue_temp); + } + } else if (shrink_order(g) == g_order) { + cur_glue = cur_glue - shrink(g); + vet_glue(float_cast(glue_set(this_box)) * cur_glue); + cur_g = float_round(glue_temp); + } + } + w += cur_g; + break; + case disc_node: + if (vlink(no_break(q)) != null) + w += simple_advance_width(no_break(q)); + break; + case math_node: + w += surround(q); + break; + case whatsit_node: + if (subtype(q) == dir_node) { + if (dir_dir(q) >= 0) + incr(dir_nest); + else + decr(dir_nest); + if (dir_nest == 0) { + enddir_ptr = q; + dir_cur_h(enddir_ptr) = w; + q = null; + } + } else if ((subtype(q) == pdf_refxform_node) + || (subtype(q) == pdf_refximage_node)) + w += width(q); + break; + default: + break; + } + } + } + if (enddir_ptr == p) /* no enddir found, just transport w by begindir */ + dir_cur_h(enddir_ptr) = w; + return enddir_ptr; +} + +@ The |out_what| procedure takes care of outputting the whatsit nodes for +|vlist_out| and |hlist_out|, which are similar for either case. + +We don't implement \.{\\write} inside of leaders. (The reason is that +the number of times a leader box appears might be different in different +implementations, due to machine-dependent rounding in the glue calculations.) +@^leaders@> + +@c +void out_what(PDF pdf, halfword p) +{ + int j; /* write stream number */ + switch (subtype(p)) { + /* function(pdf, p) */ + case pdf_save_node: /* |pdf_out_save(pdf, p)|; */ + case pdf_restore_node: /* |pdf_out_restore(pdf, p)|; */ + case pdf_end_link_node: /* |end_link(pdf, p)|; */ + case pdf_end_thread_node: /* |end_thread(pdf, p)|; */ + case pdf_literal_node: /* |pdf_out_literal(pdf, p)|; */ + case pdf_colorstack_node: /* |pdf_out_colorstack(pdf, p)|; */ + case pdf_setmatrix_node: /* |pdf_out_setmatrix(pdf, p)|; */ + case special_node: /* |pdf_special(pdf, p)|; */ + case late_lua_node: /* |late_lua(pdf, p)|; */ + case pdf_refobj_node: /* |pdf_ref_obj(pdf, p)| */ + backend_out_whatsit[subtype(p)] (pdf, p); + break; + case open_node: + case write_node: + case close_node: + /* Do some work that has been queued up for \.{\\write} */ + if (!doing_leaders) { + j = write_stream(p); + if (subtype(p) == write_node) { + write_out(p); + } else { + if (write_open[j]) + lua_a_close_out(write_file[j]); + if (subtype(p) == close_node) { + write_open[j] = false; + } else if (j < 16) { + char *fn; + cur_name = open_name(p); + cur_area = open_area(p); + cur_ext = open_ext(p); + if (cur_ext == get_nullstr()) + cur_ext = maketexstring(".tex"); + fn = pack_file_name(cur_name, cur_area, cur_ext); + while (!lua_a_open_out(&(write_file[j]), fn, (j + 1))) + fn = prompt_file_name("output file name", ".tex"); + write_open[j] = true; + } + } + } + break; + case dir_node: /* in a vlist */ + break; + case local_par_node: + case cancel_boundary_node: + case user_defined_node: + break; + default: + /* this should give an error about missing whatsit backend function */ + backend_out_whatsit[subtype(p)] (pdf, p); + } +} + +@ @c +void hlist_out(PDF pdf, halfword this_box) +{ + + posstructure localpos; /* the position structure local within this function */ + posstructure *refpos; /* the list origin pos. on the page, provided by the caller */ + + scaledpos cur = { 0, 0 }, tmpcur, basepoint; + scaledpos size = { 0, 0 }; /* rule dimensions */ + scaled effective_horizontal; + scaled save_h; /* what |cur.h| should pop to */ + scaled edge; /* right edge of sub-box or leader space */ + halfword enddir_ptr; /* temporary pointer to enddir node */ + int g_order; /* applicable order of infinity for glue */ + int g_sign; /* selects type of glue */ + halfword p, q; /* current position in the hlist */ + halfword leader_box; /* the leader box being replicated */ + scaled leader_wd; /* width of leader box being replicated */ + scaled lx; /* extra space between leader boxes */ + boolean outer_doing_leaders; /* were we doing leaders? */ + halfword prev_p; /* one step behind |p| */ + real glue_temp; /* glue value before rounding */ + real cur_glue = 0.0; /* glue seen so far */ + scaled cur_g = 0; /* rounded equivalent of |cur_glue| times the glue ratio */ + scaled_whd rule, ci; + int i; /* index to scan |pdf_link_stack| */ + int save_loc = 0; /* DVI! \.{DVI} byte location upon entry */ + scaledpos save_dvi = { 0, 0 }; /* DVI! what |dvi| should pop to */ + + g_order = glue_order(this_box); + g_sign = glue_sign(this_box); + p = list_ptr(this_box); + + refpos = pdf->posstruct; + pdf->posstruct = &localpos; /* use local structure for recursion */ + localpos.pos = refpos->pos; + localpos.dir = box_dir(this_box); + + incr(cur_s); + if (cur_s > max_push) + max_push = cur_s; + + if (pdf->o_mode == OMODE_DVI) { + if (cur_s > 0) { /* DVI! */ + dvi_push(); /* DVI! */ + save_dvi = dvi; /* DVI! */ + } + save_loc = dvi_offset + dvi_ptr /* DVI! */ ; + } + + prev_p = this_box + list_offset; + /* Create link annotations for the current hbox if needed */ + for (i = 1; i <= pdf->link_stack_ptr; i++) { + assert(is_running(width(pdf->link_stack[i].link_node))); + if (pdf->link_stack[i].nesting_level == cur_s) + append_link(pdf, this_box, cur, (small_number) i); + } + + /* Start hlist {\sl Sync\TeX} information record */ + if (int_par(synctex_code)) + synctexhlist(this_box); + + while (p != null) { + if (is_char_node(p)) { + do { + if (x_displace(p) != 0 || y_displace(p) != 0) { + tmpcur.h = cur.h + x_displace(p); + tmpcur.v = cur.v - y_displace(p); + synch_pos_with_cur(pdf->posstruct, refpos, tmpcur); + } + output_one_char(pdf, font(p), character(p)); + ci = get_charinfo_whd(font(p), character(p)); + if (textdir_parallel(localpos.dir, dir_TLT)) + cur.h += ci.wd; + else + cur.h += ci.ht + ci.dp; + synch_pos_with_cur(pdf->posstruct, refpos, cur); + p = vlink(p); + } while (is_char_node(p)); + /* Record current point {\sl Sync\TeX} information */ + if (int_par(synctex_code)) + synctexcurrent(); + } else { + /* Output the non-|char_node| |p| for |hlist_out| + and move to the next node */ + switch (type(p)) { + case hlist_node: + case vlist_node: + /* (\pdfTeX) Output a box in an hlist */ + + if (textdir_parallel(box_dir(p), localpos.dir)) { + effective_horizontal = width(p); + basepoint.v = 0; + if (textdir_opposite(box_dir(p), localpos.dir)) + basepoint.h = width(p); + else + basepoint.h = 0; + } else { + effective_horizontal = height(p) + depth(p); + if (!is_mirrored(box_dir(p))) { + if (partextdir_eq(box_dir(p), localpos.dir)) + basepoint.h = height(p); + else + basepoint.h = depth(p); + } else { + if (partextdir_eq(box_dir(p), localpos.dir)) + basepoint.h = depth(p); + else + basepoint.h = height(p); + } + if (is_rotated(localpos.dir)) { + if (partextdir_eq(localpos.dir, box_dir(p))) + basepoint.v = -width(p) / 2; /* `up' */ + else + basepoint.v = width(p) / 2; /* `down' */ + } else if (is_mirrored(localpos.dir)) { + if (partextdir_eq(localpos.dir, box_dir(p))) + basepoint.v = 0; + else + basepoint.v = width(p); /* `down' */ + } else { + if (partextdir_eq(localpos.dir, box_dir(p))) + basepoint.v = -width(p); /* `up' */ + else + basepoint.v = 0; + } + } + if (!is_mirrored(localpos.dir)) + basepoint.v = basepoint.v + shift_amount(p); /* shift the box `down' */ + else + basepoint.v = basepoint.v - shift_amount(p); /* shift the box `up' */ + if (list_ptr(p) == null) { + /* Record void list {\sl Sync\TeX} information */ + if (int_par(synctex_code)) { + if (type(p) == vlist_node) + synctexvoidvlist(p, this_box); + else + synctexvoidhlist(p, this_box); + } + } else { + assert(cur.v == 0); + tmpcur.h = cur.h + basepoint.h; + tmpcur.v = basepoint.v; + synch_pos_with_cur(pdf->posstruct, refpos, tmpcur); + if (type(p) == vlist_node) + vlist_out(pdf, p); + else + hlist_out(pdf, p); + } + cur.h += effective_horizontal; + break; + case disc_node: + if (vlink(no_break(p)) != null) { + if (subtype(p) != select_disc) { + q = tail_of_list(vlink(no_break(p))); /* TODO, this should be a tlink */ + vlink(q) = vlink(p); + q = vlink(no_break(p)); + vlink(no_break(p)) = null; + vlink(p) = q; + } + } + break; + case rule_node: + if (rule_dir(p)<0) + rule_dir(p) = localpos.dir; + if (pardir_parallel(rule_dir(p), localpos.dir)) { + rule.ht = height(p); + rule.dp = depth(p); + rule.wd = width(p); + } else { + rule.ht = width(p) / 2; + rule.dp = width(p) / 2; + rule.wd = height(p) + depth(p); + } + goto FIN_RULE; + break; + case whatsit_node: + /* Output the whatsit node |p| in |hlist_out| */ + switch (subtype(p)) { + case pdf_save_pos_node: + pdf_last_pos = pdf->posstruct->pos; + pos_info.curpos = pdf->posstruct->pos; + pos_info.boxpos.pos = refpos->pos; + pos_info.boxpos.dir = localpos.dir; + pos_info.boxdim.wd = width(this_box); + pos_info.boxdim.ht = height(this_box); + pos_info.boxdim.dp = depth(this_box); + break; + /* |function(pdf, p, this_box, cur)|; too many args for |out_what()| */ + case pdf_annot_node: /* |do_annot(pdf, p, this_box, cur);| */ + case pdf_start_link_node: /* |do_link(pdf, p, this_box, cur);| */ + case pdf_dest_node: /* |do_dest(pdf, p, this_box, cur);| */ + case pdf_start_thread_node: + case pdf_thread_node: /* |do_thread(pdf, p, this_box, cur);| */ + backend_out_whatsit[subtype(p)] (pdf, p, this_box, cur); + break; + case pdf_refxform_node: /* |pdf_place_form(pdf, pdf_xform_objnum(p));| */ + case pdf_refximage_node: /* |pdf_place_image(pdf, pdf_ximage_idx(p));| */ + /* Output a Form node in a hlist */ + /* Output an Image node in a hlist */ + switch (localpos.dir) { + case dir_TLT: + pos_down(depth(p)); + break; + case dir_TRT: + pos_left(width(p)); + pos_down(depth(p)); + break; + case dir_LTL: + pos_left(height(p)); + pos_down(width(p)); + break; + case dir_RTT: + pos_left(depth(p)); + pos_down(width(p)); + break; + } + backend_out_whatsit[subtype(p)] (pdf, p); + cur.h += width(p); + break; + case dir_node: + /* Output a reflection instruction if the direction has changed */ + if (dir_dir(p) >= 0) { + /* Calculate the needed width to the matching |enddir|, return the |enddir| node, + with width info */ + enddir_ptr = + calculate_width_to_enddir(p, cur_glue, cur_g, + this_box); + if (textdir_parallel(dir_dir(p), localpos.dir)) { + dir_cur_h(enddir_ptr) += cur.h; + if (textdir_opposite(dir_dir(p), localpos.dir)) + cur.h = dir_cur_h(enddir_ptr); + } else + dir_cur_h(enddir_ptr) = cur.h; + if (enddir_ptr != p) { /* only if it is an enddir */ + dir_cur_v(enddir_ptr) = cur.v; + dir_refpos_h(enddir_ptr) = refpos->pos.h; + dir_refpos_v(enddir_ptr) = refpos->pos.v; + dir_dir(enddir_ptr) = localpos.dir - 64; /* negative: mark it as |enddir| */ + } + /* fake a nested |hlist_out| */ + synch_pos_with_cur(pdf->posstruct, refpos, cur); + refpos->pos = pdf->posstruct->pos; + localpos.dir = dir_dir(p); + cur.h = 0; + cur.v = 0; + } else { + refpos->pos.h = dir_refpos_h(p); + refpos->pos.v = dir_refpos_v(p); + localpos.dir = dir_dir(p) + 64; + cur.h = dir_cur_h(p); + cur.v = dir_cur_v(p); + } + break; + default: + out_what(pdf, p); + } + break; + case glue_node: + /* (\pdfTeX) Move right or output leaders */ + + g = glue_ptr(p); + rule.wd = width(g) - cur_g; + if (g_sign != normal) { + if (g_sign == stretching) { + if (stretch_order(g) == g_order) { + cur_glue = cur_glue + stretch(g); + vet_glue(float_cast(glue_set(this_box)) * cur_glue); /* real multiplication */ + cur_g = float_round(glue_temp); + } + } else if (shrink_order(g) == g_order) { + cur_glue = cur_glue - shrink(g); + vet_glue(float_cast(glue_set(this_box)) * cur_glue); + cur_g = float_round(glue_temp); + } + } + rule.wd = rule.wd + cur_g; + if (subtype(p) >= a_leaders) { + /* (\pdfTeX) Output leaders in an hlist, |goto fin_rule| if a rule + or to |next_p| if done */ + leader_box = leader_ptr(p); + if (type(leader_box) == rule_node) { + rule.ht = height(leader_box); + rule.dp = depth(leader_box); + goto FIN_RULE; + } + if (textdir_parallel(box_dir(leader_box), localpos.dir)) + leader_wd = width(leader_box); + else + leader_wd = height(leader_box) + depth(leader_box); + if ((leader_wd > 0) && (rule.wd > 0)) { + rule.wd = rule.wd + 10; /* compensate for floating-point rounding */ + edge = cur.h + rule.wd; + lx = 0; + /* Let |cur.h| be the position of the first box, and set |leader_wd+lx| + to the spacing between corresponding parts of boxes */ + + if (subtype(p) == g_leaders) { + save_h = cur.h; + switch (localpos.dir) { + case dir_TLT: + cur.h += refpos->pos.h - shipbox_refpos.h; + cur.h = leader_wd * (cur.h / leader_wd); + cur.h -= refpos->pos.h - shipbox_refpos.h; + break; + case dir_TRT: + cur.h = + refpos->pos.h - shipbox_refpos.h - cur.h; + cur.h = leader_wd * (cur.h / leader_wd); + cur.h = + refpos->pos.h - shipbox_refpos.h - cur.h; + break; + case dir_LTL: + case dir_RTT: + cur.h = + refpos->pos.v - shipbox_refpos.v - cur.h; + cur.h = leader_wd * (cur.h / leader_wd); + cur.h = + refpos->pos.v - shipbox_refpos.v - cur.h; + break; + } + if (cur.h < save_h) + cur.h += leader_wd; + } else if (subtype(p) == a_leaders) { + save_h = cur.h; + cur.h = leader_wd * (cur.h / leader_wd); + if (cur.h < save_h) + cur.h += leader_wd; + } else { + lq = rule.wd / leader_wd; /* the number of box copies */ + lr = rule.wd % leader_wd; /* the remaining space */ + if (subtype(p) == c_leaders) { + cur.h += lr / 2; + } else { + lx = lr / (lq + 1); + cur.h += (lr - (lq - 1) * lx) / 2; + } + } + + while (cur.h + leader_wd <= edge) { + /* (\pdfTeX) Output a leader box at |cur.h|, + then advance |cur.h| by |leader_wd+lx| */ + + if (pardir_parallel + (box_dir(leader_box), localpos.dir)) { + basepoint.v = 0; + if (textdir_opposite + (box_dir(leader_box), localpos.dir)) + basepoint.h = width(leader_box); + else + basepoint.h = 0; + } else { + if (!is_mirrored(box_dir(leader_box))) { + if (partextdir_eq + (box_dir(leader_box), localpos.dir)) + basepoint.h = height(leader_box); + else + basepoint.h = depth(leader_box); + } else { + if (partextdir_eq + (box_dir(leader_box), localpos.dir)) + basepoint.h = depth(leader_box); + else + basepoint.h = height(leader_box); + } + if (partextdir_eq + (localpos.dir, box_dir(leader_box))) + basepoint.v = -(width(leader_box) / 2); + else + basepoint.v = (width(leader_box) / 2); + } + if (!is_mirrored(localpos.dir)) + basepoint.v = basepoint.v + shift_amount(leader_box); /* shift the box `down' */ + else + basepoint.v = basepoint.v - shift_amount(leader_box); /* shift the box `up' */ + assert(cur.v == 0); + tmpcur.h = cur.h + basepoint.h; + tmpcur.v = basepoint.v; + synch_pos_with_cur(pdf->posstruct, refpos, tmpcur); + outer_doing_leaders = doing_leaders; + doing_leaders = true; + if (type(leader_box) == vlist_node) + vlist_out(pdf, leader_box); + else + hlist_out(pdf, leader_box); + doing_leaders = outer_doing_leaders; + cur.h += leader_wd + lx; + } + cur.h = edge - 10; + goto NEXTP; + } + } + goto MOVE_PAST; + break; + case margin_kern_node: + cur.h += width(p); + break; + case kern_node: + /* Record |kern_node| {\sl Sync\TeX} information */ + if (int_par(synctex_code)) + synctexkern(p, this_box); + cur.h += width(p); + break; + case math_node: + /* Record |math_node| {\sl Sync\TeX} information */ + if (int_par(synctex_code)) + synctexmath(p, this_box); + cur.h += surround(p); + break; + default: + break; + } + goto NEXTP; + FIN_RULE: + /* (\pdfTeX) Output a rule in an hlist */ + if (is_running(rule.ht)) + rule.ht = height(this_box); + if (is_running(rule.dp)) + rule.dp = depth(this_box); + if ((rule.ht + rule.dp) > 0 && rule.wd > 0) { /* we don't output empty rules */ + switch (localpos.dir) { + case dir_TLT: + size.h = rule.wd; + size.v = rule.ht + rule.dp; + pos_down(rule.dp); + break; + case dir_TRT: + size.h = rule.wd; + size.v = rule.ht + rule.dp; + pos_left(size.h); + pos_down(rule.dp); + break; + case dir_LTL: + size.h = rule.ht + rule.dp; + size.v = rule.wd; + pos_left(rule.ht); + pos_down(size.v); + break; + case dir_RTT: + size.h = rule.ht + rule.dp; + size.v = rule.wd; + pos_left(rule.dp); + pos_down(size.v); + break; + default:; + } + backend_out[rule_node] (pdf, p, size); /* |pdf_place_rule(pdf, p, rule.ht + rule.dp, rule.wd);| */ + } + MOVE_PAST: + cur.h += rule.wd; + /* Record horizontal |rule_node| or |glue_node| {\sl Sync\TeX} information */ + if (int_par(synctex_code)) { + synch_pos_with_cur(pdf->posstruct, refpos, cur); + synctexhorizontalruleorglue(p, this_box); + } + NEXTP: + prev_p = p; + p = vlink(p); + synch_pos_with_cur(pdf->posstruct, refpos, cur); + } + } + + /* Finish hlist {\sl Sync\TeX} information record */ + if (int_par(synctex_code)) + synctextsilh(this_box); + + if (pdf->o_mode == OMODE_DVI) { + prune_movements(save_loc); /* DVI! */ + if (cur_s > 0) { /* DVI! */ + dvi_pop(save_loc); /* DVI! */ + dvi = save_dvi; /* DVI! */ + } + } + decr(cur_s); + pdf->posstruct = refpos; +} + +@ @c +void vlist_out(PDF pdf, halfword this_box) +{ + posstructure localpos; /* the position structure local within this function */ + posstructure *refpos; /* the list origin pos. on the page, provided by the caller */ + + scaledpos cur, tmpcur, basepoint; + scaledpos size = { 0, 0 }; /* rule dimensions */ + scaled effective_vertical; + scaled save_v; /* what |cur.v| should pop to */ + scaled top_edge; /* the top coordinate for this box */ + scaled edge; /* bottom boundary of leader space */ + glue_ord g_order; /* applicable order of infinity for glue */ + int g_sign; /* selects type of glue */ + halfword p; /* current position in the vlist */ + halfword leader_box; /* the leader box being replicated */ + scaled leader_ht; /* height of leader box being replicated */ + scaled lx; /* extra space between leader boxes */ + boolean outer_doing_leaders; /* were we doing leaders? */ + real glue_temp; /* glue value before rounding */ + real cur_glue = 0.0; /* glue seen so far */ + scaled cur_g = 0; /* rounded equivalent of |cur_glue| times the glue ratio */ + scaled_whd rule; + int save_loc = 0; /* DVI! \.{DVI} byte location upon entry */ + scaledpos save_dvi = { 0, 0 }; /* DVI! what |dvi| should pop to */ + + g_order = (glue_ord) glue_order(this_box); + g_sign = glue_sign(this_box); + p = list_ptr(this_box); + + cur.h = 0; + cur.v = -height(this_box); + top_edge = cur.v; + + refpos = pdf->posstruct; + pdf->posstruct = &localpos; /* use local structure for recursion */ + localpos.dir = box_dir(this_box); + synch_pos_with_cur(pdf->posstruct, refpos, cur); + + incr(cur_s); + if (cur_s > max_push) + max_push = cur_s; + + if (pdf->o_mode == OMODE_DVI) { + if (cur_s > 0) { /* DVI! */ + dvi_push(); /* DVI! */ + save_dvi = dvi; /* DVI! */ + } + save_loc = dvi_offset + dvi_ptr; /* DVI! */ + } + + /* Start vlist {\sl Sync\TeX} information record */ + if (int_par(synctex_code)) + synctexvlist(this_box); + + /* Create thread for the current vbox if needed */ + check_running_thread(pdf, this_box, cur); + + while (p != null) { + if (is_char_node(p)) { + confusion("vlistout"); /* this can't happen */ + } else { + /* Output the non-|char_node| |p| for |vlist_out| */ + + switch (type(p)) { + case hlist_node: + case vlist_node: + /* (\pdfTeX) Output a box in a vlist */ + + /* TODO: the direct test to switch between |width(p)| and |-width(p)| + is definately wrong, because it does not nest properly. But at least + it fixes a very obvious problem that otherwise occured with + \.{\\pardir TLT} in a document with \.{\\bodydir TRT}, and so it + will have to do for now. + */ + if (pardir_parallel(box_dir(p), localpos.dir)) { + effective_vertical = height(p) + depth(p); + if ((type(p) == hlist_node) && is_mirrored(box_dir(p))) + basepoint.v = depth(p); + else + basepoint.v = height(p); + if (textdir_opposite(box_dir(p), localpos.dir)) + basepoint.h = width(p); + else + basepoint.h = 0; + } else { + effective_vertical = width(p); + if (!is_mirrored(box_dir(p))) { + if (partextdir_eq(box_dir(p), localpos.dir)) + basepoint.h = height(p); + else + basepoint.h = depth(p); + } else { + if (partextdir_eq(box_dir(p), localpos.dir)) + basepoint.h = depth(p); + else + basepoint.h = height(p); + } + if (partextdir_eq(localpos.dir, box_dir(p))) + basepoint.v = 0; + else + basepoint.v = width(p); + } + basepoint.h = basepoint.h + shift_amount(p); /* shift the box `right' */ + if (list_ptr(p) == null) { + cur.v += effective_vertical; + /* Record void list {\sl Sync\TeX} information */ + if (int_par(synctex_code)) { + synch_pos_with_cur(pdf->posstruct, refpos, cur); + if (type(p) == vlist_node) + synctexvoidvlist(p, this_box); + else + synctexvoidhlist(p, this_box); + } + } else { + assert(cur.h == 0); + tmpcur.h = basepoint.h; + tmpcur.v = cur.v + basepoint.v; + synch_pos_with_cur(pdf->posstruct, refpos, tmpcur); + if (type(p) == vlist_node) + vlist_out(pdf, p); + else + hlist_out(pdf, p); + cur.v += effective_vertical; + } + break; + case rule_node: + if (rule_dir(p)<0) + rule_dir(p) = localpos.dir; + if (pardir_parallel(rule_dir(p), localpos.dir)) { + rule.ht = height(p); + rule.dp = depth(p); + rule.wd = width(p); + } else { + rule.ht = width(p) / 2; + rule.dp = width(p) / 2; + rule.wd = height(p) + depth(p); + } + goto FIN_RULE; + break; + case whatsit_node: + /* Output the whatsit node |p| in |vlist_out| */ + switch (subtype(p)) { + case pdf_save_pos_node: + pdf_last_pos = pdf->posstruct->pos; + pos_info.curpos = pdf->posstruct->pos; + pos_info.boxpos.pos = refpos->pos; + pos_info.boxpos.dir = localpos.dir; + pos_info.boxdim.wd = width(this_box); + pos_info.boxdim.ht = height(this_box); + pos_info.boxdim.dp = depth(this_box); + break; + /* |function(pdf, p, this_box, cur)|; too many args for |out_what()| */ + case pdf_annot_node: /* |do_annot(pdf, p, this_box, cur);| */ + case pdf_start_link_node: /* |do_link(pdf, p, this_box, cur);| */ + case pdf_dest_node: /* |do_dest(pdf, p, this_box, cur);| */ + case pdf_start_thread_node: + case pdf_thread_node: /* |do_thread(pdf, p, this_box, cur);| */ + backend_out_whatsit[subtype(p)] (pdf, p, this_box, cur); + break; + case pdf_refxform_node: /* |pdf_place_form(pdf, pdf_xform_objnum(p));| */ + case pdf_refximage_node: /* |pdf_place_image(pdf, pdf_ximage_idx(p));| */ + /* Output a Form node in a vlist */ + /* Output an Image node in a vlist */ + switch (localpos.dir) { + case dir_TLT: + pos_down(height(p) + depth(p)); + break; + case dir_TRT: + pos_left(width(p)); + pos_down(height(p) + depth(p)); + break; + case dir_LTL: + pos_down(width(p)); + break; + case dir_RTT: + pos_left(height(p) + depth(p)); + pos_down(width(p)); + break; + default: + break; + } + backend_out_whatsit[subtype(p)] (pdf, p); + cur.v += height(p) + depth(p); + break; + default: + out_what(pdf, p); + } + break; + case glue_node: + /* (\pdfTeX) Move down or output leaders */ + g = glue_ptr(p); + rule.ht = width(g) - cur_g; + if (g_sign != normal) { + if (g_sign == stretching) { + if (stretch_order(g) == g_order) { + cur_glue = cur_glue + stretch(g); + vet_glue(float_cast(glue_set(this_box)) * cur_glue); /* real multiplication */ + cur_g = float_round(glue_temp); + } + } else if (shrink_order(g) == g_order) { + cur_glue = cur_glue - shrink(g); + vet_glue(float_cast(glue_set(this_box)) * cur_glue); + cur_g = float_round(glue_temp); + } + } + rule.ht = rule.ht + cur_g; + if (subtype(p) >= a_leaders) { + /* (\pdfTeX) Output leaders in a vlist, |goto fin_rule| if a rule or to |next_p| if done */ + leader_box = leader_ptr(p); + if (type(leader_box) == rule_node) { + rule.wd = width(leader_box); + rule.dp = 0; + goto FIN_RULE; + } + leader_ht = height(leader_box) + depth(leader_box); + if ((leader_ht > 0) && (rule.ht > 0)) { + rule.ht = rule.ht + 10; /* compensate for floating-point rounding */ + edge = cur.v + rule.ht; + lx = 0; + /* Let |cur.v| be the position of the first box, and set |leader_ht+lx| + to the spacing between corresponding parts of boxes */ + + if (subtype(p) == g_leaders) { + save_v = cur.v; + switch (localpos.dir) { + case dir_LTL: + cur.v += refpos->pos.h - shipbox_refpos.h; + cur.v = leader_ht * (cur.v / leader_ht); + cur.v -= refpos->pos.h - shipbox_refpos.h; + break; + case dir_RTT: + cur.v = + refpos->pos.h - shipbox_refpos.h - cur.v; + cur.v = leader_ht * (cur.v / leader_ht); + cur.v = + refpos->pos.h - shipbox_refpos.h - cur.v; + break; + case dir_TLT: + case dir_TRT: + cur.v = + refpos->pos.v - shipbox_refpos.v - cur.v; + cur.v = leader_ht * (cur.v / leader_ht); + cur.v = + refpos->pos.v - shipbox_refpos.v - cur.v; + break; + } + if (cur.v < save_v) + cur.v += leader_ht; + } else if (subtype(p) == a_leaders) { + save_v = cur.v; + cur.v = + top_edge + + leader_ht * ((cur.v - top_edge) / leader_ht); + if (cur.v < save_v) + cur.v += leader_ht; + } else { + lq = rule.ht / leader_ht; /* the number of box copies */ + lr = rule.ht % leader_ht; /* the remaining space */ + if (subtype(p) == c_leaders) { + cur.v += lr / 2; + } else { + lx = lr / (lq + 1); + cur.v += (lr - (lq - 1) * lx) / 2; + } + } + + while (cur.v + leader_ht <= edge) { + /* (\pdfTeX) Output a leader box at |cur.v|, + then advance |cur.v| by |leader_ht+lx| */ + assert(cur.h == 0); + tmpcur.h = shift_amount(leader_box); + tmpcur.v = cur.v + height(leader_box); + synch_pos_with_cur(pdf->posstruct, refpos, tmpcur); + outer_doing_leaders = doing_leaders; + doing_leaders = true; + if (type(leader_box) == vlist_node) + vlist_out(pdf, leader_box); + else + hlist_out(pdf, leader_box); + doing_leaders = outer_doing_leaders; + cur.v += leader_ht + lx; + } + cur.v = edge - 10; + goto NEXTP; + } + } + goto MOVE_PAST; + break; + case kern_node: + cur.v += width(p); + break; + default: + break; + } + goto NEXTP; + FIN_RULE: + /* (\pdfTeX) Output a rule in a vlist, |goto next_p| */ + if (is_running(rule.wd)) + rule.wd = width(this_box); + if ((rule.ht + rule.dp) > 0 && rule.wd > 0) { /* we don't output empty rules */ + switch (localpos.dir) { + case dir_TLT: + size.h = rule.wd; + size.v = rule.ht + rule.dp; + pos_down(size.v); + break; + case dir_TRT: + size.h = rule.wd; + size.v = rule.ht + rule.dp; + pos_left(size.h); + pos_down(size.v); + break; + case dir_LTL: + size.h = rule.ht + rule.dp; + size.v = rule.wd; + pos_down(size.v); + break; + case dir_RTT: + size.h = rule.ht + rule.dp; + size.v = rule.wd; + pos_left(size.h); + pos_down(size.v); + break; + default:; + } + backend_out[rule_node] (pdf, p, size); /* |pdf_place_rule(pdf, rule.ht, rule.wd);| */ + cur.v += rule.ht + rule.dp; + } + goto NEXTP; + MOVE_PAST: + cur.v += rule.ht; + NEXTP: + p = vlink(p); + } + synch_pos_with_cur(pdf->posstruct, refpos, cur); + } + /* Finish vlist {\sl Sync\TeX} information record */ + if (int_par(synctex_code)) + synctextsilv(this_box); + + if (pdf->o_mode == OMODE_DVI) { + prune_movements(save_loc); /* DVI! */ + if (cur_s > 0) { /* DVI! */ + dvi_pop(save_loc); /* DVI! */ + dvi = save_dvi; /* DVI! */ + } + } + decr(cur_s); + pdf->posstruct = refpos; +} diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfliteral.h b/Build/source/texk/web2c/luatexdir/pdf/pdfliteral.h new file mode 100644 index 00000000000..9b698ef9437 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdfliteral.h @@ -0,0 +1,34 @@ +/* pdfliteral.h + + Copyright 2009 Taco Hoekwater <taco@luatex.org> + + 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 <http://www.gnu.org/licenses/>. */ + +/* $Id: pdfliteral.h 3261 2009-12-18 11:38:21Z taco $ */ + +#ifndef PDFLITERAL_H +# define PDFLITERAL_H + + +# define set_pdf_literal_mode(A,B) pdf_literal_mode(A)=B +# define set_pdf_literal_type(A,B) pdf_literal_type(A)=B +# define set_pdf_literal_data(A,B) pdf_literal_data(A)=B + +extern void pdf_literal(PDF pdf, str_number s, int literal_mode, boolean warn); +extern void pdf_special(PDF pdf, halfword p); +extern void pdf_out_literal(PDF pdf, halfword p); + +#endif diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfliteral.w b/Build/source/texk/web2c/luatexdir/pdf/pdfliteral.w new file mode 100644 index 00000000000..fbbd9b9cb37 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdfliteral.w @@ -0,0 +1,154 @@ +% pdfliteral.w +% +% Copyright 2009-2010 Taco Hoekwater <taco@@luatex.org> + +% 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 <http://www.gnu.org/licenses/>. + +@ @c +#include "ptexlib.h" + +static const char _svn_version[] = + "$Id: pdfliteral.w 3571 2010-04-02 13:50:45Z taco $" + "$URL: http://foundry.supelec.fr/svn/luatex/tags/beta-0.60.0/source/texk/web2c/luatexdir/pdf/pdfliteral.w $"; + +@ @c +void pdf_special(PDF pdf, halfword p) +{ + int old_setting; /* holds print |selector| */ + str_number s; + old_setting = selector; + selector = new_string; + show_token_list(token_link(write_tokens(p)), null, -1); + selector = old_setting; + s = make_string(); + pdf_literal(pdf, s, scan_special, true); + flush_str(s); +} + + +@ To ship out a \TeX\ box to PDF page description we need to implement +|hlist_out|, |vlist_out| and |ship_out|, which are equivalent to +the \TeX' original |hlist_out|, |vlist_out| and |ship_out| resp. But first we +need to declare some procedures needed in |hlist_out| and |vlist_out|. + +@c +void pdf_out_literal(PDF pdf, halfword p) +{ + int old_setting; /* holds print |selector| */ + str_number s; + if (pdf_literal_type(p) == normal) { + old_setting = selector; + selector = new_string; + show_token_list(token_link(pdf_literal_data(p)), null, -1); + selector = old_setting; + s = make_string(); + pdf_literal(pdf, s, pdf_literal_mode(p), false); + flush_str(s); + } else { + assert(pdf_literal_mode(p) != scan_special); + switch (pdf_literal_mode(p)) { + case set_origin: + pdf_goto_pagemode(pdf); + pdf_set_pos(pdf, pdf->posstruct->pos); + break; + case direct_page: + pdf_goto_pagemode(pdf); + break; + case direct_always: + pdf_end_string_nl(pdf); + break; + default: + confusion("literal1"); + break; + } + lua_pdf_literal(pdf, pdf_literal_data(p)); + } +} + +@ test equality of start of strings +@c +static boolean str_in_cstr(str_number s, const char *r, unsigned i) +{ + const unsigned char *k, *l; + if ((unsigned) str_length(s) < i + strlen(r)) + return false; + k = (const unsigned char *) r; + l = str_string(s) + i; + while ((*l) && (*k)) { + if (*l++ != *k++) + return false; + } + return true; +} + +@ @c +void pdf_literal(PDF pdf, str_number s, int literal_mode, boolean warn) +{ + pool_pointer j = 0; /* current character code position, initialized to make the compiler happy */ + if (s >= STRING_OFFSET) { /* needed for |out_save| */ + j = 0; + if (literal_mode == scan_special) { + if (!(str_in_cstr(s, "PDF:", 0) || str_in_cstr(s, "pdf:", 0))) { + if (warn + && + ((!(str_in_cstr(s, "SRC:", 0) || str_in_cstr(s, "src:", 0))) + || (str_length(s) == 0))) + tprint_nl("Non-PDF special ignored!"); + return; + } + j = j + (pool_pointer) strlen("PDF:"); + if (str_in_cstr(s, "direct:", strlen("PDF:"))) { + j = j + (pool_pointer) strlen("direct:"); + literal_mode = direct_always; + } else if (str_in_cstr(s, "page:", strlen("PDF:"))) { + j = j + (pool_pointer) strlen("page:"); + literal_mode = direct_page; + } else { + literal_mode = set_origin; + } + } + } + switch (literal_mode) { + case set_origin: + pdf_goto_pagemode(pdf); + pdf_set_pos(pdf, pdf->posstruct->pos); + break; + case direct_page: + pdf_goto_pagemode(pdf); + break; + case direct_always: + pdf_end_string_nl(pdf); + break; + default: + confusion("literal1"); + break; + } + if (s >= STRING_OFFSET) { + unsigned char *ss = str_string(s); + size_t l = str_length(s) - (size_t) j; + if (l < max_single_pdf_print) { + pdf_out_block(pdf, (ss + j), l); + } else { + + while (l--) + pdf_out(pdf, *(ss + j++)); + } + } else { + assert(s < 256); + pdf_out(pdf, s); + } + pdf_print_nl(pdf); +} diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfobj.h b/Build/source/texk/web2c/luatexdir/pdf/pdfobj.h new file mode 100644 index 00000000000..35325a1e8bb --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdfobj.h @@ -0,0 +1,66 @@ +/* pdfobj.h + + Copyright 2009 Taco Hoekwater <taco@luatex.org> + + 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 <http://www.gnu.org/licenses/>. */ + +/* $Id: pdfobj.h 3261 2009-12-18 11:38:21Z taco $ */ + +#ifndef PDFOBJ_H +# define PDFOBJ_H + +/* data structure for \.{\\pdfobj} and \.{\\pdfrefobj} */ + +# define set_pdf_obj_objnum(A, B) pdf_obj_objnum(A) = (B) + +# define pdfmem_obj_size 5 /* size of memory in |mem| which |obj_data_ptr| holds */ + +# define obj_obj_data(pdf, A) pdf->mem[obj_data_ptr((pdf), (A)) + 0] /* object data */ +# define obj_obj_stream_attr(pdf, A) pdf->mem[obj_data_ptr((pdf), (A)) + 1] /* additional attributes into stream dict */ +# define obj_obj_flags(pdf, A) pdf->mem[obj_data_ptr((pdf), (A)) + 2] /* stream/file flags */ +# define obj_obj_pdfcompresslevel(pdf, A) pdf->mem[obj_data_ptr((pdf), (A)) + 3] /* overrides \pdfcompresslevel */ +# define obj_obj_pdfoslevel(pdf, A) pdf->mem[obj_data_ptr((pdf), (A)) + 4] /* for object stream compression */ + +/* define set_obj_obj_data(pdf, A, B) obj_obj_data((pdf), (A)) = (B) */ +/* define set_obj_obj_flags(pdf, A, B) obj_obj_flags((pdf), (A)) = (B) */ +/* define set_obj_obj_stream_attr(pdf, A, B) obj_obj_stream_attr((pdf), (A)) = (B) */ +/* define set_obj_obj_pdfcompresslevel(pdf, A, B) obj_obj_pdfcompresslevel((pdf), (A)) = (B) */ +/* define set_obj_obj_pdfoslevel(pdf, A, B) obj_obj_pdfoslevel((pdf), (A)) = (B) */ + +/**********************************************************************/ + +# define OBJ_FLAG_ISSTREAM (1 << 0) +# define OBJ_FLAG_ISFILE (1 << 1) + +# define obj_obj_is_stream(pdf,A) ((obj_obj_flags((pdf), (A)) & OBJ_FLAG_ISSTREAM) != 0) +# define set_obj_obj_is_stream(pdf,A) ((obj_obj_flags((pdf), (A)) |= OBJ_FLAG_ISSTREAM)) +# define unset_obj_obj_is_stream(pdf,A) ((obj_obj_flags((pdf), (A)) &= ~OBJ_FLAG_ISSTREAM)) + +# define obj_obj_is_file(pdf,A) ((obj_obj_flags((pdf), (A)) & OBJ_FLAG_ISFILE) != 0) +# define set_obj_obj_is_file(pdf,A) ((obj_obj_flags((pdf), (A)) |= OBJ_FLAG_ISFILE)) +# define unset_obj_obj_is_file(pdf,A) ((obj_obj_flags((pdf), (A)) &= ~OBJ_FLAG_ISFILE)) + +/**********************************************************************/ + +extern int pdf_last_obj; + +extern void init_obj_obj(PDF pdf, int k); +extern void pdf_write_obj(PDF pdf, int n); +extern void scan_obj(PDF pdf); +extern void scan_refobj(PDF pdf); +extern void pdf_ref_obj(PDF pdf, halfword p); + +#endif diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfobj.w b/Build/source/texk/web2c/luatexdir/pdf/pdfobj.w new file mode 100644 index 00000000000..ab3d1314024 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdfobj.w @@ -0,0 +1,214 @@ +% pdfobj.w + +% Copyright 2009-2010 Taco Hoekwater <taco@@luatex.org> + +% 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 <http://www.gnu.org/licenses/>. + +@ @c +static const char _svn_version[] = + "$Id: pdfobj.w 3571 2010-04-02 13:50:45Z taco $" + "$URL: http://foundry.supelec.fr/svn/luatex/tags/beta-0.60.0/source/texk/web2c/luatexdir/pdf/pdfobj.w $"; + +#include "ptexlib.h" + +@ @c +#include "lua/luatex-api.h" + +int pdf_last_obj; + +@ write a raw PDF object + +@c +void pdf_write_obj(PDF pdf, int k) +{ + lstring data; + const_lstring st; + size_t i, li; /* index into |data.s| */ + int saved_compress_level = pdf->compress_level; + int os_level = 1; /* gives compressed objects for \.{\\pdfobjcompresslevel} $>$ 0 */ + int l = 0; /* possibly a lua registry reference */ + int ll = 0; + data.s = NULL; + if (obj_obj_pdfcompresslevel(pdf, k) > -1) /* -1 = "unset" */ + pdf->compress_level = obj_obj_pdfcompresslevel(pdf, k); + if (obj_obj_pdfoslevel(pdf, k) > -1) /* -1 = "unset" */ + os_level = obj_obj_pdfoslevel(pdf, k); + if (obj_obj_is_stream(pdf, k)) { + pdf_begin_dict(pdf, k, 0); + l = obj_obj_stream_attr(pdf, k); + if (l != LUA_NOREF) { + lua_rawgeti(Luas, LUA_REGISTRYINDEX, l); + assert(lua_isstring(Luas, -1)); + st.s = lua_tolstring(Luas, -1, &li); + st.l = li; + for (i = 0; i < st.l; i++) + pdf_out(pdf, st.s[i]); + if (st.s[st.l - 1] != '\n') + pdf_out(pdf, '\n'); + luaL_unref(Luas, LUA_REGISTRYINDEX, l); + obj_obj_stream_attr(pdf, k) = LUA_NOREF; + } + pdf_begin_stream(pdf); + } else + pdf_begin_obj(pdf, k, os_level); + l = obj_obj_data(pdf, k); + lua_rawgeti(Luas, LUA_REGISTRYINDEX, l); + assert(lua_isstring(Luas, -1)); + st.s = lua_tolstring(Luas, -1, &li); + st.l = li; + if (obj_obj_is_file(pdf, k)) { + boolean res = false; /* callback status value */ + const char *fnam = NULL; /* callback found filename */ + int callback_id; + /* st.s is also |\0|-terminated, even as lstring */ + fnam = luatex_find_file(st.s, find_data_file_callback); + callback_id = callback_defined(read_data_file_callback); + if (fnam && callback_id > 0) { + boolean file_opened = false; + res = run_callback(callback_id, "S->bSd", fnam, + &file_opened, &data.s, &ll); + data.l = (size_t) ll; + if (!file_opened) + pdf_error("ext5", "cannot open file for embedding"); + } else { + byte_file f; /* the data file's FILE* */ + if (!fnam) + fnam = st.s; + if (!luatex_open_input + (&f, fnam, kpse_tex_format, FOPEN_RBIN_MODE, true)) + pdf_error("ext5", "cannot open file for embedding"); + res = read_data_file(f, &data.s, &ll); + data.l = (size_t) ll; + close_file(f); + } + if (data.l == 0L) + pdf_error("ext5", "empty file for embedding"); + if (!res) + pdf_error("ext5", "error reading file for embedding"); + tprint("<<"); + tprint(st.s); + for (i = 0; i < data.l; i++) + pdf_out(pdf, data.s[i]); + if (!obj_obj_is_stream(pdf, k) && data.s[data.l - 1] != '\n') + pdf_out(pdf, '\n'); + xfree(data.s); + tprint(">>"); + } else { + for (i = 0; i < st.l; i++) + pdf_out(pdf, st.s[i]); + if (!obj_obj_is_stream(pdf, k) && st.s[st.l - 1] != '\n') + pdf_out(pdf, '\n'); + } + if (obj_obj_is_stream(pdf, k)) + pdf_end_stream(pdf); + else + pdf_end_obj(pdf); + luaL_unref(Luas, LUA_REGISTRYINDEX, l); + obj_obj_data(pdf, k) = LUA_NOREF; + pdf->compress_level = saved_compress_level; +} + +@ @c +void init_obj_obj(PDF pdf, int k) +{ + obj_obj_stream_attr(pdf, k) = LUA_NOREF; + obj_obj_data(pdf, k) = LUA_NOREF; + unset_obj_obj_is_stream(pdf, k); + unset_obj_obj_is_file(pdf, k); + obj_obj_pdfcompresslevel(pdf, k) = -1; /* unset */ + obj_obj_pdfoslevel(pdf, k) = -1; /* unset */ +} + +@ The \.{\\pdfobj} primitive is used to create a ``raw'' object in the PDF + output file. The object contents will be hold in memory and will be written + out only when the object is referenced by \.{\\pdfrefobj}. When \.{\\pdfobj} + is used with \.{\\immediate}, the object contents will be written out + immediately. Objects referenced in the current page are appended into + |pdf_obj_list|. + +@c +void scan_obj(PDF pdf) +{ + int k; + lstring *st = NULL; + if (scan_keyword("reserveobjnum")) { + /* Scan an optional space */ + get_x_token(); + if (cur_cmd != spacer_cmd) + back_input(); + incr(pdf->obj_count); + pdf_create_obj(pdf, obj_type_obj, pdf->sys_obj_ptr + 1); + k = pdf->sys_obj_ptr; + } else { + if (scan_keyword("useobjnum")) { + scan_int(); + k = cur_val; + check_obj_exists(pdf, obj_type_obj, k); + if (is_obj_scheduled(pdf, k) || obj_data_ptr(pdf, k) != 0) + luaL_error(Luas, "object in use"); + } else { + incr(pdf->obj_count); + pdf_create_obj(pdf, obj_type_obj, pdf->sys_obj_ptr + 1); + k = pdf->sys_obj_ptr; + } + obj_data_ptr(pdf, k) = pdf_get_mem(pdf, pdfmem_obj_size); + init_obj_obj(pdf, k); + if (scan_keyword("uncompressed")) { + obj_obj_pdfcompresslevel(pdf, k) = 0; /* \pdfcompresslevel = 0 */ + obj_obj_pdfoslevel(pdf, k) = 0; + } + if (scan_keyword("stream")) { + set_obj_obj_is_stream(pdf, k); + if (scan_keyword("attr")) { + scan_pdf_ext_toks(); + st = tokenlist_to_lstring(def_ref, true); + flush_list(def_ref); + lua_pushlstring(Luas, (char *) st->s, st->l); + obj_obj_stream_attr(pdf, k) = luaL_ref(Luas, LUA_REGISTRYINDEX); + free_lstring(st); + st = NULL; + } + } + if (scan_keyword("file")) + set_obj_obj_is_file(pdf, k); + scan_pdf_ext_toks(); + st = tokenlist_to_lstring(def_ref, true); + flush_list(def_ref); + lua_pushlstring(Luas, (char *) st->s, st->l); + obj_obj_data(pdf, k) = luaL_ref(Luas, LUA_REGISTRYINDEX); + free_lstring(st); + st = NULL; + } + pdf_last_obj = k; +} + +@ @c +#define tail cur_list.tail_field + +void scan_refobj(PDF pdf) +{ + scan_int(); + check_obj_exists(pdf, obj_type_obj, cur_val); + new_whatsit(pdf_refobj_node); + pdf_obj_objnum(tail) = cur_val; +} + +@ @c +void pdf_ref_obj(PDF pdf, halfword p) +{ + if (!is_obj_scheduled(pdf, pdf_obj_objnum(p))) + addto_page_resources(pdf, obj_type_obj, pdf_obj_objnum(p)); +} diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfoutline.h b/Build/source/texk/web2c/luatexdir/pdf/pdfoutline.h new file mode 100644 index 00000000000..2b0bd8712a2 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdfoutline.h @@ -0,0 +1,28 @@ +/* pdfoutline.h + + Copyright 2009 Taco Hoekwater <taco@luatex.org> + + 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 <http://www.gnu.org/licenses/>. */ + +/* $Id: pdfoutline.h 3261 2009-12-18 11:38:21Z taco $ */ + +#ifndef PDFOUTLINE_H +# define PDFOUTLINE_H + +extern void scan_pdfoutline(PDF pdf); +extern int print_outlines(PDF pdf); + +#endif diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfoutline.w b/Build/source/texk/web2c/luatexdir/pdf/pdfoutline.w new file mode 100644 index 00000000000..90c9675ac5b --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdfoutline.w @@ -0,0 +1,240 @@ +% pdfoutline.w +% +% Copyright 2009-2010 Taco Hoekwater <taco@@luatex.org> + +% 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 <http://www.gnu.org/licenses/>. + +@ @c +#include "ptexlib.h" + +static const char _svn_version[] = + "$Id: pdfoutline.w 3571 2010-04-02 13:50:45Z taco $" + "$URL: http://foundry.supelec.fr/svn/luatex/tags/beta-0.60.0/source/texk/web2c/luatexdir/pdf/pdfoutline.w $"; + +@ Data structure of outlines; it's not able to write out outline entries +before all outline entries are defined, so memory allocated for outline +entries can't not be deallocated and will stay in memory. For this reason we +will store data of outline entries in |pdf->mem| instead of |mem| + +@c +#define pdfmem_outline_size 8 /* size of memory in |pdf->mem| which |obj_outline_ptr| points to */ + +#define obj_outline_count obj_info /* count of all opened children */ +#define set_obj_outline_count(pdf,A,B) obj_outline_count(pdf,A)=B +#define obj_outline_ptr obj_aux /* pointer to |pdf->mem| */ +#define set_obj_outline_ptr(pdf,A,B) obj_outline_ptr(pdf,A)=B + +#define obj_outline_title(pdf,A) pdf->mem[obj_outline_ptr(pdf,A)] +#define obj_outline_parent(pdf,A) pdf->mem[obj_outline_ptr(pdf,A) + 1] +#define obj_outline_prev(pdf,A) pdf->mem[obj_outline_ptr(pdf,A) + 2] +#define obj_outline_next(pdf,A) pdf->mem[obj_outline_ptr(pdf,A) + 3] +#define obj_outline_first(pdf,A) pdf->mem[obj_outline_ptr(pdf,A) + 4] +#define obj_outline_last(pdf,A) pdf->mem[obj_outline_ptr(pdf,A) + 5] +#define obj_outline_action_objnum(pdf,A) pdf->mem[obj_outline_ptr(pdf,A) + 6] /* object number of action */ +#define obj_outline_attr(pdf,A) pdf->mem[obj_outline_ptr(pdf,A) + 7] + +#define set_obj_outline_action_objnum(pdf,A,B) obj_outline_action_objnum(pdf,A)=B +#define set_obj_outline_title(pdf,A,B) obj_outline_title(pdf,A)=B +#define set_obj_outline_prev(pdf,A,B) obj_outline_prev(pdf,A)=B +#define set_obj_outline_next(pdf,A,B) obj_outline_next(pdf,A)=B +#define set_obj_outline_first(pdf,A,B) obj_outline_first(pdf,A)=B +#define set_obj_outline_last(pdf,A,B) obj_outline_last(pdf,A)=B +#define set_obj_outline_parent(pdf,A,B) obj_outline_parent(pdf,A)=B +#define set_obj_outline_attr(pdf,A,B) obj_outline_attr(pdf,A)=B + +@ @c +static int open_subentries(PDF pdf, halfword p) +{ + int k, c; + int l, r; + k = 0; + if (obj_outline_first(pdf, p) != 0) { + l = obj_outline_first(pdf, p); + do { + incr(k); + c = open_subentries(pdf, l); + if (obj_outline_count(pdf, l) > 0) + k = k + c; + obj_outline_parent(pdf, l) = p; + r = obj_outline_next(pdf, l); + if (r == 0) + obj_outline_last(pdf, p) = l; + l = r; + } while (l != 0); + } + if (obj_outline_count(pdf, p) > 0) + obj_outline_count(pdf, p) = k; + else + obj_outline_count(pdf, p) = -k; + return k; +} + +@ return number of outline entries in the same level with |p| + +@c +static int outline_list_count(PDF pdf, pointer p) +{ + int k = 1; + while (obj_outline_prev(pdf, p) != 0) { + incr(k); + p = obj_outline_prev(pdf, p); + } + return k; +} + +@ @c +void scan_pdfoutline(PDF pdf) +{ + halfword p, q, r; + int i, j, k; + if (scan_keyword("attr")) { + scan_pdf_ext_toks(); + r = def_ref; + } else { + r = 0; + } + p = scan_action(pdf); + if (scan_keyword("count")) { + scan_int(); + i = cur_val; + } else { + i = 0; + } + scan_pdf_ext_toks(); + q = def_ref; + pdf_new_obj(pdf, obj_type_others, 0, 1); + j = pdf->obj_ptr; + write_action(pdf, p); + pdf_end_obj(pdf); + delete_action_ref(p); + pdf_create_obj(pdf, obj_type_outline, 0); + k = pdf->obj_ptr; + set_obj_outline_ptr(pdf, k, pdf_get_mem(pdf, pdfmem_outline_size)); + set_obj_outline_action_objnum(pdf, k, j); + set_obj_outline_count(pdf, k, i); + pdf_new_obj(pdf, obj_type_others, 0, 1); + { + char *s = tokenlist_to_cstring(q, true, NULL); + pdf_print_str_ln(pdf, s); + xfree(s); + } + delete_token_ref(q); + pdf_end_obj(pdf); + set_obj_outline_title(pdf, k, pdf->obj_ptr); + set_obj_outline_prev(pdf, k, 0); + set_obj_outline_next(pdf, k, 0); + set_obj_outline_first(pdf, k, 0); + set_obj_outline_last(pdf, k, 0); + set_obj_outline_parent(pdf, k, pdf->parent_outline); + set_obj_outline_attr(pdf, k, r); + if (pdf->first_outline == 0) + pdf->first_outline = k; + if (pdf->last_outline == 0) { + if (pdf->parent_outline != 0) + set_obj_outline_first(pdf, pdf->parent_outline, k); + } else { + set_obj_outline_next(pdf, pdf->last_outline, k); + set_obj_outline_prev(pdf, k, pdf->last_outline); + } + pdf->last_outline = k; + if (obj_outline_count(pdf, k) != 0) { + pdf->parent_outline = k; + pdf->last_outline = 0; + } else if ((pdf->parent_outline != 0) && + (outline_list_count(pdf, k) == + abs(obj_outline_count(pdf, pdf->parent_outline)))) { + j = pdf->last_outline; + do { + set_obj_outline_last(pdf, pdf->parent_outline, j); + j = pdf->parent_outline; + pdf->parent_outline = obj_outline_parent(pdf, pdf->parent_outline); + } while (!((pdf->parent_outline == 0) || + (outline_list_count(pdf, j) < + abs(obj_outline_count(pdf, pdf->parent_outline))))); + if (pdf->parent_outline == 0) + pdf->last_outline = pdf->first_outline; + else + pdf->last_outline = obj_outline_first(pdf, pdf->parent_outline); + while (obj_outline_next(pdf, pdf->last_outline) != 0) + pdf->last_outline = obj_outline_next(pdf, pdf->last_outline); + } +} + +@ In the end we must flush PDF objects that cannot be written out +immediately after shipping out pages. + +@c +int print_outlines(PDF pdf) +{ + int k, l, a; + int outlines; + if (pdf->first_outline != 0) { + pdf_new_dict(pdf, obj_type_others, 0, 1); + outlines = pdf->obj_ptr; + l = pdf->first_outline; + k = 0; + do { + incr(k); + a = open_subentries(pdf, l); + if (obj_outline_count(pdf, l) > 0) + k = k + a; + set_obj_outline_parent(pdf, l, pdf->obj_ptr); + l = obj_outline_next(pdf, l); + } while (l != 0); + pdf_printf(pdf, "/Type /Outlines\n"); + pdf_indirect_ln(pdf, "First", pdf->first_outline); + pdf_indirect_ln(pdf, "Last", pdf->last_outline); + pdf_int_entry_ln(pdf, "Count", k); + pdf_end_dict(pdf); + /* Output PDF outline entries */ + + k = pdf->head_tab[obj_type_outline]; + while (k != 0) { + if (obj_outline_parent(pdf, k) == pdf->parent_outline) { + if (obj_outline_prev(pdf, k) == 0) + pdf->first_outline = k; + if (obj_outline_next(pdf, k) == 0) + pdf->last_outline = k; + } + pdf_begin_dict(pdf, k, 1); + pdf_indirect_ln(pdf, "Title", obj_outline_title(pdf, k)); + pdf_indirect_ln(pdf, "A", obj_outline_action_objnum(pdf, k)); + if (obj_outline_parent(pdf, k) != 0) + pdf_indirect_ln(pdf, "Parent", obj_outline_parent(pdf, k)); + if (obj_outline_prev(pdf, k) != 0) + pdf_indirect_ln(pdf, "Prev", obj_outline_prev(pdf, k)); + if (obj_outline_next(pdf, k) != 0) + pdf_indirect_ln(pdf, "Next", obj_outline_next(pdf, k)); + if (obj_outline_first(pdf, k) != 0) + pdf_indirect_ln(pdf, "First", obj_outline_first(pdf, k)); + if (obj_outline_last(pdf, k) != 0) + pdf_indirect_ln(pdf, "Last", obj_outline_last(pdf, k)); + if (obj_outline_count(pdf, k) != 0) + pdf_int_entry_ln(pdf, "Count", obj_outline_count(pdf, k)); + if (obj_outline_attr(pdf, k) != 0) { + pdf_print_toks_ln(pdf, obj_outline_attr(pdf, k)); + delete_token_ref(obj_outline_attr(pdf, k)); + set_obj_outline_attr(pdf, k, null); + } + pdf_end_dict(pdf); + k = obj_link(pdf, k); + } + + } else { + outlines = 0; + } + return outlines; +} diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfpage.c b/Build/source/texk/web2c/luatexdir/pdf/pdfpage.c deleted file mode 100644 index cde4f128c4e..00000000000 --- a/Build/source/texk/web2c/luatexdir/pdf/pdfpage.c +++ /dev/null @@ -1,561 +0,0 @@ -/* pdfpage.c - - Copyright 2006-2009 Taco Hoekwater <taco@luatex.org> - - 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 <http://www.gnu.org/licenses/>. */ - -#include <stdlib.h> -#include <stdio.h> -#include <assert.h> -#include <math.h> - -#include "ptexlib.h" - -static const char __svn_version[] = - "$Id: pdfpage.c 2491 2009-06-14 13:11:08Z hhenkel $ " - "$URL: http://foundry.supelec.fr/svn/luatex/tags/beta-0.40.6/source/texk/web2c/luatexdir/pdf/pdfpage.c $"; - -#define lround(a) (long) floor((a) + 0.5) -#define setpdffloat(a,b,c) {(a).m = (b); (a).e = (c);} -#define pdf2double(a) ((double) (a).m / exp10_arr[(a).e]) - -/* eternal constants */ -#define one_bp ((double) 65536 * (double) 72.27 / 72) /* number of sp per 1bp */ -#define e_tj 3 /* must be 3; movements in []TJ are in fontsize/10^3 units */ - -/* definitions from luatex.web */ -#define pdf_font_blink(a) font_tables[a]->_pdf_font_blink - -pdfstructure *pstruct = NULL; - -static long *exp10_arr = NULL; - -/**********************************************************************/ - -static pdfstructure *new_pdfstructure(void) -{ - return xmalloc(sizeof(pdfstructure)); -} - -static void calc_k1(pdfstructure * p) -{ - p->k1 = exp10_arr[p->pdf.h.e] / one_bp; -} - -static void calc_k2(pdfstructure * p) -{ - p->tm[0].m = - lround(pdf2double(p->hz) * pdf2double(p->ext) * exp10_arr[p->tm[0].e]); - p->k2 = - exp10_arr[e_tj + - p->cw.e] / (exp10_arr[p->pdf.h.e] * pdf2double(p->fs) * - pdf2double(p->tm[0])); -} - -void pdf_page_init(void) -{ - pdfstructure *p; - int i, decimal_digits = fixed_decimal_digits; - if (exp10_arr == NULL) { - exp10_arr = xmalloc(10 * sizeof(long)); - exp10_arr[0] = 1; - for (i = 1; i < 10; i++) - exp10_arr[i] = 10 * exp10_arr[i - 1]; - } - if (pstruct == NULL) - pstruct = new_pdfstructure(); - p = pstruct; - setpdffloat(p->pdf.h, 0, decimal_digits); - setpdffloat(p->pdf.v, 0, decimal_digits); - p->cw.e = 1; - p->fs.e = decimal_digits + 2; /* "+ 2" makes less corrections inside []TJ */ - setpdffloat(p->hz, 1000, 3); /* m = 1000 = default = unexpanded, e must be 3 */ - setpdffloat(p->ext, 1000, 3); /* m = 1000 = default = unextended, e must be 3 */ - /* for placement outside BT...ET */ - setpdffloat(p->cm[0], 1, 0); - setpdffloat(p->cm[1], 0, 0); - setpdffloat(p->cm[2], 0, 0); - setpdffloat(p->cm[3], 1, 0); - setpdffloat(p->cm[4], 0, decimal_digits); /* horizontal movement on page */ - setpdffloat(p->cm[5], 0, decimal_digits); /* vertical movement on page */ - /* for placement inside BT...ET */ - setpdffloat(p->tm[0], exp10_arr[6], 6); /* mantissa holds HZ expand * ExtendFont */ - setpdffloat(p->tm[1], 0, 0); - setpdffloat(p->tm[2], 0, 3); /* mantissa holds SlantFont, 0 = default */ - setpdffloat(p->tm[3], 1, 0); - setpdffloat(p->tm[4], 0, decimal_digits); /* mantissa holds delta from pdf_bt_pos.h */ - setpdffloat(p->tm[5], 0, decimal_digits); /* mantissa holds delta from pdf_bt_pos.v */ - /* */ - p->f_cur = null_font; - p->f_pdf = null_font; - p->wmode = WMODE_H; - p->mode = PMODE_PAGE; - calc_k1(p); -} - -/**********************************************************************/ - -#ifdef SYNCH_POS_WITH_CUR -/* some time this will be needed */ -void synch_pos_with_cur(scaledpos * pos, scaledpos * cur, scaledpos * box_pos) -{ - switch (dvi_direction) { - case dir_TL_: - pos->h = box_pos->h + cur->h; - pos->v = box_pos->v - cur->v; - break; - case dir_TR_: - pos->h = box_pos->h - cur->h; - pos->v = box_pos->v - cur->v; - break; - case dir_BL_: - pos->h = box_pos->h + cur->h; - pos->v = box_pos->v + cur->v; - break; - case dir_BR_: - pos->h = box_pos->h - cur->h; - pos->v = box_pos->v + cur->v; - break; - case dir_LT_: - pos->h = box_pos->h + cur->v; - pos->v = box_pos->v - cur->h; - break; - case dir_RT_: - pos->h = box_pos->h - cur->v; - pos->v = box_pos->v - cur->h; - break; - case dir_LB_: - pos->h = box_pos->h + cur->v; - pos->v = box_pos->v + cur->h; - break; - case dir_RB_: - pos->h = box_pos->h - cur->v; - pos->v = box_pos->v + cur->h; - break; - default:; - } -} -#endif - -/**********************************************************************/ - -boolean calc_pdfpos(pdfstructure * p, scaledpos * pos) -{ - scaledpos new; - int move_pdfpos = FALSE; - switch (p->mode) { - case PMODE_PAGE: - new.h = lround(pos->h * p->k1); - new.v = lround(pos->v * p->k1); - p->cm[4].m = new.h - p->pdf.h.m; /* cm is concatenated */ - p->cm[5].m = new.v - p->pdf.v.m; - if (new.h != p->pdf.h.m || new.v != p->pdf.v.m) - move_pdfpos = TRUE; - break; - case PMODE_TEXT: - new.h = lround(pos->h * p->k1); - new.v = lround(pos->v * p->k1); - p->tm[4].m = new.h - p->pdf_bt_pos.h.m; /* Tm replaces */ - p->tm[5].m = new.v - p->pdf_bt_pos.v.m; - if (new.h != p->pdf.h.m || new.v != p->pdf.v.m) - move_pdfpos = TRUE; - break; - case PMODE_CHAR: - case PMODE_CHARARRAY: - switch (p->wmode) { - case WMODE_H: - new.h = lround((pos->h * p->k1 - p->pdf_tj_pos.h.m) * p->k2); - new.v = lround(pos->v * p->k1); - p->tj_delta.m = - -lround((new.h - p->cw.m) / exp10_arr[p->cw.e - p->tj_delta.e]); - p->tm[5].m = new.v - p->pdf_bt_pos.v.m; /* p->tm[4] is meaningless */ - if (p->tj_delta.m != 0 || new.v != p->pdf.v.m) - move_pdfpos = TRUE; - break; - case WMODE_V: - new.h = lround(pos->h * p->k1); - new.v = lround((p->pdf_tj_pos.v.m - pos->v * p->k1) * p->k2); - p->tm[4].m = new.h - p->pdf_bt_pos.h.m; /* p->tm[5] is meaningless */ - p->tj_delta.m = - -lround((new.v - p->cw.m) / exp10_arr[p->cw.e - p->tj_delta.e]); - if (p->tj_delta.m != 0 || new.h != p->pdf.h.m) - move_pdfpos = TRUE; - break; - default: - assert(0); - } - break; - default: - assert(0); - } - return move_pdfpos; -} - -/**********************************************************************/ - -void print_pdffloat(pdffloat * f) -{ - char a[24]; - int e = f->e, i, j; - long l, m = f->m; - if (m < 0) { - pdf_printf("-"); - m *= -1; - } - l = m / exp10_arr[e]; - pdf_print_int(l); - l = m % exp10_arr[e]; - if (l != 0) { - pdf_printf("."); - j = snprintf(a, 23, "%ld", l + exp10_arr[e]); - assert(j < 23); - for (i = e; i > 0; i--) { - if (a[i] != '0') - break; - a[i] = '\0'; - } - pdf_printf("%s", a + 1); - } -} - -static void print_pdf_matrix(pdffloat * tm) -{ - int i; - for (i = 0; i < 5; i++) { - print_pdffloat(tm + i); - pdf_printf(" "); - } - print_pdffloat(tm + i); -} - -void pdf_print_cm(pdffloat * cm) -{ - print_pdf_matrix(cm); - pdf_printf(" cm\n"); -} - -static void pdf_print_tm(pdffloat * tm) -{ - print_pdf_matrix(tm); - pdf_printf(" Tm "); -} - -static void set_pos(pdfstructure * p, scaledpos * pos) -{ - boolean move; - assert(is_pagemode(p)); - move = calc_pdfpos(p, pos); - if (move == TRUE) { - pdf_print_cm(p->cm); - p->pdf.h.m += p->cm[4].m; - p->pdf.v.m += p->cm[5].m; - } -} - -static void set_pos_temp(pdfstructure * p, scaledpos * pos) -{ - boolean move; - assert(is_pagemode(p)); - move = calc_pdfpos(p, pos); - if (move == TRUE) - pdf_print_cm(p->cm); -} - -void pdf_set_pos(scaled h, scaled v) -{ - scaledpos pos; - pos.h = h; - pos.v = v; - set_pos(pstruct, &pos); -} - -/**********************************************************************/ - -static long pdf_char_width(pdfstructure * p, internal_font_number f, int i) -{ - /* use exactly this formula also for calculating the /Width array values */ - return - lround((double) char_width(f, i) / font_size(f) * - exp10_arr[e_tj + p->cw.e]); -} - -void pdf_print_charwidth(internal_font_number f, int i) -{ - pdffloat cw; - assert(pdf_font_blink(f) == null_font); /* must use unexpanded font! */ - cw.m = pdf_char_width(pstruct, f, i); - cw.e = pstruct->cw.e; - print_pdffloat(&cw); -} - -/**********************************************************************/ - -static void begin_text(pdfstructure * p) -{ - assert(is_pagemode(p)); - p->pdf_bt_pos = p->pdf; - pdf_printf("BT\n"); - p->mode = PMODE_TEXT; -} - -static void end_text(pdfstructure * p) -{ - assert(is_textmode(p)); - pdf_printf("ET\n"); - p->pdf = p->pdf_bt_pos; - p->mode = PMODE_PAGE; -} - -static void begin_charmode(pdfstructure * p) -{ - assert(is_chararraymode(p)); - pdf_printf("("); - p->mode = PMODE_CHAR; -} - -static void end_charmode(pdfstructure * p) -{ - assert(is_charmode(p)); - pdf_printf(")"); - p->mode = PMODE_CHARARRAY; -} - -static void begin_chararray(pdfstructure * p) -{ - assert(is_textmode(p)); - p->pdf_tj_pos = p->pdf; - p->cw.m = 0; - pdf_printf("["); - p->mode = PMODE_CHARARRAY; -} - -static void end_chararray(pdfstructure * p) -{ - assert(is_chararraymode(p)); - pdf_printf("]TJ\n"); - p->pdf = p->pdf_tj_pos; - p->mode = PMODE_TEXT; -} - -void pdf_end_string_nl(void) -{ - if (is_charmode(pstruct)) - end_charmode(pstruct); - if (is_chararraymode(pstruct)) - end_chararray(pstruct); -} - -/**********************************************************************/ - -static void goto_pagemode(pdfstructure * p) -{ - assert(p != NULL); - if (!is_pagemode(p)) { - if (is_charmode(p)) - end_charmode(p); - if (is_chararraymode(p)) - end_chararray(p); - if (is_textmode(p)) - end_text(p); - assert(is_pagemode(p)); - } -} - -void pdf_goto_pagemode(void) -{ - goto_pagemode(pstruct); -} - -static void goto_textmode(pdfstructure * p) -{ - scaledpos origin = { - 0, 0 - }; - if (!is_textmode(p)) { - if (is_pagemode(p)) { - set_pos(p, &origin); /* reset to page origin */ - begin_text(p); - } else { - if (is_charmode(p)) - end_charmode(p); - if (is_chararraymode(p)) - end_chararray(p); - } - assert(is_textmode(p)); - } -} - -void pos_finish(pdfstructure * p) -{ - goto_pagemode(p); -} - -/**********************************************************************/ - -static void place_rule(pdfstructure * p, scaledpos * pos, scaled wd, scaled ht) -{ - pdfpos dim; - scaledpos tmppos = *pos; - goto_pagemode(p); - dim.h.m = lround(wd * p->k1); - dim.h.e = p->pdf.h.e; - dim.v.m = lround(ht * p->k1); - dim.v.e = p->pdf.v.e; - pdf_printf("q\n"); - if (ht <= one_bp) { - tmppos.v += lround(0.5 * ht); - set_pos_temp(p, &tmppos); - pdf_printf("[]0 d 0 J "); - print_pdffloat(&(dim.v)); - pdf_printf(" w 0 0 m "); - print_pdffloat(&(dim.h)); - pdf_printf(" 0 l S\n"); - } else if (wd <= one_bp) { - tmppos.h += lround(0.5 * wd); - set_pos_temp(p, &tmppos); - pdf_printf("[]0 d 0 J "); - print_pdffloat(&(dim.h)); - pdf_printf(" w 0 0 m 0 "); - print_pdffloat(&(dim.v)); - pdf_printf(" l S\n"); - } else { - set_pos_temp(p, &tmppos); - pdf_printf("0 0 "); - print_pdffloat(&(dim.h)); - pdf_printf(" "); - print_pdffloat(&(dim.v)); - pdf_printf(" re f\n"); - } - pdf_printf("Q\n"); -} - -void pdf_place_rule(scaled h, scaled v, scaled wd, scaled ht) -{ - scaledpos pos; - pos.h = h; - pos.v = v; - place_rule(pstruct, &pos, wd, ht); -} - -/**********************************************************************/ - -static void setup_fontparameters(pdfstructure * p, internal_font_number f) -{ - p->f_cur = f; - p->f_pdf = pdf_set_font(f); - p->tj_delta.e = p->cw.e - 1; /* "- 1" makes less corrections inside []TJ */ - /* no need to be more precise than TeX (1sp) */ - while (p->tj_delta.e > 0 - && (double) font_size(f) / exp10_arr[p->tj_delta.e + e_tj] < 0.5) - p->tj_delta.e--; /* happens for very tiny fonts */ - assert(p->cw.e >= p->tj_delta.e); /* else we would need, e. g., exp10_arr[-1] */ - p->fs.m = lround(font_size(f) / one_bp * exp10_arr[p->fs.e]); - p->hz.m = pdf_font_expand_ratio(f) + exp10_arr[p->hz.e]; - calc_k2(p); -} - -static void set_textmatrix(pdfstructure * p, scaledpos * pos) -{ - boolean move; - assert(is_textmode(p)); - move = calc_pdfpos(p, pos); - if (move == TRUE) { - pdf_print_tm(p->tm); - p->pdf.h.m = p->pdf_bt_pos.h.m + p->tm[4].m; /* Tm replaces */ - p->pdf.v.m = p->pdf_bt_pos.v.m + p->tm[5].m; - } -} - -static void set_font(pdfstructure * p) -{ - pdf_printf("/F%d", (int) p->f_pdf); - pdf_print_resname_prefix(); - pdf_printf(" "); - print_pdffloat(&(p->fs)); - pdf_printf(" Tf "); -} - -/**********************************************************************/ - -static void -place_glyph(pdfstructure * p, scaledpos * pos, internal_font_number f, - integer c) -{ - boolean move; - if (f != p->f_cur || is_textmode(p) || is_pagemode(p)) { - goto_textmode(p); - if (f != p->f_cur) - setup_fontparameters(p, f); - set_font(p); - set_textmatrix(p, pos); - begin_chararray(p); - } - assert(is_charmode(p) || is_chararraymode(p)); - move = calc_pdfpos(p, pos); - if (move == TRUE) { - if ((p->wmode == WMODE_H - && (p->pdf_bt_pos.v.m + p->tm[5].m) != p->pdf.v.m) - || (p->wmode == WMODE_V - && (p->pdf_bt_pos.h.m + p->tm[4].m) != p->pdf.h.m) - || abs(p->tj_delta.m) >= 1000000) { - goto_textmode(p); - set_textmatrix(p, pos); - begin_chararray(p); - move = calc_pdfpos(p, pos); - } - if (move == TRUE) { - assert((p->wmode == WMODE_H - && (p->pdf_bt_pos.v.m + p->tm[5].m) == p->pdf.v.m) - || (p->wmode == WMODE_V - && (p->pdf_bt_pos.h.m + p->tm[4].m) == p->pdf.h.m)); - if (is_charmode(p)) - end_charmode(p); - assert(p->tj_delta.m != 0); - print_pdffloat(&(p->tj_delta)); - p->cw.m -= p->tj_delta.m * exp10_arr[p->cw.e - p->tj_delta.e]; - } - } - if (is_chararraymode(p)) - begin_charmode(p); - pdf_print_char(f, c); /* this also does pdf_mark_char() */ - p->cw.m += pdf_char_width(p, p->f_pdf, c); /* aka adv_char_width() */ -} - -void pdf_place_glyph(internal_font_number f, integer c) -{ - if (char_exists(f, c)) - place_glyph(pstruct, &pos, f, c); -} - -/**********************************************************************/ - -static void place_form(pdfstructure * p, scaledpos * pos, integer i) -{ - goto_pagemode(p); - pdf_printf("q\n"); - set_pos_temp(p, pos); - pdf_printf("/Fm%d", (int) i); - pdf_print_resname_prefix(); - pdf_printf(" Do\nQ\n"); -} - -void pdf_place_form(scaled h, scaled v, integer i) -{ - scaledpos pos; - pos.h = h; - pos.v = v; - place_form(pstruct, &pos, i); -} diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfpage.h b/Build/source/texk/web2c/luatexdir/pdf/pdfpage.h index 1c9ccb02569..39a15ab5ff9 100644 --- a/Build/source/texk/web2c/luatexdir/pdf/pdfpage.h +++ b/Build/source/texk/web2c/luatexdir/pdf/pdfpage.h @@ -17,74 +17,37 @@ You should have received a copy of the GNU General Public License along with LuaTeX; if not, see <http://www.gnu.org/licenses/>. */ -/* $Id: pdfpage.h 2448 2009-06-08 07:43:50Z taco $ */ +/* $Id: pdfpage.h 3003 2009-08-16 19:55:55Z hhenkel $ */ #ifndef PDFPAGE_H # define PDFPAGE_H -typedef struct { - long m; /* mantissa (significand) */ - int e; /* exponent * -1 */ -} pdffloat; - -typedef struct { - pdffloat h; - pdffloat v; -} pdfpos; - -typedef enum { PMODE_NONE, PMODE_PAGE, PMODE_TEXT, PMODE_CHARARRAY, - PMODE_CHAR -} pos_mode; - -typedef enum { WMODE_H, WMODE_V } writing_mode; /* []TJ runs horizontal or vertical */ - # define is_pagemode(p) ((p)->mode == PMODE_PAGE) # define is_textmode(p) ((p)->mode == PMODE_TEXT) # define is_chararraymode(p) ((p)->mode == PMODE_CHARARRAY) # define is_charmode(p) ((p)->mode == PMODE_CHAR) -# define setpdffloat(a,b,c) {(a).m = (b); (a).e = (c);} +# define setpdffloat(a,b,c) do {(a).m = (b); (a).e = (c);} while (0) # ifdef hz /* AIX 4.3 defines hz as 100 in system headers */ # undef hz # endif -typedef struct { - pdfpos pdf; /* pos. on page (PDF page raster) */ - pdfpos pdf_bt_pos; /* pos. at begin of BT-ET group (PDF page raster) */ - pdfpos pdf_tj_pos; /* pos. at begin of TJ array (PDF page raster) */ - pdffloat cw; /* pos. within [(..)..]TJ array (glyph raster); - cw.e = fractional digits in /Widths array */ - pdffloat tj_delta; /* rel. movement in [(..)..]TJ array (glyph raster) */ - pdffloat fs; /* font size in PDF units */ - pdffloat hz; /* HZ expansion factor */ - pdffloat ext; /* ExtendFont factor */ - pdffloat cm[6]; /* cm array */ - pdffloat tm[6]; /* Tm array */ - double k1; /* conv. factor from TeX sp to PDF page raster */ - double k2; /* conv. factor from PDF page raster to TJ array raster */ - internal_font_number f_cur; /* TeX font number */ - internal_font_number f_pdf; /* /F* font number, of unexpanded base font! */ - writing_mode wmode; /* PDF writing mode WMode (horizontal/vertical) */ - pos_mode mode; /* current positioning mode */ -} pdfstructure; - -extern pdfstructure *pstruct; - /**********************************************************************/ -boolean calc_pdfpos(pdfstructure * p, scaledpos * pos); -void pdf_end_string_nl(void); -void pdf_goto_pagemode(void); -void pdf_page_init(void); -void pdf_place_form(scaled h, scaled v, integer i); -void pdf_place_glyph(internal_font_number f, integer c); -void pdf_place_rule(scaled h, scaled v, scaled wd, scaled ht); -void pdf_print_charwidth(internal_font_number f, int i); -void pdf_print_cm(pdffloat * cm); -void pdf_set_pos(scaled h, scaled v); -void pos_finish(pdfstructure * p); -void print_pdffloat(pdffloat * f); +void synch_pos_with_cur(posstructure * pos, posstructure * refpos, + scaledpos cur); + +boolean calc_pdfpos(pdfstructure * p, scaledpos pos); +void pdf_end_string_nl(PDF pdf); +void pdf_goto_pagemode(PDF pdf); +void pdf_goto_textmode(PDF pdf); +void init_pdf_pagecalculations(PDF pdf); +void pdf_print_cm(PDF pdf, pdffloat * cm); +void pdf_set_pos(PDF pdf, scaledpos pos); +void pdf_set_pos_temp(PDF pdf, scaledpos pos); +void print_pdffloat(PDF pdf, pdffloat f); +void print_pdf_matrix(PDF pdf, pdffloat * tm); #endif diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfpage.w b/Build/source/texk/web2c/luatexdir/pdf/pdfpage.w new file mode 100644 index 00000000000..6b810a5cef6 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdfpage.w @@ -0,0 +1,292 @@ +% pdfpage.w + +% Copyright 2006-2010 Taco Hoekwater <taco@@luatex.org> + +% 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 <http://www.gnu.org/licenses/>. + +@ @c +static const char _svn_version[] = + "$Id: pdfpage.w 3571 2010-04-02 13:50:45Z taco $ " + "$URL: http://foundry.supelec.fr/svn/luatex/tags/beta-0.60.0/source/texk/web2c/luatexdir/pdf/pdfpage.w $"; + +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> +#include <math.h> + +#include "ptexlib.h" + +#define lround(a) (long) floor((a) + 0.5) + +@ eternal constants +@c +#define one_bp ((double) 65536 * (double) 72.27 / 72) /* number of sp per 1bp */ + +@ @c +void init_pdf_pagecalculations(PDF pdf) +{ + pdfstructure *p; + int decimal_digits = pdf->decimal_digits; + assert(pdf != NULL); + if (pdf->pstruct == NULL) + pdf->pstruct = xmalloc(sizeof(pdfstructure)); + p = pdf->pstruct; + setpdffloat(p->pdf.h, 0, decimal_digits); + setpdffloat(p->pdf.v, 0, decimal_digits); + p->cw.e = 1; + p->fs_cur.e = p->fs.e = decimal_digits + 2; /* "+ 2" makes less corrections inside []TJ */ + /* for placement outside BT...ET */ + setpdffloat(p->cm[0], 1, 0); + setpdffloat(p->cm[1], 0, 0); + setpdffloat(p->cm[2], 0, 0); + setpdffloat(p->cm[3], 1, 0); + setpdffloat(p->cm[4], 0, decimal_digits); /* horizontal movement on page */ + setpdffloat(p->cm[5], 0, decimal_digits); /* vertical movement on page */ + /* for placement inside BT...ET */ + setpdffloat(p->tm[0], ten_pow[6], 6); /* mantissa holds HZ expand * ExtendFont */ + setpdffloat(p->tm[1], 0, 0); + setpdffloat(p->tm[2], 0, 3); /* mantissa holds SlantFont, 0 = default */ + setpdffloat(p->tm[3], 1, 0); + setpdffloat(p->tm[4], 0, decimal_digits); /* mantissa holds delta from |pdf_bt_pos.h| */ + setpdffloat(p->tm[5], 0, decimal_digits); /* mantissa holds delta from |pdf_bt_pos.v| */ + /* */ + p->f_pdf_cur = p->f_pdf = null_font; + p->fs_cur.m = p->fs.m = 0; + p->wmode = WMODE_H; + p->mode = PMODE_PAGE; + p->ishex = 0; + p->k1 = ten_pow[p->pdf.h.e] / one_bp; +} + +@ @c +void synch_pos_with_cur(posstructure * pos, posstructure * refpos, + scaledpos cur) +{ + switch (pos->dir) { + case dir_TLT: + pos->pos.h = refpos->pos.h + cur.h; + pos->pos.v = refpos->pos.v - cur.v; + break; + case dir_TRT: + pos->pos.h = refpos->pos.h - cur.h; + pos->pos.v = refpos->pos.v - cur.v; + break; + case dir_LTL: + pos->pos.h = refpos->pos.h + cur.v; + pos->pos.v = refpos->pos.v - cur.h; + break; + case dir_RTT: + pos->pos.h = refpos->pos.h - cur.v; + pos->pos.v = refpos->pos.v - cur.h; + break; + default: + assert(0); + } +} + +@ @c +boolean calc_pdfpos(pdfstructure * p, scaledpos pos) +{ + scaledpos new; + int move_pdfpos = FALSE; + switch (p->mode) { + case PMODE_PAGE: + new.h = lround(pos.h * p->k1); + new.v = lround(pos.v * p->k1); + p->cm[4].m = new.h - p->pdf.h.m; /* cm is concatenated */ + p->cm[5].m = new.v - p->pdf.v.m; + if (new.h != p->pdf.h.m || new.v != p->pdf.v.m) + move_pdfpos = TRUE; + break; + case PMODE_TEXT: + new.h = lround(pos.h * p->k1); + new.v = lround(pos.v * p->k1); + p->tm[4].m = new.h - p->pdf_bt_pos.h.m; /* Tm replaces */ + p->tm[5].m = new.v - p->pdf_bt_pos.v.m; + if (new.h != p->pdf.h.m || new.v != p->pdf.v.m) + move_pdfpos = TRUE; + break; + case PMODE_CHAR: + case PMODE_CHARARRAY: + switch (p->wmode) { + case WMODE_H: + new.h = + lround((pos.h * p->k1 - (double) p->pdf_tj_pos.h.m) * p->k2); + new.v = lround(pos.v * p->k1); + p->tj_delta.m = -lround((double) + ((new.h - p->cw.m) / ten_pow[p->cw.e - + p-> + tj_delta.e])); + p->tm[5].m = new.v - p->pdf_bt_pos.v.m; /* p->tm[4] is meaningless */ + if (p->tj_delta.m != 0 || new.v != p->pdf.v.m) + move_pdfpos = TRUE; + break; + case WMODE_V: + new.h = lround(pos.h * p->k1); + new.v = + lround(((double) p->pdf_tj_pos.v.m - pos.v * p->k1) * p->k2); + p->tm[4].m = new.h - p->pdf_bt_pos.h.m; /* p->tm[5] is meaningless */ + p->tj_delta.m = -lround((double) + ((new.v - p->cw.m) / ten_pow[p->cw.e - + p-> + tj_delta.e])); + if (p->tj_delta.m != 0 || new.h != p->pdf.h.m) + move_pdfpos = TRUE; + break; + default: + assert(0); + } + break; + default: + assert(0); + } + return move_pdfpos; +} + +@ @c +void print_pdffloat(PDF pdf, pdffloat f) +{ + char a[24]; + int e = f.e, i, j; + long l, m = f.m; + if (m < 0) { + pdf_puts(pdf, "-"); + m *= -1; + } + l = m / ten_pow[e]; + pdf_print_int(pdf, l); + l = m % ten_pow[e]; + if (l != 0) { + pdf_puts(pdf, "."); + j = snprintf(a, 23, "%ld", l + ten_pow[e]); + assert(j < 23); + for (i = e; i > 0; i--) { + if (a[i] != '0') + break; + a[i] = '\0'; + } + pdf_puts(pdf, (a + 1)); + } +} + +@ @c +void print_pdf_matrix(PDF pdf, pdffloat * tm) +{ + int i; + for (i = 0; i < 5; i++) { + print_pdffloat(pdf, tm[i]); + pdf_puts(pdf, " "); + } + print_pdffloat(pdf, tm[i]); +} + +@ @c +void pdf_print_cm(PDF pdf, pdffloat * cm) +{ + print_pdf_matrix(pdf, cm); + pdf_puts(pdf, " cm\n"); +} + +@ @c +void pdf_set_pos(PDF pdf, scaledpos pos) +{ + boolean move; + pdfstructure *p = pdf->pstruct; + assert(is_pagemode(p)); + move = calc_pdfpos(p, pos); + if (move == TRUE) { + pdf_print_cm(pdf, p->cm); + p->pdf.h.m += p->cm[4].m; + p->pdf.v.m += p->cm[5].m; + } +} + +@ @c +void pdf_set_pos_temp(PDF pdf, scaledpos pos) +{ + boolean move; + pdfstructure *p = pdf->pstruct; + assert(is_pagemode(p)); + move = calc_pdfpos(p, pos); + if (move == TRUE) + pdf_print_cm(pdf, p->cm); +} + +@ @c +static void begin_text(PDF pdf) +{ + pdfstructure *p = pdf->pstruct; + assert(is_pagemode(p)); + p->pdf_bt_pos = p->pdf; + pdf_puts(pdf, "BT\n"); + p->mode = PMODE_TEXT; + p->f_pdf_cur = null_font; /* forces Tf operator */ + p->fs_cur.m = 0; +} + +static void end_text(PDF pdf) +{ + pdfstructure *p = pdf->pstruct; + assert(is_textmode(p)); + pdf_puts(pdf, "ET\n"); + p->pdf = p->pdf_bt_pos; + p->mode = PMODE_PAGE; +} + +void pdf_end_string_nl(PDF pdf) +{ + pdfstructure *p = pdf->pstruct; + if (is_charmode(p)) + end_charmode(pdf); + if (is_chararraymode(p)) + end_chararray(pdf); +} + +@ @c +void pdf_goto_pagemode(PDF pdf) +{ + pdfstructure *p = pdf->pstruct; + assert(p != NULL); + if (!is_pagemode(p)) { + if (is_charmode(p)) + end_charmode(pdf); + if (is_chararraymode(p)) + end_chararray(pdf); + if (is_textmode(p)) + end_text(pdf); + assert(is_pagemode(p)); + } +} + +void pdf_goto_textmode(PDF pdf) +{ + pdfstructure *p = pdf->pstruct; + scaledpos origin = { + 0, 0 + }; + if (!is_textmode(p)) { + if (is_pagemode(p)) { + pdf_set_pos(pdf, origin); /* reset to page origin */ + begin_text(pdf); + } else { + if (is_charmode(p)) + end_charmode(pdf); + if (is_chararraymode(p)) + end_chararray(pdf); + } + assert(is_textmode(p)); + } +} diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfrule.h b/Build/source/texk/web2c/luatexdir/pdf/pdfrule.h new file mode 100644 index 00000000000..d1d13b77f00 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdfrule.h @@ -0,0 +1,27 @@ +/* pdfrule.h + + Copyright 2009 Taco Hoekwater <taco@luatex.org> + + 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 <http://www.gnu.org/licenses/>. */ + +/* $Id: pdfrule.h 3003 2009-08-16 19:55:55Z hhenkel $ */ + +#ifndef PDFRULE_H +# define PDFRULE_H + +void pdf_place_rule(PDF pdf, halfword p, scaledpos size); + +#endif diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfrule.w b/Build/source/texk/web2c/luatexdir/pdf/pdfrule.w new file mode 100644 index 00000000000..fc13da2c32e --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdfrule.w @@ -0,0 +1,70 @@ +% pdfrule.w +% +% Copyright 2010 Taco Hoekwater <taco@@luatex.org> + +% 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 <http://www.gnu.org/licenses/>. + +@ @c +static const char _svn_version[] = + "$Id: pdfrule.w 3584 2010-04-02 17:45:55Z hhenkel $" + "$URL: http://foundry.supelec.fr/svn/luatex/tags/beta-0.60.0/source/texk/web2c/luatexdir/pdf/pdfrule.w $"; + +#include "ptexlib.h" + +@ @c +#include "pdf/pdfpage.h" + +#define lround(a) (long) floor((a) + 0.5) + +@ @c +void pdf_place_rule(PDF pdf, halfword q, scaledpos size) +{ + pdfpos dim; + pdfstructure *p = pdf->pstruct; + scaledpos pos = pdf->posstruct->pos; + (void) q; + pdf_goto_pagemode(pdf); + dim.h.m = lround(size.h * p->k1); + dim.h.e = p->pdf.h.e; + dim.v.m = lround(size.v * p->k1); + dim.v.e = p->pdf.v.e; + pdf_printf(pdf, "q\n"); + if (size.v <= one_bp) { + pos.v += (int) lround(0.5 * size.v); + pdf_set_pos_temp(pdf, pos); + pdf_printf(pdf, "[]0 d 0 J "); + print_pdffloat(pdf, dim.v); + pdf_printf(pdf, " w 0 0 m "); + print_pdffloat(pdf, dim.h); + pdf_printf(pdf, " 0 l S\n"); + } else if (size.h <= one_bp) { + pos.h += (int) lround(0.5 * size.h); + pdf_set_pos_temp(pdf, pos); + pdf_printf(pdf, "[]0 d 0 J "); + print_pdffloat(pdf, dim.h); + pdf_printf(pdf, " w 0 0 m 0 "); + print_pdffloat(pdf, dim.v); + pdf_printf(pdf, " l S\n"); + } else { + pdf_set_pos_temp(pdf, pos); + pdf_printf(pdf, "0 0 "); + print_pdffloat(pdf, dim.h); + pdf_printf(pdf, " "); + print_pdffloat(pdf, dim.v); + pdf_printf(pdf, " re f\n"); + } + pdf_printf(pdf, "Q\n"); +} diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfsaverestore.h b/Build/source/texk/web2c/luatexdir/pdf/pdfsaverestore.h new file mode 100644 index 00000000000..146b7e7e6c5 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdfsaverestore.h @@ -0,0 +1,37 @@ +/* pdfsaverestore.h + + Copyright 2009 Taco Hoekwater <taco@luatex.org> + + 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 <http://www.gnu.org/licenses/>. */ + +/* $Id: pdfsaverestore.h 3003 2009-08-16 19:55:55Z hhenkel $ */ + +#ifndef PDFSAVERESTORE_H +# define PDFSAVERESTORE_H + +/* stack for positions of \pdfsave */ +typedef struct { + scaledpos pos; + int matrix_stack; +} pos_entry; +extern pos_entry *pos_stack; /* the stack */ +extern int pos_stack_size; /* initially empty */ +extern int pos_stack_used; /* used entries */ + +extern void pdf_out_save(PDF pdf, halfword p); +extern void pdf_out_restore(PDF pdf, halfword p); + +#endif diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfsaverestore.w b/Build/source/texk/web2c/luatexdir/pdf/pdfsaverestore.w new file mode 100644 index 00000000000..c953b8242a5 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdfsaverestore.w @@ -0,0 +1,88 @@ +% pdfsaverestore.w +% +% Copyright 2010 Taco Hoekwater <taco@@luatex.org> + +% 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 <http://www.gnu.org/licenses/>. + +@ @c +static const char _svn_version[] = + "$Id: pdfsaverestore.w 3571 2010-04-02 13:50:45Z taco $ " + "$URL: http://foundry.supelec.fr/svn/luatex/tags/beta-0.60.0/source/texk/web2c/luatexdir/pdf/pdfsaverestore.w $"; + +#include "ptexlib.h" + +@ @c +pos_entry *pos_stack = 0; /* the stack */ +int pos_stack_size = 0; /* initially empty */ +int pos_stack_used = 0; /* used entries */ + +@ @c +static void checkpdfsave(scaledpos pos) +{ + pos_entry *new_stack; + + if (pos_stack_used >= pos_stack_size) { + pos_stack_size += STACK_INCREMENT; + new_stack = xtalloc((unsigned) pos_stack_size, pos_entry); + memcpy((void *) new_stack, (void *) pos_stack, + (unsigned) pos_stack_used * sizeof(pos_entry)); + xfree(pos_stack); + pos_stack = new_stack; + } + pos_stack[pos_stack_used].pos.h = pos.h; + pos_stack[pos_stack_used].pos.v = pos.v; + if (page_mode) { + pos_stack[pos_stack_used].matrix_stack = matrix_stack_used; + } + pos_stack_used++; +} + +@ @c +static void checkpdfrestore(scaledpos pos) +{ + scaledpos diff; + if (pos_stack_used == 0) { + pdftex_warn("%s", "\\pdfrestore: missing \\pdfsave"); + return; + } + pos_stack_used--; + diff.h = pos.h - pos_stack[pos_stack_used].pos.h; + diff.v = pos.v - pos_stack[pos_stack_used].pos.v; + if (diff.h != 0 || diff.v != 0) { + pdftex_warn("Misplaced \\pdfrestore by (%dsp, %dsp)", (int) diff.h, + (int) diff.v); + } + if (page_mode) { + matrix_stack_used = pos_stack[pos_stack_used].matrix_stack; + } +} + + +@ @c +void pdf_out_save(PDF pdf, halfword p) +{ + (void) p; + checkpdfsave(pdf->posstruct->pos); + pdf_literal(pdf, 'q', set_origin, false); +} + +@ @c +void pdf_out_restore(PDF pdf, halfword p) +{ + (void) p; + checkpdfrestore(pdf->posstruct->pos); + pdf_literal(pdf, 'Q', set_origin, false); +} diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfsetmatrix.h b/Build/source/texk/web2c/luatexdir/pdf/pdfsetmatrix.h new file mode 100644 index 00000000000..c4900e07046 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdfsetmatrix.h @@ -0,0 +1,52 @@ +/* pdfsetmatrix.h + + Copyright 2009 Taco Hoekwater <taco@luatex.org> + + 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 <http://www.gnu.org/licenses/>. */ + +/* $Id: pdfsetmatrix.h 3217 2009-12-03 16:52:01Z taco $ */ + +#ifndef PDFSETMATRIX_H +# define PDFSETMATRIX_H + +# define set_pdf_setmatrix_data(A,B) pdf_setmatrix_data(A)=B + +typedef struct { + double a; + double b; + double c; + double d; + double e; + double f; +} matrix_entry; + +extern matrix_entry *matrix_stack; +extern int matrix_stack_size; +extern int matrix_stack_used; + + +scaled getllx(void); +scaled getlly(void); +scaled geturx(void); +scaled getury(void); +void matrixtransformpoint(scaled x, scaled y); +void matrixtransformrect(scaled llx, scaled lly, scaled urx, scaled ury); +boolean matrixused(void); +void matrixrecalculate(scaled urx); + +extern void pdf_out_setmatrix(PDF pdf, halfword p); + +#endif diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfsetmatrix.w b/Build/source/texk/web2c/luatexdir/pdf/pdfsetmatrix.w new file mode 100644 index 00000000000..765ac0fb1e2 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdfsetmatrix.w @@ -0,0 +1,238 @@ +% pdfsetmatrix.w +% +% Copyright 2009 Taco Hoekwater <taco@@luatex.org> + +% 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 <http://www.gnu.org/licenses/>. + +@ @c +static const char _svn_version[] = + "$Id: pdfsetmatrix.w 3571 2010-04-02 13:50:45Z taco $ " + "$URL: http://foundry.supelec.fr/svn/luatex/tags/beta-0.60.0/source/texk/web2c/luatexdir/pdf/pdfsetmatrix.w $"; + +#include "ptexlib.h" + +@ stack for \.{\\pdfsetmatrix} + +@c +matrix_entry *matrix_stack = NULL; +int matrix_stack_size = 0; +int matrix_stack_used = 0; + +@ @c +boolean matrixused(void) +{ + return matrix_stack_used > 0; +} + +void matrix_stack_room(void) +{ + matrix_entry *new_stack; + + if (matrix_stack_used >= matrix_stack_size) { + matrix_stack_size += STACK_INCREMENT; + new_stack = xtalloc((unsigned) matrix_stack_size, matrix_entry); + memcpy((void *) new_stack, (void *) matrix_stack, + (unsigned) matrix_stack_used * sizeof(matrix_entry)); + xfree(matrix_stack); + matrix_stack = new_stack; + } +} + +@ \.{\\pdfsetmatrix{a b c d}} + + |e| := pos.h + + |f| := pos.v + + |M_top|: current active matrix at the top of + the matrix stack + + The origin of \.{\\pdfsetmatrix} is the current point. + The annotation coordinate system is the original + page coordinate system. When pdfTeX calculates + annotation rectangles it does not take into + account this transformations, it uses the original + coordinate system. To get the corrected values, + first we go back to the origin, perform the + transformation and go back: + +{\obeylines\obeyspaces\tt + ( 1 0 0 ) ( a b 0 ) ( 1 0 0 ) + ( 0 1 0 ) x ( c d 0 ) x ( 0 1 0 ) x M\_top + ( -e -f 1 ) ( 0 0 1 ) ( e f 1 ) + + ( 1 0 0 ) ( a b 0 ) + = ( 0 1 0 ) x ( c d 0 ) x M\_top + ( e f 1 ) ( -e -f 1 ) + + ( a b 0 ) + = ( c d 0 ) x M\_top + ( e(1-a)-fc f(1-d)-eb 1 ) +} + +@c +static void pdfsetmatrix(const char *in, scaledpos pos) +{ + /* Argument of \.{\\pdfsetmatrix} starts with |str_pool[in]| and ends + before |str_pool[pool_ptr]|. */ + + matrix_entry x, *y, *z; + + if (page_mode) { + if (sscanf((const char *) in, " %lf %lf %lf %lf ", + &x.a, &x.b, &x.c, &x.d) != 4) { + pdftex_warn("Unrecognized format of \\pdfsetmatrix{%s}", in); + return; + } + /* calculate this transformation matrix */ + x.e = (double) pos.h * (1.0 - x.a) - (double) pos.v * x.c; + x.f = (double) pos.v * (1.0 - x.d) - (double) pos.h * x.b; + matrix_stack_room(); + z = &matrix_stack[matrix_stack_used]; + if (matrix_stack_used > 0) { + y = &matrix_stack[matrix_stack_used - 1]; + z->a = x.a * y->a + x.b * y->c; + z->b = x.a * y->b + x.b * y->d; + z->c = x.c * y->a + x.d * y->c; + z->d = x.c * y->b + x.d * y->d; + z->e = x.e * y->a + x.f * y->c + y->e; + z->f = x.e * y->b + x.f * y->d + y->f; + } else { + z->a = x.a; + z->b = x.b; + z->c = x.c; + z->d = x.d; + z->e = x.e; + z->f = x.f; + } + matrix_stack_used++; + } +} + +@ Apply matrix to point (x,y) + +{\obeylines\obeyspaces\tt + ( a b 0 ) + ( x y 1 ) x ( c d 0 ) = ( xa+yc+e xb+yd+f 1 ) + ( e f 1 ) +} + +If \.{\\pdfsetmatrix} wasn't used, then return the value unchanged. + +@c +/* Return values for matrix tranform functions */ +static scaled ret_llx; +static scaled ret_lly; +static scaled ret_urx; +static scaled ret_ury; + +scaled getllx(void) +{ + return ret_llx; +} + +scaled getlly(void) +{ + return ret_lly; +} + +scaled geturx(void) +{ + return ret_urx; +} + +scaled getury(void) +{ + return ret_ury; +} + +@ @c +static int last_llx; +static int last_lly; +static int last_urx; +static int last_ury; + +#define DO_ROUND(x) ((x > 0) ? (x + .5) : (x - .5)) +#define DO_MIN(a, b) ((a < b) ? a : b) +#define DO_MAX(a, b) ((a > b) ? a : b) + +void do_matrixtransform(scaled x, scaled y, scaled * retx, scaled * rety) +{ + matrix_entry *m = &matrix_stack[matrix_stack_used - 1]; + double x_old = x; + double y_old = y; + double x_new = x_old * m->a + y_old * m->c + m->e; + double y_new = x_old * m->b + y_old * m->d + m->f; + *retx = (scaled) DO_ROUND(x_new); + *rety = (scaled) DO_ROUND(y_new); +} + +void matrixtransformrect(scaled llx, scaled lly, scaled urx, scaled ury) +{ + scaled x1, x2, x3, x4, y1, y2, y3, y4; + + if (page_mode && matrix_stack_used > 0) { + last_llx = llx; + last_lly = lly; + last_urx = urx; + last_ury = ury; + do_matrixtransform(llx, lly, &x1, &y1); + do_matrixtransform(llx, ury, &x2, &y2); + do_matrixtransform(urx, lly, &x3, &y3); + do_matrixtransform(urx, ury, &x4, &y4); + ret_llx = DO_MIN(DO_MIN(x1, x2), DO_MIN(x3, x4)); + ret_lly = DO_MIN(DO_MIN(y1, y2), DO_MIN(y3, y4)); + ret_urx = DO_MAX(DO_MAX(x1, x2), DO_MAX(x3, x4)); + ret_ury = DO_MAX(DO_MAX(y1, y2), DO_MAX(y3, y4)); + } else { + ret_llx = llx; + ret_lly = lly; + ret_urx = urx; + ret_ury = ury; + } +} + +void matrixtransformpoint(scaled x, scaled y) +{ + if (page_mode && matrix_stack_used > 0) { + do_matrixtransform(x, y, &ret_llx, &ret_lly); + } else { + ret_llx = x; + ret_lly = y; + } +} + +void matrixrecalculate(scaled urx) +{ + matrixtransformrect(last_llx, last_lly, urx, last_ury); +} + +@ @c +void pdf_out_setmatrix(PDF pdf, halfword p) +{ + scaledpos pos = pdf->posstruct->pos; + int old_setting; /* holds print |selector| */ + str_number s; + old_setting = selector; + selector = new_string; + show_token_list(token_link(pdf_setmatrix_data(p)), null, -1); + pdfsetmatrix((char *) cur_string, pos); + tprint(" 0 0 cm"); + selector = old_setting; + s = make_string(); + pdf_literal(pdf, s, set_origin, false); + flush_str(s); +} diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfshipout.h b/Build/source/texk/web2c/luatexdir/pdf/pdfshipout.h new file mode 100644 index 00000000000..1070996a5ba --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdfshipout.h @@ -0,0 +1,30 @@ +/* pdfshipout.h + + Copyright 2009 Taco Hoekwater <taco@luatex.org> + + 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 <http://www.gnu.org/licenses/>. */ + +/* $Id: pdfshipout.h 2977 2009-08-08 12:49:35Z hhenkel $ */ + +#ifndef PDFSHIPOUT_H +# define PDFSHIPOUT_H + +extern boolean is_shipping_page; /* set to |shipping_page| when |ship_out| starts */ +extern scaledpos shipbox_refpos; /* for \gleaders */ + +extern void ship_out(PDF pdf, halfword p, boolean shipping_page); + +#endif diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfshipout.w b/Build/source/texk/web2c/luatexdir/pdf/pdfshipout.w new file mode 100644 index 00000000000..70809ef1b0f --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdfshipout.w @@ -0,0 +1,332 @@ +% pdfshipout.w + +% Copyright 2010 Taco Hoekwater <taco@@luatex.org> + +% 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 <http://www.gnu.org/licenses/>. + +@ @c +static const char _svn_version[] = + "$Id: pdfshipout.w 3571 2010-04-02 13:50:45Z taco $" + "$URL: http://foundry.supelec.fr/svn/luatex/tags/beta-0.60.0/source/texk/web2c/luatexdir/pdf/pdfshipout.w $"; + +#include "ptexlib.h" + +@ @c +#define count(A) eqtb[count_base+(A)].cint +#define h_offset dimen_par(h_offset_code) +#define mag int_par(mag_code) +#define page_bottom_offset dimen_par(page_bottom_offset_code) +#define page_direction int_par(page_direction_code) +#define page_height dimen_par(page_height_code) +#define page_left_offset dimen_par(page_left_offset_code) +#define page_right_offset dimen_par(page_right_offset_code) +#define page_top_offset dimen_par(page_top_offset_code) +#define page_width dimen_par(page_width_code) +#define pdf_h_origin dimen_par(pdf_h_origin_code) +#define pdf_v_origin dimen_par(pdf_v_origin_code) +#define tracing_output int_par(tracing_output_code) +#define tracing_stats int_par(tracing_stats_code) +#define v_offset dimen_par(v_offset_code) + +scaledpos shipbox_refpos; + +@ |ship_out| is used to shipout a box to PDF or DVI mode. +If |shipping_page| is not set then the output will be a Form object +(only PDF), otherwise it will be a Page object. + +@c +void ship_out(PDF pdf, halfword p, boolean shipping_page) +{ + /* output the box |p| */ + int j, k; /* indices to first ten count registers */ + int post_callback_id; + int pre_callback_id; + posstructure refpoint; /* the origin pos. on the page */ + scaledpos cur = { 0, 0 }; + refpoint.pos.h = 0; + refpoint.pos.v = 0; + + ensure_output_state(pdf, ST_HEADER_WRITTEN); + fix_o_mode(pdf); /* this is only for complaining if \.{\\pdfoutput} has changed */ + init_backend_functionpointers(pdf->o_mode); + + pdf->f_cur = null_font; + + /* Start sheet {\sl Sync\TeX} information record */ + /* {\sl Sync\TeX}: we assume that |pdf_output| is properly set up */ + if (int_par(synctex_code)) + synctexsheet(mag); + + pre_callback_id = callback_defined(start_page_number_callback); + post_callback_id = callback_defined(stop_page_number_callback); + if ((tracing_output > 0) && (pre_callback_id == 0)) { + tprint_nl(""); + print_ln(); + tprint("Completed box being shipped out"); + } + is_shipping_page = shipping_page; + if (shipping_page) { + if (pre_callback_id > 0) + (void) run_callback(pre_callback_id, "->"); + else if (pre_callback_id == 0) { + if (term_offset > max_print_line - 9) + print_ln(); + else if ((term_offset > 0) || (file_offset > 0)) + print_char(' '); + print_char('['); + j = 9; + while ((count(j) == 0) && (j > 0)) + decr(j); + for (k = 0; k <= j; k++) { + print_int(count(k)); + if (k < j) + print_char('.'); + } + } + } + if ((tracing_output > 0) && shipping_page) { + print_char(']'); + update_terminal(); + begin_diagnostic(); + show_box(p); + end_diagnostic(true); + } + + /* Ship box |p| out */ + if (shipping_page && box_dir(p) != page_direction) + pdf_warning("\\shipout", + "\\pagedir != \\bodydir; " + "\\box\\outputbox may be placed wrongly on the page.", true, + true); + /* Update the values of |max_h| and |max_v|; but if the page is too large, |goto done| */ + /* Sometimes the user will generate a huge page because other error messages + are being ignored. Such pages are not output to the \.{dvi} file, since they + may confuse the printing software. */ + + if ((height(p) > max_dimen) || (depth(p) > max_dimen) + || (height(p) + depth(p) + v_offset > max_dimen) + || (width(p) + h_offset > max_dimen)) { + const char *hlp[] = + { "The page just created is more than 18 feet tall or", + "more than 18 feet wide, so I suspect something went wrong.", + NULL + }; + tex_error("Huge page cannot be shipped out", hlp); + if (tracing_output <= 0) { + begin_diagnostic(); + tprint_nl("The following box has been deleted:"); + show_box(p); + end_diagnostic(true); + } + goto DONE; + } + if (height(p) + depth(p) + v_offset > max_v) + max_v = height(p) + depth(p) + v_offset; + if (width(p) + h_offset > max_h) + max_h = width(p) + h_offset; + + /* Calculate page dimensions and margins */ + if (is_shipping_page) { + if (page_width > 0) + cur_page_size.h = page_width; + else { + switch (page_direction) { + case dir_TLT: + cur_page_size.h = width(p) + 2 * page_left_offset; + break; + case dir_TRT: + cur_page_size.h = width(p) + 2 * page_right_offset; + break; + case dir_LTL: + cur_page_size.h = height(p) + depth(p) + 2 * page_left_offset; + break; + case dir_RTT: + cur_page_size.h = height(p) + depth(p) + 2 * page_right_offset; + break; + } + } + if (page_height > 0) + cur_page_size.v = page_height; + else { + switch (page_direction) { + case dir_TLT: + case dir_TRT: + cur_page_size.v = height(p) + depth(p) + 2 * page_top_offset; + break; + case dir_LTL: + case dir_RTT: + cur_page_size.v = width(p) + 2 * page_top_offset; + break; + } + } + + /* Think in upright page/paper coordinates (page origin = lower left edge). + First preset |refpoint.pos| to the DVI origin (near upper left page edge). */ + + switch (pdf->o_mode) { + case OMODE_DVI: + refpoint.pos.h = one_true_inch; + refpoint.pos.v = cur_page_size.v - one_true_inch; + dvi = refpoint.pos; + break; + case OMODE_PDF: + case OMODE_LUA: + refpoint.pos.h = pdf_h_origin; + refpoint.pos.v = cur_page_size.v - pdf_v_origin; + break; + default: + assert(0); + } + + /* Then shift |refpoint.pos| of the DVI origin depending on the + |page_direction| within the upright (TLT) page coordinate system */ + + switch (page_direction) { + case dir_TLT: + case dir_LTL: + refpoint.pos.h += h_offset; + refpoint.pos.v -= v_offset; + break; + case dir_TRT: + case dir_RTT: + refpoint.pos.h += + cur_page_size.h - page_right_offset - one_true_inch; + refpoint.pos.v -= v_offset; + break; + } + + /* Then switch to page box coordinate system; do |height(p)| movement, + to get the location of the box origin. */ + + pdf->posstruct->dir = page_direction; + cur.h = 0; + cur.v = height(p); + synch_pos_with_cur(pdf->posstruct, &refpoint, cur); + } else { /* shipping a /Form */ + assert(pdf->o_mode == OMODE_PDF); + pdf->posstruct->dir = box_dir(p); + switch (pdf->posstruct->dir) { + case dir_TLT: + case dir_TRT: + cur_page_size.h = width(p); + cur_page_size.v = height(p) + depth(p); + break; + case dir_LTL: + case dir_RTT: + cur_page_size.h = height(p) + depth(p); + cur_page_size.v = width(p); + break; + } + switch (pdf->posstruct->dir) { + case dir_TLT: + pdf->posstruct->pos.h = 0; + pdf->posstruct->pos.v = depth(p); + break; + case dir_TRT: + pdf->posstruct->pos.h = width(p); + pdf->posstruct->pos.v = depth(p); + break; + case dir_LTL: + pdf->posstruct->pos.h = height(p); + pdf->posstruct->pos.v = width(p); + break; + case dir_RTT: + pdf->posstruct->pos.h = depth(p); + pdf->posstruct->pos.v = width(p); + break; + } + } + + /* Now we are at the point on the page where the origin of the page box should go. */ + + shipbox_refpos = pdf->posstruct->pos; /* for \.{\\gleaders} */ + + switch (pdf->o_mode) { + case OMODE_DVI: + assert(shipping_page); + dvi_begin_page(pdf); + break; + case OMODE_PDF: + pdf_begin_page(pdf, shipping_page); + break; + case OMODE_LUA: + assert(shipping_page); + lua_begin_page(pdf); + break; + default: + assert(0); + } + + switch (type(p)) { + case vlist_node: + vlist_out(pdf, p); + break; + case hlist_node: + hlist_out(pdf, p); + break; + default: + assert(0); + } + + if (shipping_page) + incr(total_pages); + cur_s = -1; + + /* Finish shipping */ + + switch (pdf->o_mode) { + case OMODE_DVI: + dvi_end_page(pdf); + break; + case OMODE_PDF: + pdf_end_page(pdf, shipping_page); + break; + case OMODE_LUA: + lua_end_page(pdf); + break; + default: + assert(0); + } + + DONE: + if ((tracing_output <= 0) && (post_callback_id == 0) && shipping_page) { + print_char(']'); + update_terminal(); + } + dead_cycles = 0; + /* Flush the box from memory, showing statistics if requested */ + if ((tracing_stats > 1) && (pre_callback_id == 0)) { + tprint_nl("Memory usage before: "); + print_int(var_used); + print_char('&'); + print_int(dyn_used); + print_char(';'); + } + flush_node_list(p); + if ((tracing_stats > 1) && (post_callback_id == 0)) { + tprint(" after: "); + print_int(var_used); + print_char('&'); + print_int(dyn_used); + print_ln(); + } + if (shipping_page && (post_callback_id > 0)) + (void) run_callback(post_callback_id, "->"); + + /* Finish sheet {\sl Sync\TeX} information record */ + if (int_par(synctex_code)) + synctexteehs(); +} diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdftables.h b/Build/source/texk/web2c/luatexdir/pdf/pdftables.h new file mode 100644 index 00000000000..f44c6b2a7c6 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdftables.h @@ -0,0 +1,136 @@ +/* pdftables.h + + Copyright 2009 Taco Hoekwater <taco@luatex.org> + + 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 <http://www.gnu.org/licenses/>. */ + +/* $Id: pdftables.h 3261 2009-12-18 11:38:21Z taco $ */ + +#ifndef PDFTABLES_H +# define PDFTABLES_H + +typedef enum { + union_type_int, + union_type_cstring, +} union_type; + +typedef struct { + union { + int int0; + char *str0; + } u; + union_type u_type; /* integer or char * in union above */ + int objptr; +} oentry; + +/* +The cross-reference table |obj_tab| is an array of |obj_tab_size| of +|obj_entry|. Each entry contains five integer fields and represents an object +in PDF file whose object number is the index of this entry in |obj_tab|. +Objects in |obj_tab| maybe linked into list; objects in such a linked list have +the same type. +*/ + +/* +The first field contains information representing identifier of this object. +It is usally a number for most of object types, but it may be a string number +for named destination or named thread. + +The second field of |obj_entry| contains link to the next +object in |obj_tab| if this object is linked in a list. + +The third field holds the byte offset of the object in the output PDF file, +or its byte offset within an object stream. As long as the object is not +written, this field is used for flags about the write status of the object; +then it has a negative value. + +The fourth field holds the object number of the object stream, into which +the object is included. + +The last field usually represents the pointer to some auxiliary data +structure depending on the object type; however it may be used as a counter as +well. +*/ + +# define obj_info(pdf,A) pdf->obj_tab[(A)].u.int0 /* information representing identifier of this object */ +# define obj_start(pdf,A) pdf->obj_tab[(A)].u.str0 +# define obj_link(pdf,A) pdf->obj_tab[(A)].int1 /* link to the next entry in linked list */ +# define obj_offset(pdf,A) pdf->obj_tab[(A)].int2 /* negative (flags), or byte offset for this object in PDF + output file, or object stream number for this object */ +# define obj_os_idx(pdf,A) pdf->obj_tab[(A)].int3 /* index of this object in object stream */ +# define obj_aux(pdf,A) pdf->obj_tab[(A)].v.int4 /* auxiliary pointer */ +# define obj_stop(pdf,A) pdf->obj_tab[(A)].v.str4 +# define obj_type(pdf,A) pdf->obj_tab[(A)].objtype + +# define obj_data_ptr obj_aux /* pointer to |pdf->mem| */ + +# define set_obj_link(pdf,A,B) obj_link(pdf,A)=B +# define set_obj_start(pdf,A,B) obj_start(pdf,A)=B +# define set_obj_info(pdf,A,B) obj_info(pdf,A)=B +# define set_obj_offset(pdf,A,B) obj_offset(pdf,A)=B +# define set_obj_aux(pdf,A,B) obj_aux(pdf,A)=B +# define set_obj_stop(pdf,A,B) obj_stop(pdf,A)=B +# define set_obj_data_ptr(pdf,A,B) obj_data_ptr(pdf,A)=B + +# define set_obj_fresh(pdf,A) obj_offset(pdf,(A))=-2 +# define set_obj_scheduled(pdf,A) if (intcast(obj_offset(pdf,A))==-2) obj_offset(pdf,A)=-1 +# define is_obj_scheduled(pdf,A) (intcast(obj_offset(pdf,A))>-2) +# define is_obj_written(pdf,A) (intcast(obj_offset(pdf,A))>-1) + +/* NOTE: The data structure definitions for the nodes on the typesetting side are + inside |nodes.h| */ + +/* Some constants */ +# define inf_pk_dpi 72 /* min PK pixel density value from \.{texmf.cnf} */ +# define sup_pk_dpi 8000 /* max PK pixel density value from \.{texmf.cnf} */ + +extern int find_obj(PDF pdf, int t, int i, boolean byname); +extern void check_obj_exists(PDF pdf, int t, int n); +extern int get_obj(PDF pdf, int t, int i, boolean byname); +extern void pdf_create_obj(PDF pdf, int t, int i); +extern int pdf_new_objnum(PDF pdf); + +extern void set_rect_dimens(PDF pdf, halfword p, halfword parent_box, + scaledpos cur, scaled_whd alt_rule, scaled margin); + +extern void libpdffinish(PDF); + +extern void dump_pdftex_data(PDF pdf); +extern void undump_pdftex_data(PDF pdf); + +# define set_width(A, B) width(A) = (B) +# define set_height(A, B) height(A) = (B) +# define set_depth(A, B) depth(A) = (B) + +/* interface definitions for eqtb locations */ +# define pdf_minor_version int_par(pdf_minor_version_code) +# define pdf_decimal_digits int_par(pdf_decimal_digits_code) +# define pdf_gamma int_par(pdf_gamma_code) +# define pdf_image_gamma int_par(pdf_image_gamma_code) +# define pdf_image_hicolor int_par(pdf_image_hicolor_code) +# define pdf_image_apply_gamma int_par(pdf_image_apply_gamma_code) +# define pdf_objcompresslevel int_par(pdf_objcompresslevel_code) +# define pdf_draftmode int_par(pdf_draftmode_code) +# define pdf_inclusion_copy_font int_par(pdf_inclusion_copy_font_code) +# define pdf_inclusion_errorlevel int_par(pdf_inclusion_errorlevel_code) +# define pdf_replace_font int_par(pdf_replace_font_code) +# define pdf_pk_resolution int_par(pdf_pk_resolution_code) +# define pdf_pk_mode equiv(pdf_pk_mode_loc) +# define pdf_unique_resname int_par(pdf_unique_resname_code) +# define pdf_compress_level int_par(pdf_compress_level_code) +# define pdf_move_chars int_par(pdf_move_chars_code) + +#endif diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdftables.w b/Build/source/texk/web2c/luatexdir/pdf/pdftables.w new file mode 100644 index 00000000000..ef4787fb3b6 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdftables.w @@ -0,0 +1,456 @@ +% pdftables.w + +% Copyright 2009-2010 Taco Hoekwater <taco@@luatex.org> + +% 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 <http://www.gnu.org/licenses/>. + +@ @c +static const char _svn_version[] = + "$Id: pdftables.w 3571 2010-04-02 13:50:45Z taco $" + "$URL: http://foundry.supelec.fr/svn/luatex/tags/beta-0.60.0/source/texk/web2c/luatexdir/pdf/pdftables.w $"; + +#include "ptexlib.h" + +@ One AVL tree each for a few |obj_type| out of |0...PDF_OBJ_TYPE_MAX| + +@c +/* mark which objects should be searchable through AVL tree */ + +static int obj_in_tree[PDF_OBJ_TYPE_MAX + 1] = { + 0, /* |obj_type_font = 0|, */ + 0, /* |obj_type_outline = 1|, */ + 1, /* |obj_type_dest = 2|, */ + 0, /* |obj_type_obj = 3|, */ + 0, /* |obj_type_xform = 4|, */ + 0, /* |obj_type_ximage = 5|, */ + 1, /* |obj_type_thread = 6|, */ + /* the ones below don't go into a linked list */ + 0, /* |obj_type_pagestream = 7|, */ + 1, /* |obj_type_page = 8|, */ + 0, /* |obj_type_pages = 9|, */ + 0, /* |obj_type_link = 10|, */ + 0, /* |obj_type_bead = 11|, */ + 0, /* |obj_type_annot = 12|, */ + 0, /* |obj_type_objstm = 13|, */ + 0 /* |obj_type_others = 14| */ +}; + +@ AVL sort oentry into |avl_table[]| +@c +static int compare_info(const void *pa, const void *pb, void *param) +{ + const oentry *a, *b; + (void) param; + a = (const oentry *) pa; + b = (const oentry *) pb; + 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; + assert(t >= 0 || t <= PDF_OBJ_TYPE_MAX || obj_in_tree[t] == 1); + if (pdf->obj_tree[t] == NULL) { + pdf->obj_tree[t] = avl_create(compare_info, NULL, &avl_xallocator); + if (pdf->obj_tree[t] == NULL) + pdftex_fail("avlstuff.c: avl_create() pdf->obj_tree failed"); + } + pp = avl_probe(pdf->obj_tree[t], oe); + if (pp == NULL) + pdftex_fail("avlstuff.c: avl_probe() out of memory in insertion"); +} + +static void avl_put_int_obj(PDF pdf, int int0, int objptr, int t) +{ + oentry *oe; + 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; + 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; + assert(t >= 0 || t <= PDF_OBJ_TYPE_MAX || obj_in_tree[t] == 1); + 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; + assert(t >= 0 || t <= PDF_OBJ_TYPE_MAX || obj_in_tree[t] == 1); + 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 +void pdf_create_obj(PDF pdf, int t, int i) +{ + int a; + char *ss = NULL; + if (pdf->sys_obj_ptr == sup_obj_tab_size) + overflow("indirect objects table size", (unsigned) pdf->obj_tab_size); + if (pdf->sys_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); + } + incr(pdf->sys_obj_ptr); + pdf->obj_ptr = pdf->sys_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 + 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); + } +} +@ @c +int find_obj(PDF pdf, int t, int i, boolean byname) +{ + char *ss = NULL; + int ret; + assert(i >= 0); /* no tricks */ + 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 get_obj(PDF pdf, int t, int i, boolean byname) +{ + int r; + str_number s; + assert(i >= 0); + 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) { + pdf_create_obj(pdf, t, -s); + s = 0; + } else { + pdf_create_obj(pdf, t, i); + } + r = pdf->obj_ptr; + if (t == obj_type_dest) + set_obj_dest_ptr(pdf, r, null); + } + if (s != 0) + flush_str(s); + return r; +} + +@ create a new object and return its number + +@c +int pdf_new_objnum(PDF pdf) +{ + pdf_create_obj(pdf, obj_type_others, 0); + return pdf->obj_ptr; +} + +void check_obj_exists(PDF pdf, int t, int objnum) +{ + if (objnum < 0 || objnum > pdf->obj_ptr) + pdf_error("ext1", "cannot find referenced object"); + if (t != obj_type(pdf, objnum)) + pdf_error("ext1", "referenced object has wrong type"); +} + +@ @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 (is_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) +{ + fb_free(pdf); + xfree(pdf->job_id_string); + fm_free(); + t1_free(); + enc_free(); + epdf_free(); + ttf_free(); + sfd_free(); + glyph_unicode_free(); + zip_free(pdf); +} + + +@ Store some of the pdftex data structures in the format. The idea here is +to ensure that any data structures referenced from pdftex-specific whatsit +nodes are retained. For the sake of simplicity and speed, all the filled parts +of |pdf->mem| and |obj_tab| are retained, in the present implementation. We also +retain three of the linked lists that start from |head_tab|, so that it is +possible to, say, load an image in the \.{INITEX} run and then reference it in a +\.{VIRTEX} run that uses the dumped format. + +@c +void dump_pdftex_data(PDF pdf) +{ + int k, x; + pdf_object_list *l; + dumpimagemeta(); /* the image information array */ + dump_int(pdf->mem_size); + dump_int(pdf->mem_ptr); + for (k = 1; k <= pdf->mem_ptr - 1; k++) { + x = pdf->mem[k]; + dump_int(x); + } + print_ln(); + print_int(pdf->mem_ptr - 1); + tprint(" words of pdf memory"); + x = pdf->obj_tab_size; + dump_int(x); + x = pdf->obj_ptr; + dump_int(x); + x = pdf->sys_obj_ptr; + dump_int(x); + for (k = 1; k <= pdf->sys_obj_ptr; k++) { + x = obj_info(pdf, k); + dump_int(x); + x = obj_link(pdf, k); + dump_int(x); + x = obj_os_idx(pdf, k); + dump_int(x); + x = obj_aux(pdf, k); + dump_int(x); + x = obj_type(pdf, k); + dump_int(x); + } + print_ln(); + print_int(pdf->sys_obj_ptr); + tprint(" indirect objects"); + dump_int(pdf->obj_count); + dump_int(pdf->xform_count); + dump_int(pdf->ximage_count); + if ((l = get_page_resources_list(pdf, obj_type_obj)) != NULL) { + while (l != NULL) { + dump_int(l->info); + l = l->link; + } + } + dump_int(0); /* signal end of |obj_list| */ + if ((l = get_page_resources_list(pdf, obj_type_xform)) != NULL) { + while (l != NULL) { + dump_int(l->info); + l = l->link; + } + } + dump_int(0); /* signal end of |xform_list| */ + if ((l = get_page_resources_list(pdf, obj_type_ximage)) != NULL) { + while (l != NULL) { + dump_int(l->info); + l = l->link; + } + } + dump_int(0); /* signal end of |ximage_list| */ + x = pdf->head_tab[obj_type_obj]; + dump_int(x); + x = pdf->head_tab[obj_type_xform]; + dump_int(x); + x = pdf->head_tab[obj_type_ximage]; + dump_int(x); + dump_int(pdf_last_obj); + dump_int(pdf_last_xform); + dump_int(pdf_last_ximage); +} + +@ And restoring the pdftex data structures from the format. The +two function arguments to |undumpimagemeta| have been restored +already in an earlier module. + +@c +void undump_pdftex_data(PDF pdf) +{ + int k, x; + undumpimagemeta(pdf, pdf_minor_version, pdf_inclusion_errorlevel); /* the image information array */ + undump_int(pdf->mem_size); + pdf->mem = xreallocarray(pdf->mem, int, (unsigned) pdf->mem_size); + undump_int(pdf->mem_ptr); + for (k = 1; k <= pdf->mem_ptr - 1; k++) { + undump_int(x); + pdf->mem[k] = (int) x; + } + undump_int(x); + pdf->obj_tab_size = x; + undump_int(x); + pdf->obj_ptr = x; + undump_int(x); + pdf->sys_obj_ptr = x; + for (k = 1; k <= pdf->sys_obj_ptr; k++) { + undump_int(x); + obj_info(pdf, k) = x; + undump_int(x); + obj_link(pdf, k) = x; + set_obj_offset(pdf, k, -1); + undump_int(x); + obj_os_idx(pdf, k) = x; + undump_int(x); + obj_aux(pdf, k) = x; + undump_int(x); + obj_type(pdf, k) = x; + } + + undump_int(x); + pdf->obj_count = x; + undump_int(x); + pdf->xform_count = x; + undump_int(x); + pdf->ximage_count = x; + /* todo : the next 3 loops can be done much more efficiently */ + undump_int(x); + while (x != 0) { + addto_page_resources(pdf, obj_type_obj, x); + undump_int(x); + } + undump_int(x); + while (x != 0) { + addto_page_resources(pdf, obj_type_xform, x); + undump_int(x); + } + undump_int(x); + while (x != 0) { + addto_page_resources(pdf, obj_type_ximage, x); + undump_int(x); + } + + undump_int(x); + pdf->head_tab[obj_type_obj] = x; + undump_int(x); + pdf->head_tab[obj_type_xform] = x; + undump_int(x); + pdf->head_tab[obj_type_ximage] = x; + undump_int(pdf_last_obj); + undump_int(pdf_last_xform); + undump_int(pdf_last_ximage); +} diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfthread.h b/Build/source/texk/web2c/luatexdir/pdf/pdfthread.h new file mode 100644 index 00000000000..45d50a4551f --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdfthread.h @@ -0,0 +1,71 @@ +/* pdfthread.h + + Copyright 2009 Taco Hoekwater <taco@luatex.org> + + 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 <http://www.gnu.org/licenses/>. */ + +/* $Id: pdfthread.h 3261 2009-12-18 11:38:21Z taco $ */ + +#ifndef PDFTHREAD_H +# define PDFTHREADH + +/* data structure of threads; words 1..4 represent the coordinates of the corners */ + +# define obj_thread_first obj_aux /* pointer to the first bead */ + +/* data structure of beads */ +# define pdfmem_bead_size 5 /* size of memory in |pdf->mem| which |obj_bead_ptr| points to */ + +# define set_pdf_thread_attr(A,B) pdf_thread_attr(A)=B +# define set_pdf_thread_id(A,B) pdf_thread_id(A)=B +# define set_pdf_thread_named_id(A,B) pdf_thread_named_id(A)=B + +# define obj_bead_ptr obj_aux /* pointer to |pdf->mem| */ +# define obj_bead_rect(pdf,A) pdf->mem[obj_bead_ptr(pdf,A)] +# define obj_bead_page(pdf,A) pdf->mem[obj_bead_ptr(pdf,A) + 1] +# define obj_bead_next(pdf,A) pdf->mem[obj_bead_ptr(pdf,A) + 2] +# define obj_bead_prev(pdf,A) pdf->mem[obj_bead_ptr(pdf,A) + 3] +# define obj_bead_attr(pdf,A) pdf->mem[obj_bead_ptr(pdf,A) + 4] + +# define set_obj_bead_rect(pdf,A,B) obj_bead_rect(pdf,A)=B +# define set_obj_bead_page(pdf,A,B) obj_bead_page(pdf,A)=B +# define set_obj_bead_next(pdf,A,B) obj_bead_next(pdf,A)=B +# define set_obj_bead_prev(pdf,A,B) obj_bead_prev(pdf,A)=B +# define set_obj_bead_attr(pdf,A,B) obj_bead_attr(pdf,A)=B + + +/* pointer to the corresponding whatsit node; |obj_bead_rect| is needed only when the bead + rectangle has been written out and after that |obj_bead_data| is not needed any more + so we can use this field for both */ +# define obj_bead_data obj_bead_rect +# define set_obj_bead_data set_obj_bead_rect + +extern void append_bead(PDF pdf, halfword p); +extern void do_thread(PDF pdf, halfword parent_box, halfword p, scaledpos cur); +extern void append_thread(PDF pdf, halfword parent_box, scaledpos cur); +extern void end_thread(PDF pdf, halfword p); +extern void scan_thread_id(void); + +extern void thread_title(PDF pdf, int t); +extern void pdf_fix_thread(PDF pdf, int t); +extern void out_thread(PDF pdf, int t); + +extern void check_running_thread(PDF pdf, halfword this_box, scaledpos cur); +extern void print_beads_list(PDF pdf); +extern void print_bead_rectangles(PDF pdf); +extern void flush_beads_list(void); + +#endif diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfthread.w b/Build/source/texk/web2c/luatexdir/pdf/pdfthread.w new file mode 100644 index 00000000000..e788a3cdf4f --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdfthread.w @@ -0,0 +1,290 @@ +% pdfthread.w + +% Copyright 2009-2010 Taco Hoekwater <taco@@luatex.org> + +% 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 <http://www.gnu.org/licenses/>. + +@ @c +static const char _svn_version[] = + "$Id: pdfthread.w 3571 2010-04-02 13:50:45Z taco $" + "$URL: http://foundry.supelec.fr/svn/luatex/tags/beta-0.60.0/source/texk/web2c/luatexdir/pdf/pdfthread.w $"; + +#include "ptexlib.h" + +@ @c +#define pdf_thread_margin dimen_par(pdf_thread_margin_code) +#define page_width dimen_par(page_width_code) +#define page_height dimen_par(page_height_code) + +@ Threads are handled in similar way as link annotations +@c +void append_bead(PDF pdf, halfword p) +{ + int a, b, c, t; + if (!is_shipping_page) + pdf_error("ext4", "threads cannot be inside an XForm"); + t = get_obj(pdf, obj_type_thread, pdf_thread_id(p), pdf_thread_named_id(p)); + b = pdf_new_objnum(pdf); + obj_bead_ptr(pdf, b) = pdf_get_mem(pdf, pdfmem_bead_size); + set_obj_bead_page(pdf, b, pdf->last_page); + set_obj_bead_data(pdf, b, p); + if (pdf_thread_attr(p) != null) + set_obj_bead_attr(pdf, b, tokens_to_string(pdf_thread_attr(p))); + else + set_obj_bead_attr(pdf, b, 0); + if (obj_thread_first(pdf, t) == 0) { + obj_thread_first(pdf, t) = b; + set_obj_bead_next(pdf, b, b); + set_obj_bead_prev(pdf, b, b); + } else { + a = obj_thread_first(pdf, t); + c = obj_bead_prev(pdf, a); + set_obj_bead_prev(pdf, b, c); + set_obj_bead_next(pdf, b, a); + set_obj_bead_prev(pdf, a, b); + set_obj_bead_next(pdf, c, b); + } + addto_page_resources(pdf, obj_type_bead, b); +} + +@ @c +void do_thread(PDF pdf, halfword p, halfword parent_box, scaledpos cur) +{ + scaled_whd alt_rule; + if ((type(p) == hlist_node) && (subtype(p) == pdf_start_thread_node)) + pdf_error("ext4", "\\pdfstartthread ended up in hlist"); + if (doing_leaders) + return; + if (subtype(p) == pdf_start_thread_node) { + pdf->thread.wd = width(p); + pdf->thread.ht = height(p); + pdf->thread.dp = depth(p); + pdf->last_thread_id = pdf_thread_id(p); + pdf->last_thread_named_id = (pdf_thread_named_id(p) > 0); + if (pdf->last_thread_named_id) + add_token_ref(pdf_thread_id(p)); + pdf->thread_level = cur_s; + } + alt_rule.wd = width(p); + alt_rule.ht = height(p); + alt_rule.dp = depth(p); + set_rect_dimens(pdf, p, parent_box, cur, alt_rule, pdf_thread_margin); + append_bead(pdf, p); + pdf->last_thread = p; +} + +@ @c +void append_thread(PDF pdf, halfword parent_box, scaledpos cur) +{ + halfword p; + scaled_whd alt_rule; + p = new_node(whatsit_node, pdf_thread_data_node); + width(p) = pdf->thread.wd; + height(p) = pdf->thread.ht; + depth(p) = pdf->thread.dp; + pdf_thread_attr(p) = null; + pdf_thread_id(p) = pdf->last_thread_id; + if (pdf->last_thread_named_id) { + add_token_ref(pdf_thread_id(p)); + pdf_thread_named_id(p) = 1; + } else { + pdf_thread_named_id(p) = 0; + } + alt_rule.wd = width(p); + alt_rule.ht = height(p); + alt_rule.dp = depth(p); + set_rect_dimens(pdf, p, parent_box, cur, alt_rule, pdf_thread_margin); + append_bead(pdf, p); + pdf->last_thread = p; +} + +@ @c +void end_thread(PDF pdf, halfword p) +{ + scaledpos pos = pdf->posstruct->pos; + if (type(p) == hlist_node) + pdf_error("ext4", "\\pdfendthread ended up in hlist"); + if (pdf->thread_level != cur_s) + pdf_error("ext4", + "\\pdfendthread ended up in different nesting level than \\pdfstartthread"); + if (is_running(pdf->thread.dp) && (pdf->last_thread != null)) { + switch (pdf->posstruct->dir) { + case dir_TLT: + case dir_TRT: + pdf_ann_bottom(pdf->last_thread) = pos.v - pdf_thread_margin; + break; + case dir_LTL: + pdf_ann_right(pdf->last_thread) = pos.h + pdf_thread_margin; + break; + case dir_RTT: + pdf_ann_left(pdf->last_thread) = pos.h - pdf_thread_margin; + break; + } + } + if (pdf->last_thread_named_id) + delete_token_ref(pdf->last_thread_id); + pdf->last_thread = null; +} + +@ The following function are needed for outputing article thread. +@c +void thread_title(PDF pdf, int t) +{ + pdf_printf(pdf, "/Title ("); + if (obj_info(pdf, t) < 0) + pdf_print(pdf, -obj_info(pdf, t)); + else + pdf_print_int(pdf, obj_info(pdf, t)); + pdf_printf(pdf, ")\n"); +} + +void pdf_fix_thread(PDF pdf, int t) +{ + halfword a; + pdf_warning("thread", "destination", false, false); + if (obj_info(pdf, t) < 0) { + tprint("name{"); + print(-obj_info(pdf, t)); + tprint("}"); + } else { + tprint("num"); + print_int(obj_info(pdf, t)); + } + tprint(" has been referenced but does not exist, replaced by a fixed one"); + print_ln(); + print_ln(); + pdf_new_dict(pdf, obj_type_others, 0, 0); + a = pdf->obj_ptr; + pdf_indirect_ln(pdf, "T", t); + pdf_indirect_ln(pdf, "V", a); + pdf_indirect_ln(pdf, "N", a); + pdf_indirect_ln(pdf, "P", pdf->last_page); + pdf_printf(pdf, "/R [0 0 "); + pdf_print_bp(pdf, page_width); + pdf_out(pdf, ' '); + pdf_print_bp(pdf, page_height); + pdf_printf(pdf, "]\n"); + pdf_end_dict(pdf); + pdf_begin_dict(pdf, t, 1); + pdf_printf(pdf, "/I << \n"); + thread_title(pdf, t); + pdf_printf(pdf, ">>\n"); + pdf_indirect_ln(pdf, "F", a); + pdf_end_dict(pdf); +} + +void out_thread(PDF pdf, int t) +{ + halfword a, b; + int last_attr; + if (obj_thread_first(pdf, t) == 0) { + pdf_fix_thread(pdf, t); + return; + } + pdf_begin_dict(pdf, t, 1); + a = obj_thread_first(pdf, t); + b = a; + last_attr = 0; + do { + if (obj_bead_attr(pdf, a) != 0) + last_attr = obj_bead_attr(pdf, a); + a = obj_bead_next(pdf, a); + } while (a != b); + if (last_attr != 0) { + pdf_print_ln(pdf, last_attr); + } else { + pdf_printf(pdf, "/I << \n"); + thread_title(pdf, t); + pdf_printf(pdf, ">>\n"); + } + pdf_indirect_ln(pdf, "F", a); + pdf_end_dict(pdf); + do { + pdf_begin_dict(pdf, a, 1); + if (a == b) + pdf_indirect_ln(pdf, "T", t); + pdf_indirect_ln(pdf, "V", obj_bead_prev(pdf, a)); + pdf_indirect_ln(pdf, "N", obj_bead_next(pdf, a)); + pdf_indirect_ln(pdf, "P", obj_bead_page(pdf, a)); + pdf_indirect_ln(pdf, "R", obj_bead_rect(pdf, a)); + pdf_end_dict(pdf); + a = obj_bead_next(pdf, a); + } while (a != b); +} + + +@ @c +void scan_thread_id(void) +{ + if (scan_keyword("num")) { + scan_int(); + if (cur_val <= 0) + pdf_error("ext1", "num identifier must be positive"); + if (cur_val > max_halfword) + pdf_error("ext1", "number too big"); + set_pdf_thread_id(cur_list.tail_field, cur_val); + set_pdf_thread_named_id(cur_list.tail_field, 0); + } else if (scan_keyword("name")) { + scan_pdf_ext_toks(); + set_pdf_thread_id(cur_list.tail_field, def_ref); + set_pdf_thread_named_id(cur_list.tail_field, 1); + } else { + pdf_error("ext1", "identifier type missing"); + } +} + +void check_running_thread(PDF pdf, halfword this_box, scaledpos cur) +{ + if ((pdf->last_thread != null) && is_running(pdf->thread.dp) + && (pdf->thread_level == cur_s)) + append_thread(pdf, this_box, cur); +} + +@ @c +void print_beads_list(PDF pdf) +{ + pdf_object_list *k; + if ((k = get_page_resources_list(pdf, obj_type_bead)) != NULL) { + pdf_printf(pdf, "/B [ "); + while (k != NULL) { + pdf_print_int(pdf, k->info); + pdf_printf(pdf, " 0 R "); + k = k->link; + } + pdf_printf(pdf, "]\n"); + } +} + +@ @c +void print_bead_rectangles(PDF pdf) +{ + halfword i; + pdf_object_list *k; + if ((k = get_page_resources_list(pdf, obj_type_bead)) != NULL) { + while (k != NULL) { + pdf_new_obj(pdf, obj_type_others, 0, 1); + pdf_out(pdf, '['); + i = obj_bead_data(pdf, k->info); /* pointer to a whatsit or whatsit-like node */ + pdf_print_rect_spec(pdf, i); + if (subtype(i) == pdf_thread_data_node) /* thanh says it mis be destroyed here */ + flush_node(i); + pdf_printf(pdf, "]\n"); + set_obj_bead_rect(pdf, k->info, pdf->obj_ptr); /* rewrite |obj_bead_data| */ + pdf_end_obj(pdf); + k = k->link; + } + } +} diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdftypes.h b/Build/source/texk/web2c/luatexdir/pdf/pdftypes.h new file mode 100644 index 00000000000..83b3c89a97e --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdftypes.h @@ -0,0 +1,291 @@ +/* pdftypes.h + + Copyright 2009-2010 Taco Hoekwater <taco@luatex.org> + + 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 <http://www.gnu.org/licenses/>. */ + +/* $Id: pdftypes.h 3341 2010-01-08 19:52:54Z hhenkel $ */ + +#ifndef PDFTYPES_H +# define PDFTYPES_H + +# include <zlib.h> + +/* This stucture holds everything that is needed for the actual pdf generation. + +Because this structure interfaces with C++, it is not wise to use |boolean| +here (C++ has a boolean type built-in that is not compatible). Also, I have +plans to convert the backend code into a C library for use with e.g. standalone +lua. Together, this means that it is best only to use the standard C types and +the types explicitly defined in this header, and stay away from types like +|integer| and |eight_bits| that are used elsewhere in the \LUATEX\ sources. +*/ + +typedef struct os_obj_data_ { + int num; + int off; +} os_obj_data; + +typedef struct { + long m; /* mantissa (significand) */ + int e; /* exponent * -1 */ +} pdffloat; + +typedef struct { + pdffloat h; + pdffloat v; +} pdfpos; + +# define scaled int + +typedef struct scaledpos_ { + scaled h; + scaled v; +} scaledpos; + +typedef struct scaled_whd_ { + scaled wd; /* TeX width */ + scaled ht; /* TeX height */ + scaled dp; /* TeX depth */ +} scaled_whd; + +typedef struct posstructure_ { + scaledpos pos; /* position on the page */ + int dir; /* direction of stuff to be put onto the page */ +} posstructure; + +typedef struct { + scaledpos curpos; /* \pdflastpos position */ + posstructure boxpos; /* box dir and position of the box origin on the page */ + scaled_whd boxdim; /* box dimensions (in hlist/vlist coordinate system) */ +} pos_info_structure; + +typedef enum { PMODE_NONE, PMODE_PAGE, PMODE_TEXT, PMODE_CHARARRAY, PMODE_CHAR +} pos_mode; + +typedef enum { OMODE_NONE, OMODE_DVI, OMODE_PDF, OMODE_LUA } output_mode; + +# define MAX_OMODE 3 /* largest index in enum output_mode */ + +typedef enum { ST_INITIAL, ST_OMODE_FIX, ST_FILE_OPEN, ST_HEADER_WRITTEN, + ST_FILE_CLOSED +} output_state; + +typedef struct pdf_object_list_ { + int info; + struct pdf_object_list_ *link; +} pdf_object_list; + +typedef enum { WMODE_H, WMODE_V } writing_mode; /* []TJ runs horizontal or vertical */ + +typedef struct { + pdfpos pdf; /* pos. on page (PDF page raster) */ + pdfpos pdf_bt_pos; /* pos. at begin of BT-ET group (PDF page raster) */ + pdfpos pdf_tj_pos; /* pos. at begin of TJ array (PDF page raster) */ + pdffloat cw; /* pos. within [(..)..]TJ array (glyph raster); + cw.e = fractional digits in /Widths array */ + pdffloat tj_delta; /* rel. movement in [(..)..]TJ array (glyph raster) */ + pdffloat fs; /* font size in PDF units */ + pdffloat fs_cur; /* to check if fs.m has changed and Tf needed */ + pdffloat cm[6]; /* cm array */ + pdffloat tm[6]; /* Tm array */ + double k1; /* conv. factor from TeX sp to PDF page raster */ + double k2; /* conv. factor from PDF page raster to TJ array raster */ + int f_pdf; /* /F* font number, of unexpanded base font! */ + int f_pdf_cur; /* to check if f_pdf has changed and Tf needed */ + writing_mode wmode; /* PDF writing mode WMode (horizontal/vertical) */ + pos_mode mode; /* current positioning mode */ + int ishex; /* Whether the current char string is <> or () */ +} pdfstructure; + +typedef struct obj_entry_ { + union { + int int0; + char *str0; + } u; + int int1; + off_t int2; + int int3; + union { + int int4; + char *str4; + } v; + int objtype; /* integer int5 */ +} obj_entry; + +typedef struct dest_name_entry_ { + char *objname; /* destination name */ + int objnum; /* destination object number */ +} dest_name_entry; + +# define pdf_max_link_level 10 /* maximum depth of link nesting */ + +typedef struct pdf_link_stack_record { + int nesting_level; + int link_node; /* holds a copy of the corresponding |pdf_start_link_node| */ + int ref_link_node; /* points to original |pdf_start_link_node|, or a + copy of |link_node| created by |append_link| in + case of multi-line link */ +} pdf_link_stack_record; + +/* types of objects */ +typedef enum { + obj_type_font = 0, /* index of linked list of Fonts objects */ + obj_type_outline = 1, /* index of linked list of outline objects */ + obj_type_dest = 2, /* index of linked list of destination objects */ + obj_type_obj = 3, /* index of linked list of raw objects */ + obj_type_xform = 4, /* index of linked list of XObject forms */ + obj_type_ximage = 5, /* index of linked list of XObject images */ + obj_type_thread = 6, /* index of linked list of num article threads */ + /* |obj_type_thread| is the highest entry in |head_tab|, but there are a few + more linked lists that are handy: */ + obj_type_pagestream = 7, /* Page stream objects */ + obj_type_page = 8, /* Page objects */ + obj_type_pages = 9, /* Pages objects */ + obj_type_link = 10, /* link objects */ + obj_type_bead = 11, /* thread bead objects */ + obj_type_annot = 12, /* annotation objects */ + obj_type_objstm = 13, /* /ObjStm objects */ + obj_type_others = 14 /* any other objects (also not linked in any list) */ +} pdf_obj_type; + +# define HEAD_TAB_MAX 6 /* obj_type_thread */ +# define PDF_OBJ_TYPE_MAX 14 /* obj_type_others */ + +typedef struct pdf_resource_struct_ { + struct avl_table *resources_tree; + int last_resources; /* halfword to most recently generated Resources object. */ +} pdf_resource_struct; + +typedef struct pdf_output_file_ { + FILE *file; /* the PDF output file handle */ + char *file_name; /* the PDF output file name */ + output_mode o_mode; /* output mode (DVI/PDF/...) */ + output_state o_state; + /* generation parameters */ + int gamma; + int image_gamma; + int image_hicolor; /* boolean */ + int image_apply_gamma; + int draftmode; + int pk_resolution; + int decimal_digits; + int gen_tounicode; + int inclusion_copy_font; + int replace_font; + int minor_version; /* fixed minor part of the PDF version */ + int compress_level; /* level for zlib object stream compression */ + int objcompresslevel; /* fixed level for activating PDF object streams */ + char *job_id_string; /* the full job string */ + + /* output file buffering */ + unsigned char *op_buf; /* the PDF output buffer */ + int op_buf_size; /* output buffer size (static) */ + int op_ptr; /* store for PDF buffer |pdf_ptr| while inside object streams */ + unsigned char *os_buf; /* the PDF object stream buffer */ + int os_buf_size; /* current size of the PDF object stream buffer, grows dynamically */ + int os_ptr; /* store for object stream |pdf_ptr| while outside object streams */ + + os_obj_data *os_obj; /* array of object stream objects */ + int os_idx; /* pointer into |pdf_os_objnum| and |pdf_os_objoff| */ + int os_cntr; /* counter for object stream objects */ + int os_mode; /* true if producing object stream */ + int os_enable; /* true if object streams are globally enabled */ + int os_cur_objnum; /* number of current object stream object */ + + unsigned char *buf; /* pointer to the PDF output buffer or PDF object stream buffer */ + int buf_size; /* end of PDF output buffer or PDF object stream buffer */ + int ptr; /* pointer to the first unused byte in the PDF buffer or object stream buffer */ + off_t save_offset; /* to save |pdf_offset| */ + off_t gone; /* number of bytes that were flushed to output */ + + char *printf_buf; /* a scratch buffer for |pdf_printf| */ + + time_t start_time; /* when this job started */ + char *start_time_str; /* minimum size for time_str is 24: "D:YYYYmmddHHMMSS+HH'MM'" */ + + /* define fb_ptr, fb_array & fb_limit */ + char *fb_array; + char *fb_ptr; + size_t fb_limit; + + char *zipbuf; + z_stream c_stream; /* compression stream */ + int zip_write_state; /* which state of compression we are in */ + + int pk_scale_factor; /* this is just a preprocessed value that depends on + |pk_resolution| and |decimal_digits| */ + + int img_page_group_val; /* page group information pointer from included pdf or png images */ + char *resname_prefix; /* global prefix of resources name */ + + int mem_size; /* allocated size of |mem| array */ + int *mem; + int mem_ptr; + + pdfstructure *pstruct; /* utity structure keeping position status in PDF page stream */ + posstructure *posstruct; /* structure for positioning within page */ + + int obj_tab_size; /* allocated size of |obj_tab| array */ + obj_entry *obj_tab; + int head_tab[HEAD_TAB_MAX + 1]; /* heads of the object lists in |obj_tab| */ + struct avl_table *obj_tree[PDF_OBJ_TYPE_MAX + 1]; /* this is useful for finding the objects back */ + + int pages_tail; + int obj_ptr; /* user objects counter */ + int sys_obj_ptr; /* system objects counter, including object streams */ + int last_pages; /* pointer to most recently generated pages object */ + int last_page; /* pointer to most recently generated page object */ + int last_stream; /* pointer to most recently generated stream */ + off_t stream_length; /* length of most recently generated stream */ + off_t stream_length_offset; /* file offset of the last stream length */ + int seek_write_length; /* flag whether to seek back and write \.{/Length} */ + int last_byte; /* byte most recently written to PDF file; for \.{endstream} in new line */ + + /* integer last_resources; halfword to most recently generated Resources object. + TH: this used to be a local in pdf_shipout, but I would like to + be able to split that function into a pre- and post part */ + + int obj_count; + int xform_count; + int ximage_count; + + pdf_resource_struct *page_resources; + + /* the variables from pdfdest */ + int dest_names_size; + int dest_names_ptr; + dest_name_entry *dest_names; + /* the (static) variables from pdfoutline */ + int first_outline; + int last_outline; + int parent_outline; + /* the pdf link stack */ + pdf_link_stack_record link_stack[(pdf_max_link_level + 1)]; + int link_stack_ptr; + /* the thread data */ + int last_thread; /* pointer to the last thread */ + scaled_whd thread; + int last_thread_id; /* identifier of the last thread */ + int last_thread_named_id; /* is identifier of the last thread named */ + int thread_level; /* depth of nesting of box containing the last thread */ + + int f_cur; /* TeX font number */ +} pdf_output_file; + +typedef pdf_output_file *PDF; + +#endif /* PDFTYPES_H */ diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfxform.h b/Build/source/texk/web2c/luatexdir/pdf/pdfxform.h new file mode 100644 index 00000000000..c117301ebe2 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdfxform.h @@ -0,0 +1,56 @@ +/* pdfxform.h + + Copyright 2009 Taco Hoekwater <taco@luatex.org> + + 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 <http://www.gnu.org/licenses/>. */ + +/* $Id: pdfxform.h 3261 2009-12-18 11:38:21Z taco $ */ + +#ifndef PDFXFORM_H +# define PDFXFORM_H + +/* data structure for \.{\\pdfxform} and \.{\\pdfrefxform} */ + +# define pdfmem_xform_size 6 /* size of memory in |pdf->mem| which |obj_data_ptr| holds */ + +# define set_pdf_xform_objnum(A,B) pdf_xform_objnum(A)=B + +# define obj_xform_width(pdf,A) pdf->mem[obj_data_ptr(pdf,A) + 0] +# define obj_xform_height(pdf,A) pdf->mem[obj_data_ptr(pdf,A) + 1] +# define obj_xform_depth(pdf,A) pdf->mem[obj_data_ptr(pdf,A) + 2] +# define obj_xform_box(pdf,A) pdf->mem[obj_data_ptr(pdf,A) + 3] /* this field holds + pointer to the corresponding box */ +# define obj_xform_attr(pdf,A) pdf->mem[obj_data_ptr(pdf,A) + 4] /* additional xform + attributes */ +# define obj_xform_resources(pdf,A) pdf->mem[obj_data_ptr(pdf,A) + 5] /* additional xform + Resources */ + + +# define set_obj_xform_width(pdf,A,B) obj_xform_width(pdf,A)=B +# define set_obj_xform_height(pdf,A,B) obj_xform_height(pdf,A)=B +# define set_obj_xform_depth(pdf,A,B) obj_xform_depth(pdf,A)=B +# define set_obj_xform_box(pdf,A,B) obj_xform_box(pdf,A)=B +# define set_obj_xform_attr(pdf,A,B) obj_xform_attr(pdf,A)=B +# define set_obj_xform_resources(pdf,A,B) obj_xform_resources(pdf,A)=B + +extern int pdf_cur_form; /* the form being output */ + +void pdf_place_form(PDF pdf, halfword p); + +void scan_pdfxform(PDF pdf); +void scan_pdfrefxform(PDF pdf); + +#endif diff --git a/Build/source/texk/web2c/luatexdir/pdf/pdfxform.w b/Build/source/texk/web2c/luatexdir/pdf/pdfxform.w new file mode 100644 index 00000000000..5f3b5802708 --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/pdf/pdfxform.w @@ -0,0 +1,128 @@ +% pdfxform.w + +% Copyright 2009-2010 Taco Hoekwater <taco@@luatex.org> + +% 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 <http://www.gnu.org/licenses/>. + +@ @c +static const char _svn_version[] = + "$Id: pdfxform.w 3571 2010-04-02 13:50:45Z taco $" + "$URL: http://foundry.supelec.fr/svn/luatex/tags/beta-0.60.0/source/texk/web2c/luatexdir/pdf/pdfxform.w $"; + +#include "ptexlib.h" + +@ @c +#include "pdf/pdfpage.h" + +@ @c +#define box(A) eqtb[box_base+(A)].hh.rh + +int pdf_cur_form; /* the form being output */ + +void pdf_place_form(PDF pdf, halfword p) +{ + scaled_whd nat, tex; + scaled x, y; + pdffloat cm[6]; + pdfstructure *q = pdf->pstruct; + int r = 6, objnum = pdf_xform_objnum(p); + nat.wd = obj_xform_width(pdf, objnum); + nat.ht = obj_xform_height(pdf, objnum); + nat.dp = obj_xform_depth(pdf, objnum); + /* no transform yet */ + tex.wd = width(p); + tex.ht = height(p); + tex.dp = depth(p); + if (nat.wd != tex.wd || nat.ht != tex.ht || nat.dp != tex.dp) { + x = ext_xn_over_d(ten_pow[r], tex.wd, nat.wd); + y = ext_xn_over_d(ten_pow[r], tex.dp + tex.ht, nat.dp + nat.ht); + } else + x = y = ten_pow[r]; + setpdffloat(cm[0], x, r); + setpdffloat(cm[1], 0, r); + setpdffloat(cm[2], 0, r); + setpdffloat(cm[3], y, r); + pdf_goto_pagemode(pdf); + (void) calc_pdfpos(q, pdf->posstruct->pos); + cm[4] = q->cm[4]; + cm[5] = q->cm[5]; + pdf_printf(pdf, "q\n"); + pdf_print_cm(pdf, cm); + pdf_printf(pdf, "/Fm%d", (int) obj_info(pdf, objnum)); + pdf_print_resname_prefix(pdf); + pdf_printf(pdf, " Do\nQ\n"); + addto_page_resources(pdf, obj_type_xform, objnum); +} + +@ @c +void scan_pdfxform(PDF pdf) +{ + int k; + halfword p; + incr(pdf->xform_count); + pdf_create_obj(pdf, obj_type_xform, pdf->xform_count); + k = pdf->obj_ptr; + set_obj_data_ptr(pdf, k, pdf_get_mem(pdf, pdfmem_xform_size)); + if (scan_keyword("attr")) { + scan_pdf_ext_toks(); + set_obj_xform_attr(pdf, k, def_ref); + } else { + set_obj_xform_attr(pdf, k, null); + } + if (scan_keyword("resources")) { + scan_pdf_ext_toks(); + set_obj_xform_resources(pdf, k, def_ref); + } else { + set_obj_xform_resources(pdf, k, null); + } + scan_int(); + p = box(cur_val); + if (p == null) + pdf_error("ext1", "\\pdfxform cannot be used with a void box"); + set_obj_xform_box(pdf, k, p); /* save pointer to the box */ + set_obj_xform_width(pdf, k, width(p)); + set_obj_xform_height(pdf, k, height(p)); + set_obj_xform_depth(pdf, k, depth(p)); + box(cur_val) = null; + pdf_last_xform = k; +} + +@ @c +#define tail cur_list.tail_field + +void scan_pdfrefxform(PDF pdf) +{ + int transform = 0; + scaled_whd alt_rule, dim, nat; + alt_rule = scan_alt_rule(); /* scans |<rule spec>| to |alt_rule| */ + scan_int(); + check_obj_exists(pdf, obj_type_xform, cur_val); + new_whatsit(pdf_refxform_node); + nat.wd = obj_xform_width(pdf, cur_val); + nat.ht = obj_xform_height(pdf, cur_val); + nat.dp = obj_xform_depth(pdf, cur_val); + if (alt_rule.wd != null_flag || alt_rule.ht != null_flag + || alt_rule.dp != null_flag) { + dim = tex_scale(nat, alt_rule); + } else { + dim = nat; + } + width(tail) = dim.wd; + height(tail) = dim.ht; + depth(tail) = dim.dp; + pdf_xform_transform(tail) = transform; /* not implemented yet */ + pdf_xform_objnum(tail) = cur_val; +} |