summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/luatexdir/pdf
diff options
context:
space:
mode:
authorTaco Hoekwater <taco@elvenkind.com>2010-04-04 13:55:46 +0000
committerTaco Hoekwater <taco@elvenkind.com>2010-04-04 13:55:46 +0000
commitf372862c42d234710b6057449b46818e63181c90 (patch)
treea9ebec66dd31ac37aed442502ebd1b9fe76245ec /Build/source/texk/web2c/luatexdir/pdf
parent2dad291ab056f30816e0aea61970f38033c2f6a5 (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')
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pagetree.h8
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pagetree.w (renamed from Build/source/texk/web2c/luatexdir/pdf/pagetree.c)155
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfaction.h78
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfaction.w207
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfannot.h37
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfannot.w99
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfcolorstack.h44
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfcolorstack.w386
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfdest.h66
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfdest.w417
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdffont.h48
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdffont.w495
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfgen.h239
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfgen.w2479
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfglyph.h30
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfglyph.w222
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfimage.h28
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfimage.w156
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdflink.h39
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdflink.w166
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdflistout.h50
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdflistout.w1139
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfliteral.h34
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfliteral.w154
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfobj.h66
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfobj.w214
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfoutline.h28
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfoutline.w240
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfpage.c561
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfpage.h67
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfpage.w292
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfrule.h27
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfrule.w70
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfsaverestore.h37
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfsaverestore.w88
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfsetmatrix.h52
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfsetmatrix.w238
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfshipout.h30
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfshipout.w332
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdftables.h136
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdftables.w456
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfthread.h71
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfthread.w290
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdftypes.h291
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfxform.h56
-rw-r--r--Build/source/texk/web2c/luatexdir/pdf/pdfxform.w128
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", &lt);
+ /* 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;
+}