diff options
Diffstat (limited to 'Build/source/texk/web2c/pdftexdir')
54 files changed, 25032 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/pdftexdir/ChangeLog b/Build/source/texk/web2c/pdftexdir/ChangeLog new file mode 100644 index 00000000000..a0a770ed962 --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/ChangeLog @@ -0,0 +1,104 @@ +2004-10-29 Jan Nieuwenhuizen <janneke@gnu.org> + + * pdftex.mk (pdftex): Build fix: pdftexextra.c depends on + pdftexextra.h. + +2004-09-07 The pdfTeX team: + + * README: pdftex version 1.20a. + + * NEWS: pdftex version 1.20a. + + * pdftex.ch: pdftex version 1.20a. + +2004-08-26 Olaf Weber <olaf@infovore.xs4all.nl> + + * pdftexlib.mk (pdftexdir/libpdf.a): Add pdftexdir/pdftexextra.h + to the dependencies, so it gets built before we go and try to + build the library. + + * pdftex.version: Is from now on a generated file. + + * pdftexextra.in: Renamed from pdftexextra.h; the current pdfTeX + version is substituted from pdftex.version. Variant of code + supplied by Peter Breitenlohner <peb@mppmu.mpg.de>. + + * pdftex.mk: Added rules to extract current pdfTeX version from + pdftex.ch and insert into pdftex.version and pdftexextra.h. + Variant of code supplied by Peter Breitenlohner + <peb@mppmu.mpg.de>. + +2004-08-25 Olaf Weber <olaf@infovore.xs4all.nl> + + * vadjust.ch: Moved here from pdfxtexdir. + + * pdftex.mk: vadjust.ch moved to this directory from pdfxtexdir. + +2004-08-23 Olaf Weber <olaf@infovore.xs4all.nl> + + * pdftex.mk: Scrap rules for pdftexinfo. These are obsolete. + + * pdftex.mak: Scrap rules for pdftexinfo. + +2004-08-06 Olaf Weber <olaf@infovore.xs4all.nl> + + * Makefile.in: The .cc.o suffix rule should use ALL_CXXFLAGS (as + is done for ALL_CFLAGS). From Jan Nieuwenhuizen + <janneke@gnu.org>. + +2004-07-29 Peter Breitenlohner <peb@mppmu.mpg.de> + + * pdftex.ch, hz.ch: Somewhat rearrange handling of kern and + math nodes in order to reduce interference between eTeX and + pdfTeX change files. Somewhat disentangle margin kerns such + that pdftex.web and pdfetex.web can be built with or without + hz.ch (not true for pdf*tex.ch). + +2004-07-25 Peter Breitenlohner <peb@mppmu.mpg.de> + + * pdftex.ch: Reorganize additional command codes for convert + and last_item in order to reduce interference between eTeX and + pdfTeX change files. + + * change-files.txt: Adjust to current status. + +2004-07-23 Peter Breitenlohner <peb@mppmu.mpg.de> + + * pdftex.ch, tex.ch[01], tex.pch: Reorganize handling of banner + string in order to reduce interference between eTeX, pdfTeX, + and web2c change files. + +2004-07-22 Peter Breitenlohner <peb@mppmu.mpg.de> + + * pdftex.ch: Removed unused token types for pdfTeX's additional + token list parameters. + +2004-07-19 Peter Breitenlohner <peb@mppmu.mpg.de> + + * hz.ch, pdftex.ch, tex.ch[01], tex.pch: Reorganize handling of + additional token list and integer parameters in order to reduce + interference between eTeX, pdfTeX, and web2c change files. + + * pdftex.ch: Add a note that this file not only defines pdftex.web + in terms of changes to be applies to tex.web, but in addition + is used to define pdfetex.web. + + * tex.pch: Add a note that this file is used to construct the + web2c change files for both pdfTeX and pfdeTeX. + + * pdftex.mk (pdftex.ch): Remove tex.ch2 from build rules. + + * tex.ch2: Removed + +2004-07-17 Peter Breitenlohner <peb@mppmu.mpg.de> + + * pdftex.mk: Rewrite build rules for pdftex.{web,ch}. + + * pdftex.ch: Adapt glue and leader box rounding to TeX 3.141592. + Remove a few modules that were identical copies of those in TeX. + +2004-07-16 Peter Breitenlohner <peb@mppmu.mpg.de> + + * ttf2afm.c: Add various const's, to avoid compiler warnings. + + * ChangeLog: New file. diff --git a/Build/source/texk/web2c/pdftexdir/Makefile.in b/Build/source/texk/web2c/pdftexdir/Makefile.in new file mode 100644 index 00000000000..631e10c9861 --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/Makefile.in @@ -0,0 +1,60 @@ +# Makefile for libpdf - te@dbs.uni-hannover.de +# $Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/Makefile.in#23 $ + +kpse_include ../make/common.mk +kpse_include ../make/programs.mk +kpse_include ../make/library.mk + +kpathsea_srcdir_parent = $(srcdir)/../.. +kpathsea_dir_parent = ../.. + +ALL_CXXFLAGS = @CXXFLAGS@ @DEFS@ $(XXCFLAGS) -I. -I$(srcdir) -I$(kpathsea_dir_parent) -I$(kpathsea_srcdir_parent) @LIBXPDFCPPFLAGS@ +CXX = @CXX@ + +.SUFFIXES: .cc .o +.cc.o: + $(CXX) $(ALL_CXXFLAGS) -c $< + +# XCFLAGS=-Wstrict-prototypes -Wmissing-prototypes + +LIBPNGDIR=../../../libs/libpng +LIBPNGSRCDIR=$(srcdir)/$(LIBPNGDIR) + +ZLIBDIR=../../../libs/zlib +ZLIBSRCDIR=$(srcdir)/$(ZLIBDIR) + +LIBXPDFDIR=../../../libs/xpdf +LIBXPDFSRCDIR=$(srcdir)/$(LIBXPDFDIR) + +LIBMD5DIR=../../../libs/md5 +LIBMD5SRCDIR=$(srcdir)/$(LIBMD5DIR) + +XCPPFLAGS=-I.. -I$(srcdir)/.. -I../.. -I$(srcdir)/../.. -I$(LIBMD5DIR) -I$(LIBMD5SRCDIR)\ +@LIBPNGCPPFLAGS@ @ZLIBCPPFLAGS@ -DpdfTeX + + +OBJS = epdf.o mapfile.o utils.o vfpacket.o pkin.o \ +writefont.o writet1.o writet3.o writezip.o writeenc.o writettf.o \ +writejpg.o writepng.o writeimg.o pdftoepdf.o avl.o avlstuff.o + +all: libpdf.a + +pdftosrc.o: $(srcdir)/pdftosrc.cc + +libpdf.a: $(OBJS) + rm -f $@ + $(AR) $(ARFLAGS) $@ $(OBJS) + $(RANLIB) $@ + +kpse_include ../make/clean.mk + +clean:: + rm -f libpdf.a ttf2afm pdftosrc + +depend: + rm -f $(OBJS) ttf2afm.o pdftosrc.o + XXCFLAGS=-MM XCFLAGS=-MM $(MAKE) -k $(OBJS) ttf2afm.o pdftosrc.o | \ + grep -v "^$(CC)\|$(CXX)\|$(AR)\|make\|klibtool" | \ + sed 's: [^ ]*/\.\./libs/[^ ]*::g' > $(srcdir)/depend.mk + +kpse_include pdftexdir/depend.mk diff --git a/Build/source/texk/web2c/pdftexdir/NEWS b/Build/source/texk/web2c/pdftexdir/NEWS new file mode 100644 index 00000000000..98e30db8b7f --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/NEWS @@ -0,0 +1,400 @@ +------------------------------------------------- +pdfTeX 3.141592-1.30.4 was released on 2005-10-17 +------------------------------------------------- +- bugfix: whitespaces in filenames didn't work on Unix anymore (bug 377) +- bugfix: two \immediates cancel themselves (bug 437) +- bugfix: wrong file name in error messages of image inclusion (bug 435) + +------------------------------------------------- +pdfTeX 3.141592-1.30.3 was released on 2005-09-04 +------------------------------------------------- +- bugfix: \write18 + +------------------------------------------------- +pdfTeX 3.141592-1.30.2 was released on 2005-08-25 +------------------------------------------------- +- fixed some build problems and minor bugs introduced in 1.30.1 + +------------------------------------------------- +pdfTeX 3.141592-1.30.1 was released on 2005-08-21 +------------------------------------------------- +- the eTeX extensions can now be enabled with the cmdline switch -etex +- pdfTeX uses xpdf 3.01 + +------------------------------------------------- +pdfTeX 3.141592-1.30.0 was released on 2005-08-01 +------------------------------------------------- +- pdfxtex (introduced with 1.20a) is gone; all extensions are now in pdf(e)tex. +- Some primitives have been renamed; the old names will still work, but are + deprecated and some give a warning that they are obsolete: + \pdfoptionpdfminorversion -> \pdfminorversion + \pdfoptionalwaysusepdfpagebox -> \pdfforcepagebox + \pdfoptionpdfinclusionerrorlevel -> \pdfinclusionerrorlevel +- pdftex knows two new units: + - new Didot (1nd=0.375mm) + - new Cicero (1nc=12nd) +- New primitives: + - Inclusion of pngs has been greatly improved: It now does + - alpha channel and transparency (only if %!PDF >=1.4) + - 16-bit colour (only if %!PDF >=1.5); this must be enabled by setting + \pdfimagehicolor to 1. + - gamma correction; this must be enabled by setting \pdfimageapplygamma to + 1. The device gamma is taken from \pdfgamma. If no embedded value can be + found in the png image, then the value of \pdfimagegamma is used instead. + - fast direct embedding of png streams, if their structure allows this; the + automatic fall-back is to decompress and re-compress as before. + - pdfTeX now has an interface to the precise system time (if available) as an + aid in benchmarking TeX macro code. + - \pdfelapsedtime is a read-only integer that (initially) returns the + amount of time passed since the start of this run. This amount is given + in `scaled seconds': the value 65536 counts as one second. If more time + has passed than 32767 seconds, (2^31)-1 will be returned. + - \pdfresettimer updates the internal timer, such that subsequent calls to + \pdfelapsedtime will restart from 0. + - pdfTeX can now generate random numbers: + - \pdfuniformdeviate <count> generates a uniformly distributed random + integer value between 0 (inclusive) and <count> (exclusive). + - \pdfnormaldeviate expands to a random integer value with a mean of 0 and + a unit of 65536. + - \pdfrandomseed allows access to the current seed value. + - \pdfsetrandomseed <count> sets the random seed to a specific value. + - \pdfnoligatures\f disables ligatures for the loaded font \f. + - Escaping strings: + - \pdfescapestring{<a>} escapes the string <a> so that it can be used as + PDF string. + - \pdfescapename{<a>} escapes the string <a> so that it can be used as PDF + name. + - \pdfescapehex{<a>} converts the string <a> to uppercase hexadecimal + representation. + - \pdfunescapehex{<b>} reverses the effect of \pdfescapehex + - \pdfcreationdate expands to the date string that pdfTeX uses in the info + dict as default. + - \pdffilemoddate{<file>} expands to the modification date of <file> in the + same format as \pdfcreationdate (PDF date format). + - \pdffilesize{<file>} expands to the size of <file> as string. + - \pdfmdfivesum{<abc>} or \pdfmdfivesum file {<file>} calculates the md5 + sum (of a string or a file) and converts it to uppercase hexadecimal format + (same as \pdfescapehex). + - \pdffiledump [offset <int>] [length <int>] <general text> + Expands to a hex dump of the file given in <general text>, starting at + given offset or 0 with given length. + - \pdfshellescape is a read-only integer that is 1 if \write18 is enabled, 0 + otherwise. + - \pdfxformname <object number>, which expands to the number in the + corresponding form XObject name. + - \leftmarginkern <box number> and \rightmarginkern <box number> tell the + margin kern at the left and right side of the horizontal list stored in box + <box number>. + - \pdfpkmode is a token register that sets the MF mode for pixel font + generation. The contents of this register is dumped into the format, so one + can (optionally) preset it e.g. in part of pdftexconfig.tex. + - \pdftracingfonts: An integer variable controlling the tracing of font + expansion. It is zero by default; then we get a log (with fontexpansion) + like this + ...\tenrm t + ...\tenrm (+20) e + Without font expansion, this default should be compatible with TeX's + original log output. + If \pdftracingfonts is set to 1 (or greater), we get a more verbose log: + ...\xivtt (cmtt10@14.0pt) t + ...\xivtt (cmtt10+20@14.0pt) e + See also bug 304. +- New experimental primitives: + - \pdfmatch [icase] [subcount <number>}] {<pattern>}{<string>} + Implements pattern matching using the POSIX regex. + It returns the same values as \pdfstrcmp, but with the following semantics: + -1: error case (invalid pattern, ...) + 0: no match + 1: match found + Options: + * icase: case insensitive matching + * subcount: it sets the table size for found subpatterns. + A number "-1" resets the table size to the start default. + - \pdflastmatch <number> + The result of \pdfmatch is stored in an array. The entry "0" contains the + match, the following entries submatches. The positions of the matches are + also available. They are encoded: + <position> "->" <match string> + The position "-1" with an empty string indicates that this entry is not + set. + - \pdfstrcmp{<a>}{<b>} compares two strings and returns the strings "0" if + <a> equals <b>, "-1" if <a> is less than <b>, "1" if <a> is greater than + <b> +- The primitive \pdfmovechars has been removed (bug 294) +- Bugfixes: + - empty strings are not supressed anymore (bug 335) + - \unhboxing and character protusion didn't work well together (bug 292) + - --jobname didn't work if there was no filename at all (bug 302) + - Some problem with fonts on solaris (bug 315) + - Dangling font objects with non-replacable fonts (bug 311). + - \pdfxform didn't work with box>255 (bug 310) + - cmap: unicode ???? is mapped to multiple glyphs (bug 306). +- pdfTeX uses zlib 1.2.3 + +------------------------------------------------ +pdfTeX 3.141592-1.21a was released on 2005-02-04 +------------------------------------------------ +- ttf2afm 1.0: + - added support for refering to glyphs via unicode in encoding files (ie 'uniXXX') + - added some more info to the AFM output + - some minor bug fixes + - a short documentation available +- pdftex now understand forms 'uniXXXX' in encoding files (only makes sense + with TrueType fonts) +- added subset tag for TrueType fonts +- PDF strings are now printed as following: + (This is a string) -> (This is a string) + This is a string -> (This is a string) + <a1b245c1a2...> -> <a1b245c1a2...> +- check for double newline char to get rid of empty lines in PDF output +- Fixed a bug in the scanning of map lines introduced in the fix of bug #242 in + 1.20b. +- Fixed three problems in xpdf; xpdf is now 3.00pl3 +- \ifeof18 is a simple method to test if \write18 is enabled. +- a few extensions in pdfxtex: + - \pdflastximagecolordepth returns the last color depth + - \pdfximage supports a keyword "colorspace" following an object number + representing a ColorSpace object + - \pdfstrcmp compares two strings + - \pdfescapestring/\pdflastescapedstring provide a way to escape string + - \pdffirstlineheight/\pdflastlinedepth/\pdfeachlineheight/\pdfeachlinedepth + allow fixing line dimen + - patches from Taco + - px dimen unit + - tagcode patch + - quitvmode patch + +------------------------------------------------ +pdfTeX 3.141592-1.20b was released on 2004-12-22 +------------------------------------------------ +- Fixed some minor bugs, mostly with hz +- The info line "output format initialized to PDF/DVI" isn't shown anymore, as + this info wasn't reliable (bug 112). +- Now the PDF-related statistics (PDF objects...) in the .log file is only + shown in PDF output mode. It start with a line "PDF statistics:". +- \pdfimageresolution is not limited to 2400 [dpi] anymore, can now be between + 0 and 65535 [dpi]. +- pdfTeX uses xpdf 3.00pl2 +- pdfTeX uses libpng 1.2.8, which fixes some png-related bugs. + +------------------------------------------------ +pdfTeX 3.141592-1.20a was released on 2004-09-06 +------------------------------------------------ +- There is a new program pdfxtex, which contains experimental features which + might end up in pdftex in the future. +- Most distributions now use eTeX as the default engine, so when you call + pdftex you will get pdfeTeX. Most distributions now also use pdfTeX as the + default engine, so when you call latex you will get pdfeTeX running LaTeX.:-) +- We are setting up pdfTeX as a project at sarovar + (http://sarovar.org/projects/pdftex/). Please report bugs etc. through the + site. +- Support for the file pdftex.cfg is gone completely. All parameters that had + previously been set by it can be set through primitives; their values are + dumped to the format file. +- The searchpath for encoding and mapfiles has been changed. + See http://tug.org/pipermail/tex-live/2004-January/004734.html and + http://tug.org/pipermail/tex-live/2004-January/004791.html +- eTeX is now version 2.2, incorporating the last changes to TeX (3.141592). +- New options for \pdfmapfile: + General functionality: Map items (map files, new: also single map lines; see + \pdfmapline) are put in list of pending map items. During the next shipout, + pending map items are sequentially scanned for their map entries, and an + internal map entry database is updated, using the modes below. Then the list + of pending map items is cleared. Map entries of fonts already in use are left + untouched. New: All \pdfmapfile and \pdfmapline commands can also be given + after shipout of the first page. + - \pdfmapfile {foo.map} clears the list of pending map items and starts a new + list with the only pending file foo.map. When the map entry lines of + foo.map are scanned, duplicate map entries are ignored and a warning is + issued. This is the old behaviour. + - \pdfmapfile {+foo.map} puts foo.map in the list of pending map items. When + the map entry lines of foo.map are scanned, duplicate map entries are + ignored and a warning is issued. + - \pdfmapfile {=foo.map} puts foo.map in the list of pending map items. When + foo.map is scanned, matching map entries in database are replaced by new + entries from foo.map. + - \pdfmapfile {-foo.map} puts foo.map in the list of pending map items. When + foo.map is scanned, matching map entries are deleted from database. + - \pdfmapfile {} clears the list of pending map items. It does not affect map + entries already registered into the database. This is the old behaviour. +- New command \pdfmapline {line}. It's like \pdfmapfile but here you can set + single map lines like in the map files directly. The modifiers (+-=) have the + same effect as with \pdfmapfile. +- Simplified the handling of the 14 Type 1 "standard fonts" (Times, + Helvetica...): They are now more or less handled like any other Type 1 font. + See http://www.ntg.nl/pipermail/ntg-pdftex/2004-July/000648.html +- hz: So far the font expansion feature required that the user must be able to + create expanded tfms (eg cmr10+10.tfm). Now font expansion can be used + without creating these tfms. + See http://www.ntg.nl/pipermail/ntg-pdftex/2004-May/000504.html +- hz: Changed \pdffontexpand primitive --> the expand factor is now fixed to + 1000 and the argument is ignored. This will lead to spurious texts of "1000" + in your output if you compile old documents. +- New command \pdftexbanner which returns a string with the full banner of the + current binary (e.g. "This is pdfTeX, Version 3.141592-1.20a (Web2C 7.5.3) + kpathsea version 3.5.3") +- The PTEX.FullBanner key is now inserted in the document info dict instead of + the catalog. Newer versions of Acrobat display it. +- Now includes support for encTeX. +- Extended \pdfannot to use reserveobjnum/useobjnum + See http://www.ntg.nl/pipermail/ntg-pdftex/2004-March/000424.html +- Bugfix: pdfTeX would read an .xpdfrc when including pdfs. + See http://tug.org/pipermail/pdftex/2004-March/004835.html +- Bugfix: The strings in /ID would sometimes be empty. +- Bugfix: Even when mapfiles or encodings or PostScript font files were + missing, pdfTeX still produced a (most often corrupt) pdf. Now it aborts with + an error in these cases. +- numerous small bugfixes. +- pdfTeX now uses the GNU libavl from Ben Pfaff for managing of fontmap + entries. +- pdfTeX uses zlib 1.2.1 +- pdfTeX uses xpdf 3.00 +- pdfTeX uses libpng 1.2.7 + +------------------------------------------------ +pdfTeX 3.141592-1.11b was released on 2003-10-06 +------------------------------------------------ +- Bugfix: The handling of /Rotate produced displaced images when /Rotate was 90 + or 270. + +------------------------------------------------ +pdfTeX 3.141592-1.11a was released on 2003-08-02 +------------------------------------------------ +- New command \pdftrailer analogue to \pdfcatalog whose argument ends up in the + trailer dictionary. +- The behaviour when an included pdf has a newer version than the one specified + with \pdfoptionpdfminorversion can be controlled by the new internal integer + \pdfoptionpdfinclusionerrorlevel: If it's 0, pdfTeX gives only a warning; if + it's 1, it raises an error. + This can also be set in pdftex.cfg with pdf_inclusion_errorlevel +- The syntax for outlines has been extended to allow attributes: + <outline spec> --> <attr spec> <action spec> [count <number>] <general text> + See http://www.ntg.nl/pipermail/ntg-pdftex/2003-June/000165.html +- The syntax of \pdfobj has been extended: + \pdfobj <object type spec> (h, v, m) + <object type spec> --> reserveobjnum + | [useobjnum <number>] [<attr spec>] [stream [<attr spec>]] <object contents> + <object contents> --> <file spec> + | <general text> + When the optional keyword `reserveobjnum' and `useobjnum' is not given, the + behaviour is unchanged. + See also http://tug.org/mailman/htdig/pdftex/2003-March/003814.html +- Bugfix: /CreationDate didn't care for the timezone and could be fooled. + See http://www.ntg.nl/pipermail/ntg-pdftex/2003-July/000223.html +- Bugfix: The translation of 8-bit characters in included pdfs that had their + eighth bit set sometimes got wrong because of a missing typecast. + See http://www.ntg.nl/pipermail/ntg-pdftex/2003-July/000216.html +- Bugfix: pdfTeX -ini would crash with a minimal file because it didn't read + it's config and so didn't know anything about fonts. + See http://tug.org/pipermail/pdftex/2003-July/004262.html +- Bugfix: \pdfstartlink would produce spurious /NewWindow entries. Also the + syntax of <action spec> and <goto-action spec> has been cleaned up. + See http://www.ntg.nl/pipermail/ntg-pdftex/2003-June/000167.html +- Bugfix: \pdffontattr was not used for T3 fonts. + See http://tug.org/pipermail/pdftex/2003-June/004127.html +- Bugfix: The cropbox of an included pdf would sometimes not be used. + See http://tug.org/pipermail/pdftex/2003-May/004037.html +- pdfTeX uses xpdf 2.02 + +------------------------------------------------ +pdfTeX 3.141592-1.10b was released on 2003-02-26 +------------------------------------------------ +- The numbers in transformation matrices are allways written with maximum + precision (see http://tug.org/pipermail/pdftex/2003-February/003596.html). +- Incorporated the new version of TeX: 3.141592 +- Bugfix: Numbers in pdfs would sometimes be just a wee bit of (changed + implementation of pdftoepdf.convertNumToPDF). +- Bugfix: When setting the /Producer, /Creator or /CreationDate keys with + /pdfinfo pdfTeX would also insert default values which caused duplicate keys + in the info dict (see + http://tug.org/pipermail/pdftex/2003-February/003524.html). +- The reading of mapfiles is much faster (see + http://tug.org/pipermail/pdftex/2002-July/002843.html). +- Bugfix: AR5 had problems with the CTM when displaying in "fit visible" mode + (see http://tug.org/pipermail/pdftex/2002-May/002688.html). +- Bugfix: str_in_str had wrong indices (see + http://tug.org/pipermail/pdftex/2002-March/002367.html). +- Bugfix: decimal_digits defaulted to 0, which caused problems with included + images when including pdfs (see + http://tug.org/pipermail/pdftex/2003-February/003518.html). + It now defaults to 4. +- Bugfix: the type of included images was decided based only on the extensions; + now pdfTeX looks for magic bytes at the start of files (see + http://tug.org/pipermail/pdftex/2003-February/003519.html) + +----------------------------------------------- +pdfTeX 3.14159-1.10a was released on 2003-01-16 +----------------------------------------------- +- pdfTeX is now able to produce pdf1.4 (which is also the default) and has + almost complete support for including pdf1.4 files: + - Additional attributes like MetaData are copied from included pdfs. + - Currently the Page Group attribute (see sections 7.3.6 and 7.5.5 of the pdf + 1.4 reference) of included pdfs is NOT copied (as we don't know how to + handle this when imposing pdfs). + This means including pdfs with transparency features will work as long as + the included pdf doesn't use Page Groups; if it does, the result might not + be what is expected (One application known to use Page Groups is Adobe + Illustrator v9++). The distributed pdfTeX binaries will give a warning + about any occurance of a Page Group in an included pdf and ignore the Page + Group (thus producing syntactically correct pdfs but probably not the + intended output). + Acrobat 5++ and newer versions of Jaws display files without Page Groups + correctly, so this might not really be a problem. + See pdftoepdf.cc for preprocessor flags which allow this behaviour to be + changed (copying the Page Group (most likely producing incorrect pdf) or + treating Page Groups as errors). +- The new primitive \pdfoptionpdfminorversion sets the pdf version of the + generated file and the latest allowed pdf version of included pdfs: + \pdfoptionpdfminorversion=3 + tells pdfTeX to set the pdf version to 1.3 and allows only included pdfs with + versions <= 1.3 . + The default for \pdfoptionpdfminorversion is 4 for pdf 1.4 + This must appear before any data is written to the generated pdf file, so + you should put it at the very start of your files. + This can also be set in pdftex.cfg with pdf_minorversion +- It is now possible to specify the pdf page box to use when including pdfs. + The syntax has been extended: + \pdfximage [<image attr spec>] <general text> (h, v, m) + <image attr spec> --> [<rule spec>] [<attr spec>] [<page spec>] [<pdf box spec>] + <pdf box spec> --> mediabox|cropbox|bleedbox|trimbox|artbox + The default is cropbox (which defaults to mediabox), to be compatible with + previous versions of pdfTeX. + The page box specified at \pdfximage can be globally overridden with the + config parameter always_use_pdfpagebox and the command + \pdfoptionalwaysusepdfpagebox <integer>, where 0 is the default (use whatever + is specified with \pdfximage), 1 is media, 2 is crop, 3 is bleed, 4 is trim + and 5 is artbox. This can only be set once per object, i.e. the value used at + \pdfximage is remembered. + See the pdf reference for an explanation of the boxes. +- The support for the inclusion of jpeg images has been extended to allow the + inclusion of JPEG/Exif files which are produced by digital photo cameras + (thanks to Hartmut Henkel). +- The support for the inclusion of tif images has been removed as it was of + limited use (it worked only for gray-scale and rgb images) and produced wrong + results (all other images types where treated as rgb images). + Tif images can be converted on *nix on-the-fly to pngs with the help of + ImageMagick, epstopdf.sty or pdftex.def v0.4 or newer, and this rule: + \DeclareGraphicsRule{.tif}{png}{.png}{`convert #1 `basename #1 .tif`.png} +- The extensions for pdf encryption have been removed, since they make the + pdfTeX code overly complex. Those needing pdf encryption are encouraged to + produce a standalone program for encrypting pdfs. +- pdfTeX now writes a usage statistic about the pdfTeX specific memory to the + log. +- numerous bugfixes, most of them in the inclusion of pdfs. +- pdfTeX uses xpdf 2.01 +- pdfTeX uses libpng 1.2.5 + +--------------------------------------------------------------------- +pdfTeX 3.14159-1.00a-pretest-20011127-ojmw was released on 2002-01-29 +--------------------------------------------------------------------- + +---------------------------------------------------------------- +pdfTeX 3.14159-1.00a-pretest-20010806 was released on 2001-08-06 +---------------------------------------------------------------- + +---------------------------------------------------------------- +pdfTeX 3.14159-1.00a-pretest-20010804 was released on 2001-08-04 +---------------------------------------------------------------- + +$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/NEWS#88 $ +// vim: tw=79:ts=2:expandtab:autoindent diff --git a/Build/source/texk/web2c/pdftexdir/README b/Build/source/texk/web2c/pdftexdir/README new file mode 100644 index 00000000000..c56f359cbbe --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/README @@ -0,0 +1,90 @@ +pdfTeX +====== + +README for version 3.14159-1.30.4 of $Date: 2005/10/17 $ +======================================================== + +This directory contains the version 1.30.4 of pdfTeX, an extended version of +TeX that can create PDF directly from TeX source files and enhance the +result of TeX typesetting with the help of PDF. When PDF output is not +selected, pdfTeX produces normal DVI output, otherwise it produces PDF +output that looks identical to the DVI output. An important aspect of this +project is to investigate alternative justification algorithms, optionally +making use of multiple master fonts. + +pdfeTeX is an even more extended version of TeX than pdfTeX because it is +not based on TeX but on eTeX, an extended version of TeX. + +pdfTeX is based on the original TeX sources and Web2c, and has been +successfully compiled on Unix, Win32 and DOS systems. It is still under +development and features may change; it produces reasonable PDF code. + +See the file NEWS for changes to the program. + +Documentation about pdfTeX can be found at http://www.pdftex.org + +There is also a mailing list on pdfTeX; go to +http://tug.org/mailman/listinfo/pdftex for more information about it. Its +searchable archive can be found at http://tug.org/pipermail/pdftex/ +Please read http://www.catb.org/~esr/faqs/smart-questions.html before +asking any questions on the pdfTeX mailing list. + +A mailing list for the developement of pdfTeX can be found at +http://www.ntg.nl/mailman/listinfo/ntg-pdftex + + +LEGAL ISSUES +============ + +pdfTeX is copyright (c) 1996-2005 Han The Thanh, <thanh@pdftex.org> + +pdfTeX 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. + +pdfTeX 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 General Public License for more +details. + +You should have received a copy of the GNU General Public License along +with pdfTeX; if not, write to the Free Software Foundation, Inc., 59 Temple +Place, Suite 330, Boston, MA 02111-1307 USA + +pdfTeX uses code from TeX; for these parts the original copyright by Don +Knuth applies. See the source files for details. + +pdfeTeX uses code from eTeX; for these parts the original copyright by +Peter Breitenlohner applies. See the source files for details. + + +WHAT TO DO IF YOU BELIEVE YOU HAVE FOUND A BUG IN pdfTeX +======================================================== + +Please read http://www.chiark.greenend.org.uk/~sgtatham/bugs.html and +follow the guidelines there. Then go to the sarovar site of pdfTeX +(http://sarovar.org/projects/pdftex/) and submit your bug report there. +Here you can also report feature requests or patches. + + +CONTRIBUTORS +============ + +Peter Breitenlohner, Ricardo Sanchez Carmenes, Otfried Cheong, Thomas +Esser, Hans Hagen, Hartmut Henkel, Taco Hoekwater, Pawel Jackowski, Tom +Kacvinsky, Akira Kakuto, Reinhard Kotucha, Derek B. Noonburg, Heiko +Oberdiek, Jiri Osoba, Fabrice Popineau, Sebastian Rahtz, Tomas Rokicki, +Martin Schröder, Petr Sojka, Olaf Weber, Jiri Zlatuska. + +pdfTeX is built on top of TeX, written by Donald Knuth cum suis (Liang and +so), and eTeX, written by Peter Breitenlohner cum suis; part of the +paragraph optimization is inspired by the work of Hermann Zapf. + + +------------------------------------------------------------------------------ + +Please send bug reports, offers of help, etc. to martin@pdftex.org + +$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/README#33 $ +// vim: tw=75 diff --git a/Build/source/texk/web2c/pdftexdir/avl.c b/Build/source/texk/web2c/pdftexdir/avl.c new file mode 100644 index 00000000000..7b6bc17eac0 --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/avl.c @@ -0,0 +1,890 @@ +/* Produced by texiweb from libavl.w on 2003/01/06 at 18:07. */ + +/* libavl - library for manipulation of binary trees. + Copyright (C) 1998-2002 Free Software Foundation, Inc. + + This program 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. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. + + The author may be contacted at <blp@gnu.org> on the Internet, or + write to Ben Pfaff, Stanford University, Computer Science Dept., 353 + Serra Mall, Stanford CA 94305, USA. +*/ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "avl.h" + +/* Creates and returns a new table + with comparison function |compare| using parameter |param| + and memory allocator |allocator|. + Returns |NULL| if memory allocation failed. */ +struct avl_table * +avl_create (avl_comparison_func *compare, void *param, + struct libavl_allocator *allocator) +{ + struct avl_table *tree; + + assert (compare != NULL); + + if (allocator == NULL) + allocator = &avl_allocator_default; + + tree = allocator->libavl_malloc (allocator, sizeof *tree); + if (tree == NULL) + return NULL; + + tree->avl_root = NULL; + tree->avl_compare = compare; + tree->avl_param = param; + tree->avl_alloc = allocator; + tree->avl_count = 0; + tree->avl_generation = 0; + + return tree; +} + +/* Search |tree| for an item matching |item|, and return it if found. + Otherwise return |NULL|. */ +void * +avl_find (const struct avl_table *tree, const void *item) +{ + const struct avl_node *p; + + assert (tree != NULL && item != NULL); + for (p = tree->avl_root; p != NULL; ) + { + int cmp = tree->avl_compare (item, p->avl_data, tree->avl_param); + + if (cmp < 0) + p = p->avl_link[0]; + else if (cmp > 0) + p = p->avl_link[1]; + else /* |cmp == 0| */ + return p->avl_data; + } + + return NULL; +} + +/* Inserts |item| into |tree| and returns a pointer to |item|'s address. + If a duplicate item is found in the tree, + returns a pointer to the duplicate without inserting |item|. + Returns |NULL| in case of memory allocation failure. */ +void ** +avl_probe (struct avl_table *tree, void *item) +{ + struct avl_node *y, *z; /* Top node to update balance factor, and parent. */ + struct avl_node *p, *q; /* Iterator, and parent. */ + struct avl_node *n; /* Newly inserted node. */ + struct avl_node *w; /* New root of rebalanced subtree. */ + int dir; /* Direction to descend. */ + + unsigned char da[AVL_MAX_HEIGHT]; /* Cached comparison results. */ + int k = 0; /* Number of cached results. */ + + assert (tree != NULL && item != NULL); + + z = (struct avl_node *) &tree->avl_root; + y = tree->avl_root; + dir = 0; + for (q = z, p = y; p != NULL; q = p, p = p->avl_link[dir]) + { + int cmp = tree->avl_compare (item, p->avl_data, tree->avl_param); + if (cmp == 0) + return &p->avl_data; + + if (p->avl_balance != 0) + z = q, y = p, k = 0; + da[k++] = dir = cmp > 0; + } + + n = q->avl_link[dir] = + tree->avl_alloc->libavl_malloc (tree->avl_alloc, sizeof *n); + if (n == NULL) + return NULL; + + tree->avl_count++; + n->avl_data = item; + n->avl_link[0] = n->avl_link[1] = NULL; + n->avl_balance = 0; + if (y == NULL) + return &n->avl_data; + + for (p = y, k = 0; p != n; p = p->avl_link[da[k]], k++) + if (da[k] == 0) + p->avl_balance--; + else + p->avl_balance++; + + if (y->avl_balance == -2) + { + struct avl_node *x = y->avl_link[0]; + if (x->avl_balance == -1) + { + w = x; + y->avl_link[0] = x->avl_link[1]; + x->avl_link[1] = y; + x->avl_balance = y->avl_balance = 0; + } + else + { + assert (x->avl_balance == +1); + w = x->avl_link[1]; + x->avl_link[1] = w->avl_link[0]; + w->avl_link[0] = x; + y->avl_link[0] = w->avl_link[1]; + w->avl_link[1] = y; + if (w->avl_balance == -1) + x->avl_balance = 0, y->avl_balance = +1; + else if (w->avl_balance == 0) + x->avl_balance = y->avl_balance = 0; + else /* |w->avl_balance == +1| */ + x->avl_balance = -1, y->avl_balance = 0; + w->avl_balance = 0; + } + } + else if (y->avl_balance == +2) + { + struct avl_node *x = y->avl_link[1]; + if (x->avl_balance == +1) + { + w = x; + y->avl_link[1] = x->avl_link[0]; + x->avl_link[0] = y; + x->avl_balance = y->avl_balance = 0; + } + else + { + assert (x->avl_balance == -1); + w = x->avl_link[0]; + x->avl_link[0] = w->avl_link[1]; + w->avl_link[1] = x; + y->avl_link[1] = w->avl_link[0]; + w->avl_link[0] = y; + if (w->avl_balance == +1) + x->avl_balance = 0, y->avl_balance = -1; + else if (w->avl_balance == 0) + x->avl_balance = y->avl_balance = 0; + else /* |w->avl_balance == -1| */ + x->avl_balance = +1, y->avl_balance = 0; + w->avl_balance = 0; + } + } + else + return &n->avl_data; + z->avl_link[y != z->avl_link[0]] = w; + + tree->avl_generation++; + return &n->avl_data; +} + +/* Inserts |item| into |table|. + Returns |NULL| if |item| was successfully inserted + or if a memory allocation error occurred. + Otherwise, returns the duplicate item. */ +void * +avl_insert (struct avl_table *table, void *item) +{ + void **p = avl_probe (table, item); + return p == NULL || *p == item ? NULL : *p; +} + +/* Inserts |item| into |table|, replacing any duplicate item. + Returns |NULL| if |item| was inserted without replacing a duplicate, + or if a memory allocation error occurred. + Otherwise, returns the item that was replaced. */ +void * +avl_replace (struct avl_table *table, void *item) +{ + void **p = avl_probe (table, item); + if (p == NULL || *p == item) + return NULL; + else + { + void *r = *p; + *p = item; + return r; + } +} + +/* Deletes from |tree| and returns an item matching |item|. + Returns a null pointer if no matching item found. */ +void * +avl_delete (struct avl_table *tree, const void *item) +{ + /* Stack of nodes. */ + struct avl_node *pa[AVL_MAX_HEIGHT]; /* Nodes. */ + unsigned char da[AVL_MAX_HEIGHT]; /* |avl_link[]| indexes. */ + int k; /* Stack pointer. */ + + struct avl_node *p; /* Traverses tree to find node to delete. */ + int cmp; /* Result of comparison between |item| and |p|. */ + + assert (tree != NULL && item != NULL); + + k = 0; + p = (struct avl_node *) &tree->avl_root; + for (cmp = -1; cmp != 0; + cmp = tree->avl_compare (item, p->avl_data, tree->avl_param)) + { + int dir = cmp > 0; + + pa[k] = p; + da[k++] = dir; + + p = p->avl_link[dir]; + if (p == NULL) + return NULL; + } + item = p->avl_data; + + if (p->avl_link[1] == NULL) + pa[k - 1]->avl_link[da[k - 1]] = p->avl_link[0]; + else + { + struct avl_node *r = p->avl_link[1]; + if (r->avl_link[0] == NULL) + { + r->avl_link[0] = p->avl_link[0]; + r->avl_balance = p->avl_balance; + pa[k - 1]->avl_link[da[k - 1]] = r; + da[k] = 1; + pa[k++] = r; + } + else + { + struct avl_node *s; + int j = k++; + + for (;;) + { + da[k] = 0; + pa[k++] = r; + s = r->avl_link[0]; + if (s->avl_link[0] == NULL) + break; + + r = s; + } + + s->avl_link[0] = p->avl_link[0]; + r->avl_link[0] = s->avl_link[1]; + s->avl_link[1] = p->avl_link[1]; + s->avl_balance = p->avl_balance; + + pa[j - 1]->avl_link[da[j - 1]] = s; + da[j] = 1; + pa[j] = s; + } + } + + tree->avl_alloc->libavl_free (tree->avl_alloc, p); + + assert (k > 0); + while (--k > 0) + { + struct avl_node *y = pa[k]; + + if (da[k] == 0) + { + y->avl_balance++; + if (y->avl_balance == +1) + break; + else if (y->avl_balance == +2) + { + struct avl_node *x = y->avl_link[1]; + if (x->avl_balance == -1) + { + struct avl_node *w; + assert (x->avl_balance == -1); + w = x->avl_link[0]; + x->avl_link[0] = w->avl_link[1]; + w->avl_link[1] = x; + y->avl_link[1] = w->avl_link[0]; + w->avl_link[0] = y; + if (w->avl_balance == +1) + x->avl_balance = 0, y->avl_balance = -1; + else if (w->avl_balance == 0) + x->avl_balance = y->avl_balance = 0; + else /* |w->avl_balance == -1| */ + x->avl_balance = +1, y->avl_balance = 0; + w->avl_balance = 0; + pa[k - 1]->avl_link[da[k - 1]] = w; + } + else + { + y->avl_link[1] = x->avl_link[0]; + x->avl_link[0] = y; + pa[k - 1]->avl_link[da[k - 1]] = x; + if (x->avl_balance == 0) + { + x->avl_balance = -1; + y->avl_balance = +1; + break; + } + else + x->avl_balance = y->avl_balance = 0; + } + } + } + else + { + y->avl_balance--; + if (y->avl_balance == -1) + break; + else if (y->avl_balance == -2) + { + struct avl_node *x = y->avl_link[0]; + if (x->avl_balance == +1) + { + struct avl_node *w; + assert (x->avl_balance == +1); + w = x->avl_link[1]; + x->avl_link[1] = w->avl_link[0]; + w->avl_link[0] = x; + y->avl_link[0] = w->avl_link[1]; + w->avl_link[1] = y; + if (w->avl_balance == -1) + x->avl_balance = 0, y->avl_balance = +1; + else if (w->avl_balance == 0) + x->avl_balance = y->avl_balance = 0; + else /* |w->avl_balance == +1| */ + x->avl_balance = -1, y->avl_balance = 0; + w->avl_balance = 0; + pa[k - 1]->avl_link[da[k - 1]] = w; + } + else + { + y->avl_link[0] = x->avl_link[1]; + x->avl_link[1] = y; + pa[k - 1]->avl_link[da[k - 1]] = x; + if (x->avl_balance == 0) + { + x->avl_balance = +1; + y->avl_balance = -1; + break; + } + else + x->avl_balance = y->avl_balance = 0; + } + } + } + } + + tree->avl_count--; + tree->avl_generation++; + return (void *) item; +} + +/* Refreshes the stack of parent pointers in |trav| + and updates its generation number. */ +static void +trav_refresh (struct avl_traverser *trav) +{ + assert (trav != NULL); + + trav->avl_generation = trav->avl_table->avl_generation; + + if (trav->avl_node != NULL) + { + avl_comparison_func *cmp = trav->avl_table->avl_compare; + void *param = trav->avl_table->avl_param; + struct avl_node *node = trav->avl_node; + struct avl_node *i; + + trav->avl_height = 0; + for (i = trav->avl_table->avl_root; i != node; ) + { + assert (trav->avl_height < AVL_MAX_HEIGHT); + assert (i != NULL); + + trav->avl_stack[trav->avl_height++] = i; + i = i->avl_link[cmp (node->avl_data, i->avl_data, param) > 0]; + } + } +} + +/* Initializes |trav| for use with |tree| + and selects the null node. */ +void +avl_t_init (struct avl_traverser *trav, struct avl_table *tree) +{ + trav->avl_table = tree; + trav->avl_node = NULL; + trav->avl_height = 0; + trav->avl_generation = tree->avl_generation; +} + +/* Initializes |trav| for |tree| + and selects and returns a pointer to its least-valued item. + Returns |NULL| if |tree| contains no nodes. */ +void * +avl_t_first (struct avl_traverser *trav, struct avl_table *tree) +{ + struct avl_node *x; + + assert (tree != NULL && trav != NULL); + + trav->avl_table = tree; + trav->avl_height = 0; + trav->avl_generation = tree->avl_generation; + + x = tree->avl_root; + if (x != NULL) + while (x->avl_link[0] != NULL) + { + assert (trav->avl_height < AVL_MAX_HEIGHT); + trav->avl_stack[trav->avl_height++] = x; + x = x->avl_link[0]; + } + trav->avl_node = x; + + return x != NULL ? x->avl_data : NULL; +} + +/* Initializes |trav| for |tree| + and selects and returns a pointer to its greatest-valued item. + Returns |NULL| if |tree| contains no nodes. */ +void * +avl_t_last (struct avl_traverser *trav, struct avl_table *tree) +{ + struct avl_node *x; + + assert (tree != NULL && trav != NULL); + + trav->avl_table = tree; + trav->avl_height = 0; + trav->avl_generation = tree->avl_generation; + + x = tree->avl_root; + if (x != NULL) + while (x->avl_link[1] != NULL) + { + assert (trav->avl_height < AVL_MAX_HEIGHT); + trav->avl_stack[trav->avl_height++] = x; + x = x->avl_link[1]; + } + trav->avl_node = x; + + return x != NULL ? x->avl_data : NULL; +} + +/* Searches for |item| in |tree|. + If found, initializes |trav| to the item found and returns the item + as well. + If there is no matching item, initializes |trav| to the null item + and returns |NULL|. */ +void * +avl_t_find (struct avl_traverser *trav, struct avl_table *tree, void *item) +{ + struct avl_node *p, *q; + + assert (trav != NULL && tree != NULL && item != NULL); + trav->avl_table = tree; + trav->avl_height = 0; + trav->avl_generation = tree->avl_generation; + for (p = tree->avl_root; p != NULL; p = q) + { + int cmp = tree->avl_compare (item, p->avl_data, tree->avl_param); + + if (cmp < 0) + q = p->avl_link[0]; + else if (cmp > 0) + q = p->avl_link[1]; + else /* |cmp == 0| */ + { + trav->avl_node = p; + return p->avl_data; + } + + assert (trav->avl_height < AVL_MAX_HEIGHT); + trav->avl_stack[trav->avl_height++] = p; + } + + trav->avl_height = 0; + trav->avl_node = NULL; + return NULL; +} + +/* Attempts to insert |item| into |tree|. + If |item| is inserted successfully, it is returned and |trav| is + initialized to its location. + If a duplicate is found, it is returned and |trav| is initialized to + its location. No replacement of the item occurs. + If a memory allocation failure occurs, |NULL| is returned and |trav| + is initialized to the null item. */ +void * +avl_t_insert (struct avl_traverser *trav, struct avl_table *tree, void *item) +{ + void **p; + + assert (trav != NULL && tree != NULL && item != NULL); + + p = avl_probe (tree, item); + if (p != NULL) + { + trav->avl_table = tree; + trav->avl_node = + ((struct avl_node *) + ((char *) p - offsetof (struct avl_node, avl_data))); + trav->avl_generation = tree->avl_generation - 1; + return *p; + } + else + { + avl_t_init (trav, tree); + return NULL; + } +} + +/* Initializes |trav| to have the same current node as |src|. */ +void * +avl_t_copy (struct avl_traverser *trav, const struct avl_traverser *src) +{ + assert (trav != NULL && src != NULL); + + if (trav != src) + { + trav->avl_table = src->avl_table; + trav->avl_node = src->avl_node; + trav->avl_generation = src->avl_generation; + if (trav->avl_generation == trav->avl_table->avl_generation) + { + trav->avl_height = src->avl_height; + memcpy (trav->avl_stack, (const void *) src->avl_stack, + sizeof *trav->avl_stack * trav->avl_height); + } + } + + return trav->avl_node != NULL ? trav->avl_node->avl_data : NULL; +} + +/* Returns the next data item in inorder + within the tree being traversed with |trav|, + or if there are no more data items returns |NULL|. */ +void * +avl_t_next (struct avl_traverser *trav) +{ + struct avl_node *x; + + assert (trav != NULL); + + if (trav->avl_generation != trav->avl_table->avl_generation) + trav_refresh (trav); + + x = trav->avl_node; + if (x == NULL) + { + return avl_t_first (trav, trav->avl_table); + } + else if (x->avl_link[1] != NULL) + { + assert (trav->avl_height < AVL_MAX_HEIGHT); + trav->avl_stack[trav->avl_height++] = x; + x = x->avl_link[1]; + + while (x->avl_link[0] != NULL) + { + assert (trav->avl_height < AVL_MAX_HEIGHT); + trav->avl_stack[trav->avl_height++] = x; + x = x->avl_link[0]; + } + } + else + { + struct avl_node *y; + + do + { + if (trav->avl_height == 0) + { + trav->avl_node = NULL; + return NULL; + } + + y = x; + x = trav->avl_stack[--trav->avl_height]; + } + while (y == x->avl_link[1]); + } + trav->avl_node = x; + + return x->avl_data; +} + +/* Returns the previous data item in inorder + within the tree being traversed with |trav|, + or if there are no more data items returns |NULL|. */ +void * +avl_t_prev (struct avl_traverser *trav) +{ + struct avl_node *x; + + assert (trav != NULL); + + if (trav->avl_generation != trav->avl_table->avl_generation) + trav_refresh (trav); + + x = trav->avl_node; + if (x == NULL) + { + return avl_t_last (trav, trav->avl_table); + } + else if (x->avl_link[0] != NULL) + { + assert (trav->avl_height < AVL_MAX_HEIGHT); + trav->avl_stack[trav->avl_height++] = x; + x = x->avl_link[0]; + + while (x->avl_link[1] != NULL) + { + assert (trav->avl_height < AVL_MAX_HEIGHT); + trav->avl_stack[trav->avl_height++] = x; + x = x->avl_link[1]; + } + } + else + { + struct avl_node *y; + + do + { + if (trav->avl_height == 0) + { + trav->avl_node = NULL; + return NULL; + } + + y = x; + x = trav->avl_stack[--trav->avl_height]; + } + while (y == x->avl_link[0]); + } + trav->avl_node = x; + + return x->avl_data; +} + +/* Returns |trav|'s current item. */ +void * +avl_t_cur (struct avl_traverser *trav) +{ + assert (trav != NULL); + + return trav->avl_node != NULL ? trav->avl_node->avl_data : NULL; +} + +/* Replaces the current item in |trav| by |new| and returns the item replaced. + |trav| must not have the null item selected. + The new item must not upset the ordering of the tree. */ +void * +avl_t_replace (struct avl_traverser *trav, void *new) +{ + void *old; + + assert (trav != NULL && trav->avl_node != NULL && new != NULL); + old = trav->avl_node->avl_data; + trav->avl_node->avl_data = new; + return old; +} + +static void +copy_error_recovery (struct avl_node **stack, int height, + struct avl_table *new, avl_item_func *destroy) +{ + assert (stack != NULL && height >= 0 && new != NULL); + + for (; height > 2; height -= 2) + stack[height - 1]->avl_link[1] = NULL; + avl_destroy (new, destroy); +} + +/* Copies |org| to a newly created tree, which is returned. + If |copy != NULL|, each data item in |org| is first passed to |copy|, + and the return values are inserted into the tree, + with |NULL| return values taken as indications of failure. + On failure, destroys the partially created new tree, + applying |destroy|, if non-null, to each item in the new tree so far, + and returns |NULL|. + If |allocator != NULL|, it is used for allocation in the new tree. + Otherwise, the same allocator used for |org| is used. */ +struct avl_table * +avl_copy (const struct avl_table *org, avl_copy_func *copy, + avl_item_func *destroy, struct libavl_allocator *allocator) +{ + struct avl_node *stack[2 * (AVL_MAX_HEIGHT + 1)]; + int height = 0; + + struct avl_table *new; + const struct avl_node *x; + struct avl_node *y; + + assert (org != NULL); + new = avl_create (org->avl_compare, org->avl_param, + allocator != NULL ? allocator : org->avl_alloc); + if (new == NULL) + return NULL; + new->avl_count = org->avl_count; + if (new->avl_count == 0) + return new; + + x = (const struct avl_node *) &org->avl_root; + y = (struct avl_node *) &new->avl_root; + for (;;) + { + while (x->avl_link[0] != NULL) + { + assert (height < 2 * (AVL_MAX_HEIGHT + 1)); + + y->avl_link[0] = + new->avl_alloc->libavl_malloc (new->avl_alloc, + sizeof *y->avl_link[0]); + if (y->avl_link[0] == NULL) + { + if (y != (struct avl_node *) &new->avl_root) + { + y->avl_data = NULL; + y->avl_link[1] = NULL; + } + + copy_error_recovery (stack, height, new, destroy); + return NULL; + } + + stack[height++] = (struct avl_node *) x; + stack[height++] = y; + x = x->avl_link[0]; + y = y->avl_link[0]; + } + y->avl_link[0] = NULL; + + for (;;) + { + y->avl_balance = x->avl_balance; + if (copy == NULL) + y->avl_data = x->avl_data; + else + { + y->avl_data = copy (x->avl_data, org->avl_param); + if (y->avl_data == NULL) + { + y->avl_link[1] = NULL; + copy_error_recovery (stack, height, new, destroy); + return NULL; + } + } + + if (x->avl_link[1] != NULL) + { + y->avl_link[1] = + new->avl_alloc->libavl_malloc (new->avl_alloc, + sizeof *y->avl_link[1]); + if (y->avl_link[1] == NULL) + { + copy_error_recovery (stack, height, new, destroy); + return NULL; + } + + x = x->avl_link[1]; + y = y->avl_link[1]; + break; + } + else + y->avl_link[1] = NULL; + + if (height <= 2) + return new; + + y = stack[--height]; + x = stack[--height]; + } + } +} + +/* Frees storage allocated for |tree|. + If |destroy != NULL|, applies it to each data item in inorder. */ +void +avl_destroy (struct avl_table *tree, avl_item_func *destroy) +{ + struct avl_node *p, *q; + + assert (tree != NULL); + + for (p = tree->avl_root; p != NULL; p = q) + if (p->avl_link[0] == NULL) + { + q = p->avl_link[1]; + if (destroy != NULL && p->avl_data != NULL) + destroy (p->avl_data, tree->avl_param); + tree->avl_alloc->libavl_free (tree->avl_alloc, p); + } + else + { + q = p->avl_link[0]; + p->avl_link[0] = q->avl_link[1]; + q->avl_link[1] = p; + } + + tree->avl_alloc->libavl_free (tree->avl_alloc, tree); +} + +/* Allocates |size| bytes of space using |malloc()|. + Returns a null pointer if allocation fails. */ +void * +avl_malloc (struct libavl_allocator *allocator, size_t size) +{ + assert (allocator != NULL && size > 0); + return malloc (size); +} + +/* Frees |block|. */ +void +avl_free (struct libavl_allocator *allocator, void *block) +{ + assert (allocator != NULL && block != NULL); + free (block); +} + +/* Default memory allocator that uses |malloc()| and |free()|. */ +struct libavl_allocator avl_allocator_default = + { + avl_malloc, + avl_free + }; + +#undef NDEBUG +#include <assert.h> + +/* Asserts that |avl_insert()| succeeds at inserting |item| into |table|. */ +void +(avl_assert_insert) (struct avl_table *table, void *item) +{ + void **p = avl_probe (table, item); + assert (p != NULL && *p == item); +} + +/* Asserts that |avl_delete()| really removes |item| from |table|, + and returns the removed item. */ +void * +(avl_assert_delete) (struct avl_table *table, void *item) +{ + void *p = avl_delete (table, item); + assert (p != NULL); + return p; +} + diff --git a/Build/source/texk/web2c/pdftexdir/avl.h b/Build/source/texk/web2c/pdftexdir/avl.h new file mode 100644 index 00000000000..446a11a0ba9 --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/avl.h @@ -0,0 +1,123 @@ +/* Produced by texiweb from libavl.w on 2003/01/06 at 18:07. */ + +/* libavl - library for manipulation of binary trees. + Copyright (C) 1998-2002 Free Software Foundation, Inc. + + This program 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. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. + + The author may be contacted at <blp@gnu.org> on the Internet, or + write to Ben Pfaff, Stanford University, Computer Science Dept., 353 + Serra Mall, Stanford CA 94305, USA. +*/ + +#ifndef AVL_H +#define AVL_H 1 + +#include <stddef.h> +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Function types. */ +typedef int avl_comparison_func (const void *avl_a, const void *avl_b, + void *avl_param); +typedef void avl_item_func (void *avl_item, void *avl_param); +typedef void *avl_copy_func (void *avl_item, void *avl_param); + +#ifndef LIBAVL_ALLOCATOR +#define LIBAVL_ALLOCATOR +/* Memory allocator. */ +struct libavl_allocator + { + void *(*libavl_malloc) (struct libavl_allocator *, size_t libavl_size); + void (*libavl_free) (struct libavl_allocator *, void *libavl_block); + }; +#endif + +/* Default memory allocator. */ +extern struct libavl_allocator avl_allocator_default; +void *avl_malloc (struct libavl_allocator *, size_t); +void avl_free (struct libavl_allocator *, void *); + +/* Maximum AVL height. */ +#ifndef AVL_MAX_HEIGHT +#define AVL_MAX_HEIGHT 32 +#endif + +/* Tree data structure. */ +struct avl_table + { + struct avl_node *avl_root; /* Tree's root. */ + avl_comparison_func *avl_compare; /* Comparison function. */ + void *avl_param; /* Extra argument to |avl_compare|. */ + struct libavl_allocator *avl_alloc; /* Memory allocator. */ + size_t avl_count; /* Number of items in tree. */ + unsigned long avl_generation; /* Generation number. */ + }; + +/* An AVL tree node. */ +struct avl_node + { + struct avl_node *avl_link[2]; /* Subtrees. */ + void *avl_data; /* Pointer to data. */ + signed char avl_balance; /* Balance factor. */ + }; + +/* AVL traverser structure. */ +struct avl_traverser + { + struct avl_table *avl_table; /* Tree being traversed. */ + struct avl_node *avl_node; /* Current node in tree. */ + struct avl_node *avl_stack[AVL_MAX_HEIGHT]; + /* All the nodes above |avl_node|. */ + size_t avl_height; /* Number of nodes in |avl_parent|. */ + unsigned long avl_generation; /* Generation number. */ + }; + +/* Table functions. */ +struct avl_table *avl_create (avl_comparison_func *, void *, + struct libavl_allocator *); +struct avl_table *avl_copy (const struct avl_table *, avl_copy_func *, + avl_item_func *, struct libavl_allocator *); +void avl_destroy (struct avl_table *, avl_item_func *); +void **avl_probe (struct avl_table *, void *); +void *avl_insert (struct avl_table *, void *); +void *avl_replace (struct avl_table *, void *); +void *avl_delete (struct avl_table *, const void *); +void *avl_find (const struct avl_table *, const void *); +void avl_assert_insert (struct avl_table *, void *); +void *avl_assert_delete (struct avl_table *, void *); + +#define avl_count(table) ((size_t) (table)->avl_count) + +/* Table traverser functions. */ +void avl_t_init (struct avl_traverser *, struct avl_table *); +void *avl_t_first (struct avl_traverser *, struct avl_table *); +void *avl_t_last (struct avl_traverser *, struct avl_table *); +void *avl_t_find (struct avl_traverser *, struct avl_table *, void *); +void *avl_t_insert (struct avl_traverser *, struct avl_table *, void *); +void *avl_t_copy (struct avl_traverser *, const struct avl_traverser *); +void *avl_t_next (struct avl_traverser *); +void *avl_t_prev (struct avl_traverser *); +void *avl_t_cur (struct avl_traverser *); +void *avl_t_replace (struct avl_traverser *, void *); + +#if defined(__cplusplus) +} +#endif + +#endif /* avl.h */ diff --git a/Build/source/texk/web2c/pdftexdir/avlstuff.c b/Build/source/texk/web2c/pdftexdir/avlstuff.c new file mode 100644 index 00000000000..1fab93223f1 --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/avlstuff.c @@ -0,0 +1,131 @@ +/* +Copyright (c) 2004 Han The Thanh, <thanh@pdftex.org> + +This file is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by Free +Software Foundation; either version 2 of the License, or (at your option) +any later version. + +This file 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 General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with this file; if not, write to the Free Software Foundation, Inc., +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/avlstuff.c#5 $ + +formatted by indent -kr +*/ + +#include "ptexlib.h" +#include <kpathsea/c-vararg.h> +#include <kpathsea/c-proto.h> +#include "avl.h" + +static const char perforce_id[] = + "$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/avlstuff.c#5 $"; + +/* One AVL tree for each obj_type 0...pdfobjtypemax */ + +static struct avl_table *PdfObjTree[pdfobjtypemax + 1] = + { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + + +/* memory management functions for avl */ + +void *avl_xmalloc(struct libavl_allocator *allocator, size_t size) +{ + assert(allocator != NULL && size > 0); + return xmalloc(size); +} + +void avl_xfree(struct libavl_allocator *allocator, void *block) +{ + assert(allocator != NULL && block != NULL); + xfree(block); +} + +struct libavl_allocator avl_xallocator = { + avl_xmalloc, + avl_xfree +}; + + +/* AVL sort objentry into avl_table[] */ + +int compare_info(const void *pa, const void *pb, void *param) +{ + integer a, b; + int as, ae, bs, be, al, bl; + + a = ((const objentry *) pa)->int0; + b = ((const objentry *) pb)->int0; + if (a < 0 && b < 0) { /* string comparison */ + as = strstart[-a]; + ae = strstart[-a + 1]; /* start of next string in pool */ + bs = strstart[-b]; + be = strstart[-b + 1]; + al = ae - as; + bl = be - bs; + if (al < bl) /* compare first by string length */ + return -1; + else if (al > bl) + return 1; + else + for (; as < ae; as++, bs++) { + if (strpool[as] < strpool[bs]) + return -1; + if (strpool[as] > strpool[bs]) + return 1; + } + return 0; + } else { /* integer comparison */ + if (a < b) + return -1; + else if (a > b) + return 1; + else + return 0; + } +} + + +void avlputobj(integer objptr, integer t) +{ + static void **pp; + + if (PdfObjTree[t] == NULL) { + PdfObjTree[t] = avl_create(compare_info, NULL, &avl_xallocator); + if (PdfObjTree[t] == NULL) + pdftex_fail("avlstuff.c: avl_create() PdfObjTree failed"); + } + pp = avl_probe(PdfObjTree[t], &(objtab[objptr])); + if (pp == NULL) + pdftex_fail("avlstuff.c: avl_probe() out of memory in insertion"); +} + + +/* replacement for linear search pascal function "find_obj" */ + +integer avlfindobj(integer t, integer i, integer byname) +{ + static objentry *p; + static objentry tmp; + + if (byname > 0) + tmp.int0 = -i; + else + tmp.int0 = i; + if (PdfObjTree[t] == NULL) + return 0; + p = (objentry *) avl_find(PdfObjTree[t], &tmp); + if (p == NULL) + return 0; + else + return (int) (p - (objentry *) objtab); +} + +/* end of file avlstuff.c */ diff --git a/Build/source/texk/web2c/pdftexdir/avlstuff.h b/Build/source/texk/web2c/pdftexdir/avlstuff.h new file mode 100644 index 00000000000..2ffa57b627d --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/avlstuff.h @@ -0,0 +1,29 @@ +/* +Copyright (c) 2004 Han The Thanh, <thanh@pdftex.org> + +This file is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by Free +Software Foundation; either version 2 of the License, or (at your option) +any later version. + +This file 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 General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with this file; if not, write to the Free Software Foundation, Inc., +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/avlstuff.h#5 $ + +formatted by indent -kr +*/ + +#include "avl.h" + +/* memory management functions for avl */ + +extern struct libavl_allocator avl_xallocator; + +/* end of file avlstuff.h */ diff --git a/Build/source/texk/web2c/pdftexdir/change-files.txt b/Build/source/texk/web2c/pdftexdir/change-files.txt new file mode 100644 index 00000000000..496c1e313ed --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/change-files.txt @@ -0,0 +1,132 @@ +How change files are applied for pdftex/pdfetex? + +============================= pdftex ============================= + +1) pdftex.web is generated from + ./tie -m pdftex.web $(srcdir)/tex.web \ + $(srcdir)/pdftexdir/pdftex.ch \ + $(srcdir)/pdftexdir/hz.ch \ + $(srcdir)/pdftexdir/misc.ch + +Input: + tex.web: + the original tex sources + + pdftexdir/pdftex.ch: + PDF-specific changes + + pdftexdir/hz.ch: + HZ extension + + pdftexdir/misc.ch: + miscellany extensions + + +Output: + pdftex.web: + pdftex without system-dependent changes + +2) pdftex.ch is generated from + ./tie -c pdftex.ch pdftex.web \ + $(srcdir)/pdftexdir/tex.ch0 \ + $(srcdir)/tex.ch \ + $(srcdir)/pdftexdir/tex.ch1 \ + $(srcdir)/pdftexdir/tex.pch + +Input: + pdftex.web: + from step 1), ie pdftex without system-dependent changes + + pdftexdir/tex.ch0: + % Change file to assist in creating the web2c-specific change file. + % This one comes first, resolves inconsistencies between the + % generated pdftex.web and tex.ch + + change the pdftex banner to tex banner, so tex.ch can be applied + + tex.ch: + the main web2c-specific (or other system-dependent) change file + + pdftexdir/tex.ch1: + % Change file to assist in creating the web2c-specific change file. + % This one resolves inconsistencies between tex.ch and tex.pch. + + change the tex banner to pdftex banner (reverse tex.ch0) + + pdftexdir/tex.pch: + % Change file containing web2c-specific or system-dependent changes to + % pdftex + +Output: + pdftex.ch (not pdftexdir/pdftex.ch): + additional & system-dependent changes + + +============================= pdfetex ============================= + +1) pdfetex.web is generated from + ./tie -m pdfetex.web $(srcdir)/tex.web \ + $(srcdir)/etexdir/etex.ch \ + $(srcdir)/pdfetexdir/pdfetex.ch1 \ + $(srcdir)/pdftexdir/pdftex.ch \ + $(srcdir)/pdftexdir/hz.ch \ + $(srcdir)/pdftexdir/misc.ch \ + $(srcdir)/pdfetexdir/pdfetex.ch2 + + pdfetex.web should contain system-independent changes only; + +Input: + etexdir/etex.ch: + system-independent changes by etex + + pdfetexdir/pdfetex.ch1: + reverse some etex changes so system-independent pdftex change files can + be applied + + pdftexdir/{pdftex,hz,misc}.ch: + system-independent changes by pdftex + + pdfetexdir/pdfetex.ch2: + merge changes by etexdir/etex.ch & pdftexdir/{pdftex,hz,...}.ch + +Output: + pdfetex.web: + pdfetex without system-dependent changes + + +2) pdfetex.ch is generated from + ./tie -c pdfetex.ch pdfetex.web \ + $(srcdir)/pdfetexdir/tex.ch0 \ + $(srcdir)/tex.ch \ + $(srcdir)/etexdir/tex.ch1 \ + $(srcdir)/etexdir/tex.ech \ + $(srcdir)/pdfetexdir/tex.ch1 \ + $(srcdir)/pdftexdir/tex.pch + +Input: + pdfetex.web: + from step 1), ie pdfetex without system-dependent changes + + pdfetexdir/tex.ch0: + % Change file to assist in creating the web2c-specific change file. + % This one comes first, resolves inconsistencies between the generated + % pdfetex.web and tex.ch + + change the pdfetex banner to tex banner, so tex.ch can be applied + + tex.ch: + the main web2c-specific (or other system-dependent) change file + + the etex changes files: + system-dependent changes by etex + + pdfetexdir/tex.ch1: + reverses some system-dependent changes by etex (the banner) so + pdftexdir/tex.pch can be applied + + pdftexdir/tex.pch: + system-dependent changes by pdftex + +Output: + pdfetex.ch: + additional & system-dependent changes diff --git a/Build/source/texk/web2c/pdftexdir/depend.mak b/Build/source/texk/web2c/pdftexdir/depend.mak new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/depend.mak diff --git a/Build/source/texk/web2c/pdftexdir/depend.mk b/Build/source/texk/web2c/pdftexdir/depend.mk new file mode 100644 index 00000000000..3f83c3d34d9 --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/depend.mk @@ -0,0 +1,54 @@ +epdf.o: epdf.c ptexlib.h ../pdftexd.h ../texmfmp.h ../cpascal.h \ + ../config.h ../help.h ../texmfmem.h ../pdftexcoerce.h ptexmac.h +mapfile.o: mapfile.c ptexlib.h ../pdftexd.h ../texmfmp.h ../cpascal.h \ + ../config.h ../help.h ../texmfmem.h ../pdftexcoerce.h ptexmac.h +papersiz.o: papersiz.c ptexlib.h ../pdftexd.h ../texmfmp.h \ + ../cpascal.h ../config.h ../help.h ../texmfmem.h ../pdftexcoerce.h \ + ptexmac.h +utils.o: utils.c ptexlib.h ../pdftexd.h ../texmfmp.h ../cpascal.h \ + ../config.h ../help.h ../texmfmem.h ../pdftexcoerce.h ptexmac.h \ + ../../../libs/zlib/zlib.h ../../../libs/zlib/zconf.h \ + ../../../libs/md5/md5.h pdftexextra.h +vfpacket.o: vfpacket.c ptexlib.h ../pdftexd.h ../texmfmp.h \ + ../cpascal.h ../config.h ../help.h ../texmfmem.h ../pdftexcoerce.h \ + ptexmac.h +pkin.o: pkin.c ptexlib.h ../pdftexd.h ../texmfmp.h ../cpascal.h \ + ../config.h ../help.h ../texmfmem.h ../pdftexcoerce.h ptexmac.h +writefont.o: writefont.c ../../../libs/xpdf/goo/gmem.h ptexlib.h \ + ../pdftexd.h ../texmfmp.h ../cpascal.h ../config.h ../help.h \ + ../texmfmem.h ../pdftexcoerce.h ptexmac.h +writet1.o: writet1.c ptexlib.h ../pdftexd.h ../texmfmp.h ../cpascal.h \ + ../config.h ../help.h ../texmfmem.h ../pdftexcoerce.h ptexmac.h +writet3.o: writet3.c ptexlib.h ../pdftexd.h ../texmfmp.h ../cpascal.h \ + ../config.h ../help.h ../texmfmem.h ../pdftexcoerce.h ptexmac.h +writezip.o: writezip.c ptexlib.h ../pdftexd.h ../texmfmp.h \ + ../cpascal.h ../config.h ../help.h ../texmfmem.h ../pdftexcoerce.h \ + ptexmac.h ../../../libs/zlib/zlib.h ../../../libs/zlib/zconf.h +writeenc.o: writeenc.c ptexlib.h ../pdftexd.h ../texmfmp.h \ + ../cpascal.h ../config.h ../help.h ../texmfmem.h ../pdftexcoerce.h \ + ptexmac.h +writettf.o: writettf.c ptexlib.h ../pdftexd.h ../texmfmp.h \ + ../cpascal.h ../config.h ../help.h ../texmfmem.h ../pdftexcoerce.h \ + ptexmac.h macnames.c +writejpg.o: writejpg.c ptexlib.h ../pdftexd.h ../texmfmp.h \ + ../cpascal.h ../config.h ../help.h ../texmfmem.h ../pdftexcoerce.h \ + ptexmac.h image.h +writepng.o: writepng.c ptexlib.h ../pdftexd.h ../texmfmp.h \ + ../cpascal.h ../config.h ../help.h ../texmfmem.h ../pdftexcoerce.h \ + ptexmac.h image.h +writeimg.o: writeimg.c ptexlib.h ../pdftexd.h ../texmfmp.h \ + ../cpascal.h ../config.h ../help.h ../texmfmem.h ../pdftexcoerce.h \ + ptexmac.h image.h +pdftoepdf.o: pdftoepdf.cc ../../../libs/xpdf/xpdf/Object.h \ + ../../../libs/xpdf/goo/gmem.h ../../../libs/xpdf/xpdf/Array.h \ + ../../../libs/xpdf/xpdf/Dict.h ../../../libs/xpdf/xpdf/Stream.h \ + ../../../libs/xpdf/xpdf/XRef.h ../../../libs/xpdf/xpdf/Catalog.h \ + ../../../libs/xpdf/xpdf/Page.h ../../../libs/xpdf/xpdf/GfxFont.h \ + ../../../libs/xpdf/xpdf/Error.h epdf.h +ttf2afm.o: ttf2afm.c macnames.c +pdftosrc.o: pdftosrc.cc ../../../libs/xpdf/xpdf/Object.h \ + ../../../libs/xpdf/xpdf/Array.h ../../../libs/xpdf/xpdf/Dict.h \ + ../../../libs/xpdf/xpdf/Stream.h ../../../libs/xpdf/xpdf/XRef.h \ + ../../../libs/xpdf/xpdf/Catalog.h ../../../libs/xpdf/xpdf/Page.h \ + ../../../libs/xpdf/xpdf/PDFDoc.h ../../../libs/xpdf/xpdf/Link.h \ + ../../../libs/xpdf/xpdf/Error.h ../../../libs/xpdf/xpdf/config.h diff --git a/Build/source/texk/web2c/pdftexdir/epdf.c b/Build/source/texk/web2c/pdftexdir/epdf.c new file mode 100644 index 00000000000..95000755b0d --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/epdf.c @@ -0,0 +1,75 @@ +/* +Copyright (c) 1996-2002 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/epdf.c#10 $ +*/ + +#include "ptexlib.h" +#include <kpathsea/c-vararg.h> +#include <kpathsea/c-proto.h> + +integer pdfbufmax = pdfbufsize; + +extern void epdf_check_mem(void); + +int is_subsetable(fm_entry *fm) +{ + return is_included(fm) && is_subsetted(fm); +} + +int is_type1(fm_entry *fm) +{ + return is_t1fontfile(fm); +} + +void mark_glyphs(fm_entry *fm, char *charset) +{ + char *new_charset = fm->charset; + if (charset == NULL) + return; + if (new_charset == NULL) + new_charset = xstrdup(charset); + else { + xretalloc(new_charset, strlen(new_charset)+strlen(charset)+1, char); + strcat(new_charset, charset); + } + fm->charset = new_charset; +} + +void embed_whole_font(fm_entry *fm) +{ + fm->all_glyphs = true; +} + +integer get_fontfile(fm_entry *fm) +{ + return fm->ff_objnum; +} + +integer get_fontname(fm_entry *fm) +{ + if (fm->fn_objnum == 0) + fm->fn_objnum = pdfnewobjnum(); + return fm->fn_objnum; +} + +void epdf_free(void) +{ + epdf_check_mem(); +} diff --git a/Build/source/texk/web2c/pdftexdir/epdf.h b/Build/source/texk/web2c/pdftexdir/epdf.h new file mode 100644 index 00000000000..27ce221061d --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/epdf.h @@ -0,0 +1,103 @@ +/* +Copyright (c) 1996-2004 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/epdf.h#17 $ +*/ + +extern "C" { + +#include <kpathsea/c-auto.h> + +/* the following code is extremly ugly but needed for including web2c/config.h */ + +#include <kpathsea/c-proto.h> /* define P?H macros */ + +typedef const char *const_string; /* including kpathsea/types.h doesn't work on some systems */ + +#define KPATHSEA_CONFIG_H /* avoid including other kpathsea header files */ + /* from web2c/config.h */ + +#ifdef CONFIG_H /* CONFIG_H has been defined by some xpdf */ +#undef CONFIG_H /* header file */ +#endif + +#include <web2c/c-auto.h> /* define SIZEOF_LONG */ +#include <web2c/config.h> /* define type integer */ + +#include <web2c/pdftexdir/ptexmac.h> + +#define pdfbufsize pdfbufmax + +extern float epdf_width; +extern float epdf_height; +extern float epdf_orig_x; +extern float epdf_orig_y; +extern integer epdf_selected_page; +extern integer epdf_num_pages; +extern integer epdf_page_box; +extern integer epdf_always_use_pdf_pagebox; +extern void *epdf_doc; +extern void *epdf_xref; + +extern integer pdfstreamlength; +extern integer pdfptr; +typedef unsigned char eightbits ; +extern eightbits pdfbuf[]; +extern integer pdfbufmax; + +extern char notdef[]; + +extern int is_subsetable(struct fm_entry *); +extern int is_type1(struct fm_entry *); +extern struct fm_entry * lookup_fontmap(char *); +extern integer get_fontfile(struct fm_entry *); +extern integer get_fontname(struct fm_entry *); +extern integer pdfnewobjnum(void); +extern integer read_pdf_info(char*, char*, integer, integer, integer, integer); +extern void embed_whole_font(struct fm_entry *); +extern void epdf_check_mem(void); +extern void epdf_delete(void); +extern void epdf_free(void); +extern void mark_glyphs(struct fm_entry *, char *); +extern void pdf_printf(const char *fmt,...); +extern void pdf_puts(const char *); +extern void pdfbeginstream(void); +extern void pdfendobj(void); +extern void pdfendstream(void); +extern void pdfflush(void); +extern void pdftex_fail(const char *fmt,...); +extern void pdftex_warn(const char *fmt,...); +extern void tex_printf(const char *, ...); +extern void write_enc(char **, struct enc_entry *, integer); +extern void write_epdf(void); +extern void zpdfbegindict(integer); +extern void zpdfbeginobj(integer); +extern void zpdfcreateobj(integer, integer); +extern void zpdfnewdict(integer, integer); + +/* utils.c */ +extern char *convertStringToPDFString(char *in, int len); + +/* config.c */ +extern integer cfgpar(integer); + +/* avlstuff.c */ +extern void avl_put_obj (integer, integer); +extern integer avl_find_obj (integer, integer, integer); +} diff --git a/Build/source/texk/web2c/pdftexdir/hz.ch b/Build/source/texk/web2c/pdftexdir/hz.ch new file mode 100644 index 00000000000..d8ec58fb5e7 --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/hz.ch @@ -0,0 +1,1935 @@ +% WEB change file containing HZ extensions for pdfTeX +% +% Copyright (c) 1996-2002 Han Th\^e\llap{\raise 0.5ex\hbox{\'{}}} Th\`anh, <thanh@pdftex.org> +% +% This file is part of pdfTeX. +% +% pdfTeX 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. +% +% pdfTeX 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 General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with pdfTeX; if not, write to the Free Software +% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +% +% $Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/hz.ch#15 $ + +@x [155] - margin kerning +@d acc_kern=2 {|subtype| of kern nodes from accents} +@y +@d acc_kern=2 {|subtype| of kern nodes from accents} + +@# {memory structure for marginal kerns} +@d margin_kern_node = 40 +@d margin_kern_node_size = 3 +@d margin_char(#) == info(# + 2) + +@# {|subtype| of marginal kerns} +@d left_side == 0 +@d right_side == 1 + +@# {base for lp/rp/ef codes starts from 2: + 0 for |hyphen_char|, + 1 for |skew_char|} +@d lp_code_base == 2 +@d rp_code_base == 3 +@d ef_code_base == 4 + +@d max_hlist_stack = 512 {maximum fill level for |hlist_stack|} +{maybe good if larger than |2 * max_quarterword|, so that box nesting level would overflow first} +@z + +@x [183] - margin kerning + kern_node: @<Display kern |p|@>; +@y + margin_kern_node: begin + print_esc("kern"); + print_scaled(width(p)); + if subtype(p) = left_side then + print(" (left margin)") + else + print(" (right margin)"); + end; + kern_node: @<Display kern |p|@>; +@z + +@x [202] - margin kerning + kern_node,math_node,penalty_node: do_nothing; +@y + kern_node,math_node,penalty_node: do_nothing; + margin_kern_node: begin + free_avail(margin_char(p)); + free_node(p, margin_kern_node_size); + goto done; + end; +@z + +@x [206] - margin kerning +kern_node,math_node,penalty_node: begin r:=get_node(small_node_size); + words:=small_node_size; + end; +@y +kern_node,math_node,penalty_node: begin r:=get_node(small_node_size); + words:=small_node_size; + end; +margin_kern_node: begin + r := get_node(margin_kern_node_size); + fast_get_avail(margin_char(r)); + font(margin_char(r)) := font(margin_char(p)); + character(margin_char(r)) := character(margin_char(p)); + words := small_node_size; + end; +@z + +@x [236] +@d pdf_int_pars=pdftex_first_integer_code + 17 {total number of \pdfTeX's integer parameters} +@y +@d pdf_adjust_spacing_code = pdftex_first_integer_code + 17 {level of spacing adjusting} +@d pdf_protrude_chars_code = pdftex_first_integer_code + 18 {protrude chars at left/right edge of paragraphs} +@d pdf_tracing_fonts_code = pdftex_first_integer_code + 19 {level of font detail in log} +@d pdf_int_pars=pdftex_first_integer_code + 20 {total number of \pdfTeX's integer parameters} +@z + +@x [236] +@d error_context_lines==int_par(error_context_lines_code) +@y +@d error_context_lines==int_par(error_context_lines_code) +@# +@d pdf_adjust_spacing == int_par(pdf_adjust_spacing_code) +@d pdf_protrude_chars == int_par(pdf_protrude_chars_code) +@d pdf_tracing_fonts == int_par(pdf_tracing_fonts_code) +@z + +@x [237] +error_context_lines_code:print_esc("errorcontextlines"); +@y +error_context_lines_code:print_esc("errorcontextlines"); +@# +pdf_adjust_spacing_code: print_esc("pdfadjustspacing"); +pdf_protrude_chars_code: print_esc("pdfprotrudechars"); +pdf_tracing_fonts_code: print_esc("pdftracingfonts"); +@z + +@x [238] +primitive("errorcontextlines",assign_int,int_base+error_context_lines_code);@/ +@!@:error_context_lines_}{\.{\\errorcontextlines} primitive@> +@y +primitive("errorcontextlines",assign_int,int_base+error_context_lines_code);@/ +@!@:error_context_lines_}{\.{\\errorcontextlines} primitive@> +primitive("pdfadjustspacing",assign_int,int_base+pdf_adjust_spacing_code);@/ +@!@:pdf_adjust_spacing_}{\.{\\pdfadjustspacing} primitive@> +primitive("pdfprotrudechars",assign_int,int_base+pdf_protrude_chars_code);@/ +@!@:pdf_protrude_chars_}{\.{\\pdfprotrudechars} primitive@> +primitive("pdftracingfonts",assign_int,int_base+pdf_tracing_fonts_code);@/ +@!@:pdf_tracing_fonts_}{\.{\\pdftracingfonts} primitive@> +@z + +@x [267] - displaying fonts +@<Print the font identifier for |font(p)|@>= +print_esc(font_id_text(font(p))) +@y +@<Print the font identifier for |font(p)|@>= +begin + print_esc(font_id_text(font(p))); + if pdf_tracing_fonts > 0 then begin + print(" ("); + print(font_name[font(p)]); + if font_size[font(p)] <> font_dsize[font(p)] then begin + print("@@"); + print_scaled(font_size[font(p)]); + print("pt"); + end; + print(")"); + end else + if pdf_font_expand_ratio[font(p)] <> 0 then begin + print(" ("); + if pdf_font_expand_ratio[font(p)] > 0 then + print("+"); + print_int(pdf_font_expand_ratio[font(p)]); + print(")"); + end; +end +@z + +@x [413] - font expansion +var m:halfword; {|chr_code| part of the operand token} +@y +var m:halfword; {|chr_code| part of the operand token} + n, k: integer; {accumulators} +@z + +@x [426] - font expansion, margin kerning +begin scan_font_ident; +if m=0 then scanned_result(hyphen_char[cur_val])(int_val) +else scanned_result(skew_char[cur_val])(int_val); +@y +begin scan_font_ident; +if m=0 then scanned_result(hyphen_char[cur_val])(int_val) +else if m=1 then scanned_result(skew_char[cur_val])(int_val) +else begin + n := cur_val; + scan_char_num; + k := cur_val; + case m of + lp_code_base: scanned_result(get_lp_code(n, k))(int_val); + rp_code_base: scanned_result(get_rp_code(n, k))(int_val); + ef_code_base: scanned_result(get_ef_code(n, k))(int_val); + end; +end; +@z + +@x [468] +@d pdftex_convert_codes = pdftex_first_expand_code + 9 {end of \pdfTeX's command codes} +@y +@d left_margin_kern_code = pdftex_first_expand_code + 9 {command code for \.{\\leftmarginkern}} +@d right_margin_kern_code = pdftex_first_expand_code + 10 {command code for \.{\\rightmarginkern}} +@d pdftex_convert_codes = pdftex_first_expand_code + 11 {end of \pdfTeX's command codes} +@z + +@x [468] +primitive("pdfpageref",convert,pdf_page_ref_code);@/ +@!@:pdf_page_ref_}{\.{\\pdfpageref} primitive@> +@y +primitive("pdfpageref",convert,pdf_page_ref_code);@/ +@!@:pdf_page_ref_}{\.{\\pdfpageref} primitive@> +primitive("leftmarginkern",convert,left_margin_kern_code);@/ +@!@:left_margin_kern_}{\.{\\leftmarginkern} primitive@> +primitive("rightmarginkern",convert,right_margin_kern_code);@/ +@!@:right_margin_kern_}{\.{\\rightmarginkern} primitive@> +@z + +@x [469] + pdf_page_ref_code: print_esc("pdfpageref"); +@y + pdf_page_ref_code: print_esc("pdfpageref"); + left_margin_kern_code: print_esc("leftmarginkern"); + right_margin_kern_code: print_esc("rightmarginkern"); +@z + +@x [470] +var old_setting:0..max_selector; {holds |selector| setting} +@y +var old_setting:0..max_selector; {holds |selector| setting} +p, q: pointer; +@z + +@x [471] +pdf_page_ref_code: begin + scan_int; + if cur_val <= 0 then + pdf_error("pageref", "invalid page number"); +end; +@y +pdf_page_ref_code: begin + scan_int; + if cur_val <= 0 then + pdf_error("pageref", "invalid page number"); +end; +left_margin_kern_code, right_margin_kern_code: begin + scan_int; + if (box(cur_val) = null) or (type(box(cur_val)) <> hlist_node) then + pdf_error("marginkern", "a non-empty hbox expected") +end; +@z + +@x [472] +pdf_page_ref_code: print_int(get_obj(obj_type_page, cur_val, false)); +@y +pdf_page_ref_code: print_int(get_obj(obj_type_page, cur_val, false)); +left_margin_kern_code: begin + p := list_ptr(box(cur_val)); + if (p <> null) and (not is_char_node(p)) and + (type(p) = glue_node) and (subtype(p) = left_skip_code + 1) then + p := link(p); + if (p <> null) and (not is_char_node(p)) and + (type(p) = margin_kern_node) and (subtype(p) = left_side) then + print_scaled(width(p)) + else + print("0"); + print("pt"); +end; +right_margin_kern_code: begin + q := list_ptr(box(cur_val)); + p := null; + if q <> null then begin + p := prev_rightmost(q, null); + if (p <> null) and (not is_char_node(p)) and + (type(p) = glue_node) and (subtype(p) = right_skip_code + 1) then + p := prev_rightmost(q, p); + end; + if (p <> null) and (not is_char_node(p)) and + (type(p) = margin_kern_node) and (subtype(p) = right_side) then + print_scaled(width(p)) + else + print("0"); + print("pt"); +end; +@z + +@x [622] - margin kerning +glue_node: @<Move right or output leaders@>; +@y +glue_node: @<Move right or output leaders@>; +margin_kern_node, +@z + + +@x [???] - font expansion +@!tmp_f: internal_font_number; {for use with |pdf_init_font|} + +@y +@!tmp_f: internal_font_number; {for use with |pdf_init_font|} +@ Here come some subroutines to deal with expanded fonts for HZ-algorithm. + +@p +function init_font_base(v: integer): integer; +var i, j: integer; +begin + i := pdf_get_mem(256); + for j := 0 to 255 do + pdf_mem[i + j] := v; + init_font_base := i; +end; + +procedure set_lp_code(f: internal_font_number; c: eight_bits; i: integer); +begin + if pdf_font_lp_base[f] = 0 then + pdf_font_lp_base[f] := init_font_base(0); + pdf_mem[pdf_font_lp_base[f] + c] := fix_int(i, -1000, 1000); +end; + +procedure set_rp_code(f: internal_font_number; c: eight_bits; i: integer); +begin + if pdf_font_rp_base[f] = 0 then + pdf_font_rp_base[f] := init_font_base(0); + pdf_mem[pdf_font_rp_base[f] + c] := fix_int(i, -1000, 1000); +end; + +procedure set_ef_code(f: internal_font_number; c: eight_bits; i: integer); +begin + if pdf_font_ef_base[f] = 0 then + pdf_font_ef_base[f] := init_font_base(1000); + pdf_mem[pdf_font_ef_base[f] + c] := fix_int(i, 0, 1000); +end; + +function expand_font_name(f: internal_font_number; e: integer): str_number; +var old_setting:0..max_selector; {holds |selector| setting} +begin + old_setting:=selector; selector:=new_string; + print(font_name[f]); + if e > 0 then + print("+"); {minus sign will be printed by |print_int|} + print_int(e); + selector:=old_setting; + expand_font_name := make_string; +end; + +function auto_expand_font(f: internal_font_number; e: integer): internal_font_number; +{creates an expanded font from the base font; doesn't load expanded tfm at all} +var k: internal_font_number; + nw, nk, ni, i, j: integer; +begin + k := font_ptr + 1; + incr(font_ptr); + if (font_ptr >= font_max) then + overflow("maximum internal font number (font_max)", font_max); + font_name[k] := expand_font_name(f, e); + font_area[k] := font_area[f]; + font_id_text(k) := font_id_text(f); + hyphen_char[k] := hyphen_char[f]; + skew_char[k] := skew_char[f]; + font_bchar[k] := font_bchar[f]; + font_false_bchar[k] := font_false_bchar[f]; + font_bc[k] := font_bc[f]; + font_ec[k] := font_ec[f]; + font_size[k] := font_size[f]; + font_dsize[k] := font_dsize[f]; + font_params[k] := font_params[f]; + font_glue[k] := font_glue[f]; + bchar_label[k] := bchar_label[f]; + + char_base[k] := char_base[f]; + height_base[k] := height_base[f]; + depth_base[k] := depth_base[f]; + lig_kern_base[k] := lig_kern_base[f]; + exten_base[k] := exten_base[f]; + param_base[k] := param_base[f]; + + nw := height_base[f] - width_base[f]; + ni := lig_kern_base[f] - italic_base[f]; + nk := exten_base[f] - (kern_base[f] + kern_base_offset); + if (fmem_ptr + nw + ni + nk >= font_mem_size) then + overflow("number of words of font memory (font_mem_size)", font_mem_size); + width_base[k] := fmem_ptr; + italic_base[k] := width_base[k] + nw; + kern_base[k] := italic_base[k] + ni - kern_base_offset; + fmem_ptr := fmem_ptr + nw + ni + nk; + + for i := 0 to nw - 1 do + font_info[width_base[k] + i].sc := + round_xn_over_d(font_info[width_base[f] + i].sc, 1000 + e, 1000); + for i := 0 to ni - 1 do + font_info[italic_base[k] + i].sc := + round_xn_over_d(font_info[italic_base[f] + i].sc, 1000 + e, 1000); + for i := 0 to nk - 1 do + font_info[kern_base[k] + kern_base_offset + i].sc := + round_xn_over_d(font_info[kern_base[f] + kern_base_offset + i].sc, 1000 + e, 1000); + + auto_expand_font := k; +end; + +procedure set_expand_param(k, f: internal_font_number; e: integer); +var i, j: integer; +begin + if pdf_font_rp_base[f] = 0 then + pdf_font_rp_base[f] := init_font_base(0); + if pdf_font_lp_base[f] = 0 then + pdf_font_lp_base[f] := init_font_base(0); + if pdf_font_ef_base[f] = 0 then + pdf_font_ef_base[f] := init_font_base(1000); + pdf_font_expand_ratio[k] := e; + pdf_font_step[k] := pdf_font_step[f]; + pdf_font_auto_expand[k] := pdf_font_auto_expand[f]; + pdf_font_blink[k] := f; {???} + pdf_font_lp_base[k] := pdf_font_lp_base[f]; + pdf_font_rp_base[k] := pdf_font_rp_base[f]; + pdf_font_ef_base[k] := pdf_font_ef_base[f]; +end; + +function tfm_lookup(s: str_number; fs: scaled): internal_font_number; +{looks up for a TFM with name |s| loaded at |fs| size; if found then flushes |s|} +var k: internal_font_number; +begin + if fs <> 0 then begin + for k := font_base + 1 to font_ptr do + if str_eq_str(font_name[k], s) and (font_size[k] = fs) then begin + flush_str(s); + tfm_lookup := k; + return; + end; + end + else begin + for k := font_base + 1 to font_ptr do + if str_eq_str(font_name[k], s) then begin + flush_str(s); + tfm_lookup := k; + return; + end; + end; + tfm_lookup := null_font; +end; + +function load_expand_font(f: internal_font_number; e: integer): internal_font_number; +{loads font |f| expanded by |e| thousandths into font memory; |e| is nonzero +and is a multiple of |pdf_font_step[f]|} +label found; +var s: str_number; {font name} + k: internal_font_number; +begin + s := expand_font_name(f, e); + k := tfm_lookup(s, font_size[f]); + if k = null_font then begin + if pdf_font_auto_expand[f] then + k := auto_expand_font(f, e) + else + k := read_font_info(null_cs, s, "", font_size[f]); + end; + set_expand_param(k, f, e); + load_expand_font := k; +end; + +function auto_expand_vf(f: internal_font_number): boolean; +{check for a virtual auto-expanded font} +var save_f, bf, lf, k: internal_font_number; + e: integer; +begin + auto_expand_vf := false; + if (not pdf_font_auto_expand[f]) or (pdf_font_blink[f] = null_font) then + return; {not an auto-expanded font} + bf := pdf_font_blink[f]; + if pdf_font_type[bf] = new_font_type then {we must process the base font first} + begin + save_f := tmp_f; + tmp_f := bf; + do_vf; + tmp_f := save_f; + end; + + if pdf_font_type[bf] <> virtual_font_type then + return; {not a virtual font} + + e := pdf_font_expand_ratio[f]; + for k := 0 to vf_local_font_num[bf] - 1 do begin + lf := vf_default_font[bf] + k; + vf_e_fnts[vf_nf] := vf_e_fnts[lf]; + vf_i_fnts[vf_nf] := auto_expand_font(vf_i_fnts[lf], e); + set_expand_param(vf_i_fnts[vf_nf], vf_i_fnts[lf], e); + incr(vf_nf); + end; + vf_packet_base[f] := vf_packet_base[bf]; + vf_local_font_num[f] := vf_local_font_num[bf]; + vf_default_font[f] := vf_nf - vf_local_font_num[f]; + + pdf_font_type[f] := virtual_font_type; + auto_expand_vf := true; +end; + +function fix_expand_value(f: internal_font_number; e: integer): integer; +{return the multiple of |pdf_font_step[f]| that is nearest to |e|} +var step: integer; + max_expand: integer; + neg: boolean; +begin + fix_expand_value := 0; + if e = 0 then + return; + if e < 0 then begin + e := -e; + neg := true; + max_expand := -pdf_font_expand_ratio[pdf_font_shrink[f]]; + end + else begin + neg := false; + max_expand := pdf_font_expand_ratio[pdf_font_stretch[f]]; + end; + if e > max_expand then + e := max_expand + else begin + step := pdf_font_step[f]; + if e mod step > 0 then + e := step*round_xn_over_d(e, 1, step); + end; + if neg then + e := -e; + fix_expand_value := e; +end; + +function get_expand_font(f: internal_font_number; e: integer): internal_font_number; +{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 |pdf_font_step[f]|} +var k: internal_font_number; +begin + k := pdf_font_elink[f]; + while k <> null_font do begin + if pdf_font_expand_ratio[k] = e then begin + get_expand_font := k; + return; + end; + k := pdf_font_elink[k]; + end; + k := load_expand_font(f, e); + pdf_font_elink[k] := pdf_font_elink[f]; + pdf_font_elink[f] := k; + get_expand_font := k; +end; + +function expand_font(f: internal_font_number; e: integer): internal_font_number; +{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} +var max_expand: integer; +begin + expand_font := f; + if e = 0 then + return; + e := fix_expand_value(f, e); + if e = 0 then + return; + if pdf_font_elink[f] = null_font then + pdf_error("font expansion", "uninitialized pdf_font_elink"); + expand_font := get_expand_font(f, e); +end; + +procedure read_expand_font; {read font expansion spec and load expanded font} +var font_shrink, font_stretch, font_step: integer; + f: internal_font_number; + auto_expand: boolean; +begin + {read font expansion parameters} + scan_font_ident; + f := cur_val; + if f = null_font then + pdf_error("font expansion", "invalid font identifier"); + scan_optional_equals; + scan_int; + font_stretch := fix_int(cur_val, 0, 1000); + scan_int; + font_shrink := fix_int(cur_val, 0, 1000); + scan_int; + font_step := fix_int(cur_val, 0, 1000); + if font_step = 0 then + pdf_error("font expansion", "invalid step"); + font_stretch := font_stretch - font_stretch mod font_step; + if font_stretch < 0 then + font_stretch := 0; + font_shrink := font_shrink - font_shrink mod font_step; + if font_shrink < 0 then + font_shrink := 0; + if font_shrink = 1000 then + font_shrink := font_shrink - font_step; {don't allow zero-width font} + if (font_stretch = 0) and (font_shrink = 0) then + pdf_error("font expansion", "invalid limit"); + auto_expand := false; + if scan_keyword("autoexpand") then begin + auto_expand := true; + @<Scan an optional space@>; end; + + {check if the font can be expanded} + if (pdf_font_expand_ratio[f] <> 0) then + pdf_error("font expansion", "this font has been expanded by another font so it cannot be used now"); + if (pdf_font_step[f] <> 0) then + {this font has been expanded, ensure the expansion parameters are identical} + begin + if (pdf_font_step[f] <> font_step) or + ((pdf_font_stretch[f] = null_font) and (font_stretch <> 0)) or + ((pdf_font_stretch[f] <> null_font) and + (pdf_font_expand_ratio[pdf_font_stretch[f]] <> font_stretch)) or + ((pdf_font_shrink[f] = null_font) and (font_shrink <> 0)) or + ((pdf_font_shrink[f] <> null_font) and + (pdf_font_expand_ratio[pdf_font_shrink[f]] <> -font_shrink)) or + (pdf_font_auto_expand[f] <> auto_expand) + then + pdf_error("font expansion", "font has been expanded with different parameters"); + end + else begin + pdf_font_step[f] := font_step; + pdf_font_auto_expand[f] := auto_expand; + if font_stretch > 0 then + pdf_font_stretch[f] := get_expand_font(f, font_stretch); + if font_shrink > 0 then + pdf_font_shrink[f] := get_expand_font(f, -font_shrink); + end; +end; +@z + +@x [32f] - margin kerning +glue_node: @<(\pdfTeX) Move right or output leaders@>; +@y +glue_node: @<(\pdfTeX) Move right or output leaders@>; +margin_kern_node, +@z + +@x [649] - font expansion +@ Here now is |hpack|, which contains few if any surprises. + +@p function hpack(@!p:pointer;@!w:scaled;@!m:small_number):pointer; +@y +@ @<Glob...@>= +@!pdf_font_blink: ^internal_font_number; {link to base font (used for expanded fonts only)} +@!pdf_font_elink: ^internal_font_number; {link to expanded fonts (used for base fonts only)} +@!pdf_font_stretch: ^integer; {limit of stretching} +@!pdf_font_shrink: ^integer; {limit of shrinking} +@!pdf_font_step: ^integer; {amount of one step of expansion} +@!pdf_font_expand_ratio: ^integer; {expansion ratio of a particular font} +@!pdf_font_auto_expand: ^boolean; {this font is auto-expanded?} +@!pdf_font_lp_base: ^integer; {base of left-protruding factor} +@!pdf_font_rp_base: ^integer; {base of right-protruding factor} +@!pdf_font_ef_base: ^integer; {base of font expansion factor} +@!font_expand_ratio: integer; {current expansion ratio} +@!last_leftmost_char: pointer; +@!last_rightmost_char: pointer; +@!hlist_stack:array[0..max_hlist_stack] of pointer; {stack for |find_protchar_left()| and |find_protchar_right()|} +@!hlist_stack_level:0..max_hlist_stack; {fill level for |hlist_stack|} + +@ @d cal_margin_kern_var(#) == +begin + character(cp) := character(#); + font(cp) := font(#); + do_subst_font(cp, 1000); + if font(cp) <> font(#) then + margin_kern_stretch := margin_kern_stretch + left_pw(#) - left_pw(cp); + font(cp) := font(#); + do_subst_font(cp, -1000); + if font(cp) <> font(#) then + margin_kern_shrink := margin_kern_shrink + left_pw(cp) - left_pw(#); +end + +@<Calculate variations of marginal kerns@>= +begin + lp := last_leftmost_char; + rp := last_rightmost_char; + fast_get_avail(cp); + if lp <> null then + cal_margin_kern_var(lp); + if rp <> null then + cal_margin_kern_var(rp); + free_avail(cp); +end + +@ Here is |hpack|, which is place where we do font substituting when +font expansion is being used. We define some constants used when calling +|hpack| to deal with font expansion. + +@d cal_expand_ratio == 2 {calculate amount for font expansion after breaking + paragraph into lines} +@d subst_ex_font == 3 {substitute fonts} + +@d substituted = 3 {|subtype| of kern nodes that should be substituted} + +@d left_pw(#) == char_pw(#, left_side) +@d right_pw(#) == char_pw(#, right_side) + +@p +function check_expand_pars(f: internal_font_number): boolean; +var k: internal_font_number; +begin + check_expand_pars := false; + if (pdf_font_step[f] = 0) or ((pdf_font_stretch[f] = null_font) and + (pdf_font_shrink[f] = null_font)) then + return; + if cur_font_step < 0 then + cur_font_step := pdf_font_step[f] + else if cur_font_step <> pdf_font_step[f] then + pdf_error("font expansion", "using fonts with different step of expansion in one paragraph is not allowed"); + k := pdf_font_stretch[f]; + if k <> null_font then begin + if max_stretch_ratio < 0 then + max_stretch_ratio := pdf_font_expand_ratio[k] + else if max_stretch_ratio <> pdf_font_expand_ratio[k] then + pdf_error("font expansion", "using fonts with different limit of expansion in one paragraph is not allowed"); + end; + k := pdf_font_shrink[f]; + if k <> null_font then begin + if max_shrink_ratio < 0 then + max_shrink_ratio := pdf_font_expand_ratio[k] + else if max_shrink_ratio <> pdf_font_expand_ratio[k] then + pdf_error("font expansion", "using fonts with different limit of expansion in one paragraph is not allowed"); + end; + check_expand_pars := true; +end; + +function char_stretch(f: internal_font_number; c: eight_bits): scaled; +var k: internal_font_number; + dw: scaled; + ef: integer; +begin + char_stretch := 0; + k := pdf_font_stretch[f]; + ef := get_ef_code(f, c); + if (k <> null_font) and (ef > 0) then begin + dw := char_width(k)(char_info(k)(c)) - char_width(f)(char_info(f)(c)); + if dw > 0 then + char_stretch := round_xn_over_d(dw, ef, 1000); + end; +end; + +function char_shrink(f: internal_font_number; c: eight_bits): scaled; +var k: internal_font_number; + dw: scaled; + ef: integer; +begin + char_shrink := 0; + k := pdf_font_shrink[f]; + ef := get_ef_code(f, c); + if (k <> null_font) and (ef > 0) then begin + dw := char_width(f)(char_info(f)(c)) - char_width(k)(char_info(k)(c)); + if dw > 0 then + char_shrink := round_xn_over_d(dw, ef, 1000); + end; +end; + +function get_kern(f: internal_font_number; lc, rc: eight_bits): scaled; +label continue; +var i: four_quarters; + j: four_quarters; + k: font_index; + p: pointer; + s: integer; +begin + get_kern := 0; + i := char_info(f)(lc); + if char_tag(i) <> lig_tag then + return; + k := lig_kern_start(f)(i); + j := font_info[k].qqqq; + if skip_byte(j) <= stop_flag then + goto continue + 1; + k := lig_kern_restart(f)(j); +continue: + j := font_info[k].qqqq; +continue + 1: + if (next_char(j) = rc) and (skip_byte(j) <= stop_flag) and + (op_byte(j) >= kern_flag) + then begin + get_kern := char_kern(f)(j); + return; + end; + if skip_byte(j) = qi(0) then + incr(k) + else begin + if skip_byte(j) >= stop_flag then + return; + k := k + qo(skip_byte(j)) + 1; + end; + goto continue; +end; + +function kern_stretch(p: pointer): scaled; +var l, r: pointer; + d: scaled; +begin + kern_stretch := 0; + if (prev_char_p = null) or (link(prev_char_p) <> p) or (link(p) = null) + then + return; + l := prev_char_p; + r := link(p); + if type(l) = ligature_node then + l := lig_char(l); + if type(r) = ligature_node then + r := lig_char(r); + if not (is_char_node(l) and is_char_node(r) and + (font(l) = font(r)) and + (pdf_font_stretch[font(l)] <> null_font)) + then + return; + d := get_kern(pdf_font_stretch[font(l)], character(l), character(r)); + kern_stretch := round_xn_over_d(d - width(p), + get_ef_code(font(l), character(l)), 1000); +end; + +function kern_shrink(p: pointer): scaled; +var l, r: pointer; + d: scaled; +begin + kern_shrink := 0; + if (prev_char_p = null) or (link(prev_char_p) <> p) or (link(p) = null) + then + return; + l := prev_char_p; + r := link(p); + if type(l) = ligature_node then + l := lig_char(l); + if type(r) = ligature_node then + r := lig_char(r); + if not (is_char_node(l) and is_char_node(r) and + (font(l) = font(r)) and + (pdf_font_shrink[font(l)] <> null_font)) + then + return; + d := get_kern(pdf_font_shrink[font(l)], character(l), character(r)); + kern_shrink := round_xn_over_d(width(p) - d, + get_ef_code(font(l), character(l)), 1000); +end; + +procedure do_subst_font(p: pointer; ex_ratio: integer); +var f, k: internal_font_number; + r: pointer; + ef: integer; +begin + if not is_char_node(p) and (type(p) = disc_node) then begin + r := pre_break(p); + while r <> null do begin + if is_char_node(r) or (type(r) = ligature_node) then + do_subst_font(r, ex_ratio); + r := link(r); + end; + r := post_break(p); + while r <> null do begin + if is_char_node(r) or (type(r) = ligature_node) then + do_subst_font(r, ex_ratio); + r := link(r); + end; + return; + end; + if is_char_node(p) then + r := p + else if type(p) = ligature_node then + r := lig_char(p) + else begin + {|short_display_n(p, 5);|} + pdf_error("font expansion", "invalid node type"); + end; + f := font(r); + ef := get_ef_code(f, character(r)); + if ef = 0 then + return; + if (pdf_font_stretch[f] <> null_font) and (ex_ratio > 0) then + k := expand_font(f, divide_scaled(ex_ratio* + pdf_font_expand_ratio[pdf_font_stretch[f]]*ef, + 1000000, 0)) + else if (pdf_font_shrink[f] <> null_font) and (ex_ratio < 0) then + k := expand_font(f, -divide_scaled(ex_ratio* + pdf_font_expand_ratio[pdf_font_shrink[f]]*ef, + 1000000, 0)) + else + k := f; + if k <> f then begin + font(r) := k; + if not is_char_node(p) then begin + r := lig_ptr(p); + while r <> null do begin + font(r) := k; + r := link(r); + end; + end; + end; +end; + +function char_pw(p: pointer; side: small_number): scaled; +var f: internal_font_number; + c: integer; +begin + char_pw := 0; + if side = left_side then + last_leftmost_char := null + else + last_rightmost_char := null; + if p = null then + return; + if not is_char_node(p) then begin + if type(p) = ligature_node then + p := lig_char(p) + else + return; + end; + f := font(p); + if side = left_side then begin + c := get_lp_code(f, character(p)); + last_leftmost_char := p; + end + else begin + c := get_rp_code(f, character(p)); + last_rightmost_char := p; + end; + if c = 0 then + return; + char_pw := + round_xn_over_d(quad(f), c, 1000); +end; + +function new_margin_kern(w: scaled; p: pointer; side: small_number): pointer; +var k: pointer; +begin + k := get_node(margin_kern_node_size); + type(k) := margin_kern_node; + subtype(k) := side; + width(k) := w; + if p = null then + pdf_error("margin kerning", "invalid pointer to marginal char node"); + fast_get_avail(margin_char(k)); + character(margin_char(k)) := character(p); + font(margin_char(k)) := font(p); + new_margin_kern := k; +end; + +function hpack(@!p:pointer;@!w:scaled;@!m:small_number):pointer; +@z + +@x [649] - font expansion +begin last_badness:=0; r:=get_node(box_node_size); type(r):=hlist_node; +subtype(r):=min_quarterword; shift_amount(r):=0; +q:=r+list_offset; link(q):=p;@/ +@y +font_stretch: scaled; +font_shrink: scaled; +k: scaled; +begin last_badness:=0; r:=get_node(box_node_size); type(r):=hlist_node; +subtype(r):=min_quarterword; shift_amount(r):=0; +q:=r+list_offset; link(q):=p;@/ +if m = cal_expand_ratio then begin + prev_char_p := null; + font_stretch := 0; + font_shrink := 0; + font_expand_ratio := 0; +end; +@z + +@x [649] - font expansion +hpack:=r; +@y +if (m = cal_expand_ratio) and (font_expand_ratio <> 0) then begin + font_expand_ratio := fix_int(font_expand_ratio, -1000, 1000); + q := list_ptr(r); + free_node(r, box_node_size); + r := hpack(q, w, subst_ex_font); +end; +hpack:=r; +@z + +@x [651] - font expansion + kern_node: x:=x+width(p); +@y + margin_kern_node: begin + if m = cal_expand_ratio then begin + f := font(margin_char(p)); + do_subst_font(margin_char(p), 1000); + if f <> font(margin_char(p)) then + font_stretch := font_stretch - width(p) - + char_pw(margin_char(p), subtype(p)); + font(margin_char(p)) := f; + do_subst_font(margin_char(p), -1000); + if f <> font(margin_char(p)) then + font_shrink := font_shrink - width(p) - + char_pw(margin_char(p), subtype(p)); + font(margin_char(p)) := f; + end + else if m = subst_ex_font then begin + do_subst_font(margin_char(p), font_expand_ratio); + width(p) := -char_pw(margin_char(p), subtype(p)); + end; + x := x + width(p); + end; + kern_node: begin + if (m = cal_expand_ratio) and (subtype(p) = normal) then begin + k := kern_stretch(p); + if k <> 0 then begin + subtype(p) := substituted; + font_stretch := font_stretch + k; + end; + k := kern_shrink(p); + if k <> 0 then begin + subtype(p) := substituted; + font_shrink := font_shrink + k; + end; + end + else if (m = subst_ex_font) and (subtype(p) = substituted) then begin + if type(link(p)) = ligature_node then + width(p) := get_kern(font(prev_char_p), + character(prev_char_p), + character(lig_char(link(p)))) + else + width(p) := get_kern(font(prev_char_p), + character(prev_char_p), + character(link(p))) + end; + x := x + width(p); + end; +@z + +@x [651] - font expansion + ligature_node: @<Make node |p| look like a |char_node| + and |goto reswitch|@>; +@y + ligature_node: begin + if m = subst_ex_font then + do_subst_font(p, font_expand_ratio); + @<Make node |p| look like a |char_node| and |goto reswitch|@>; + end; + disc_node: + if m = subst_ex_font then + do_subst_font(p, font_expand_ratio); +@z + +@x [654] - font expansion +begin f:=font(p); i:=char_info(f)(character(p)); hd:=height_depth(i); +@y +begin +if m >= cal_expand_ratio then begin + prev_char_p := p; + case m of + cal_expand_ratio: begin + f := font(p); + add_char_stretch(font_stretch)(character(p)); + add_char_shrink(font_shrink)(character(p)); + end; + subst_ex_font: + do_subst_font(p, font_expand_ratio); + endcases; +end; +f:=font(p); i:=char_info(f)(character(p)); hd:=height_depth(i); +@z + +@x [658] - font expansion +@ @<Determine horizontal glue stretch setting...@>= +begin @<Determine the stretch order@>; +@y +@ If |hpack| is called with |m=cal_expand_ratio| we calculate +|font_expand_ratio| and return without checking for overfull or underfull box. + +@<Determine horizontal glue stretch setting...@>= +begin @<Determine the stretch order@>; +if (m = cal_expand_ratio) and (o = normal) and (font_stretch > 0) then begin + font_expand_ratio := divide_scaled(x, font_stretch, 3); + return; +end; +@z + +@x [664] - font expansion +@ @<Determine horizontal glue shrink setting...@>= +begin @<Determine the shrink order@>; +@y +@ @<Determine horizontal glue shrink setting...@>= +begin @<Determine the shrink order@>; +if (m = cal_expand_ratio) and (o = normal) and (font_shrink > 0) then begin + font_expand_ratio := divide_scaled(x, font_shrink, 3); + return; +end; +@z + +@x [822] - font expansion +@d delta_node_size=7 {number of words in a delta node} +@y +@d delta_node_size=9 {number of words in a delta node} +@z + +@x [823] - font expansion, margin kerning, avoiding overfull boxes +@<Glo...@>= +@!active_width:array[1..6] of scaled; + {distance from first active node to~|cur_p|} +@!cur_active_width:array[1..6] of scaled; {distance from current active node} +@!background:array[1..6] of scaled; {length of an ``empty'' line} +@!break_width:array[1..6] of scaled; {length being computed after current break} +@y +@d do_seven_eight(#) == if pdf_adjust_spacing > 1 then begin #(7);#(8); end +@d do_all_eight(#) == do_all_six(#); do_seven_eight(#) +@d do_one_seven_eight(#) == #(1); do_seven_eight(#) + +@d total_font_stretch == cur_active_width[7] +@d total_font_shrink == cur_active_width[8] + +@d save_active_width(#) == prev_active_width[#] := active_width[#] +@d restore_active_width(#) == active_width[#] := prev_active_width[#] + +@<Glo...@>= +@!active_width:array[1..8] of scaled; + {distance from first active node to~|cur_p|} +@!cur_active_width:array[1..8] of scaled; {distance from current active node} +@!background:array[1..8] of scaled; {length of an ``empty'' line} +@!break_width:array[1..8] of scaled; {length being computed after current break} +@# +@!auto_breaking: boolean; {make |auto_breaking| accessible out of |line_break|} +@!prev_p: pointer; {make |prev_p| accessible out of |line_break|} +@!first_p: pointer; {to access the first node of the paragraph} +@!prev_char_p: pointer; {pointer to the previous char of an implicit kern} +@!next_char_p: pointer; {pointer to the next char of an implicit kern} +@# +@!try_prev_break: boolean; {force break at the previous legal breakpoint?} +@!prev_legal: pointer; {the previous legal breakpoint} +@!prev_prev_legal: pointer; {to save |prev_p| corresponding to |prev_legal|} +@!prev_auto_breaking: boolean; {to save |auto_breaking| corresponding to |prev_legal|} +@!prev_active_width: array[1..8] of scaled; {to save |active_width| corresponding to |prev_legal|} +@!rejected_cur_p: pointer; {the last |cur_p| that has been rejected} +@!before_rejected_cur_p: boolean; {|cur_p| is still before |rejected_cur_p|?} +@# +@!max_stretch_ratio: integer; {maximal stretch ratio of expanded fonts} +@!max_shrink_ratio: integer; {maximal shrink ratio of expanded fonts} +@!cur_font_step: integer; {the current step of expanded fonts} +@z + +@x [827] - font expansion +background[6]:=shrink(q)+shrink(r); +@y +background[6]:=shrink(q)+shrink(r); +if pdf_adjust_spacing > 1 then begin + background[7] := 0; + background[8] := 0; + max_stretch_ratio := -1; + max_shrink_ratio := -1; + cur_font_step := -1; + prev_char_p := null; +end; +@z + +@x [829] - margin kerning +@<Declare subprocedures for |line_break|@>= +procedure try_break(@!pi:integer;@!break_type:small_number); +@y +@d cp_skipable(#) == {skipable nodes at the margins during character protrusion} +( + not is_char_node(#) and + ( + (type(#) = ins_node) + or (type(#) = mark_node) + or (type(#) = adjust_node) + or (type(#) = penalty_node) + or ((type(#) = whatsit_node) and + (subtype(#) <> pdf_refximage_node) and + (subtype(#) <> pdf_refxform_node)) {reference to an image or XObject form} + or ((type(#) = disc_node) and + (pre_break(#) = null) and + (post_break(#) = null) and + (replace_count(#) = 0)) {an empty |disc_node|} + or ((type(#) = math_node) and (width(#) = 0)) + or ((type(#) = kern_node) and + ((width(#) = 0) or (subtype(#) = normal))) + or ((type(#) = glue_node) and (glue_ptr(#) = zero_glue)) + or ((type(#) = hlist_node) and (width(#) = 0) and (height(#) = 0) and + (depth(#) = 0) and (list_ptr(#) = null)) + ) +) + + +@<Declare subprocedures for |line_break|@>= +procedure push_node(p: pointer); +begin + if hlist_stack_level > max_hlist_stack then + pdf_error("push_node", "stack overflow"); + hlist_stack[hlist_stack_level] := p; + hlist_stack_level := hlist_stack_level + 1; +end; + +function pop_node: pointer; +begin + hlist_stack_level := hlist_stack_level - 1; + if hlist_stack_level < 0 then {would point to some bug} + pdf_error("pop_node", "stack underflow (internal error)"); + pop_node := hlist_stack[hlist_stack_level]; +end; + +function find_protchar_left(l: pointer; d: boolean): pointer; +{searches left to right from list head |l|, returns 1st non-skipable item} +var t: pointer; + run: boolean; +begin + if (link(l) <> null) and (type(l) = hlist_node) and (width(l) = 0) + and (height(l) = 0) and (depth(l) = 0) and (list_ptr(l) = null) then + l := link(l) {for paragraph start with \.{\\parindent = 0pt}} + else if d then + while (link(l) <> null) and (not (is_char_node(l) or non_discardable(l))) do + l := link(l); {std.\ discardables at line break, \TeX book, p 95} + hlist_stack_level := 0; + run := true; + repeat + t := l; + while run and (type(l) = hlist_node) and (list_ptr(l) <> null) do begin + push_node(l); + l := list_ptr(l); + end; + while run and cp_skipable(l) do begin + while (link(l) = null) and (hlist_stack_level > 0) do begin + l := pop_node; {don't visit this node again} + end; + if link(l) <> null then + l := link(l) + else if hlist_stack_level = 0 then run := false + end; + until t = l; + find_protchar_left := l; +end; + +function find_protchar_right(l, r: pointer): pointer; +{searches right to left from list tail |r| to head |l|, returns 1st non-skipable item} +var t: pointer; + run: boolean; +begin + find_protchar_right := null; + if r = null then return; + hlist_stack_level := 0; + run := true; + repeat + t := r; + while run and (type(r) = hlist_node) and (list_ptr(r) <> null) do begin + push_node(l); + push_node(r); + l := list_ptr(r); + r := l; + while link(r) <> null do + r := link(r); + end; + while run and cp_skipable(r) do begin + while (r = l) and (hlist_stack_level > 0) do begin + r := pop_node; {don't visit this node again} + l := pop_node; + end; + if (r <> l) and (r <> null) then + r := prev_rightmost(l, r) + else if (r = l) and (hlist_stack_level = 0) then run := false + end; + until t = r; + find_protchar_right := r; +end; + +function total_pw(q, p: pointer): scaled; +{returns the total width of character protrusion of a line; +|cur_break(break_node(q))| and |p| is the leftmost resp. rightmost node in the +horizontal list representing the actual line} +var l, r, s: pointer; + n: integer; +begin + if break_node(q) = null then + l := first_p + else + l := cur_break(break_node(q)); + r := prev_rightmost(prev_p, p); {get |link(r)=p|} + {let's look at the right margin first} + {| + short_display_n(r, 2); + print("&"); + short_display_n(p, 2); + print_ln; + |} + if (p <> null) and (type(p) = disc_node) and (pre_break(p) <> null) then + {a |disc_node| with non-empty |pre_break|, protrude the last char of |pre_break|} + begin + r := pre_break(p); + while link(r) <> null do + r := link(r); + end else r := find_protchar_right(l, r); + {now the left margin} + {| + short_display_n(l, 2); + print_ln; + breadth_max := 10; + depth_threshold := 2; + show_node_list(l); + print_ln; + |} + if (l <> null) and (type(l) = disc_node) then begin + if post_break(l) <> null then begin + l := post_break(l); {protrude the first char} + goto done; + end else {discard |replace_count(l)| nodes} + begin + n := replace_count(l); + l := link(l); + while n > 0 do begin + if link(l) <> null then + l := link(l); + decr(n); + end; + end; + end; + l := find_protchar_left(l, true); +done: + total_pw := left_pw(l) + right_pw(r); +end; + +procedure try_break(@!pi:integer;@!break_type:small_number); +@z + +@x +var r:pointer; {runs through the active list} +@y +var r:pointer; {runs through the active list} +@!margin_kern_stretch: scaled; +@!margin_kern_shrink: scaled; +@!lp, rp, cp: pointer; +@z + + +@x [829] - font expansion +do_all_six(copy_to_cur_active); +@y +do_all_eight(copy_to_cur_active); +@z + +@x [832] - font expansion + begin do_all_six(update_width); +@y + begin do_all_eight(update_width); +@z + +@x [837] - font expansion +begin no_break_yet:=false; do_all_six(set_break_width_to_background); +@y +begin no_break_yet:=false; do_all_eight(set_break_width_to_background); +@z + +@x [839] - font expansion +@<Glob...@>= +@!disc_width:scaled; {the length of discretionary material preceding a break} +@y +@d reset_disc_width(#) == disc_width[#] := 0 + +@d add_disc_width_to_break_width(#) == + break_width[#] := break_width[#] + disc_width[#] + +@d add_disc_width_to_active_width(#) == + active_width[#] := active_width[#] + disc_width[#] + +@d sub_disc_width_from_active_width(#) == + active_width[#] := active_width[#] - disc_width[#] + +@d add_char_stretch_end(#) == char_stretch(f, #) +@d add_char_stretch(#) == # := # + add_char_stretch_end + +@d add_char_shrink_end(#) == char_shrink(f, #) +@d add_char_shrink(#) == # := # + add_char_shrink_end + +@d sub_char_stretch_end(#) == char_stretch(f, #) +@d sub_char_stretch(#) == # := # - sub_char_stretch_end + +@d sub_char_shrink_end(#) == char_shrink(f, #) +@d sub_char_shrink(#) == # := # - sub_char_shrink_end + +@d add_kern_stretch_end(#) == kern_stretch(#) +@d add_kern_stretch(#) == # := # + add_kern_stretch_end + +@d add_kern_shrink_end(#) == kern_shrink(#) +@d add_kern_shrink(#) == # := # + add_kern_shrink_end + +@d sub_kern_stretch_end(#) == kern_stretch(#) +@d sub_kern_stretch(#) == # := # - sub_kern_stretch_end + +@d sub_kern_shrink_end(#) == kern_shrink(#) +@d sub_kern_shrink(#) == # := # - sub_kern_shrink_end + +@<Glob...@>= +@!disc_width: array[1..8] of scaled; {the length of discretionary material preceding a break} +@z + +@x [840] - font expansion +break_width[1]:=break_width[1]+disc_width; +@y +do_one_seven_eight(add_disc_width_to_break_width); +@z + +@x [841] - font expansion + break_width[1]:=break_width[1]-char_width(f)(char_info(f)(character(v))); +@y + break_width[1]:=break_width[1]-char_width(f)(char_info(f)(character(v))); + if (pdf_adjust_spacing > 1) and check_expand_pars(f) then begin + prev_char_p := v; + sub_char_stretch(break_width[7])(character(v)); + sub_char_shrink(break_width[8])(character(v)); + end; +@z + +@x [841] - font expansion + break_width[1]:=@|break_width[1]- + char_width(f)(char_info(f)(character(lig_char(v)))); +@y + break_width[1]:=@|break_width[1]- + char_width(f)(char_info(f)(character(lig_char(v)))); + if (pdf_adjust_spacing > 1) and check_expand_pars(f) then begin + prev_char_p := v; + sub_char_stretch(break_width[7])(character(lig_char(v))); + sub_char_shrink(break_width[8])(character(lig_char(v))); + end; +@z + +@x [841] - font expansion + hlist_node,vlist_node,rule_node,kern_node: + break_width[1]:=break_width[1]-width(v); +@y + hlist_node,vlist_node,rule_node,kern_node: begin + break_width[1]:=break_width[1]-width(v); + if (type(v) = kern_node) and + (pdf_adjust_spacing > 1) and (subtype(v) = normal) + then begin + sub_kern_stretch(break_width[7])(v); + sub_kern_shrink(break_width[8])(v); + end; + end; +@z + +@x [842] - font expansion + break_width[1]:=@|break_width[1]+char_width(f)(char_info(f)(character(s))); +@y + break_width[1]:=@|break_width[1]+char_width(f)(char_info(f)(character(s))); + if (pdf_adjust_spacing > 1) and check_expand_pars(f) then begin + prev_char_p := s; + add_char_stretch(break_width[7])(character(s)); + add_char_shrink(break_width[8])(character(s)); + end; +@z + +@x [842] - font expansion + break_width[1]:=break_width[1]+ + char_width(f)(char_info(f)(character(lig_char(s)))); +@y + break_width[1]:=break_width[1]+ + char_width(f)(char_info(f)(character(lig_char(s)))); + if (pdf_adjust_spacing > 1) and check_expand_pars(f) then begin + prev_char_p := s; + add_char_stretch(break_width[7])(character(lig_char(s))); + add_char_shrink(break_width[8])(character(lig_char(s))); + end; +@z + +@x [842] - font expansion + hlist_node,vlist_node,rule_node,kern_node: + break_width[1]:=break_width[1]+width(s); +@y + hlist_node,vlist_node,rule_node,kern_node: begin + break_width[1]:=break_width[1]+width(s); + if (type(s) = kern_node) and + (pdf_adjust_spacing > 1) and (subtype(s) = normal) + then begin + add_kern_stretch(break_width[7])(s); + add_kern_shrink(break_width[8])(s); + end; + end; +@z + +@x [843] - font expansion + begin do_all_six(convert_to_break_width); +@y + begin do_all_eight(convert_to_break_width); +@z + +@x [843] - font expansion + begin do_all_six(store_break_width); +@y + begin do_all_eight(store_break_width); +@z + +@x [843] - font expansion + do_all_six(new_delta_to_break_width); +@y + do_all_eight(new_delta_to_break_width); +@z + +@x [844] - font expansion + do_all_six(new_delta_from_break_width); +@y + do_all_eight(new_delta_from_break_width); +@z + +@x [851] - font expansion, margin kerning +shortfall:=line_width-cur_active_width[1]; {we're this much too short} +@y +shortfall:=line_width-cur_active_width[1]; {we're this much too short} + +{| +if pdf_output > 2 then begin +print_ln; +if (r <> null) and (break_node(r) <> null) then + short_display_n(cur_break(break_node(r)), 5); +print_ln; +short_display_n(cur_p, 5); +print_ln; +end; +|} + +if pdf_protrude_chars > 1 then + shortfall := shortfall + total_pw(r, cur_p); +if (pdf_adjust_spacing > 1) and (shortfall <> 0) then begin + margin_kern_stretch := 0; + margin_kern_shrink := 0; + if pdf_protrude_chars > 1 then + @<Calculate variations of marginal kerns@>; + if (shortfall > 0) and ((total_font_stretch + margin_kern_stretch) > 0) + then begin + if (total_font_stretch + margin_kern_stretch) > shortfall then + shortfall := ((total_font_stretch + margin_kern_stretch) div + (max_stretch_ratio div cur_font_step)) div 2 + else + shortfall := shortfall - (total_font_stretch + margin_kern_stretch); + end + else if (shortfall < 0) and ((total_font_shrink + margin_kern_shrink) > 0) + then begin + if (total_font_shrink + margin_kern_shrink) > -shortfall then + shortfall := -((total_font_shrink + margin_kern_shrink) div + (max_shrink_ratio div cur_font_step)) div 2 + else + shortfall := shortfall + (total_font_shrink + margin_kern_shrink); + end; +end; +@z + +@x [860] - font expansion + begin do_all_six(downdate_width); +@y + begin do_all_eight(downdate_width); +@z + +@x [860] - font expansion + begin do_all_six(update_width); + do_all_six(combine_two_deltas); +@y + begin do_all_eight(update_width); + do_all_eight(combine_two_deltas); +@z + +@x [861] - font expansion + begin do_all_six(update_active); + do_all_six(copy_to_cur_active); +@y + begin do_all_eight(update_active); + do_all_eight(copy_to_cur_active); +@z + +@x [862] - margin kerning, avoiding overfull boxes +@!auto_breaking:boolean; {is node |cur_p| outside a formula?} +@!prev_p:pointer; {helps to determine when glue nodes are breakpoints} +@y +@z + +@x [863] - margin kerning, avoiding overfull boxes + while (cur_p<>null)and(link(active)<>last_active) do +@y + prev_char_p := null; + prev_legal := null; + rejected_cur_p := null; + try_prev_break := false; + before_rejected_cur_p := false; + first_p := cur_p; {to access the first node of paragraph as the first active + node has |break_node=null|} + while (cur_p<>null)and(link(active)<>last_active) do +@z + +@x [864] - font expansion +do_all_six(store_background);@/ +@y +do_all_eight(store_background);@/ +@z + +@x [666] - font expansion + else act_width:=act_width+width(cur_p); +@y + else begin + act_width:=act_width+width(cur_p); + if (pdf_adjust_spacing > 1) and (subtype(cur_p) = normal) then begin + add_kern_stretch(active_width[7])(cur_p); + add_kern_shrink(active_width[8])(cur_p); + end; + end; +@z + +@x [866] - font expansion + act_width:=act_width+char_width(f)(char_info(f)(character(lig_char(cur_p)))); +@y + act_width:=act_width+char_width(f)(char_info(f)(character(lig_char(cur_p)))); + if (pdf_adjust_spacing > 1) and check_expand_pars(f) then begin + prev_char_p := cur_p; + add_char_stretch(active_width[7])(character(lig_char(cur_p))); + add_char_shrink(active_width[8])(character(lig_char(cur_p))); + end; +@z + +@x [867] - font expansion +act_width:=act_width+char_width(f)(char_info(f)(character(cur_p))); +@y +act_width:=act_width+char_width(f)(char_info(f)(character(cur_p))); +if (pdf_adjust_spacing > 1) and check_expand_pars(f) then begin + prev_char_p := cur_p; + add_char_stretch(active_width[7])(character(cur_p)); + add_char_shrink(active_width[8])(character(cur_p)); +end; +@z + +@x [869] - font expansion +begin s:=pre_break(cur_p); disc_width:=0; +@y +begin s:=pre_break(cur_p); +do_one_seven_eight(reset_disc_width); +@z + +@x [869] - font expansion + act_width:=act_width+disc_width; + try_break(hyphen_penalty,hyphenated); + act_width:=act_width-disc_width; +@y + do_one_seven_eight(add_disc_width_to_active_width); + try_break(hyphen_penalty,hyphenated); + do_one_seven_eight(sub_disc_width_from_active_width); +@z + +@x [870] - font expansion + disc_width:=disc_width+char_width(f)(char_info(f)(character(s))); +@y + disc_width[1]:=disc_width[1]+char_width(f)(char_info(f)(character(s))); + if (pdf_adjust_spacing > 1) and check_expand_pars(f) then begin + prev_char_p := s; + add_char_stretch(disc_width[7])(character(s)); + add_char_shrink(disc_width[8])(character(s)); + end; +@z + +@x [870] - font expansion + disc_width:=disc_width+ + char_width(f)(char_info(f)(character(lig_char(s)))); +@y + disc_width[1]:=disc_width[1]+ + char_width(f)(char_info(f)(character(lig_char(s)))); + if (pdf_adjust_spacing > 1) and check_expand_pars(f) then begin + prev_char_p := s; + add_char_stretch(disc_width[7])(character(lig_char(s))); + add_char_shrink(disc_width[8])(character(lig_char(s))); + end; +@z + +@x [870] - font expansion + hlist_node,vlist_node,rule_node,kern_node: + disc_width:=disc_width+width(s); +@y + hlist_node,vlist_node,rule_node,kern_node: begin + disc_width[1]:=disc_width[1]+width(s); + if (type(s) = kern_node) and + (pdf_adjust_spacing > 1) and (subtype(s) = normal) + then begin + add_kern_stretch(disc_width[7])(s); + add_kern_shrink(disc_width[8])(s); + end; + end; +@z + +@x [871] - font expansion + act_width:=act_width+char_width(f)(char_info(f)(character(s))); +@y + act_width:=act_width+char_width(f)(char_info(f)(character(s))); + if (pdf_adjust_spacing > 1) and check_expand_pars(f) then begin + prev_char_p := s; + add_char_stretch(active_width[7])(character(s)); + add_char_shrink(active_width[8])(character(s)); + end; +@z + +@x [871] - font expansion + act_width:=act_width+ + char_width(f)(char_info(f)(character(lig_char(s)))); +@y + act_width:=act_width+ + char_width(f)(char_info(f)(character(lig_char(s)))); + if (pdf_adjust_spacing > 1) and check_expand_pars(f) then begin + prev_char_p := s; + add_char_stretch(active_width[7])(character(lig_char(s))); + add_char_shrink(active_width[8])(character(lig_char(s))); + end; +@z + +@x [871] - font expansion + hlist_node,vlist_node,rule_node,kern_node: + act_width:=act_width+width(s); +@y + hlist_node,vlist_node,rule_node,kern_node: begin + act_width:=act_width+width(s); + if (type(s) = kern_node) and + (pdf_adjust_spacing > 1) and (subtype(s) = normal) + then begin + add_kern_stretch(active_width[7])(s); + add_kern_shrink(active_width[8])(s); + end; + end; +@z + +@x [877] - margin kerning +var q,@!r,@!s:pointer; {temporary registers for list manipulation} +@y +var q,@!r,@!s:pointer; {temporary registers for list manipulation} + p, k: pointer; + w: scaled; + glue_break: boolean; {was a break at glue?} + ptmp: pointer; +@z + +@x [881] - margin kerning +q:=cur_break(cur_p); disc_break:=false; post_disc_break:=false; +@y +q:=cur_break(cur_p); disc_break:=false; post_disc_break:=false; +glue_break := false; +@z + +@x [881] - margin kerning + subtype(q):=right_skip_code+1; add_glue_ref(right_skip); + goto done; +@y + subtype(q):=right_skip_code+1; add_glue_ref(right_skip); + glue_break := true; + goto done; +@z + +@x [881] - margin kerning +@<Put the \(r)\.{\\rightskip} glue after node |q|@>; +done: +@y +done: + +{at this point |q| is the rightmost breakpoint; the only exception is the case +of a discretionary break with non-empty |pre_break|, then |q| has been changed +to the last node of the |pre_break| list} + +if pdf_protrude_chars > 0 then begin + if disc_break and (is_char_node(q) or (type(q) <> disc_node)) + {|q| has been reset to the last node of |pre_break|} + then begin + p := q; + ptmp := p; + end else begin + p := prev_rightmost(temp_head, q); {get |link(p) = q|} + ptmp := p; + p := find_protchar_right(temp_head, p); + end; + {| + short_display_n(p, 1); + print_ln; + |} + w := right_pw(p); + if w <> 0 then {we have found a marginal kern, append it after |ptmp|} + begin + k := new_margin_kern(-w, last_rightmost_char, right_side); + link(k) := link(ptmp); + link(ptmp) := k; + if (ptmp = q) then + q := link(q); + end; +end; + +{if |q| was not a breakpoint at glue and has been reset to |rightskip| then + we append |rightskip| after |q| now} +if not glue_break then begin + @<Put the \(r)\.{\\rightskip} glue after node |q|@>; +end; +@z + +@x [887] - margin kerning +if left_skip<>zero_glue then +@y +{at this point |q| is the leftmost node; all discardable nodes have been discarded} +if pdf_protrude_chars > 0 then begin + p := q; + p := find_protchar_left(p, false); {no more discardables} + w := left_pw(p); + if w <> 0 then begin + k := new_margin_kern(-w, last_leftmost_char, left_side); + link(k) := q; + q := k; + end; +end; +if left_skip<>zero_glue then +@z + +@x [889] - font expansion, pre vadjust +just_box:=hpack(q,cur_width,exactly); +@y +if pdf_adjust_spacing > 0 then + just_box := hpack(q, cur_width, cal_expand_ratio) +else + just_box := hpack(q, cur_width, exactly); +@z + +@x [1110] - margin kerning +var p:pointer; {the box} +@y +var p:pointer; {the box} + r: pointer; {to remove marginal kern nodes} +@z + +@x [1110] - margin kerning +while link(tail)<>null do tail:=link(tail); +@y +while link(tail) <> null do begin + r := link(tail); + if not is_char_node(r) and (type(r) = margin_kern_node) then begin + link(tail) := link(r); + free_avail(margin_char(r)); + free_node(r, margin_kern_node_size); + end; + tail:=link(tail); +end; +@z + +@x [1147] - margin kerning +ligature_node:@<Make node |p| look like a |char_node|...@>; +@y +ligature_node:@<Make node |p| look like a |char_node|...@>; +margin_kern_node: d:=width(p); +@z + +@x [1253] - font expansion +assign_font_int: begin n:=cur_chr; scan_font_ident; f:=cur_val; + scan_optional_equals; scan_int; + if n=0 then hyphen_char[f]:=cur_val@+else skew_char[f]:=cur_val; + end; +@y +assign_font_int: begin n:=cur_chr; scan_font_ident; f:=cur_val; + if n < lp_code_base then begin + scan_optional_equals; scan_int; + if n=0 then hyphen_char[f]:=cur_val@+else skew_char[f]:=cur_val; + end + else begin + scan_char_num; p := cur_val; + scan_optional_equals; scan_int; + case n of + lp_code_base: set_lp_code(f, p, cur_val); + rp_code_base: set_rp_code(f, p, cur_val); + ef_code_base: set_ef_code(f, p, cur_val); + end; + end; +end; +@z + +@x [1254] - font expansion +primitive("skewchar",assign_font_int,1); +@!@:skew_char_}{\.{\\skewchar} primitive@> +@y +primitive("skewchar",assign_font_int,1); +@!@:skew_char_}{\.{\\skewchar} primitive@> +primitive("lpcode",assign_font_int,lp_code_base); +@!@:lp_code_}{\.{\\lpcode} primitive@> +primitive("rpcode",assign_font_int,rp_code_base); +@!@:rp_code_}{\.{\\rpcode} primitive@> +primitive("efcode",assign_font_int,ef_code_base); +@!@:ef_code_}{\.{\\efcode} primitive@> +@z + +@x [1255] - font expansion +assign_font_int: if chr_code=0 then print_esc("hyphenchar") + else print_esc("skewchar"); +@y +assign_font_int: case chr_code of +0: print_esc("hyphenchar"); +1: print_esc("skewchar"); +lp_code_base: print_esc("lpcode"); +rp_code_base: print_esc("rpcode"); +ef_code_base: print_esc("efcode"); +endcases; +@z + +@x [1344] +@d pdftex_last_extension_code == pdftex_first_extension_code + 27 +@y +@d pdf_font_expand_code == pdftex_first_extension_code + 28 +@d pdftex_last_extension_code == pdftex_first_extension_code + 28 +@z + +@x [1344] +primitive("setlanguage",extension,set_language_code);@/ +@!@:set_language_}{\.{\\setlanguage} primitive@> +@y +primitive("setlanguage",extension,set_language_code);@/ +@!@:set_language_}{\.{\\setlanguage} primitive@> +primitive("pdffontexpand",extension,pdf_font_expand_code);@/ +@!@:pdf_font_expand_}{\.{\\pdffontexpand} primitive@> +@z + +@x [1346] + immediate_code:print_esc("immediate"); + set_language_code:print_esc("setlanguage"); +@y + immediate_code:print_esc("immediate"); + set_language_code:print_esc("setlanguage"); + pdf_font_expand_code: print_esc("pdffontexpand"); +@z + +@x [1348] +set_language_code:@<Implement \.{\\setlanguage}@>; +@y +set_language_code:@<Implement \.{\\setlanguage}@>; +pdf_font_expand_code: @<Implement \.{\\pdffontexpand}@>; +@z + +@x [1354] +@<Implement \.{\\special}@>= +begin new_whatsit(special_node,write_node_size); write_stream(tail):=null; +p:=scan_toks(false,true); write_tokens(tail):=def_ref; +end +@y +@<Implement \.{\\special}@>= +begin new_whatsit(special_node,write_node_size); write_stream(tail):=null; +p:=scan_toks(false,true); write_tokens(tail):=def_ref; +end + +@ @<Implement \.{\\pdffontexpand}@>= + read_expand_font +@z + +@x [15??] +@<Declare procedures that need to be declared forward for pdftex@>= +@y +@<Declare procedures that need to be declared forward for pdftex@>= +function prev_rightmost(s, e: pointer): pointer; +{finds the node preceding the rightmost node |e|; |s| is some node +before |e|} +var p: pointer; +begin + prev_rightmost := null; + p := s; + if p = null then + return; + while link(p) <> e do begin + p := link(p); + if p = null then + return; + end; + prev_rightmost := p; +end; +@z + diff --git a/Build/source/texk/web2c/pdftexdir/image.h b/Build/source/texk/web2c/pdftexdir/image.h new file mode 100644 index 00000000000..2f9dcc94171 --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/image.h @@ -0,0 +1,104 @@ +/* +Copyright (c) 1996-2002 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/image.h#10 $ +*/ + +#include <png.h> + +/* JPG_IMAGE_INFO is main structure for interchange of image data */ + +#define JPG_UINT16 unsigned int +#define JPG_UINT32 unsigned long +#define JPG_UINT8 unsigned char + +typedef struct { + int color_space; /* used color space. See JPG_ constants */ + JPG_UINT8 bits_per_component; /* bits per component */ + JPG_UINT32 length; /* length of file/data */ + FILE *file; /* jpg file */ +} JPG_IMAGE_INFO; + +typedef struct { + png_structp png_ptr; + png_infop info_ptr; +} png_image_struct; + +typedef struct { + integer orig_x; + integer orig_y; + integer selected_page; + integer page_box; + integer always_use_pdfpagebox; + void *doc; +} pdf_image_struct; + +typedef struct { + char *image_name; + int image_type; + int color_type; + integer width; + integer height; + integer x_res; + integer y_res; + integer num_pages; + integer colorspace_ref; + union { + pdf_image_struct *pdf; + png_image_struct png; + JPG_IMAGE_INFO *jpg; + } image_struct; +} image_entry; + +extern image_entry *image_ptr, *image_array; +extern integer image_max; + +#define IMAGE_TYPE_NONE 0 +#define IMAGE_TYPE_PDF 1 +#define IMAGE_TYPE_PNG 2 +#define IMAGE_TYPE_JPG 3 +#define IMAGE_TYPE_TIF 4 + +#define IMAGE_COLOR_B 1 +#define IMAGE_COLOR_C 2 +#define IMAGE_COLOR_I 4 + +#define img_ptr(N) (image_array + (N)) +#define img_name(N) (img_ptr(N)->image_name) +#define img_type(N) (img_ptr(N)->image_type) +#define img_color(N) (img_ptr(N)->color_type) +#define img_colorspace_ref(N) (img_ptr(N)->colorspace_ref) +#define img_pages(N) (img_ptr(N)->num_pages) +#define img_width(N) (img_ptr(N)->width) +#define img_height(N) (img_ptr(N)->height) +#define img_xres(N) (img_ptr(N)->x_res) +#define img_yres(N) (img_ptr(N)->y_res) +#define png_ptr(N) (img_ptr(N)->image_struct.png.png_ptr) +#define png_info(N) (img_ptr(N)->image_struct.png.info_ptr) +#define pdf_ptr(N) (img_ptr(N)->image_struct.pdf) +#define jpg_ptr(N) (img_ptr(N)->image_struct.jpg) +#define tif_ptr(N) (img_ptr(N)->image_struct.tif) + +extern integer read_pdf_info(char*, char*, integer, integer, integer, integer); +extern void write_epdf(void); +extern void epdf_delete(void); +extern void read_png_info(integer); +extern void write_png(integer); +extern void read_jpg_info(integer); +extern void write_jpg(integer); diff --git a/Build/source/texk/web2c/pdftexdir/macnames.c b/Build/source/texk/web2c/pdftexdir/macnames.c new file mode 100644 index 00000000000..7f2005e8e20 --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/macnames.c @@ -0,0 +1,312 @@ +/* +Copyright (c) 1996-2002 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/macnames.c#5 $ +*/ + +const char notdef[] = ".notdef"; + +const char *mac_glyph_names[] = { +/* 0x00 */ + notdef, + ".null", + "CR", + "space", + "exclam", + "quotedbl", + "numbersign", + "dollar", + "percent", + "ampersand", + "quotesingle", + "parenleft", + "parenright", + "asterisk", + "plus", + "comma", +/* 0x10 */ + "hyphen", + "period", + "slash", + "zero", + "one", + "two", + "three", + "four", + "five", + "six", + "seven", + "eight", + "nine", + "colon", + "semicolon", + "less", +/* 0x20 */ + "equal", + "greater", + "question", + "at", + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", +/* 0x30 */ + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", + "bracketleft", + "backslash", +/* 0x40 */ + "bracketright", + "asciicircum", + "underscore", + "grave", + "a", + "b", + "c", + "d", + "e", + "f", + "g", + "h", + "i", + "j", + "k", + "l", +/* 0x50 */ + "m", + "n", + "o", + "p", + "q", + "r", + "s", + "t", + "u", + "v", + "w", + "x", + "y", + "z", + "braceleft", + "bar", +/* 0x60 */ + "braceright", + "asciitilde", + "Adieresis", + "Aring", + "Ccedilla", + "Eacute", + "Ntilde", + "Odieresis", + "Udieresis", + "aacute", + "agrave", + "acircumflex", + "adieresis", + "atilde", + "aring", + "ccedilla", +/* 0x70 */ + "eacute", + "egrave", + "ecircumflex", + "edieresis", + "iacute", + "igrave", + "icircumflex", + "idieresis", + "ntilde", + "oacute", + "ograve", + "ocircumflex", + "odieresis", + "otilde", + "uacute", + "ugrave", +/* 0x80 */ + "ucircumflex", + "udieresis", + "dagger", + "degree", + "cent", + "sterling", + "section", + "bullet", + "paragraph", + "germandbls", + "registered", + "copyright", + "trademark", + "acute", + "dieresis", + "notequal", +/* 0x90 */ + "AE", + "Oslash", + "infinity", + "plusminus", + "lessequal", + "greaterequal", + "yen", + "mu", + "partialdiff", + "Sigma", + "Pi", + "pi", + "integral", + "ordfeminine", + "ordmasculine", + "Omega", +/* 0xa0 */ + "ae", + "oslash", + "questiondown", + "exclamdown", + "logicalnot", + "radical", + "florin", + "approxequal", + "Delta", + "guillemotleft", + "guillemotright", + "ellipsis", + "nbspace", + "Agrave", + "Atilde", + "Otilde", +/* 0xb0 */ + "OE", + "oe", + "endash", + "emdash", + "quotedblleft", + "quotedblright", + "quoteleft", + "quoteright", + "divide", + "lozenge", + "ydieresis", + "Ydieresis", + "fraction", + "currency", + "guilsinglleft", + "guilsinglright", +/* 0xc0 */ + "fi", + "fl", + "daggerdbl", + "periodcentered", + "quotesinglbase", + "quotedblbase", + "perthousand", + "Acircumflex", + "Ecircumflex", + "Aacute", + "Edieresis", + "Egrave", + "Iacute", + "Icircumflex", + "Idieresis", + "Igrave", +/* 0xd0 */ + "Oacute", + "Ocircumflex", + "applelogo", + "Ograve", + "Uacute", + "Ucircumflex", + "Ugrave", + "dotlessi", + "circumflex", + "tilde", + "macron", + "breve", + "dotaccent", + "ring", + "cedilla", + "hungarumlaut", +/* 0xe0 */ + "ogonek", + "caron", + "Lslash", + "lslash", + "Scaron", + "scaron", + "Zcaron", + "zcaron", + "brokenbar", + "Eth", + "eth", + "Yacute", + "yacute", + "Thorn", + "thorn", + "minus", +/* 0xf0 */ + "multiply", + "onesuperior", + "twosuperior", + "threesuperior", + "onehalf", + "onequarter", + "threequarters", + "franc", + "Gbreve", + "gbreve", + "Idot", + "Scedilla", + "scedilla", + "Cacute", + "cacute", + "Ccaron", +/* 0x100 */ + "ccaron", + "dmacron" +}; + +const char *ambiguous_names[] = { + "Delta", /* increment */ + "Omega", /* Ohm */ + "Pi", /* product */ + "Sigma", /* summation */ + "dmacron", /* dslash */ + "macron", /* overscore */ + "periodcentered", /* middot */ + NULL +}; diff --git a/Build/source/texk/web2c/pdftexdir/mapfile.c b/Build/source/texk/web2c/pdftexdir/mapfile.c new file mode 100644 index 00000000000..758290127ca --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/mapfile.c @@ -0,0 +1,1150 @@ +/* +Copyright (c) 1996-2005 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/mapfile.c#30 $ + +source code indentation by "indent -kr -nut" +*/ + +#include <math.h> +#include "ptexlib.h" +#include <kpathsea/c-auto.h> +#include <kpathsea/c-memstr.h> +#include "avlstuff.h" + +static const char perforce_id[] = + "$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/mapfile.c#30 $"; + +#define FM_BUF_SIZE 1024 + +static FILE *fm_file; + +#define fm_open() \ + open_input (&fm_file, kpse_fontmap_format, FOPEN_RBIN_MODE) +#define fm_close() xfclose(fm_file, cur_file_name) +#define fm_getchar() xgetc(fm_file) +#define fm_eof() feof(fm_file) + +enum _mode { FM_DUPIGNORE, FM_REPLACE, FM_DELETE }; +enum _ltype { MAPFILE, MAPLINE }; +enum _tfmavail { TFM_UNCHECKED, TFM_FOUND, TFM_NOTFOUND }; + +typedef struct mitem { + int mode; /* FM_DUPIGNORE or FM_REPLACE or FM_DELETE */ + int type; /* map file or map line */ + char *line; /* pointer to map file name or map line */ + int lineno; /* line number in map file */ + struct mitem *next; /* pointer to next item, or NULL */ +} mapitem; +mapitem *miptr, *mapitems = NULL; + +fm_entry *fm_cur; +static const char nontfm[] = "<nontfm>"; +static fm_entry *loaded_tfm_found; +static fm_entry *avail_tfm_found; +static fm_entry *non_tfm_found; +static fm_entry *not_avail_tfm_found; + +#define read_field(r, q, buf) do { \ + for (q = buf; *r != ' ' && *r != 10; *q++ = *r++); \ + *q = 0; \ + skip (r, ' '); \ +} while (0) + +#define set_field(F) do { \ + if (q > buf) \ + fm->F = xstrdup(buf); \ + if (*r == 10) \ + goto done; \ +} while (0) + +static fm_entry *new_fm_entry(void) +{ + fm_entry *fm; + fm = xtalloc(1, fm_entry); + fm->tfm_name = NULL; + fm->ps_name = NULL; + fm->flags = 0; + fm->ff_name = NULL; + fm->subset_tag = NULL; + fm->encoding = NULL; + fm->tfm_num = getnullfont(); + fm->tfm_avail = TFM_UNCHECKED; + fm->type = 0; + fm->slant = 0; + fm->extend = 0; + fm->ff_objnum = 0; + fm->fn_objnum = 0; + fm->fd_objnum = 0; + fm->charset = NULL; + fm->all_glyphs = false; + fm->links = 0; + return fm; +} + +static void delete_fm_entry(fm_entry * fm) +{ + xfree(fm->tfm_name); + xfree(fm->ps_name); + xfree(fm->ff_name); + xfree(fm->subset_tag); + xfree(fm->charset); + xfree(fm); +} + +static ff_entry *new_ff_entry(void) +{ + ff_entry *ff; + ff = xtalloc(1, ff_entry); + ff->ff_name = NULL; + ff->ff_path = NULL; + return ff; +} + +static void delete_ff_entry(ff_entry * ff) +{ + xfree(ff->ff_name); + xfree(ff->ff_path); + xfree(ff); +} + +static fm_entry *dummy_fm_entry() +{ + static const fm_entry const_fm_entry; + return (fm_entry *) & const_fm_entry; +} + +char *mk_base_tfm(char *tfmname, int *i) +{ + static char buf[SMALL_BUF_SIZE]; + char *p = tfmname, *r = strend(p) - 1, *q = r; + while (q > p && isdigit(*q)) + --q; + if (!(q > p) || q == r || (*q != '+' && *q != '-')) + return NULL; + check_buf(q - p + 1, SMALL_BUF_SIZE); + strncpy(buf, p, (unsigned) (q - p)); + buf[q - p] = 0; + *i = atoi(q); + return buf; +} + +static fmentryptr fmlookup(internalfontnumber); + +boolean hasfmentry(internalfontnumber f) +{ + if (pdffontmap[f] == NULL) + pdffontmap[f] = fmlookup(f); + assert(pdffontmap[f] != NULL); + return pdffontmap[f] != (fmentryptr) dummy_fm_entry(); +} + +/**********************************************************************/ + +struct avl_table *tfm_tree = NULL; +struct avl_table *ps_tree = NULL; +struct avl_table *ff_tree = NULL; + +/* AVL sort fm_entry into tfm_tree by tfm_name */ + +static int comp_fm_entry_tfm(const void *pa, const void *pb, void *p) +{ + return strcmp(((const fm_entry *) pa)->tfm_name, + ((const fm_entry *) pb)->tfm_name); +} + +#define cmp_return(a, b) \ + if (a > b) \ + return 1; \ + if (a < b) \ + return -1 + +/* AVL sort fm_entry into ps_tree by ps_name, slant, and extend */ + +static int comp_fm_entry_ps(const void *pa, const void *pb, void *p) +{ + const fm_entry *p1 = (const fm_entry *) pa, *p2 = + (const fm_entry *) pb; + int i; + assert(p1->ps_name != NULL && p2->ps_name != NULL); + if ((i = strcmp(p1->ps_name, p2->ps_name)) != 0) + return i; + cmp_return(p1->slant, p2->slant); + cmp_return(p1->extend, p2->extend); + if (p1->tfm_name != NULL && p2->tfm_name != NULL && + (i = strcmp(p1->tfm_name, p2->tfm_name)) != 0) + return i; + return 0; +} + +/* AVL sort ff_entry into ff_tree by ff_name */ + +static int comp_ff_entry(const void *pa, const void *pb, void *p) +{ + return strcmp(((const ff_entry *) pa)->ff_name, + ((const ff_entry *) pb)->ff_name); +} + +static void create_avl_trees() +{ + if (tfm_tree == NULL) { + tfm_tree = avl_create(comp_fm_entry_tfm, NULL, &avl_xallocator); + assert(tfm_tree != NULL); + } + if (ps_tree == NULL) { + ps_tree = avl_create(comp_fm_entry_ps, NULL, &avl_xallocator); + assert(ps_tree != NULL); + } + if (ff_tree == NULL) { + ff_tree = avl_create(comp_ff_entry, NULL, &avl_xallocator); + assert(ff_tree != NULL); + } +} + +/* +The function avl_do_entry() is not completely symmetrical with regards +to tfm_name and ps_name handling, e. g. a duplicate tfm_name gives a +"goto exit", and no ps_name link is tried. This is to keep it compatible +with the original version. +*/ + +static int avl_do_entry(fm_entry * fp, int mode) +{ + fm_entry *p, *p2; + void *a; + void **aa; + struct avl_traverser trav; + + /* handle tfm_name link */ + + if (strcmp(fp->tfm_name, nontfm) != 0) { + p = (fm_entry *) avl_find(tfm_tree, fp); + if (p != NULL) { + if (mode == FM_DUPIGNORE) { + pdftex_warn + ("fontmap entry for `%s' already exists, duplicates ignored", + fp->tfm_name); + goto exit; + } else { /* mode == FM_REPLACE / FM_DELETE */ + if (fontused[p->tfm_num]) { + pdftex_warn + ("fontmap entry for `%s' has been used, replace/delete not allowed", + fp->tfm_name); + goto exit; + } + a = avl_delete(tfm_tree, p); + assert(a != NULL); + unset_tfmlink(p); + if (!has_pslink(p)) + delete_fm_entry(p); + } + } + if (mode != FM_DELETE) { + aa = avl_probe(tfm_tree, fp); + assert(aa != NULL); + set_tfmlink(fp); + } + } + + /* handle ps_name link */ + + if (fp->ps_name != NULL) { + assert(fp->tfm_name != NULL); + p = (fm_entry *) avl_find(ps_tree, fp); + if (p != NULL) { + if (mode == FM_DUPIGNORE) { + pdftex_warn + ("ps_name entry for `%s' already exists, duplicates ignored", + fp->ps_name); + goto exit; + } else { /* mode == FM_REPLACE / FM_DELETE */ + if (fontused[p->tfm_num]) { + /* REPLACE/DELETE not allowed */ + pdftex_warn + ("fontmap entry for `%s' has been used, replace/delete not allowed", + p->tfm_name); + goto exit; + } + a = avl_delete(ps_tree, p); + assert(a != NULL); + unset_pslink(p); + if (!has_tfmlink(p)) + delete_fm_entry(p); + } + } + if (mode != FM_DELETE) { + aa = avl_probe(ps_tree, fp); + assert(aa != NULL); + set_pslink(fp); + } + } + exit: + if (!has_tfmlink(fp) && !has_pslink(fp)) /* e. g. after FM_DELETE */ + return 1; /* deallocation of fm_entry structure required */ + else + return 0; +} + +/**********************************************************************/ +/* consistency check for map entry, with warn flag */ + +int check_fm_entry(fm_entry * fm, boolean warn) +{ + int a = 0; + assert(fm != NULL); + if (fm->ps_name != NULL) { + if (is_basefont(fm)) { + if (is_fontfile(fm) && !is_included(fm)) { + if (warn) + pdftex_warn + ("invalid entry for `%s': font file must be included or omitted for base fonts", + fm->tfm_name); + a += 1; + } + } else { /* not a base font */ + /* if no font file given, drop this entry */ + if (!is_fontfile(fm)) { + if (warn) + pdftex_warn + ("invalid entry for `%s': font file missing", + fm->tfm_name); + a += 2; + } + } + } + if (is_truetype(fm) && is_reencoded(fm) && !is_subsetted(fm)) { + if (warn) + pdftex_warn + ("invalid entry for `%s': only subsetted TrueType font can be reencoded", + fm->tfm_name); + a += 4; + } + if ((fm->slant != 0 || fm->extend != 0) && + (!is_included(fm) || is_truetype(fm))) { + if (warn) + pdftex_warn + ("invalid entry for `%s': SlantFont/ExtendFont can be used only with embedded T1 fonts", + fm->tfm_name); + a += 8; + } + if (abs(fm->slant) > 1000) { + if (warn) + pdftex_warn + ("invalid entry for `%s': too big value of SlantFont (%g)", + fm->tfm_name, fm->slant / 1000.0); + a += 16; + } + if (abs(fm->extend) > 2000) { + if (warn) + pdftex_warn + ("invalid entry for `%s': too big value of ExtendFont (%g)", + fm->tfm_name, fm->extend / 1000.0); + a += 32; + } + return a; +} + +/**********************************************************************/ +/* returns true if s is one of the 14 std. font names; speed-trimmed. */ + +boolean check_basefont(char *s) +{ + static const char *basefont_names[] = { + "Courier", /* 0:7 */ + "Courier-Bold", /* 1:12 */ + "Courier-Oblique", /* 2:15 */ + "Courier-BoldOblique", /* 3:19 */ + "Helvetica", /* 4:9 */ + "Helvetica-Bold", /* 5:14 */ + "Helvetica-Oblique", /* 6:17 */ + "Helvetica-BoldOblique", /* 7:21 */ + "Symbol", /* 8:6 */ + "Times-Roman", /* 9:11 */ + "Times-Bold", /* 10:10 */ + "Times-Italic", /* 11:12 */ + "Times-BoldItalic", /* 12:16 */ + "ZapfDingbats" /* 13:12 */ + }; + static const int index[] = + { -1, -1, -1, -1, -1, -1, 8, 0, -1, 4, 10, 9, -1, -1, 5, 2, 12, 6, + -1, 3, -1, 7 + }; + int n = strlen(s), k = -1; + if (n > 21) + return false; + if (n == 12) { /* three names have length 12 */ + switch (*s) { + case 'C': + k = 1; /* Courier-Bold */ + break; + case 'T': + k = 11; /* Times-Italic */ + break; + case 'Z': + k = 13; /* ZapfDingbats */ + break; + default: + return false; + } + } else + k = index[n]; + if (k > -1 && strcmp(basefont_names[k], s) == 0) + return true; + return false; +}; + +/**********************************************************************/ + +static void fm_scan_line(mapitem * mitem) +{ + int a, b, c, j, u = 0, v = 0; + float d; + char fm_line[FM_BUF_SIZE], buf[FM_BUF_SIZE]; + fm_entry *fm; + char *p, *q, *r, *s; + p = fm_line; + switch (mitem->type) { + case MAPFILE: + do { + c = fm_getchar(); + append_char_to_buf(c, p, fm_line, FM_BUF_SIZE); + } + while (c != 10); + break; + case MAPLINE: + s = mitem->line; + while ((c = *s++) != 0) + append_char_to_buf(c, p, fm_line, FM_BUF_SIZE); + break; + default: + assert(0); + } + append_eol(p, fm_line, FM_BUF_SIZE); + if (is_cfg_comment(*fm_line)) + return; + r = fm_line; + read_field(r, q, buf); + fm = new_fm_entry(); + set_field(tfm_name); + p = r; + read_field(r, q, buf); + if (*buf != '<' && *buf != '"') + set_field(ps_name); + else + r = p; /* unget the field */ + if (isdigit(*r)) { /* font flags given */ + fm->flags = atoi(r); + while (isdigit(*r)) + r++; + } else + fm->flags = 4; /* treat as Symbol font */ + while (1) { /* loop through "specials", encoding, font file */ + skip(r, ' '); + switch (*r) { + case 10: + goto done; + case '"': /* opening quote */ + r++; + u = v = 0; + do { + skip(r, ' '); + if (sscanf(r, "%f %n", &d, &j) > 0) { + s = r + j; /* jump behind number, eat also blanks, if any */ + if (*(s - 1) == 'E' || *(s - 1) == 'e') + s--; /* e. g. 0.5ExtendFont: %f = 0.5E */ + if (strncmp(s, "SlantFont", strlen("SlantFont")) == 0) { + d *= 1000.0; /* correct rounding also for neg. numbers */ + fm->slant = (integer) (d > 0 ? d + 0.5 : d - 0.5); + r = s + strlen("SlantFont"); + } else + if (strncmp(s, "ExtendFont", strlen("ExtendFont")) + == 0) { + d *= 1000.0; + fm->extend = (integer) (d > 0 ? d + 0.5 : d - 0.5); + if (fm->extend == 1000) + fm->extend = 0; + r = s + strlen("ExtendFont"); + } else { /* unknown name */ + for (r = s; *r != ' ' && *r != '"' && *r != 10; r++); /* jump over name */ + c = *r; /* remember char for temporary end of string */ + *r = '\0'; + pdftex_warn + ("invalid entry for `%s': unknown name `%s' ignored", + fm->tfm_name, s); + *r = c; + } + } else + for (; *r != ' ' && *r != '"' && *r != 10; r++); + } + while (*r == ' '); + if (*r == '"') /* closing quote */ + r++; + else { + pdftex_warn + ("invalid entry for `%s': closing quote missing", + fm->tfm_name); + goto bad_line; + } + break; + default: /* encoding or font file specification */ + a = b = 0; + if (*r == '<') { + a = *r++; + if (*r == '<' || *r == '[') + b = *r++; + } + read_field(r, q, buf); + /* encoding, formats: '8r.enc' or '<8r.enc' or '<[8r.enc' */ + if (strlen(buf) > 4 + && strcasecmp(strend(buf) - 4, ".enc") == 0) { + fm->encoding = add_enc(buf); + u = v = 0; /* u, v used if intervening blank: "<< foo" */ + } else if (strlen(buf) > 0) { /* file name given */ + /* font file, formats: + * subsetting: '<cmr10.pfa' + * no subsetting: '<<cmr10.pfa' + * no embedding: 'cmr10.pfa' + */ + if (a == '<' || u == '<') { + set_included(fm); + if ((a == '<' && b == 0) || (a == 0 && v == 0)) + set_subsetted(fm); + /* otherwise b == '<' (or '[') => no subsetting */ + } + set_field(ff_name); + u = v = 0; + } else { + u = a; + v = b; + } + } + } + done: + if (fm->ps_name != NULL && check_basefont(fm->ps_name)) + set_basefont(fm); + if (is_fontfile(fm) + && strcasecmp(strend(fm_fontfile(fm)) - 4, ".ttf") == 0) + set_truetype(fm); + if (check_fm_entry(fm, true) != 0) + goto bad_line; + /* + Until here the map line has been completely scanned without errors; + fm points to a valid, freshly filled-out fm_entry structure. + Now follows the actual work of registering/deleting. + */ + if (avl_do_entry(fm, mitem->mode) == 0) /* if success */ + return; + bad_line: + delete_fm_entry(fm); +} + +/**********************************************************************/ + +void fm_read_info() +{ + mapitem *tmp; + create_avl_trees(); + while (mapitems != NULL) { + assert(mapitems->line != NULL); + mapitems->lineno = 1; + switch (mapitems->type) { + case MAPFILE: + set_cur_file_name(mapitems->line); + if (!fm_open()) { + pdftex_warn("cannot open font map file"); + } else { + cur_file_name = (char *) nameoffile + 1; + tex_printf("{%s", cur_file_name); + while (!fm_eof()) { + fm_scan_line(mapitems); + mapitems->lineno++; + } + fm_close(); + tex_printf("}"); + fm_file = NULL; + } + break; + case MAPLINE: + cur_file_name = NULL; /* makes pdftex_warn() shorter */ + fm_scan_line(mapitems); + break; + default: + assert(0); + } + tmp = mapitems; + mapitems = mapitems->next; + xfree(tmp->line); + xfree(tmp); + } + cur_file_name = NULL; + return; +} + +/**********************************************************************/ + +/* +char *mk_exname(char *basename, int e) +{ + static char buf[SMALL_BUF_SIZE]; + char *p = basename, *r; + if ((r = strrchr(p, '.')) == NULL) + r = strend(p); + check_buf(r - p + strlen(r) + 10, SMALL_BUF_SIZE); + strncpy(buf, p, (unsigned) (r - p)); + sprintf(buf + (r - p), "%+i", e); + strcat(buf, r); + return buf; +} +*/ + +internalfontnumber tfmoffm(fmentryptr fm_pt) +{ + return ((fm_entry *) fm_pt)->tfm_num; +} + +static fm_entry *mk_ex_fm(internalfontnumber f, fm_entry * basefm, int ex) +{ + fm_entry *fm; + integer e = basefm->extend; + if (e == 0) + e = 1000; + fm = new_fm_entry(); + fm->flags = basefm->flags; + fm->encoding = basefm->encoding; + fm->type = basefm->type; + fm->slant = basefm->slant; + fm->extend = roundxnoverd(e, 1000 + ex, 1000); /* modify ExtentFont to simulate expansion */ + if (fm->extend == 1000) + fm->extend = 0; + fm->tfm_name = xstrdup(makecstring(fontname[f])); + if (basefm->ps_name != NULL) + fm->ps_name = xstrdup(basefm->ps_name); + fm->ff_name = xstrdup(basefm->ff_name); + fm->ff_objnum = pdfnewobjnum(); + fm->tfm_num = f; + fm->tfm_avail = TFM_FOUND; + assert(strcmp(fm->tfm_name, nontfm) != 0); + return fm; +} + +static void init_fm(fm_entry * fm, internalfontnumber f) +{ + if (fm->fd_objnum == 0 && !no_font_desc(fm)) + fm->fd_objnum = pdfnewobjnum(); + if (fm->ff_objnum == 0 && is_included(fm)) + fm->ff_objnum = pdfnewobjnum(); + if (fm->tfm_num == getnullfont()) { + fm->tfm_num = f; + fm->tfm_avail = TFM_FOUND; + } +} + +static fmentryptr fmlookup(internalfontnumber f) +{ + char *tfm, *p; + fm_entry *fm, *exfm; + fm_entry tmp; + int ai, e; + if (tfm_tree == NULL || mapitems != NULL) + fm_read_info(); + tfm = makecstring(fontname[f]); + assert(strcmp(tfm, nontfm) != 0); + + /* Look up for full <tfmname>[+-]<expand> */ + tmp.tfm_name = tfm; + fm = (fm_entry *) avl_find(tfm_tree, &tmp); + if (fm != NULL) { + init_fm(fm, f); + return (fmentryptr) fm; + } + tfm = mk_base_tfm(makecstring(fontname[f]), &e); + if (tfm == NULL) /* not an expanded font, nothing to do */ + return (fmentryptr) dummy_fm_entry(); + + tmp.tfm_name = tfm; + fm = (fm_entry *) avl_find(tfm_tree, &tmp); + if (fm != NULL) { /* found an entry with the base tfm name, e.g. cmr10 */ + if (!is_t1fontfile(fm) || !is_included(fm)) { + pdftex_warn + ("font %s cannot be expanded (not an included Type1 font)", + tfm); + return (fmentryptr) dummy_fm_entry(); + } + exfm = mk_ex_fm(f, fm, e); /* copies all fields from fm except tfm name */ + init_fm(exfm, f); + ai = avl_do_entry(exfm, FM_DUPIGNORE); + assert(ai == 0); + return (fmentryptr) exfm; + } + return (fmentryptr) dummy_fm_entry(); +} + +/* + Early check whether a font file exists. Used e. g. for replacing fonts + of embedded PDF files: Without font file, the font within the embedded + PDF-file is used. Search tree ff_tree is used in 1st instance, as it + may be faster than the kpse_find_file(), and kpse_find_file() is called + only once per font file name + expansion parameter. This might help + keeping speed, if many PDF pages with same fonts are to be embedded. + + The ff_tree contains only font files, which are actually needed, + so this tree typically is much smaller than the tfm_tree or ps_tree. +*/ + +ff_entry *check_ff_exist(fm_entry * fm) +{ + ff_entry *ff; + ff_entry tmp; + char *ex_ffname; + void **aa; + + assert(fm->ff_name != NULL); + tmp.ff_name = fm->ff_name; + ff = (ff_entry *) avl_find(ff_tree, &tmp); + if (ff == NULL) { /* not yet in database */ + ff = new_ff_entry(); + ff->ff_name = xstrdup(fm->ff_name); + if (is_truetype(fm)) + ff->ff_path = + kpse_find_file(fm->ff_name, kpse_truetype_format, 0); + else + ff->ff_path = + kpse_find_file(fm->ff_name, kpse_type1_format, 0); + aa = avl_probe(ff_tree, ff); + assert(aa != NULL); + } + return ff; +} + +/**********************************************************************/ + +static boolean used_tfm(fm_entry * p) +{ + internalfontnumber f; + strnumber s; + ff_entry *ff; + + /* check if the font file is not a TrueType font */ + /* font replacement makes sense only for included Type1 files */ + if (is_truetype(p) || !is_included(p)) + return false; + + /* check if the font file is available */ + ff = check_ff_exist(p); + if (ff->ff_path == NULL) + return false; + + /* check whether this font has been used */ + if (fontused[p->tfm_num]) + return true; + assert(p->tfm_name != NULL); + + /* check whether we didn't find a loaded font yet, + * and this font has been loaded */ + if (loaded_tfm_found == NULL && strcmp(p->tfm_name, nontfm) != 0) { + s = maketexstring(p->tfm_name); + if ((f = tfmlookup(s, 0)) != getnullfont()) { + loaded_tfm_found = p; + if (pdffontmap[f] == NULL) + pdffontmap[f] = (fmentryptr) p; + if (p->tfm_num == getnullfont()) + p->tfm_num = f; + assert(p->tfm_num == f); + /* don't call flushstr() here as it has been called by tfmlookup() */ + } else + flushstr(s); + } + + /* check whether we didn't find either a loaded or a loadable font yet, + * and this font is loadable */ + if (avail_tfm_found == NULL && loaded_tfm_found == NULL && + strcmp(p->tfm_name, nontfm) != 0) { + if (p->tfm_avail == TFM_UNCHECKED) { + if (kpse_find_file(p->tfm_name, kpse_tfm_format, 0) != NULL) { + avail_tfm_found = p; + p->tfm_avail = TFM_FOUND; + } else { + p->tfm_avail = TFM_NOTFOUND; + if (not_avail_tfm_found == NULL) + not_avail_tfm_found = p; + } + } + } + + /* check whether the current entry is a <nontfm> entry */ + if (non_tfm_found == NULL && strcmp(p->tfm_name, nontfm) == 0) + non_tfm_found = p; + + return false; +} + +/* lookup_ps_name looks for an entry with a given ps name + slant + extend; + * return NULL if not found. + * + * As there may exist several such entries, we need to select the `right' + * one. We do so by checking all such entries and return the first one that + * fulfils the following criteria (in descending priority): + * + * - the tfm has been used (some char from this font has been typeset) + * - the tfm has been loaded (but not used yet) + * - the tfm can be loaded (but not loaded yet) + * - the tfm is present in map files, but cannot be loaded. In this case a + * dummy tfm can be loaded instead, and a warning should be written out + */ + +static fm_entry *lookup_ps_name(fm_entry * fm) +{ + fm_entry *p, *p2; + struct avl_traverser t, t2; + strnumber s; + int a; + + loaded_tfm_found = NULL; + avail_tfm_found = NULL; + non_tfm_found = NULL; + not_avail_tfm_found = NULL; + + assert(fm->tfm_name == NULL); + p = (fm_entry *) avl_t_find(&t, ps_tree, fm); + if (p == NULL) + return NULL; + t2 = t; + p2 = avl_t_prev(&t2); + + /* search forward */ + do { + if (used_tfm(p)) + return p; + p = avl_t_next(&t); + } + while (p != NULL && comp_fm_entry_ps(fm, p, NULL) == 0); + + /* search backward */ + while (p2 != NULL && comp_fm_entry_ps(fm, p2, NULL) == 0) { + if (used_tfm(p2)) + return p2; + p2 = avl_t_prev(&t2); + } + + if (loaded_tfm_found != NULL) + p = loaded_tfm_found; + else if (avail_tfm_found != NULL) { + p = avail_tfm_found; + p->tfm_num = readfontinfo(getnullcs(), maketexstring(p->tfm_name), + getnullstr(), -1000); + p->tfm_avail = TFM_FOUND; + } else if (non_tfm_found != NULL) { + p = non_tfm_found; + p->tfm_num = newdummyfont(); + p->tfm_avail = TFM_FOUND; + } else if (not_avail_tfm_found != NULL) { + p = not_avail_tfm_found; + pdftex_warn("`%s' not loadable, use a dummy tfm instead", + p->tfm_name); + p2 = new_fm_entry(); + p2->flags = p->flags; + p2->encoding = p->encoding; + p2->type = p->type; + p2->slant = p->slant; + p2->extend = p->extend; + p2->tfm_name = xstrdup(nontfm); + p2->ps_name = xstrdup(p->ps_name); + if (p->ff_name != NULL) + p2->ff_name = xstrdup(p->ff_name); + p2->tfm_num = newdummyfont(); + p2->tfm_avail = TFM_FOUND; + a = avl_do_entry(p2, FM_DUPIGNORE); + assert(a == 0); + p = p2; + } else + return NULL; + assert(p->tfm_num != getnullfont()); + return p; +} + +/* Lookup fontmap for /BaseFont entries of embedded PDF-files; + * return dummy_fm_entry() if not found */ + +fm_entry *lookup_fontmap(char *bname) +{ + fm_entry *fm, *fmx; + fm_entry tmp, tmpx; + ff_entry *ff; + char buf[SMALL_BUF_SIZE]; + char *a, *b, *c, *d, *e, *s; + strnumber str; + int i, sl, ex, ai; + if (tfm_tree == NULL || mapitems != NULL) + fm_read_info(); + if (bname == NULL) + return NULL; + if (strlen(bname) >= SMALL_BUF_SIZE) + pdftex_fail("Font name too long: `%s'", bname); + strcpy(buf, bname); /* keep bname untouched for later */ + s = buf; + if (strlen(buf) > 7) { /* check for subsetted name tag */ + for (i = 0; i < 6; i++, s++) + if (*s < 'A' || *s > 'Z') + break; + if (i == 6 && *s == '+') + s++; /* if name tag found, skip behind it */ + else + s = buf; + } + + /* + Scan -Slant_<slant> and -Extend_<extend> font name extensions; + three valid formats: + <fontname>-Slant_<slant> + <fontname>-Slant_<slant>-Extend_<extend> + <fontname>-Extend_<extend> + Slant entry must come _before_ Extend entry + */ + + tmp.slant = 0; + tmp.extend = 0; + if ((a = strstr(s, "-Slant_")) != NULL) { + b = a + strlen("-Slant_"); + sl = (int) strtol(b, &e, 10); + if ((e != b) && (e == strend(b))) { + tmp.slant = sl; + *a = 0; /* bname string ends before "-Slant_" */ + } else { + if (e != b) { /* only if <slant> is valid number */ + if ((c = strstr(e, "-Extend_")) != NULL) { + d = c + strlen("-Extend_"); + ex = (int) strtol(d, &e, 10); + if ((e != d) && (e == strend(d))) { + tmp.slant = sl; + tmp.extend = ex; + *a = 0; /* bname string ends before "-Slant_" */ + } + } + } + } + } else { + if ((a = strstr(s, "-Extend_")) != NULL) { + b = a + strlen("-Extend_"); + ex = (int) strtol(b, &e, 10); + if ((e != b) && (e == strend(b))) { + tmp.extend = ex; + *a = 0; /* bname string ends before "-Extend_" */ + } + } + } + tmp.ps_name = s; + tmp.tfm_name = NULL; + fm = lookup_ps_name(&tmp); + if (fm != NULL) { + if (!(is_type1(fm) && is_included(fm))) { + pdftex_warn + ("PS name '%s' is found but ignored (not an included Type1 font)", + tmp.ps_name); + return NULL; + } + i = fm->tfm_num; + assert(i != getnullfont()); + if (pdffontmap[i] == NULL) + pdffontmap[i] = (fmentryptr) fm; + if (fm->ff_objnum == 0 && is_included(fm)) + fm->ff_objnum = pdfnewobjnum(); + if (!fontused[i]) + pdfinitfont(i); + return fm; + } +/* + The following code snipplet handles fonts with "Slant" and "Extend" + name extensions in embedded PDF files, which don't yet have an + fm_entry. If such a font is found (e. g. CMR10-Extend_1020), and no + fm_entry for this is found in the ps_tree (e. g. ps_name = "CMR10", + extend = 1020), and if an unextended base font (e. g. CMR10) is found, + a new <nontfm> fm_entry is created and put into the ps_tree. Then + the lookup_fontmap() function is (recursively) called again, which + then should find the new fm_entry. The same can be done manually by + a map entry e. g.: + + \pdfmapline{+<nontfm> CMR10 "1.02 ExtendFont" <cmr10.pfb} + + This would also match the embedded font CMR10-Extend_1020, and replace + it by an extended copy of cmr10.pfb. -- But not by an expanded version; + no MM files (e.g. cmr10+20.pfb) would be used. +*/ + + tmpx.ps_name = s; + tmpx.tfm_name = NULL; + tmpx.slant = 0; + tmpx.extend = 0; +/* fm = (fm_entry *) avl_find(ps_tree, &tmpx); */ + fm = lookup_ps_name(&tmpx); + if (fm != NULL) { + if (is_truetype(fm) || !is_included(fm)) + return NULL; + ff = check_ff_exist(fm); + if (ff->ff_path == NULL) + return NULL; + fmx = new_fm_entry(); + fmx->flags = fm->flags; + fmx->encoding = fm->encoding; + fmx->type = fm->type; + fmx->slant = tmp.slant; + fmx->extend = tmp.extend; + fmx->tfm_name = xstrdup(nontfm); + fmx->ps_name = xstrdup(s); + fmx->ff_name = xstrdup(fm->ff_name); + ai = avl_do_entry(fmx, FM_DUPIGNORE); + assert(ai == 0); + fm = lookup_fontmap(bname); /* new try */ + assert(fm != NULL); + return fm; + } + return NULL; +} + +/**********************************************************************/ +/* +Add map file name or map line contents to the linked list "mapitems". +Items not beginning with [+-=] flush list with pending items. Leading +blanks and blanks immediately following [+-=] are ignored. +*/ + +char *add_map_item(char *s, int type) +{ + char *p; + int l; /* length of map item (without [+-=]) */ + mapitem *tmp; + int mode; + for (; *s == ' '; s++); /* ignore leading blanks */ + switch (*s) { + case '+': /* +mapfile.map, +mapline */ + mode = FM_DUPIGNORE; /* insert entry, if it is not duplicate */ + s++; + break; + case '=': /* =mapfile.map, =mapline */ + mode = FM_REPLACE; /* try to replace earlier entry */ + s++; + break; + case '-': /* -mapfile.map, -mapline */ + mode = FM_DELETE; /* try to delete entry */ + s++; + break; + default: + mode = FM_DUPIGNORE; /* also flush pending list */ + while (mapitems != NULL) { + tmp = mapitems; + mapitems = mapitems->next; + xfree(tmp->line); + xfree(tmp); + } + } + for (; *s == ' '; s++); /* ignore blanks after [+-=] */ + p = s; /* map item starts here */ + switch (type) { /* find end of map item */ + case MAPFILE: + for (; *p != 0 && *p != ' ' && *p != 10; p++); + break; + case MAPLINE: /* blanks allowed */ + for (; *p != 0 && *p != 10; p++); + break; + default: + assert(0); + } + l = p - s; + if (l > 0) { /* only if real item to add */ + tmp = xtalloc(1, mapitem); + if (mapitems == NULL) + mapitems = tmp; /* start new list */ + else + miptr->next = tmp; + miptr = tmp; + miptr->mode = mode; + miptr->type = type; + miptr->line = xtalloc(l + 1, char); + *(miptr->line) = 0; + strncat(miptr->line, s, l); + miptr->next = NULL; + } + return p; +} + +void pdfmapfile(integer t) +{ + add_map_item(makecstring(tokenstostring(t)), MAPFILE); + flushstr(lasttokensstring); +} + +void pdfmapline(integer t) +{ + add_map_item(makecstring(tokenstostring(t)), MAPLINE); + flushstr(lasttokensstring); +} + +void pdfinitmapfile(string map_name) +{ + if (mapitems == NULL) { + mapitems = xtalloc(1, mapitem); + miptr = mapitems; + miptr->mode = FM_DUPIGNORE; + miptr->type = MAPFILE; + miptr->line = xstrdup(map_name); + miptr->next = NULL; + } +} + +/**********************************************************************/ +/* cleaning up... */ + +static void destroy_fm_entry_tfm(void *pa, void *pb) +{ + fm_entry *fm; + fm = (fm_entry *) pa; + if (!has_pslink(fm)) + delete_fm_entry(fm); + else + unset_tfmlink(fm); +} + +static void destroy_fm_entry_ps(void *pa, void *pb) +{ + fm_entry *fm; + fm = (fm_entry *) pa; + if (!has_tfmlink(fm)) + delete_fm_entry(fm); + else + unset_pslink(fm); +} + +static void destroy_ff_entry(void *pa, void *pb) +{ + ff_entry *ff; + ff = (ff_entry *) pa; + delete_ff_entry(ff); +} + +void fm_free(void) +{ + if (tfm_tree != NULL) + avl_destroy(tfm_tree, destroy_fm_entry_tfm); + if (ps_tree != NULL) + avl_destroy(ps_tree, destroy_fm_entry_ps); + if (ff_tree != NULL) + avl_destroy(ff_tree, destroy_ff_entry); +} + +/**********************************************************************/ +/* end of mapfile.c */ diff --git a/Build/source/texk/web2c/pdftexdir/misc.ch b/Build/source/texk/web2c/pdftexdir/misc.ch new file mode 100644 index 00000000000..0d69f25597c --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/misc.ch @@ -0,0 +1,21 @@ +% WEB change file containing miscellany extensions for pdfTeX +% +% Copyright (c) 1996-2002 Han Th\^e\llap{\raise 0.5ex\hbox{\'{}}} Th\`anh, <thanh@pdftex.org> +% +% This file is part of pdfTeX. +% +% pdfTeX 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. +% +% pdfTeX 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 General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with pdfTeX; if not, write to the Free Software +% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +% +% $Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/misc.ch#5 $ diff --git a/Build/source/texk/web2c/pdftexdir/noligatures.ch b/Build/source/texk/web2c/pdftexdir/noligatures.ch new file mode 100644 index 00000000000..2a8ef91f4a1 --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/noligatures.ch @@ -0,0 +1,116 @@ +% Copyright (c) 2005 Han Th\^e\llap{\raise 0.5ex\hbox{\'{}}} Th\`anh, <thanh@pdftex.org> +% +% This file is part of pdfTeX. +% +% pdfTeX 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. +% +% pdfTeX 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 General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with pdfTeX; if not, write to the Free Software +% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +% +% $Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/pdftex.ch#163 $ +@ This change file creates an extra primitive named \.{\\pdfnoligatures}, allowing +you to destroy all ligatures of a loaded font. The command code is +|assign_font_int|, with the new modifier value |no_lig_code|. + +Nothing other than the |char_tag| value is changed, and nothing is saved. +The primitive works directly on |font_info|, so all changes are global, +the same as for the other font assignment primitives. Usage is quite +straightforward: \.{\\pdfnoligatures \\f } disables ligatures for font \.{\\f}. +The expansion of \.{\\pdfnoligatures \\f } is either |1|, when the font has +no ligatures, or |0|, when the font does have ligatures. + +Thanh: this patch uses |orig_char_info| because it is to be inserted +after tex.pch. If you merge this into pdftex.ch, you may want to change +back to |char_info|. It would not compile without using the +|orig| trick because |effective_char| is not yet known at the spot +where |test_no_ligatures| is used. sigh. + +@x [230] +@d ef_code_base == 4 +@y +@d ef_code_base == 4 +@d no_lig_code == 6 {|tag_code| is 5 } +@z + +@x [230] +begin scan_font_ident; +if m=0 then scanned_result(hyphen_char[cur_val])(int_val) +else if m=1 then scanned_result(skew_char[cur_val])(int_val) +@y +begin scan_font_ident; +if m=0 then scanned_result(hyphen_char[cur_val])(int_val) +else if m=1 then scanned_result(skew_char[cur_val])(int_val) +else if m=no_lig_code then scanned_result(test_no_ligatures(cur_val))(int_val) +@z + +@x [577] +@<Declare procedures that scan font-related stuff@>= +function get_tag_code(f: internal_font_number; c: eight_bits): integer; +@y +@<Declare procedures that scan font-related stuff@>= +function test_no_ligatures(f: internal_font_number): integer; +label exit; +var c:integer; +begin + test_no_ligatures:= 1; + for c := font_bc[f] to font_ec[f] do + if char_exists(orig_char_info(f)(c)) then + if odd(char_tag(orig_char_info(f)(c))) then begin + test_no_ligatures:= 0; + return; + end; + exit: +end; + +function get_tag_code(f: internal_font_number; c: eight_bits): integer; +@z + +@x [???] +function init_font_base(v: integer): integer; +@y +procedure set_no_ligatures(f: internal_font_number); +var c:integer; +begin + for c := font_bc[f] to font_ec[f] do + if char_exists(orig_char_info(f)(c)) then + if char_tag(orig_char_info(f)(c))=lig_tag then + op_byte(orig_char_info(f)(c)) := (op_byte(orig_char_info(f)(c))) - lig_tag; +end; + +function init_font_base(v: integer): integer; +@z + +@x [1253] +assign_font_int: begin n:=cur_chr; scan_font_ident; f:=cur_val; + if n < lp_code_base then begin +@y +assign_font_int: begin n:=cur_chr; scan_font_ident; f:=cur_val; + if n = no_lig_code then set_no_ligatures(f) + else if n < lp_code_base then begin +@z + +@x [1254] +primitive("efcode",assign_font_int,ef_code_base); +@!@:ef_code_}{\.{\\efcode} primitive@> +@y +primitive("efcode",assign_font_int,ef_code_base); +@!@:ef_code_}{\.{\\efcode} primitive@> +primitive("pdfnoligatures",assign_font_int,no_lig_code); +@!@:no_lig_code_}{\.{\\pdfnoligatures} primitive@> +@z + +@x [1255] +ef_code_base: print_esc("efcode"); +@y +ef_code_base: print_esc("efcode"); +no_lig_code: print_esc("pdfnoligatures"); +@z diff --git a/Build/source/texk/web2c/pdftexdir/pdfstrcmp.ch b/Build/source/texk/web2c/pdftexdir/pdfstrcmp.ch new file mode 100644 index 00000000000..071ba74f281 --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/pdfstrcmp.ch @@ -0,0 +1,609 @@ +% Copyright (c) 2005 Han Th\^e\llap{\raise 0.5ex\hbox{\'{}}} Th\`anh, <thanh@pdftex.org> +% +% This file is part of pdfTeX. +% +% pdfTeX 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. +% +% pdfTeX 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 General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with pdfTeX; if not, write to the Free Software +% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +% +% $Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/pdftex.ch#163 $ +% +% experimental patch to make \pdfstrcmp expandable +% +% put it after tex.pch +% +% x line numbers of file pdfetex-org.web before patch +% +%*********************************************************************** + +@x 9388 +@d pdftex_last_item_codes = pdftex_first_rint_code + 10 {end of \pdfTeX's command codes} +@y +@d pdf_shell_escape_code = pdftex_first_rint_code + 11 {code for \.{\\pdfshellescape}} +@d pdftex_last_item_codes = pdftex_first_rint_code + 11 {end of \pdfTeX's command codes} +@z + +@x 9442 +primitive("pdfelapsedtime",last_item,elapsed_time_code); +@!@:elapsed_time_}{\.{\\pdfelapsedtime} primitive@> +@y +primitive("pdfelapsedtime",last_item,elapsed_time_code); +@!@:elapsed_time_}{\.{\\pdfelapsedtime} primitive@> +primitive("pdfshellescape",last_item,pdf_shell_escape_code); +@!@:elapsed_time_}{\.{\\pdfshellescape} primitive@> +@z + +@x 9470 + elapsed_time_code: print_esc("pdfelapsedtime"); +@y + elapsed_time_code: print_esc("pdfelapsedtime"); + pdf_shell_escape_code: print_esc("pdfshellescape"); +@z + +@x 9561 + elapsed_time_code: cur_val := get_microinterval; +@y + elapsed_time_code: cur_val := get_microinterval; + pdf_shell_escape_code: + begin + if shell_enabled_p then cur_val := 1 + else cur_val := 0; + end; +@z + +@x 10332 +@d pdf_last_escaped_string_code = pdftex_first_expand_code + 7 {command code for \.{\\pdflastescapedstring}} +@d pdf_last_escaped_name_code = pdftex_first_expand_code + 8 {command code for \.{\\pdflastescapename}} +@y +@d pdf_escape_string_code = pdftex_first_expand_code + 7 {command code for \.{\\pdfescapestring}} +@d pdf_escape_name_code = pdftex_first_expand_code + 8 {command code for \.{\\pdfescapename}} +@z + +@x 10336 +@d pdftex_convert_codes = pdftex_first_expand_code + 11 {end of \pdfTeX's command codes} +@y +@d pdf_strcmp_code = pdftex_first_expand_code + 11 {command code for \.{\\pdfstrcmp}} +@d pdf_escape_hex_code = pdftex_first_expand_code + 12 {command code for \.{\\pdfescapehex}} +@d pdf_unescape_hex_code = pdftex_first_expand_code + 13 {command code for \.{\\pdfunescapehex}} +@d pdf_creation_date_code = pdftex_first_expand_code + 14 {command code for \.{\\pdfcreationdate}} +@d pdf_file_mod_date_code = pdftex_first_expand_code + 15 {command code for \.{\\pdffilemoddate}} +@d pdf_file_size_code = pdftex_first_expand_code + 16 {command code for \.{\\pdffilesize}} +@d pdf_mdfive_sum_code = pdftex_first_expand_code + 17 {command code for \.{\\pdfmdfivesum}} +@d pdf_file_dump_code = pdftex_first_expand_code + 18 {command code for \.{\\pdffiledump}} +@d pdf_match_code = pdftex_first_expand_code + 19 {command code for \.{\\pdfmatch}} +@d pdf_last_match_code = pdftex_first_expand_code + 20 {command code for \.{\\pdflastmatch}} +@d pdftex_convert_codes = pdftex_first_expand_code + 21 {end of \pdfTeX's command codes} +@z + +%*********************************************************************** + +@x 10369 +primitive("pdflastescapedstring",convert,pdf_last_escaped_string_code);@/ +@!@:pdf_last_escaped_string_}{\.{\\pdflastescapedstring} primitive@> +primitive("pdflastescapedname",convert,pdf_last_escaped_name_code);@/ +@!@:pdf_last_escaped_name_}{\.{\\pdflastescapedname} primitive@> +@y +primitive("pdfescapestring",convert,pdf_escape_string_code);@/ +@!@:pdf_escape_string_}{\.{\\pdfescapestring} primitive@> +primitive("pdfescapename",convert,pdf_escape_name_code);@/ +@!@:pdf_escape_name_}{\.{\\pdfescapename} primitive@> +primitive("pdfescapehex",convert,pdf_escape_hex_code);@/ +@!@:pdf_escape_hex_}{\.{\\pdfescapehex} primitive@> +primitive("pdfunescapehex",convert,pdf_unescape_hex_code);@/ +@!@:pdf_unescape_hex_}{\.{\\pdfunescapehex} primitive@> +primitive("pdfcreationdate",convert,pdf_creation_date_code);@/ +@!@:pdf_creation_date_}{\.{\\pdfcreationdate} primitive@> +primitive("pdffilemoddate",convert,pdf_file_mod_date_code);@/ +@!@:pdf_file_mod_date_}{\.{\\pdffilemoddate} primitive@> +primitive("pdffilesize",convert,pdf_file_size_code);@/ +@!@:pdf_file_size_}{\.{\\pdffilesize} primitive@> +primitive("pdfmdfivesum",convert,pdf_mdfive_sum_code);@/ +@!@:pdf_mdfive_sum_}{\.{\\pdfmdfivesum} primitive@> +primitive("pdffiledump",convert,pdf_file_dump_code);@/ +@!@:pdf_file_dump_}{\.{\\pdffiledump} primitive@> +primitive("pdfmatch",convert,pdf_match_code);@/ +@!@:pdf_match_}{\.{\\pdfmatch} primitive@> +primitive("pdflastmatch",convert,pdf_last_match_code);@/ +@!@:pdf_last_match_}{\.{\\pdflastmatch} primitive@> +primitive("pdfstrcmp",convert,pdf_strcmp_code);@/ +@!@:pdf_strcmp_}{\.{\\pdfstrcmp} primitive@> +@z + +%*********************************************************************** + +@x 10394 + pdf_last_escaped_string_code: print_esc("pdflastescapedstring"); + pdf_last_escaped_name_code: print_esc("pdflastescapedname"); +@y + pdf_escape_string_code: print_esc("pdfescapestring"); + pdf_escape_name_code: print_esc("pdfescapename"); + pdf_escape_hex_code: print_esc("pdfescapehex"); + pdf_unescape_hex_code: print_esc("pdfunescapehex"); + pdf_creation_date_code: print_esc("pdfcreationdate"); + pdf_file_mod_date_code: print_esc("pdffilemoddate"); + pdf_file_size_code: print_esc("pdffilesize"); + pdf_mdfive_sum_code: print_esc("pdfmdfivesum"); + pdf_file_dump_code: print_esc("pdffiledump"); + pdf_match_code: print_esc("pdfmatch"); + pdf_last_match_code: print_esc("pdflastmatch"); + pdf_strcmp_code: print_esc("pdfstrcmp"); +@z + +%*********************************************************************** + +@x 10403 +@p procedure conv_toks; +var old_setting:0..max_selector; {holds |selector| setting} +p, q: pointer; +@!c:number_code..job_name_code; {desired type of conversion} +@!save_scanner_status:small_number; {|scanner_status| upon entry} +@!b:pool_pointer; {base of temporary string} +@!i, l: integer; {index to access escaped string or name} +begin c:=cur_chr; @<Scan the argument for command |c|@>; +old_setting:=selector; selector:=new_string; b:=pool_ptr; +@<Print the result of command |c|@>; +selector:=old_setting; link(garbage):=str_toks(b); ins_list(link(temp_head)); +end; +@y +@p procedure conv_toks; +label exit; +var old_setting:0..max_selector; {holds |selector| setting} +p, q: pointer; +@!c:number_code..job_name_code; {desired type of conversion} +@!save_scanner_status:small_number; {|scanner_status| upon entry} +@!save_def_ref: pointer; {|def_ref| upon entry, important if inside `\.{\\message}'} +@!save_warning_index: pointer; +@!bool: boolean; {temp boolean} +@!i: integer; {first temp integer} +@!j: integer; {second temp integer} +@!b:pool_pointer; {base of temporary string} +@!s: str_number; {first temp string} +@!t: str_number; {second temp string} +begin c:=cur_chr; @<Scan the argument for command |c|@>; +old_setting:=selector; selector:=new_string; b:=pool_ptr; +@<Print the result of command |c|@>; +selector:=old_setting; link(garbage):=str_toks(b); ins_list(link(temp_head)); +exit:end; +@z + +@x 10450 +pdf_last_escaped_string_code: do_nothing; +pdf_last_escaped_name_code: do_nothing; +job_name_code: if job_name=0 then open_log_file; +@y +pdf_escape_string_code: + begin + save_scanner_status := scanner_status; + save_warning_index := warning_index; + save_def_ref := def_ref; + scan_pdf_ext_toks; + s := tokens_to_string(def_ref); + delete_token_ref(def_ref); + def_ref := save_def_ref; + warning_index := save_warning_index; + scanner_status := save_scanner_status; + b := pool_ptr; + escapestring(str_start[s]); + link(garbage) := str_toks(b); + flush_str(s); + ins_list(link(temp_head)); + return; + end; +pdf_escape_name_code: + begin + save_scanner_status := scanner_status; + save_warning_index := warning_index; + save_def_ref := def_ref; + scan_pdf_ext_toks; + s := tokens_to_string(def_ref); + delete_token_ref(def_ref); + def_ref := save_def_ref; + warning_index := save_warning_index; + scanner_status := save_scanner_status; + b := pool_ptr; + escapename(str_start[s]); + link(garbage) := str_toks(b); + flush_str(s); + ins_list(link(temp_head)); + return; + end; +pdf_escape_hex_code: + begin + save_scanner_status := scanner_status; + save_warning_index := warning_index; + save_def_ref := def_ref; + scan_pdf_ext_toks; + s := tokens_to_string(def_ref); + delete_token_ref(def_ref); + def_ref := save_def_ref; + warning_index := save_warning_index; + scanner_status := save_scanner_status; + b := pool_ptr; + escapehex(str_start[s]); + link(garbage) := str_toks(b); + flush_str(s); + ins_list(link(temp_head)); + return; + end; +pdf_unescape_hex_code: + begin + save_scanner_status := scanner_status; + save_warning_index := warning_index; + save_def_ref := def_ref; + scan_pdf_ext_toks; + s := tokens_to_string(def_ref); + delete_token_ref(def_ref); + def_ref := save_def_ref; + warning_index := save_warning_index; + scanner_status := save_scanner_status; + b := pool_ptr; + unescapehex(str_start[s]); + link(garbage) := str_toks(b); + flush_str(s); + ins_list(link(temp_head)); + return; + end; +pdf_creation_date_code: + begin + b := pool_ptr; + getcreationdate; + link(garbage) := str_toks(b); + ins_list(link(temp_head)); + return; + end; +pdf_file_mod_date_code: + begin + save_scanner_status := scanner_status; + save_warning_index := warning_index; + save_def_ref := def_ref; + scan_pdf_ext_toks; + s := tokens_to_string(def_ref); + delete_token_ref(def_ref); + def_ref := save_def_ref; + warning_index := save_warning_index; + scanner_status := save_scanner_status; + b := pool_ptr; + getfilemoddate(s); + link(garbage) := str_toks(b); + flush_str(s); + ins_list(link(temp_head)); + return; + end; +pdf_file_size_code: + begin + save_scanner_status := scanner_status; + save_warning_index := warning_index; + save_def_ref := def_ref; + scan_pdf_ext_toks; + s := tokens_to_string(def_ref); + delete_token_ref(def_ref); + def_ref := save_def_ref; + warning_index := save_warning_index; + scanner_status := save_scanner_status; + b := pool_ptr; + getfilesize(s); + link(garbage) := str_toks(b); + flush_str(s); + ins_list(link(temp_head)); + return; + end; +pdf_mdfive_sum_code: + begin + save_scanner_status := scanner_status; + save_warning_index := warning_index; + save_def_ref := def_ref; + bool := scan_keyword("file"); + scan_pdf_ext_toks; + s := tokens_to_string(def_ref); + delete_token_ref(def_ref); + def_ref := save_def_ref; + warning_index := save_warning_index; + scanner_status := save_scanner_status; + b := pool_ptr; + getmd5sum(s, bool); + link(garbage) := str_toks(b); + flush_str(s); + ins_list(link(temp_head)); + return; + end; +pdf_file_dump_code: + begin + save_scanner_status := scanner_status; + save_warning_index := warning_index; + save_def_ref := def_ref; + {scan offset} + cur_val := 0; + if (scan_keyword("offset")) then begin + scan_int; + if (cur_val < 0) then begin + print_err("Bad file offset"); +@.Bad file offset@> + help2("A file offset must be between 0 and 2^{31}-1,")@/ + ("I changed this one to zero."); + int_error(cur_val); + cur_val := 0; + end; + end; + i := cur_val; + {scan length} + cur_val := 0; + if (scan_keyword("length")) then begin + scan_int; + if (cur_val < 0) then begin + print_err("Bad dump length"); +@.Bad dump length@> + help2("A dump length must be between 0 and 2^{31}-1,")@/ + ("I changed this one to zero."); + int_error(cur_val); + cur_val := 0; + end; + end; + j := cur_val; + {scan file name} + scan_pdf_ext_toks; + s := tokens_to_string(def_ref); + delete_token_ref(def_ref); + def_ref := save_def_ref; + warning_index := save_warning_index; + scanner_status := save_scanner_status; + b := pool_ptr; + getfiledump(s, i, j); + link(garbage) := str_toks(b); + flush_str(s); + ins_list(link(temp_head)); + return; + end; +pdf_match_code: + begin + save_scanner_status := scanner_status; + save_warning_index := warning_index; + save_def_ref := def_ref; + {scan for icase} + bool := scan_keyword("icase"); + {scan for subcount} + i := -1; {default for subcount} + if scan_keyword("subcount") then begin + scan_int; + i := cur_val; + end; + scan_pdf_ext_toks; + s := tokens_to_string(def_ref); + delete_token_ref(def_ref); + scan_pdf_ext_toks; + t := tokens_to_string(def_ref); + delete_token_ref(def_ref); + def_ref := save_def_ref; + warning_index := save_warning_index; + scanner_status := save_scanner_status; + b := pool_ptr; + matchstrings(s, t, i, bool); + link(garbage) := str_toks(b); + flush_str(t); + flush_str(s); + ins_list(link(temp_head)); + return; + end; +pdf_last_match_code: + begin + scan_int; + if cur_val < 0 then begin + print_err("Bad match number"); +@.Bad match number@> + help2("Since I expected zero or a positive number,")@/ + ("I changed this one to zero."); + int_error(cur_val); + cur_val := 0; + end; + b := pool_ptr; + getmatch(cur_val); + link(garbage) := str_toks(b); + ins_list(link(temp_head)); + return; + end; +pdf_strcmp_code: + begin + save_scanner_status := scanner_status; + save_warning_index := warning_index; + save_def_ref := def_ref; + compare_strings; + def_ref := save_def_ref; + warning_index := save_warning_index; + scanner_status := save_scanner_status; + end; +job_name_code: if job_name=0 then open_log_file; +@z + +%*********************************************************************** + +@x 10512 +pdf_last_escaped_string_code: begin + l := escapedstrlen; + for i := 0 to l - 1 do + print_char(getescapedstrchar(i)); +end; +pdf_last_escaped_name_code: begin + l := escapednamelen; + for i := 0 to l - 1 do + print_char(getescapednamechar(i)); +end; +job_name_code: print(job_name); +@y +pdf_strcmp_code: print_int(cur_val); +job_name_code: print(job_name); +@z + +%*********************************************************************** + +@x 32168 +@d pdf_strcmp_code == pdftex_first_extension_code + 24 +@d pdf_escape_string_code == pdftex_first_extension_code + 25 +@d pdf_escape_name_code == pdftex_first_extension_code + 26 +@d reset_timer_code == pdftex_first_extension_code + 27 +@d pdf_font_expand_code == pdftex_first_extension_code + 28 +@d pdftex_last_extension_code == pdftex_first_extension_code + 28 +@y +@d reset_timer_code == pdftex_first_extension_code + 24 +@d pdf_font_expand_code == pdftex_first_extension_code + 25 +@d pdftex_last_extension_code == pdftex_first_extension_code + 25 +@z + +%*********************************************************************** + +@x 32239 +primitive("pdfstrcmp",extension,pdf_strcmp_code);@/ +@!@:pdf_strcmp_}{\.{\\pdfstrcmp} primitive@> +primitive("pdfescapestring",extension,pdf_escape_string_code);@/ +@!@:pdf_escape_string_}{\.{\\pdfescapestring} primitive@> +primitive("pdfescapename",extension,pdf_escape_name_code);@/ +@!@:pdf_escape_name_}{\.{\\pdfescapename} primitive@> +@y +@z + +%*********************************************************************** + +@x 32287 + pdf_strcmp_code: print_esc("pdfstrcmp"); + pdf_escape_string_code: print_esc("pdfescapestring"); + pdf_escape_name_code: print_esc("pdfescapename"); +@y +@z + +%*********************************************************************** + +@x 32337 +pdf_strcmp_code: @<Implement \.{\\pdfstrcmp}@>; +pdf_escape_string_code: @<Implement \.{\\pdfescapestring}@>; +pdf_escape_name_code: @<Implement \.{\\pdfescapename}@>; +@y +@z + +%*********************************************************************** + +@x 32463 +procedure compare_strings; {to implement \.{\\pdfstrcmp}} +label done; +var s1, s2: str_number; + i1, i2, j1, j2: pool_pointer; + result: integer; +begin + call_func(scan_toks(false, true)); + s1 := tokens_to_string(def_ref); + delete_token_ref(def_ref); + call_func(scan_toks(false, true)); + s2 := tokens_to_string(def_ref); + delete_token_ref(def_ref); + i1 := str_start[s1]; + j1 := str_start[s1 + 1]; + i2 := str_start[s2]; + j2 := str_start[s2 + 1]; + while (i1 < j1) and (i2 < j2) do begin + if str_pool[i1] < str_pool[i2] then begin + result := -1; + goto done; + end; + if str_pool[i1] > str_pool[i2] then begin + result := 1; + goto done; + end; + incr(i1); + incr(i2); + end; + if (i1 = j1) and (i2 = j2) then + result := 0 + else if i1 < j1 then + result := 1 + else + result := -1; +done: + pdf_retval := result; + flush_str(s2); + flush_str(s1); +end; +@y +procedure compare_strings; {to implement \.{\\pdfstrcmp}} +label done; +var s1, s2: str_number; + i1, i2, j1, j2: pool_pointer; +begin + call_func(scan_toks(false, true)); + s1 := tokens_to_string(def_ref); + delete_token_ref(def_ref); + call_func(scan_toks(false, true)); + s2 := tokens_to_string(def_ref); + delete_token_ref(def_ref); + i1 := str_start[s1]; + j1 := str_start[s1 + 1]; + i2 := str_start[s2]; + j2 := str_start[s2 + 1]; + while (i1 < j1) and (i2 < j2) do begin + if str_pool[i1] < str_pool[i2] then begin + cur_val := -1; + goto done; + end; + if str_pool[i1] > str_pool[i2] then begin + cur_val := 1; + goto done; + end; + incr(i1); + incr(i2); + end; + if (i1 = j1) and (i2 = j2) then + cur_val := 0 + else if i1 < j1 then + cur_val := 1 + else + cur_val := -1; +done: + flush_str(s2); + flush_str(s1); + cur_val_level := int_val; +end; +@z + +%*********************************************************************** + +@x 33387 +@ @<Implement \.{\\pdfescapestring}@>= +begin + scan_pdf_ext_toks; + escapestr(tokens_to_string(def_ref)); + flush_str(last_tokens_string); + delete_token_ref(def_ref); +end + +@ @<Implement \.{\\pdfescapename}@>= +begin + scan_pdf_ext_toks; + escapename(tokens_to_string(def_ref)); + flush_str(last_tokens_string); + delete_token_ref(def_ref); +end +@y +@z + +@x 33406 +@ @<Implement \.{\\pdfstrcmp}@>= +compare_strings +@y +@z + +@x 33409 +@ @<Set initial values of key variables@>= + seconds_and_micros(epochseconds,microseconds); +@y +@ @<Set initial values of key variables@>= + seconds_and_micros(epochseconds,microseconds); + init_start_time; +@z + +%*********************************************************************** diff --git a/Build/source/texk/web2c/pdftexdir/pdftex.ch b/Build/source/texk/web2c/pdftexdir/pdftex.ch new file mode 100644 index 00000000000..6ae23335465 --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/pdftex.ch @@ -0,0 +1,6853 @@ +% WEB change file containing code for pdfTeX features extending TeX; % to be applied to tex.web (Version 3.141592) in order to define the +% pdfTeX program. +% +% Note: This file, pdftex.ch, defines pdftex.web in terms of changes to be +% applied to tex.web; in terms of a program such as TIE (or equivalent), +% +% tex.web ) +% + ) => tie -m ... => etex.web +% pdftexdir/pdftex.ch ) +% +% In addition, this file is used to define pdfetex.web, a combination +% of e-TeX and pdfTeX as follows: +% +% tex.web ) +% + ) +% etexdir/etex.ch ) +% + ) +% pdfetexdir/pdfetex.ch1 ) => tie -m ... => pdfetex.web +% + ) +% pdftexdir/pdftex.ch ) +% + ) +% pdfetexdir/pdfetex.ch2 ) +% +% where the two (small) files pdfetexdir/pdfetex.ch[12] take care of +% interferences between e-Tex changes (etexdir/etex.ch) and pdfTeX changes +% (pdftexdir/pdftex.ch). Consequently, changes in these files have to be +% coordinated. +% +% Copyright (c) 1996-2005 Han Th\^e\llap{\raise 0.5ex\hbox{\'{}}} Th\`anh, <thanh@pdftex.org> +% +% This file is part of pdfTeX. +% +% pdfTeX 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. +% +% pdfTeX 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 General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with pdfTeX; if not, write to the Free Software +% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +% +% $Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/pdftex.ch#171 $ +% +% The TeX program is copyright (C) 1982 by D. E. Knuth. +% TeX is a trademark of the American Mathematical Society. +% +% all pdfTeX new primitives have the prefix "\pdf", apart from: +% o extension of \vadjust +% o extension of \font +% o \efcode +% o \lpcode, \rpcode +% o \leftmarginkern, \rightmarginkern + +@x limbo +\def\PASCAL{Pascal} +@y +\def\PASCAL{Pascal} +\def\pdfTeX{pdf\TeX} +\def\PDF{PDF} +@z + +@x [2] - This change is made for TeX 3.141592 +@d banner=='This is TeX, Version 3.141592' {printed when \TeX\ starts} +@y +@d pdftex_version==130 { \.{\\pdftexversion} } +@d pdftex_revision=="4" { \.{\\pdftexrevision} } +@d pdftex_version_string=='-1.30.4' {current \pdfTeX\ version} +@# +@d pdfTeX_banner=='This is pdfTeX, Version 3.141592',pdftex_version_string + {printed when \pdfTeX\ starts} +@# +@d TeX_banner=='This is TeX, Version 3.141592' {printed when \TeX\ starts} +@# +@d banner==pdfTeX_banner +@z + +% Some procedures that need to be declared forward +@x [173] +@* \[12] Displaying boxes. +@y +@<Declare procedures that need to be declared forward for pdftex@>@; + +@* \[12] Displaying boxes. +@z + +% Define pdftex token list parameters +@x [230] +@d toks_base=local_base+10 {table of 256 token list registers} +@y +@d tex_toks=local_base+10 {end of \TeX's token list parameters} +@# +@d pdftex_first_loc = tex_toks {base for \pdfTeX's token list parameters} +@d pdf_pages_attr_loc = pdftex_first_loc + 0 {points to token list for \.{\\pdfpagesattr}} +@d pdf_page_attr_loc = pdftex_first_loc + 1 {points to token list for \.{\\pdfpageattr}} +@d pdf_page_resources_loc = pdftex_first_loc + 2 {points to token list for \.{\\pdfpageresources}} +@d pdf_pk_mode_loc = pdftex_first_loc + 3 {points to token list for \.{\\pdfpkmode}} +@d pdf_toks=pdftex_first_loc+4 {end of \pdfTeX's token list parameters} +@# +@d toks_base=pdf_toks {table of 256 token list registers} +@z + +@x [230] +@d err_help==equiv(err_help_loc) +@y +@d err_help==equiv(err_help_loc) +@d pdf_pages_attr==equiv(pdf_pages_attr_loc) +@d pdf_page_attr==equiv(pdf_page_attr_loc) +@d pdf_page_resources==equiv(pdf_page_resources_loc) +@d pdf_pk_mode==equiv(pdf_pk_mode_loc) +@z + +@x [230] +primitive("errhelp",assign_toks,err_help_loc); +@!@:err_help_}{\.{\\errhelp} primitive@> +@y +primitive("errhelp",assign_toks,err_help_loc); +@!@:err_help_}{\.{\\errhelp} primitive@> +primitive("pdfpagesattr",assign_toks,pdf_pages_attr_loc); +@!@:pdf_pages_attr_}{\.{\\pdfpagesattr} primitive@> +primitive("pdfpageattr",assign_toks,pdf_page_attr_loc); +@!@:pdf_page_attr_}{\.{\\pdfpageattr} primitive@> +primitive("pdfpageresources",assign_toks,pdf_page_resources_loc); +@!@:pdf_page_resources_}{\.{\\pdfpageresources} primitive@> +primitive("pdfpkmode",assign_toks,pdf_pk_mode_loc); +@!@:pdf_pk_mode_}{\.{\\pdfpkmode} primitive@> +@z + +@x [231] + othercases print_esc("errhelp") +@y + pdf_pages_attr_loc: print_esc("pdfpagesattr"); + pdf_page_attr_loc: print_esc("pdfpageattr"); + pdf_page_resources_loc: print_esc("pdfpageresources"); + pdf_pk_mode_loc: print_esc("pdfpkmode"); + othercases print_esc("errhelp") +@z + +% Define pdftex integer parameters +@x [236] +@d int_pars=55 {total number of integer parameters} +@y +@d tex_int_pars=55 {total number of \TeX's integer parameters} +@# +@d pdftex_first_integer_code = tex_int_pars {base for \pdfTeX's integer parameters} +@d pdf_output_code = pdftex_first_integer_code + 0 {switch on PDF output if positive} +@d pdf_compress_level_code = pdftex_first_integer_code + 1 {compress level of streams} +@d pdf_decimal_digits_code = pdftex_first_integer_code + 2 {digits after the decimal point of numbers} +@d pdf_move_chars_code = pdftex_first_integer_code + 3 {move chars 0..31 to higher area if possible} +@d pdf_image_resolution_code = pdftex_first_integer_code + 4 {default image resolution} +@d pdf_pk_resolution_code = pdftex_first_integer_code + 5 {default resolution of PK font} +@d pdf_unique_resname_code = pdftex_first_integer_code + 6 {generate unique names for resouces} +@d pdf_option_always_use_pdfpagebox_code = pdftex_first_integer_code + 7 {if the pdf inclusion should always use a specific pdf page box} +@d pdf_option_pdf_inclusion_errorlevel_code = pdftex_first_integer_code + 8 {if the pdf inclusion should treat pdfs newer than |pdf_minor_version| as an error} +@d pdf_minor_version_code = pdftex_first_integer_code + 9 {fractional part of the pdf version produced} +@d pdf_force_pagebox_code = pdftex_first_integer_code + 10 {if the pdf inclusion should always use a specific pdf page box} +@d pdf_inclusion_errorlevel_code = pdftex_first_integer_code + 11 {if the pdf inclusion should treat pdfs newer than |pdf_minor_version| as an error} +@d pdf_gamma_code = pdftex_first_integer_code + 12 +@d pdf_image_gamma_code = pdftex_first_integer_code + 13 +@d pdf_image_hicolor_code = pdftex_first_integer_code + 14 +@d pdf_image_apply_gamma_code = pdftex_first_integer_code + 15 +@d pdf_px_dimen_code = pdftex_first_integer_code + 16 {the code for the pixel dimen value} +@d pdf_int_pars=pdftex_first_integer_code + 17 {total number of \pdfTeX's integer parameters} +@# +@d int_pars=pdf_int_pars {total number of integer parameters} +@z + +@x [236] +@d error_context_lines==int_par(error_context_lines_code) +@y +@d error_context_lines==int_par(error_context_lines_code) +@# +@d pdf_output == int_par(pdf_output_code) +@d pdf_compress_level == int_par(pdf_compress_level_code) +@d pdf_decimal_digits == int_par(pdf_decimal_digits_code) +@d pdf_move_chars == int_par(pdf_move_chars_code) +@d pdf_image_resolution == int_par(pdf_image_resolution_code) +@d pdf_pk_resolution == int_par(pdf_pk_resolution_code) +@d pdf_unique_resname == int_par(pdf_unique_resname_code) +@d pdf_option_always_use_pdfpagebox == int_par(pdf_option_always_use_pdfpagebox_code) +@d pdf_option_pdf_inclusion_errorlevel == int_par(pdf_option_pdf_inclusion_errorlevel_code) +@d pdf_minor_version == int_par(pdf_minor_version_code) +@d pdf_force_pagebox == int_par(pdf_force_pagebox_code) +@d pdf_inclusion_errorlevel == int_par(pdf_inclusion_errorlevel_code) +@d pdf_gamma == int_par(pdf_gamma_code) +@d pdf_image_gamma == int_par(pdf_image_gamma_code) +@d pdf_image_hicolor == int_par(pdf_image_hicolor_code) +@d pdf_image_apply_gamma == int_par(pdf_image_apply_gamma_code) +@d pdf_px_dimen == int_par(pdf_px_dimen_code) +@z + +@x [237] +error_context_lines_code:print_esc("errorcontextlines"); +@y +error_context_lines_code:print_esc("errorcontextlines"); +@# +pdf_output_code: print_esc("pdfoutput"); +pdf_compress_level_code: print_esc("pdfcompresslevel"); +pdf_decimal_digits_code: print_esc("pdfdecimaldigits"); +pdf_move_chars_code: print_esc("pdfmovechars"); +pdf_image_resolution_code: print_esc("pdfimageresolution"); +pdf_pk_resolution_code: print_esc("pdfpkresolution"); +pdf_unique_resname_code: print_esc("pdfuniqueresname"); +pdf_option_always_use_pdfpagebox_code: print_esc("pdfoptionalwaysusepdfpagebox"); +pdf_option_pdf_inclusion_errorlevel_code: print_esc("pdfoptionpdfinclusionerrorlevel"); +pdf_minor_version_code: print_esc("pdfminorversion"); +pdf_force_pagebox_code: print_esc("pdfforcepagebox"); +pdf_inclusion_errorlevel_code: print_esc("pdfinclusionerrorlevel"); +pdf_gamma_code: print_esc("pdfgamma"); +pdf_image_gamma_code: print_esc("pdfimagegamma"); +pdf_image_hicolor_code: print_esc("pdfimagehicolor"); +pdf_image_apply_gamma_code: print_esc("pdfimageapplygamma"); +pdf_px_dimen_code: print_esc("pdfpxdimen"); +@z + +@x [238] +primitive("errorcontextlines",assign_int,int_base+error_context_lines_code);@/ +@!@:error_context_lines_}{\.{\\errorcontextlines} primitive@> +@y +primitive("errorcontextlines",assign_int,int_base+error_context_lines_code);@/ +@!@:error_context_lines_}{\.{\\errorcontextlines} primitive@> +primitive("pdfoutput",assign_int,int_base+pdf_output_code);@/ +@!@:pdf_output_}{\.{\\pdfoutput} primitive@> +primitive("pdfcompresslevel",assign_int,int_base+pdf_compress_level_code);@/ +@!@:pdf_compress_level_}{\.{\\pdfcompresslevel} primitive@> +primitive("pdfdecimaldigits",assign_int,int_base+pdf_decimal_digits_code);@/ +@!@:pdf_decimal_digits_}{\.{\\pdfdecimaldigits} primitive@> +primitive("pdfmovechars",assign_int,int_base+pdf_move_chars_code);@/ +@!@:pdf_move_chars_}{\.{\\pdfmovechars} primitive@> +primitive("pdfimageresolution",assign_int,int_base+pdf_image_resolution_code);@/ +@!@:pdf_image_resolution_}{\.{\\pdfimageresolution} primitive@> +primitive("pdfpkresolution",assign_int,int_base+pdf_pk_resolution_code);@/ +@!@:pdf_pk_resolution_}{\.{\\pdfpkresolution} primitive@> +primitive("pdfuniqueresname",assign_int,int_base+pdf_unique_resname_code);@/ +@!@:pdf_unique_resname_}{\.{\\pdfuniqueresname} primitive@> +primitive("pdfoptionpdfminorversion",assign_int,int_base+pdf_minor_version_code);@/ +@!@:pdf_minor_version_}{\.{\\pdfoptionpdfminorversion} primitive@> +primitive("pdfoptionalwaysusepdfpagebox",assign_int,int_base+pdf_option_always_use_pdfpagebox_code);@/ +@!@:pdf_option_always_use_pdfpagebox_}{\.{\\pdfoptionalwaysusepdfpagebox} primitive@> +primitive("pdfoptionpdfinclusionerrorlevel",assign_int,int_base+pdf_option_pdf_inclusion_errorlevel_code);@/ +@!@:pdf_option_pdf_inclusion_errorlevel_}{\.{\\pdfoptionpdfinclusionerrorlevel} primitive@> +primitive("pdfminorversion",assign_int,int_base+pdf_minor_version_code);@/ +@!@:pdf_minor_version_}{\.{\\pdfminorversion} primitive@> +primitive("pdfforcepagebox",assign_int,int_base+pdf_force_pagebox_code);@/ +@!@:pdf_force_pagebox_}{\.{\\pdfforcepagebox} primitive@> +primitive("pdfinclusionerrorlevel",assign_int,int_base+pdf_inclusion_errorlevel_code);@/ +@!@:pdf_inclusion_errorlevel_}{\.{\\pdfinclusionerrorlevel} primitive@> +primitive("pdfgamma",assign_int,int_base+pdf_gamma_code);@/ +@!@:pdf_gamma_}{\.{\\pdfgamma} primitive@> +primitive("pdfimagegamma",assign_int,int_base+pdf_image_gamma_code);@/ +@!@:pdf_image_gamma_}{\.{\\pdfimagegamma} primitive@> +primitive("pdfimagehicolor",assign_int,int_base+pdf_image_hicolor_code);@/ +@!@:pdf_image_hicolor_}{\.{\\pdfimagehicolor} primitive@> +primitive("pdfimageapplygamma",assign_int,int_base+pdf_image_apply_gamma_code);@/ +@!@:pdf_image_apply_gamma_}{\.{\\pdfimageapplygamma} primitive@> +primitive("pdfpxdimen",assign_int,int_base+pdf_px_dimen_code);@/ +@!@:pdf_px_dimen_}{\.{\\pdfpxdimen} primitive@> +@z + +@x [240] - pxdimen +for k:=int_base to del_code_base-1 do eqtb[k].int:=0; +@y +for k:=int_base to del_code_base-1 do eqtb[k].int:=0; +pdf_px_dimen := unity; +@z + +% Define pdftex dimension parameters +@x [247] +@d emergency_stretch_code=20 {reduces badnesses on final pass of line-breaking} +@y +@d emergency_stretch_code=20 {reduces badnesses on final pass of line-breaking} +@d pdftex_first_dimen_code = 21 {first number defined in this section} +@d pdf_h_origin_code = pdftex_first_dimen_code + 0 {horigin of the PDF output} +@d pdf_v_origin_code = pdftex_first_dimen_code + 1 {vorigin of the PDF output} +@d pdf_page_width_code = pdftex_first_dimen_code + 2 {page width of the PDF output} +@d pdf_page_height_code = pdftex_first_dimen_code + 3 {page height of the PDF output} +@d pdf_link_margin_code = pdftex_first_dimen_code + 4 {link margin in the PDF output} +@d pdf_dest_margin_code = pdftex_first_dimen_code + 5 {dest margin in the PDF output} +@d pdf_thread_margin_code = pdftex_first_dimen_code + 6 {thread margin in the PDF output} +@d pdf_first_line_height_code = pdftex_first_dimen_code + 7 +@d pdf_last_line_depth_code = pdftex_first_dimen_code + 8 +@d pdf_each_line_height_code = pdftex_first_dimen_code + 9 +@d pdf_each_line_depth_code = pdftex_first_dimen_code + 10 +@d pdftex_last_dimen_code = pdftex_first_dimen_code + 10 {last number defined in this section} +@z + +@x +@d dimen_pars=21 {total number of dimension parameters} +@y +@d dimen_pars = pdftex_last_dimen_code + 1 {total number of dimension parameters} +@z + +@x [247] +@d emergency_stretch==dimen_par(emergency_stretch_code) +@y +@d emergency_stretch==dimen_par(emergency_stretch_code) +@d pdf_h_origin == dimen_par(pdf_h_origin_code) +@d pdf_v_origin == dimen_par(pdf_v_origin_code) +@d pdf_page_width == dimen_par(pdf_page_width_code) +@d pdf_page_height == dimen_par(pdf_page_height_code) +@d pdf_link_margin == dimen_par(pdf_link_margin_code) +@d pdf_dest_margin == dimen_par(pdf_dest_margin_code) +@d pdf_thread_margin == dimen_par(pdf_thread_margin_code) +@d pdf_first_line_height == dimen_par(pdf_first_line_height_code) +@d pdf_last_line_depth == dimen_par(pdf_last_line_depth_code) +@d pdf_each_line_height == dimen_par(pdf_each_line_height_code) +@d pdf_each_line_depth == dimen_par(pdf_each_line_depth_code) +@z + +@x [247] +emergency_stretch_code:print_esc("emergencystretch"); +@y +emergency_stretch_code:print_esc("emergencystretch"); +pdf_h_origin_code: print_esc("pdfhorigin"); +pdf_v_origin_code: print_esc("pdfvorigin"); +pdf_page_width_code: print_esc("pdfpagewidth"); +pdf_page_height_code: print_esc("pdfpageheight"); +pdf_link_margin_code: print_esc("pdflinkmargin"); +pdf_dest_margin_code: print_esc("pdfdestmargin"); +pdf_thread_margin_code: print_esc("pdfthreadmargin"); +pdf_first_line_height_code: print_esc("pdffirstlineheight"); +pdf_last_line_depth_code: print_esc("pdflastlinedepth"); +pdf_each_line_height_code: print_esc("pdfeachlineheight"); +pdf_each_line_depth_code: print_esc("pdfeachlinedepth"); +@z + +@x [248] +primitive("emergencystretch",assign_dimen,dimen_base+emergency_stretch_code);@/ +@!@:emergency_stretch_}{\.{\\emergencystretch} primitive@> +@y +primitive("emergencystretch",assign_dimen,dimen_base+emergency_stretch_code);@/ +@!@:emergency_stretch_}{\.{\\emergencystretch} primitive@> +primitive("pdfhorigin",assign_dimen,dimen_base+pdf_h_origin_code);@/ +@!@:pdf_h_origin_}{\.{\\pdfhorigin} primitive@> +primitive("pdfvorigin",assign_dimen,dimen_base+pdf_v_origin_code);@/ +@!@:pdf_v_origin_}{\.{\\pdfvorigin} primitive@> +primitive("pdfpagewidth",assign_dimen,dimen_base+pdf_page_width_code);@/ +@!@:pdf_page_width_}{\.{\\pdfpagewidth} primitive@> +primitive("pdfpageheight",assign_dimen,dimen_base+pdf_page_height_code);@/ +@!@:pdf_page_height_}{\.{\\pdfpageheight} primitive@> +primitive("pdflinkmargin",assign_dimen,dimen_base+pdf_link_margin_code);@/ +@!@:pdf_link_margin_}{\.{\\pdflinkmargin} primitive@> +primitive("pdfdestmargin",assign_dimen,dimen_base+pdf_dest_margin_code);@/ +@!@:pdf_dest_margin_}{\.{\\pdfdestmargin} primitive@> +primitive("pdfthreadmargin",assign_dimen,dimen_base+pdf_thread_margin_code);@/ +@!@:pdf_thread_margin_}{\.{\\pdfthreadmargin} primitive@> +primitive("pdffirstlineheight",assign_dimen,dimen_base+pdf_first_line_height_code);@/ +@!@:pdf_first_line_height_}{\.{\\pdffirstlineheight} primitive@> +primitive("pdflastlinedepth",assign_dimen,dimen_base+pdf_last_line_depth_code);@/ +@!@:pdf_last_line_depth_}{\.{\\pdflastlinedepth} primitive@> +primitive("pdfeachlineheight",assign_dimen,dimen_base+pdf_each_line_height_code);@/ +@!@:pdf_each_line_height_}{\.{\\pdfeachlineheight} primitive@> +primitive("pdfeachlinedepth",assign_dimen,dimen_base+pdf_each_line_depth_code);@/ +@!@:pdf_each_line_depth_}{\.{\\pdfeachlinedepth} primitive@> +@z + +% Define some read-only pdfTeX primitives +@x [416] +|glue_val|, |input_line_no_code|, or |badness_code|. +@y +|glue_val|, |input_line_no_code|, or |badness_code|. +\pdfTeX\ adds the codes for its extensions: |pdftex_version_code|, \dots\ . +@z + +@x [416] +@d badness_code=glue_val+2 {code for \.{\\badness}} +@y +@d badness_code=input_line_no_code+1 {code for \.{\\badness}} +@# +@d pdftex_first_rint_code = badness_code + 1 {base for \pdfTeX's command codes} +@d pdftex_version_code = pdftex_first_rint_code + 0 {code for \.{\\pdftexversion}} +@d pdf_last_obj_code = pdftex_first_rint_code + 1 {code for \.{\\pdflastobj}} +@d pdf_last_xform_code = pdftex_first_rint_code + 2 {code for \.{\\pdflastxform}} +@d pdf_last_ximage_code = pdftex_first_rint_code + 3 {code for \.{\\pdflastximage}} +@d pdf_last_ximage_pages_code = pdftex_first_rint_code + 4 {code for \.{\\pdflastximagepages}} +@d pdf_last_annot_code = pdftex_first_rint_code + 5 {code for \.{\\pdflastannot}} +@d pdf_last_x_pos_code = pdftex_first_rint_code + 6 {code for \.{\\pdflastxpos}} +@d pdf_last_y_pos_code = pdftex_first_rint_code + 7 {code for \.{\\pdflastypos}} +@d pdf_retval_code = pdftex_first_rint_code + 8 {global multi-purpose return value} +@d pdf_last_ximage_colordepth_code = pdftex_first_rint_code + 9 {code for \.{\\pdflastximagecolordepth}} +@d elapsed_time_code = pdftex_first_rint_code + 10 {code for \.{\\pdfelapsedtime}} +@d pdftex_last_item_codes = pdftex_first_rint_code + 10 {end of \pdfTeX's command codes} +@z + +@x [416] +primitive("badness",last_item,badness_code); +@!@:badness_}{\.{\\badness} primitive@> +@y +primitive("badness",last_item,badness_code); +@!@:badness_}{\.{\\badness} primitive@> +primitive("pdftexversion",last_item,pdftex_version_code);@/ +@!@:pdftex_version_}{\.{\\pdftexversion} primitive@> +primitive("pdflastobj",last_item,pdf_last_obj_code);@/ +@!@:pdf_last_obj_}{\.{\\pdflastobj} primitive@> +primitive("pdflastxform",last_item,pdf_last_xform_code);@/ +@!@:pdf_last_xform_}{\.{\\pdflastxform} primitive@> +primitive("pdflastximage",last_item,pdf_last_ximage_code);@/ +@!@:pdf_last_ximage_}{\.{\\pdflastximage} primitive@> +primitive("pdflastximagepages",last_item,pdf_last_ximage_pages_code);@/ +@!@:pdf_last_ximage_pages_}{\.{\\pdflastximagepages} primitive@> +primitive("pdflastannot",last_item,pdf_last_annot_code);@/ +@!@:pdf_last_annot_}{\.{\\pdflastannot} primitive@> +primitive("pdflastxpos",last_item,pdf_last_x_pos_code);@/ +@!@:pdf_last_x_pos_}{\.{\\pdflastxpos} primitive@> +primitive("pdflastypos",last_item,pdf_last_y_pos_code);@/ +@!@:pdf_last_y_pos_}{\.{\\pdflastypos} primitive@> +primitive("pdfretval",last_item,pdf_retval_code);@/ +@!@:pdf_retval_}{\.{\\pdfretval} primitive@> +primitive("pdflastximagecolordepth",last_item,pdf_last_ximage_colordepth_code);@/ +@!@:pdf_last_ximage_colordepth_}{\.{\\pdflastximagecolordepth} primitive@> +primitive("pdfelapsedtime",last_item,elapsed_time_code); +@!@:elapsed_time_}{\.{\\pdfelapsedtime} primitive@> +@z + +@x [417] + othercases print_esc("badness") +@y + pdftex_version_code: print_esc("pdftexversion"); + pdf_last_obj_code: print_esc("pdflastobj"); + pdf_last_xform_code: print_esc("pdflastxform"); + pdf_last_ximage_code: print_esc("pdflastximage"); + pdf_last_ximage_pages_code: print_esc("pdflastximagepages"); + pdf_last_annot_code: print_esc("pdflastannot"); + pdf_last_x_pos_code: print_esc("pdflastxpos"); + pdf_last_y_pos_code: print_esc("pdflastypos"); + pdf_retval_code: print_esc("pdfretval"); + pdf_last_ximage_colordepth_code: print_esc("pdflastximagecolordepth"); + elapsed_time_code: print_esc("pdfelapsedtime"); + othercases print_esc("badness") +@z + +@x [424] +if cur_chr>glue_val then +@y +if m>=input_line_no_code then +@z + +@x [424] + begin if cur_chr=input_line_no_code then cur_val:=line + else cur_val:=last_badness; {|cur_chr=badness_code|} +@y + begin case m of + input_line_no_code: cur_val:=line; + badness_code: cur_val:=last_badness; + pdftex_version_code: cur_val := pdftex_version; + pdf_last_obj_code: cur_val := pdf_last_obj; + pdf_last_xform_code: cur_val := pdf_last_xform; + pdf_last_ximage_code: cur_val := pdf_last_ximage; + pdf_last_ximage_pages_code: cur_val := pdf_last_ximage_pages; + pdf_last_annot_code: cur_val := pdf_last_annot; + pdf_last_x_pos_code: cur_val := pdf_last_x_pos; + pdf_last_y_pos_code: cur_val := pdf_last_y_pos; + pdf_retval_code: cur_val := pdf_retval; + pdf_last_ximage_colordepth_code: cur_val := pdf_last_ximage_colordepth; + elapsed_time_code: cur_val := get_microinterval; + end; {there are no other cases} +@z + +@x [455] - pxdimen +else if scan_keyword("ex") then v:=(@<The x-height for |cur_font|@>) +@.ex@> +@y +else if scan_keyword("ex") then v:=(@<The x-height for |cur_font|@>) +@.ex@> +else if scan_keyword("px") then v:=pdf_px_dimen +@.px@> +@z + +@x new Didot (1nd=0.375mm), new Cicero (1nc=12nd) +@ The necessary conversion factors can all be specified exactly as +fractions whose numerator and denominator are 32768 or less. +According to the definitions here, $\rm2660\,dd\approx1000.33297\,mm$; +this agrees well with the value $\rm1000.333\,mm$ cited by Bosshard +@^Bosshard, Hans Rudolf@> +in {\sl Technische Grundlagen zur Satzherstellung\/} (Bern, 1980). +@y +@ The necessary conversion factors can all be specified exactly as +fractions whose numerator and denominator are 65535 or less. +According to the definitions here, $\rm2660\,dd\approx1000.33297\,mm$; +this agrees well with the value $\rm1000.333\,mm$ cited by Bosshard +@^Bosshard, Hans Rudolf@> +in {\sl Technische Grundlagen zur Satzherstellung\/} (Bern, 1980). +The Didot point has been newly standardized in 1978; +it's now exactly $\rm 1\,nd=0.375\,mm$. +Conversion uses the equation $0.375=21681/20320/72.27\cdot25.4$. +The new Cicero follows the new Didot point; $\rm 1\,nc=12\,nd$. +@z + +@x new Didot (1nd=0.375mm), new Cicero (1nc=12nd) +else if scan_keyword("cc") then set_conversion(14856)(1157) +@.cc@> +@y +else if scan_keyword("cc") then set_conversion(14856)(1157) +@.cc@> +else if scan_keyword("nd") then set_conversion(21681)(20320) +@.nd@> +else if scan_keyword("nc") then set_conversion(65043)(5080) +@.nc@> +@z + +@x new Didot (1nd=0.375mm), new Cicero (1nc=12nd) + ("cm, mm, dd, cc, bp, or sp; but yours is a new one!")@/ +@y + ("cm, mm, dd, cc, nd, nc, bp, or sp; but yours is a new one!")@/ +@z + +% Define some char token producing pdfTeX primitives +@x [468] +@d number_code=0 {command code for \.{\\number}} +@y +\pdfTeX\ adds \.{\\eTeXrevision}, \.{\\pdftexrevision}, \.{\\pdftexbanner}, +\.{\\pdffontname}, \.{\\pdffontobjnum}, \.{\\pdffontsize}, and \.{\\pdfpageref} +such that |job_name_code| remains last. + +@d number_code=0 {command code for \.{\\number}} +@z + +@x [468] +@d job_name_code=5 {command code for \.{\\jobname}} +@y +@d pdftex_first_expand_code = 5 {base for \pdfTeX's command codes} +@d pdftex_revision_code = pdftex_first_expand_code + 0 {command code for \.{\\pdftexrevision}} +@d pdftex_banner_code = pdftex_first_expand_code + 1 {command code for \.{\\pdftexbanner}} +@d pdf_font_name_code = pdftex_first_expand_code + 2 {command code for \.{\\pdffontname}} +@d pdf_font_objnum_code = pdftex_first_expand_code + 3 {command code for \.{\\pdffontobjnum}} +@d pdf_font_size_code = pdftex_first_expand_code + 4 {command code for \.{\\pdffontsize}} +@d pdf_page_ref_code = pdftex_first_expand_code + 5 {command code for \.{\\pdfpageref}} +@d pdf_xform_name_code = pdftex_first_expand_code + 6 {command code for \.{\\pdfxformname}} +@d pdf_last_escaped_string_code = pdftex_first_expand_code + 7 {command code for \.{\\pdflastescapedstring}} +@d pdf_last_escaped_name_code = pdftex_first_expand_code + 8 {command code for \.{\\pdflastescapename}} +@d pdftex_convert_codes = pdftex_first_expand_code + 9 {end of \pdfTeX's command codes} +@d job_name_code=pdftex_convert_codes {command code for \.{\\jobname}} +@z + +@x [468] +primitive("jobname",convert,job_name_code);@/ +@y +@# +primitive("pdftexrevision",convert,pdftex_revision_code);@/ +@!@:pdftex_revision_}{\.{\\pdftexrevision} primitive@> +primitive("pdftexbanner",convert,pdftex_banner_code);@/ +@!@:pdftex_banner_}{\.{\\pdftexbanner} primitive@> +primitive("pdffontname",convert,pdf_font_name_code);@/ +@!@:pdf_font_name_}{\.{\\pdffontname} primitive@> +primitive("pdffontobjnum",convert,pdf_font_objnum_code);@/ +@!@:pdf_font_objnum_}{\.{\\pdffontobjnum} primitive@> +primitive("pdffontsize",convert,pdf_font_size_code);@/ +@!@:pdf_font_size_}{\.{\\pdffontsize} primitive@> +primitive("pdfpageref",convert,pdf_page_ref_code);@/ +@!@:pdf_page_ref_}{\.{\\pdfpageref} primitive@> +primitive("pdfxformname",convert,pdf_xform_name_code);@/ +@!@:pdf_xform_name_}{\.{\\pdfxformname} primitive@> +primitive("pdflastescapedstring",convert,pdf_last_escaped_string_code);@/ +@!@:pdf_last_escaped_string_}{\.{\\pdflastescapedstring} primitive@> +primitive("pdflastescapedname",convert,pdf_last_escaped_name_code);@/ +@!@:pdf_last_escaped_name_}{\.{\\pdflastescapedname} primitive@> +@# +primitive("jobname",convert,job_name_code);@/ +@z + +@x [469] + othercases print_esc("jobname") +@y + pdftex_revision_code: print_esc("pdftexrevision"); + pdftex_banner_code: print_esc("pdftexbanner"); + pdf_font_name_code: print_esc("pdffontname"); + pdf_font_objnum_code: print_esc("pdffontobjnum"); + pdf_font_size_code: print_esc("pdffontsize"); + pdf_page_ref_code: print_esc("pdfpageref"); + pdf_xform_name_code: print_esc("pdfxformname"); + pdf_last_escaped_string_code: print_esc("pdflastescapedstring"); + pdf_last_escaped_name_code: print_esc("pdflastescapedname"); + othercases print_esc("jobname") +@z + +@x [465] - pdfescapestring +@!b:pool_pointer; {base of temporary string} +@y +@!b:pool_pointer; {base of temporary string} +@!i, l: integer; {index to access escaped string or name} +@z + +@x [471] +job_name_code: if job_name=0 then open_log_file; +@y +pdftex_revision_code: do_nothing; +pdftex_banner_code: do_nothing; +pdf_font_name_code, pdf_font_objnum_code, pdf_font_size_code: begin + scan_font_ident; + if cur_val = null_font then + pdf_error("font", "invalid font identifier"); + if c <> pdf_font_size_code then begin + pdf_check_vf(cur_val); + if not font_used[cur_val] then + pdf_init_font(cur_val); + end; +end; +pdf_page_ref_code: begin + scan_int; + if cur_val <= 0 then + pdf_error("pageref", "invalid page number"); +end; +pdf_xform_name_code: begin + scan_int; + pdf_check_obj(obj_type_xform, cur_val); +end; +pdf_last_escaped_string_code: do_nothing; +pdf_last_escaped_name_code: do_nothing; +job_name_code: if job_name=0 then open_log_file; +@z + +@x [472] +job_name_code: print(job_name); +@y +pdftex_revision_code: print(pdftex_revision); +pdftex_banner_code: print(pdftex_banner); +pdf_font_name_code, pdf_font_objnum_code: begin + set_ff(cur_val); + if c = pdf_font_name_code then + print_int(obj_info(pdf_font_num[ff])) + else + print_int(pdf_font_num[ff]); +end; +pdf_font_size_code: begin + print_scaled(font_size[cur_val]); + print("pt"); +end; +pdf_page_ref_code: print_int(get_obj(obj_type_page, cur_val, false)); +pdf_xform_name_code: print_int(obj_info(cur_val)); +pdf_last_escaped_string_code: begin + l := escapedstrlen; + for i := 0 to l - 1 do + print_char(getescapedstrchar(i)); +end; +pdf_last_escaped_name_code: begin + l := escapednamelen; + for i := 0 to l - 1 do + print_char(getescapednamechar(i)); +end; +job_name_code: print(job_name); +@z + +@x [577] - tagcode +@<Declare procedures that scan font-related stuff@>= +procedure scan_font_ident; +@y +@<Declare procedures that scan font-related stuff@>= +function get_tag_code(f: internal_font_number; c: eight_bits): integer; +var i:small_number; +begin + if is_valid_char(c) then + begin i := char_tag(char_info(f)(c)); + if i = lig_tag then + get_tag_code := 1 + else if i = list_tag then + get_tag_code := 2 + else if i = ext_tag then + get_tag_code := 4 + else + get_tag_code := 0; + end + else + get_tag_code := -1; +end; +procedure scan_font_ident; +@z + +% Shipping out to PDF +@x [638] +@ The |hlist_out| and |vlist_out| procedures are now complete, so we are +ready for the |ship_out| routine that gets them started in the first place. + +@p procedure ship_out(@!p:pointer); {output the box |p|} +@y +@ The |hlist_out| and |vlist_out| procedures are now complete, so we are +ready for the |dvi_ship_out| routine that gets them started in the first place. + +@p procedure dvi_ship_out(@!p:pointer); {output the box |p|} +@z + +@x [644] +@* \[33] Packaging. +@y + +@* \[32a] \pdfTeX\ basic. + +Initialize pdftex's parameters to some useful default value. +Helpful in case one forgets to set them during initex run. + +@<Initialize table entries...@>= +pdf_h_origin := (one_hundred_inch + 50) div 100; +pdf_v_origin := (one_hundred_inch + 50) div 100; +pdf_compress_level := 9; +pdf_decimal_digits := 4; +pdf_image_resolution := 72; +pdf_minor_version := 4; +pdf_gamma := 1000; +pdf_image_gamma := 2200; +pdf_image_hicolor := 1; +pdf_image_apply_gamma := 0; + +@ The subroutines define the corresponding macros so we can use them +in C. + +@d flushable(#) == (# = str_ptr - 1) + +@d is_valid_char(#)==((font_bc[f] <= #) and (# <= font_ec[f]) and + char_exists(char_info(f)(#))) + +@p function get_pdf_compress_level: integer; +begin + get_pdf_compress_level := pdf_compress_level; +end; + +function get_nullfont: internal_font_number; +begin + get_nullfont := null_font; +end; + +function get_nullcs: pointer; +begin + get_nullcs := null_cs; +end; + +function get_nullptr: pointer; +begin + get_nullptr := null; +end; + +function get_tex_int(code: integer): integer; +begin + get_tex_int := int_par(code); +end; + +function get_tex_dimen(code: integer): scaled; +begin + get_tex_dimen := dimen_par(code); +end; + +function get_x_height(f: internal_font_number): scaled; +begin + get_x_height := x_height(f); +end; + +function get_charwidth(f: internal_font_number; c: eight_bits): scaled; +begin + if is_valid_char(c) then + get_charwidth := char_width(f)(char_info(f)(c)) + else + get_charwidth := 0; +end; + +function get_charheight(f: internal_font_number; c: eight_bits): scaled; +begin + if is_valid_char(c) then + get_charheight := char_height(f)(height_depth(char_info(f)(c))) + else + get_charheight := 0; +end; + +function get_chardepth(f: internal_font_number; c: eight_bits): scaled; +begin + if is_valid_char(c) then + get_chardepth := char_depth(f)(height_depth(char_info(f)(c))) + else + get_chardepth := 0; +end; + +function get_quad(f: internal_font_number): scaled; +begin + get_quad := quad(f); +end; + +function get_slant(f: internal_font_number): scaled; +begin + get_slant := slant(f); +end; + +function new_dummy_font: internal_font_number; +begin + new_dummy_font := read_font_info(null_cs, "dummy", "", -1000); +end; + +@ Helper for debugging purposes + +@p procedure short_display_n(@!p, m:integer); {prints highlights of list |p|} +var n:integer; {for replacement counts} + i: integer; +begin +i := 0; +font_in_short_display:=null_font; +if p = null then + return; +while p>mem_min do + begin if is_char_node(p) then + begin if p<=mem_end then + begin if font(p)<>font_in_short_display then + begin if (font(p)<font_base)or(font(p)>font_max) then + print_char("*") +@.*\relax@> + else @<Print the font identifier for |font(p)|@>; + print_char(" "); font_in_short_display:=font(p); + end; + print_ASCII(qo(character(p))); + end; + end + else begin + if (type(p) = glue_node) or + (type(p) = disc_node) or + (type(p) = penalty_node) or + ((type(p) = kern_node) and (subtype(p) = explicit)) then + incr(i); + if i >= m then + return; + if (type(p) = disc_node) then begin + print("|"); + short_display(pre_break(p)); + print("|"); + short_display(post_break(p)); + print("|"); + n:=replace_count(p); + while n>0 do + begin if link(p)<>null then p:=link(p); + decr(n); + end; + end + else + @<Print a short indication of the contents of node |p|@>; + end; + p:=link(p); + if p = null then + return; + end; + update_terminal; +end; + +@ Sometimes it is neccesary to allocate memory for PDF output that cannot +be deallocated then, so we use |pdf_mem| for this purpose. + +@<Constants...@>= +@!inf_pdf_mem_size = 10000; {min size of the |pdf_mem| array} +@!sup_pdf_mem_size = 10000000; {max size of the |pdf_mem| array} + +@ @<Glob...@>= +@!pdf_mem_size: integer; +@!pdf_mem: ^integer; +@!pdf_mem_ptr: integer; + +@ @<Set init...@>= +pdf_mem_ptr := 1; {the first word is not used so we can use zero as a value for testing +whether a pointer to |pdf_mem| is valid} +pdf_mem_size := inf_pdf_mem_size; {allocated size of |pdf_mem| array} + +@ We use |pdf_get_mem| to allocate memory in |pdf_mem| + +@p function pdf_get_mem(s: integer): integer; {allocate |s| words in |pdf_mem|} +var a: integer; +begin + if s > sup_pdf_mem_size - pdf_mem_size then + overflow("PDF memory size (pdf_mem_size)", pdf_mem_size); + if pdf_mem_ptr + s > pdf_mem_size then begin + a := 0.2 * pdf_mem_size; + if pdf_mem_ptr + s > pdf_mem_size + a then + pdf_mem_size := pdf_mem_ptr + s + else if pdf_mem_size < sup_pdf_mem_size - a then + pdf_mem_size := pdf_mem_size + a + else + pdf_mem_size := sup_pdf_mem_size; + pdf_mem := xrealloc_array(pdf_mem, integer, pdf_mem_size); + end; + pdf_get_mem := pdf_mem_ptr; + pdf_mem_ptr := pdf_mem_ptr + s; +end; + +@* \[32b] \pdfTeX\ output low-level subroutines. +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. + +@<Constants...@>= +@!pdf_buf_size = 16384; {size of the PDF buffer} + +@ The following macros are similar as for \.{DVI} buffer handling + +@d pdf_offset == (pdf_gone + pdf_ptr) {the file offset of last byte in PDF +buffer that |pdf_ptr| points to} + +@d no_zip == 0 {no \.{ZIP} compression} +@d zip_writing == 1 {\.{ZIP} compression being used} +@d zip_finish == 2 {finish \.{ZIP} compression} + +@d pdf_quick_out(#) == {output a byte to PDF buffer without checking of +overflow} +begin + pdf_buf[pdf_ptr] := #; + incr(pdf_ptr); +end + +@d pdf_room(#) == {make sure that there are at least |n| bytes free in PDF +buffer} +begin + if pdf_buf_size < # then + overflow("PDF output buffer", pdf_buf_size); + if pdf_ptr + # > pdf_buf_size then + pdf_flush; +end + +@d pdf_out(#) == {do the same as |pdf_quick_out| and flush the PDF +buffer if necessary} +begin + if pdf_ptr > pdf_buf_size then + pdf_flush; + pdf_quick_out(#); +end + +@<Glob...@>= +@!pdf_file: byte_file; {the PDF output file} +@!pdf_buf: array[0..pdf_buf_size] of eight_bits; {the PDF buffer} +@!pdf_ptr: integer; {pointer to the first unused byte in the PDF buffer} +@!pdf_gone: integer; {number of bytes that were flushed to output} +@!pdf_save_offset: integer; {to save |pdf_offset|} +@!zip_write_state: integer; {which state of compression we are in} +@!fixed_pdf_minor_version: integer; {fixed minor part of the pdf version} +@!pdf_minor_version_written: boolean; {flag if the pdf version has been written} +@!fixed_pdfoutput: integer; {fixed output format} +@!fixed_pdfoutput_set: boolean; {|fixed_pdfoutput| has been set?} +@!fixed_gamma: integer; +@!fixed_image_gamma: integer; +@!fixed_image_hicolor: boolean; +@!fixed_image_apply_gamma: integer; +@!epochseconds: integer; +@!microseconds: integer; + +@ @<Set init...@>= +pdf_buf[0] := "%"; +pdf_buf[1] := "P"; +pdf_buf[2] := "D"; +pdf_buf[3] := "F"; +pdf_buf[4] := "-"; +pdf_buf[5] := "1"; +pdf_buf[6] := "."; +pdf_buf[7] := "4"; +pdf_buf[8] := pdf_new_line_char; +pdf_buf[9] := "%"; +pdf_buf[10] := 208; +pdf_buf[11] := 212; +pdf_buf[12] := 197; +pdf_buf[13] := 216; +pdf_buf[14] := pdf_new_line_char; +pdf_ptr := 15; +pdf_gone := 0; +zip_write_state := no_zip; +pdf_minor_version_written := false; +fixed_pdfoutput_set := false; +fixed_gamma := 1000; +fixed_image_gamma := 2200; +fixed_image_hicolor := 1; +fixed_image_apply_gamma := 0; + +@ @p +function fix_int(val, min, max: integer): integer; +begin + if val < min then + fix_int := min + else if val > max then + fix_int := max + else + fix_int := val; +end; + +@ This checks that |pdfminorversion| can only be set before any +bytes have been written to the generated pdf file. It should be called +directly after every |ensure_pdf_open|. + +@p procedure check_pdfminorversion; +begin + if not pdf_minor_version_written then begin + pdf_minor_version_written := true; + if (pdf_minor_version < 0) or (pdf_minor_version > 9) then begin + print_err("pdfTeX error (illegal pdfminorversion)"); + print_ln; + help2 ("The pdfminorversion must be between 0 and 9.")@/ + ("I changed this to 4."); + int_error (pdf_minor_version); + pdf_minor_version := 4; + end; + fixed_pdf_minor_version := pdf_minor_version; + pdf_buf[7] := chr(ord("0") + fixed_pdf_minor_version); + fixed_gamma := fix_int(pdf_gamma, 0, 1000000); + fixed_image_gamma := fix_int(pdf_image_gamma, 0, 1000000); + fixed_image_hicolor := fix_int(pdf_image_hicolor, 0, 1); + fixed_image_apply_gamma := fix_int(pdf_image_apply_gamma, 0, 1); + end + else begin + if fixed_pdf_minor_version <> pdf_minor_version then + pdf_error("setup", + "\pdfminorversion cannot be changed after data is written to the pdf file"); + end; +end; + +@ Checks that we have a name for the generated pdf file and that it's open. +|check_pdfminorversion| should be called directly +hereafter. + +@p procedure ensure_pdf_open; +begin + if output_file_name <> 0 then + return; + if job_name = 0 then + open_log_file; + pack_job_name(".pdf"); + while not b_open_out(pdf_file) do + prompt_file_name("file name for output",".pdf"); + output_file_name := b_make_name_string(pdf_file); +end; + +@ 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. + +@p procedure pdf_flush; {flush out the |pdf_buf|} +begin + ensure_pdf_open; + check_pdfminorversion; + case zip_write_state of + no_zip: if pdf_ptr > 0 then begin + write_pdf(0, pdf_ptr - 1); + pdf_gone := pdf_gone + pdf_ptr; + end; + zip_writing: + write_zip(false); + zip_finish: begin + write_zip(true); + zip_write_state := no_zip; + end; + end; + pdf_ptr := 0; +end; + +procedure pdf_begin_stream; {begin a stream} +begin + ensure_pdf_open; + check_pdfminorversion; + pdf_print_ln("/Length "); + pdf_stream_length_offset := pdf_offset - 11; + pdf_stream_length := 0; + if pdf_compress_level > 0 then begin + pdf_print_ln("/Filter /FlateDecode"); + pdf_print_ln(">>"); + pdf_print_ln("stream"); + pdf_flush; + zip_write_state := zip_writing; + end + else begin + pdf_print_ln(">>"); + pdf_print_ln("stream"); + pdf_save_offset := pdf_offset; + end; +end; + +procedure pdf_end_stream; {end a stream} +begin + if pdf_compress_level > 0 then + zip_write_state := zip_finish + else + pdf_stream_length := pdf_offset - pdf_save_offset; + pdf_flush; + write_stream_length(pdf_stream_length, pdf_stream_length_offset); + if pdf_compress_level > 0 then + pdf_out(pdf_new_line_char); + pdf_print_ln("endstream"); + pdf_end_obj; +end; + +@ 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. + +@d pdf_new_line_char == 10 {new-line character for UNIX platforms} + +@d pdf_print_nl == {output a new-line character to PDF buffer} +if (pdf_ptr > 0) and (pdf_buf[pdf_ptr - 1] <> pdf_new_line_char) then + pdf_out(pdf_new_line_char) + +@d pdf_print_ln(#) == {print out a string to PDF buffer followed by +a new-line character} +begin + pdf_print(#); + pdf_print_nl; +end + +@d pdf_print_int_ln(#) == {print out an integer to PDF buffer followed by +a new-line character} +begin + pdf_print_int(#); + pdf_print_nl; +end + +@<Declare procedures that need to be declared forward for pdftex@>= +procedure pdf_error(t, p: str_number); +begin + normalize_selector; + print_err("pdfTeX error"); + if t <> 0 then begin + print(" ("); + print(t); + print(")"); + end; + print(": "); print(p); + succumb; +end; + +procedure pdf_warning(t, p: str_number; append_nl: boolean); +begin + print_err("pdfTeX warning"); + if t <> 0 then begin + print(" ("); + print(t); + print(")"); + end; + print(": "); print(p); + if append_nl then + print_ln; +end; + +procedure remove_last_space; +begin + if (pdf_ptr > 0) and (pdf_buf[pdf_ptr - 1] = 32) then + decr(pdf_ptr); +end; + +procedure pdf_print_octal(n: integer); {prints an integer in octal form to +PDF buffer} +var k:0..23; {index to current digit; we assume that $|n|<10^{23}$} +begin + k:=0; + repeat dig[k]:=n mod 8; n:=n div 8; incr(k); + until n=0; + if k = 1 then begin + pdf_out("0"); + pdf_out("0"); + end; + if k = 2 then + pdf_out("0"); + while k>0 do begin + decr(k); + pdf_out("0"+dig[k]); + end; +end; + +procedure pdf_print_char(f: internal_font_number; c: integer); +{ 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) } +begin + if c <= 32 then + c := pdf_char_map[f, c]; + pdf_mark_char(f, c); + if (c <= 32) or (c = 92) or (c = 40) or (c = 41) or (c > 127) then begin + pdf_out(92); {output a backslash} + pdf_print_octal(c); + end + else + pdf_out(c); +end; + +procedure pdf_print(s: str_number); {print out a string to PDF buffer} +var j: pool_pointer; {current character code position} + c: integer; +begin + j := str_start[s]; + while j < str_start[s + 1] do begin + c := str_pool[j]; + pdf_out(c); + incr(j); + end; +end; + +function str_in_str(s, r: str_number; i: integer): boolean; + {test equality of strings} +label not_found; {loop exit} +var j, k: pool_pointer; {running indices} +@!result: boolean; {result of comparison} +begin + str_in_str := false; + if length(s) < i + length(r) then + return; + j := i + str_start[s]; + k := str_start[r]; + while (j < str_start[s + 1]) and (k < str_start[r + 1]) do begin + if str_pool[j] <> str_pool[k] then + return; + incr(j); + incr(k); + end; + str_in_str := true; +end; + +procedure literal(s: str_number; literal_mode: integer; warn: boolean); +var j: pool_pointer; {current character code position} +begin + j:=str_start[s]; + if literal_mode = scan_special then begin + if not (str_in_str(s, "PDF:", 0) or str_in_str(s, "pdf:", 0)) then begin + if warn and not (str_in_str(s, "SRC:", 0) + or str_in_str(s, "src:", 0) + or (length(s) = 0)) then + print_nl("Non-PDF special ignored!"); + return; + end; + j := j + length("PDF:"); + if str_in_str(s, "direct:", length("PDF:")) then begin + j := j + length("direct:"); + literal_mode := direct_always; end + else if str_in_str(s, "page:", length("PDF:")) then begin + j := j + length("page:"); + literal_mode := direct_page; end + else + literal_mode := reset_origin; + end; + case literal_mode of + reset_origin: begin + pdf_end_text; + pdf_set_origin; + end; + direct_page: + pdf_end_text; + direct_always: begin + pdf_first_space_corr := 0; + pdf_end_string; + pdf_print_nl; + end; + othercases confusion("literal1") + endcases; + while j<str_start[s+1] do begin + pdf_out(str_pool[j]); + incr(j); + end; + pdf_print_nl; +end; + +procedure pdf_print_int(n:integer); {print out a integer to PDF buffer} +var k:integer; {index to current digit ($0\le k\le23$); we assume that $|n|<10^{23}$} +m:integer; {used to negate |n| in possibly dangerous cases} +begin + k:=0; + if n<0 then + begin pdf_out("-"); + if n>-100000000 then negate(n) + else begin m:=-1-n; n:=m div 10; m:=(m mod 10)+1; k:=1; + if m<10 then dig[0]:=m + else begin dig[0]:=0; incr(n); + end; + end; + end; + repeat dig[k]:=n mod 10; n:=n div 10; incr(k); + until n=0; + pdf_room(k); + while k>0 do begin + decr(k); + pdf_quick_out("0"+dig[k]); + end; +end; + +procedure pdf_print_two(n:integer); {prints two least significant digits in +decimal form to PDF buffer} +begin n:=abs(n) mod 100; pdf_out("0"+(n div 10)); +pdf_out("0"+(n mod 10)); +end; + +function tokens_to_string(p: pointer): str_number; {return a string from tokens +list} +begin + if selector = new_string then + pdf_error("tokens", "tokens_to_string() called while selector = new_string"); + old_setting:=selector; selector:=new_string; + show_token_list(link(p),null,pool_size-pool_ptr); + selector:=old_setting; + last_tokens_string := make_string; + tokens_to_string := last_tokens_string; +end; + + +@ To print |scaled| value to PDF output we need some subroutines to ensure +accurary. + +@d max_integer == @"7FFFFFFF {$2^{31}-1$} +@d call_func(#) == begin if # <> 0 then do_nothing end + +@<Glob...@>= +@!one_bp: scaled; {scaled value corresponds to 1bp} +@!one_hundred_bp: scaled; {scaled value corresponds to 100bp} +@!one_hundred_inch: scaled; {scaled value corresponds to 100in} +@!ten_pow: array[0..9] of integer; {$10^0..10^9$} +@!scaled_out: integer; {amount of |scaled| that was taken out in +|divide_scaled|} +@!init_pdf_output: boolean; + +@ @<Set init...@>= +one_bp := 65782; {65781.76} +one_hundred_bp := 6578176; +one_hundred_inch := 473628672; +ten_pow[0] := 1; +for i := 1 to 9 do + ten_pow[i] := 10*ten_pow[i - 1]; +init_pdf_output := false; + + +@ The following function divides |s| by |m|. |dd| is number of decimal digits. + +@<Declare procedures that need to be declared forward for pdftex@>= +function divide_scaled(s, m: scaled; dd: integer): scaled; +var q, r: scaled; + sign, i: integer; +begin + sign := 1; + if s < 0 then begin + sign := -sign; + s := -s; + end; + if m < 0 then begin + sign := -sign; + m := -m; + end; + if m = 0 then + pdf_error("arithmetic", "divided by zero") + else if m >= (max_integer div 10) then + pdf_error("arithmetic", "number too big"); + q := s div m; + r := s mod m; + for i := 1 to dd do begin + q := 10*q + (10*r) div m; + r := (10*r) mod m; + end; + if 2*r >= m then begin + incr(q); + r := r - m; + end; + scaled_out := sign*(s - (r div ten_pow[dd])); + divide_scaled := sign*q; +end; + +function round_xn_over_d(@!x:scaled; @!n,@!d:integer):scaled; +var positive:boolean; {was |x>=0|?} +@!t,@!u,@!v:nonnegative_integer; {intermediate quantities} +begin if x>=0 then positive:=true +else begin negate(x); positive:=false; + end; +t:=(x mod @'100000)*n; +u:=(x div @'100000)*n+(t div @'100000); +v:=(u mod d)*@'100000 + (t mod @'100000); +if u div d>=@'100000 then arith_error:=true +else u:=@'100000*(u div d) + (v div d); +v := v mod d; +if 2*v >= d then + incr(u); +if positive then + round_xn_over_d := u +else + round_xn_over_d := -u; +end; + + +@ Next subroutines are needed for controling spacing in PDF page description. +The procedure |adv_char_width| advances |pdf_h| by the amount |w|, which is +the character width. We cannot simply add |w| to |pdf_h|, but must +calculate the amount corresponding to |w| in the PDF output. For PK fonts +things are more complicated, as we have to deal with scaling bitmaps as well. + +@p +procedure adv_char_width(f: internal_font_number; w: scaled); {update |pdf_h| +by character width |w| from font |f|} +begin + if hasfmentry(f) then begin + call_func(divide_scaled(w, pdf_font_size[f], 3)); + pdf_h := pdf_h + scaled_out; + end + else + pdf_h := pdf_h + get_pk_char_width(f, w); +end; + +procedure pdf_print_real(m, d: integer); {print $m/10^d$ as real} +var n: integer; +begin + if m < 0 then begin + pdf_out("-"); + m := -m; + end; + n := ten_pow[d]; + pdf_print_int(m div n); + m := m mod n; + if m > 0 then begin + pdf_out("."); + n := n div 10; + while m < n do begin + pdf_out("0"); + n := n div 10; + end; + while m mod 10 = 0 do + m := m div 10; + pdf_print_int(m); + end; +end; + +procedure pdf_print_bp(s: scaled); {print scaled as |bp|} +begin + pdf_print_real(divide_scaled(s, one_hundred_bp, fixed_decimal_digits + 2), + fixed_decimal_digits); +end; + +procedure pdf_print_mag_bp(s: scaled); {take |mag| into account} +begin + prepare_mag; + if mag <> 1000 then + s := round_xn_over_d(s, mag, 1000); + pdf_print_bp(s); +end; + +@* \[32c] PDF page description. + +@d pdf_x(#) == ((#) - pdf_origin_h) {convert $x$-coordinate from \.{DVI} to +PDF} +@d pdf_y(#) == (pdf_origin_v - (#)) {convert $y$-coordinate from \.{DVI} to +PDF} + +@<Glob...@>= +@!pdf_f: internal_font_number; {the current font in PDF output page} +@!pdf_h: scaled; {current horizontal coordinate in PDF output page} +@!pdf_v: scaled; {current vertical coordinate in PDF output page} +@!pdf_last_h: scaled; {last horizontal coordinate in PDF output page} +@!pdf_last_v: scaled; {last vertical coordinate in PDF output page} +@!pdf_origin_h: scaled; {current horizontal origin in PDF output page} +@!pdf_origin_v: scaled; {current vertical origin in PDF output page} +@!pdf_first_space_corr: integer; {amount of first word spacing while drawing a string; +for some reason it is not taken into account of the length of the string, so we +have to save it in order to adjust spacing when string drawing is finished} +@!pdf_doing_string: boolean; {we are writing string to PDF file?} +@!pdf_doing_text: boolean; {we are writing text section to PDF file?} +@!pdf_font_changed: boolean; {current font has been changed?} +@!min_bp_val: scaled; +@!fixed_pk_resolution: integer; +@!fixed_decimal_digits: integer; +@!pk_scale_factor: integer; +@!pdf_output_option: integer; +@!pdf_output_value: integer; + +@ Following procedures implement low-level subroutines to convert \TeX{} +internal structures to PDF page description. + +@p procedure pdf_set_origin; {set the origin to |cur_h|, |cur_v|} +begin + if (abs(cur_h - pdf_origin_h) >= min_bp_val) or + (abs(cur_v - pdf_origin_v) >= min_bp_val) then begin + pdf_print("1 0 0 1 "); + pdf_print_bp(cur_h - pdf_origin_h); + pdf_origin_h := pdf_origin_h + scaled_out; + pdf_out(" "); + pdf_print_bp(pdf_origin_v - cur_v); + pdf_origin_v := pdf_origin_v - scaled_out; + pdf_print_ln(" cm"); + end; + pdf_h := pdf_origin_h; + pdf_last_h := pdf_origin_h; + pdf_v := pdf_origin_v; + pdf_last_v := pdf_origin_v; +end; + +procedure pdf_end_string; {end the current string} +begin + if pdf_doing_string then begin + pdf_print(")]TJ"); + if pdf_first_space_corr <> 0 then begin + pdf_h := pdf_h - pdf_first_space_corr; + pdf_first_space_corr := 0; + end; + pdf_doing_string := false; + end; +end; + +procedure pdf_moveto(v, v_out: scaled); {set the next starting point to |cur_h|, |cur_v|} +begin + pdf_out(" "); + pdf_print_bp(cur_h - pdf_last_h); + pdf_h := pdf_last_h + scaled_out; + pdf_out(" "); + pdf_print_real(v, fixed_decimal_digits); + pdf_print(" Td"); + pdf_v := pdf_last_v - v_out; + pdf_last_h := pdf_h; + pdf_last_v := pdf_v; +end; + +procedure pdf_begin_text; forward; + +procedure pdf_print_font_tag(f: internal_font_number); +begin + if pdf_font_expand_ratio[f] = 0 then + return; + if pdf_font_expand_ratio[f] > 0 then + pdf_print("+"); {minus sign will be printed by |pdf_print_int|} + pdf_print_int(pdf_font_expand_ratio[f]); +end; + +procedure pdf_set_font(f: internal_font_number); +label found; +var p: pointer; + k: internal_font_number; +begin + if not font_used[f] then + pdf_init_font(f); + set_ff(f); + k := ff; + p := pdf_font_list; + while p <> null do begin + set_ff(info(p)); + if ff = k then + goto found; + p := link(p); + end; + pdf_append_list(f)(pdf_font_list); {|f| not found in |pdf_font_list|} +found: + pdf_begin_text; + pdf_print("/F"); + pdf_print_int(k); + pdf_print_font_tag(f); + pdf_print_resname_prefix; + pdf_out(" "); + pdf_print_bp(font_size[f]); + pdf_print(" Tf"); + pdf_f := f; + pdf_font_changed := true; +end; + +procedure pdf_begin_text; {begin a text section} +var temp_cur_h, temp_cur_v: scaled; +begin + if not pdf_doing_text then begin + temp_cur_h := cur_h; + temp_cur_v := cur_v; + cur_h := 0; + cur_v := cur_page_height; + pdf_set_origin; + cur_h := temp_cur_h; + cur_v := temp_cur_v; + pdf_print_ln("BT"); + pdf_doing_text := true; + pdf_f := null_font; + pdf_first_space_corr := 0; + pdf_doing_string := false; + end; +end; + +procedure pdf_begin_string(f: internal_font_number); {begin to draw a string} +var b: boolean; {|b| is true only when we must adjust word spacing +at the beginning of string} + s, s_out, v, v_out: scaled; +begin + pdf_begin_text; + if f <> pdf_f then begin + pdf_end_string; + pdf_set_font(f); + end; + b := false; + s := divide_scaled(cur_h - pdf_h, pdf_font_size[f], 3); + s_out := scaled_out; + if abs(cur_v - pdf_v) >= min_bp_val then begin + v := divide_scaled(pdf_last_v - cur_v, one_hundred_bp, + fixed_decimal_digits + 2); + v_out := scaled_out; + end + else begin + v := 0; + v_out := 0; + end; + if pdf_font_changed or (v <> 0) or (abs(s) >= @'100000) then begin + pdf_end_string; + pdf_moveto(v, v_out); + pdf_font_changed := false; + s := 0; + s_out := 0; + end; + if pdf_doing_string then begin + if s <> 0 then + pdf_out(")"); + end + else begin + pdf_out("["); + if s <> 0 then + b := true + else + pdf_out("("); + pdf_doing_string := true; + end; + if s <> 0 then begin + pdf_print_int(-s); + if b then + pdf_first_space_corr := s_out; + pdf_out("("); + pdf_h := pdf_h + s_out; + end; +end; + +procedure pdf_end_text; {end a text section} +begin + if pdf_doing_text then begin + pdf_end_string; + pdf_print_nl; + pdf_print_ln("ET"); + pdf_doing_text := false; + end; +end; + +procedure pdf_set_rule(x, y, w, h: scaled); {draw a rule} +begin + pdf_end_text; + pdf_set_origin; + if h <= one_bp then begin + pdf_print_ln("q"); + pdf_print_ln("[]0 d"); + pdf_print_ln("0 J"); + pdf_print_bp(h); pdf_print_ln(" w"); + pdf_print("0 "); pdf_print_bp((h + 1)/2); pdf_print_ln(" m"); + pdf_print_bp(w); pdf_print(" "); pdf_print_bp((h + 1)/2); + pdf_print_ln(" l"); + pdf_print_ln("S"); + pdf_print_ln("Q"); + end + else if w <= one_bp then begin + pdf_print_ln("q"); + pdf_print_ln("[]0 d"); + pdf_print_ln("0 J"); + pdf_print_bp(w); pdf_print_ln(" w"); + pdf_print_bp((w + 1)/2); pdf_print_ln(" 0 m"); + pdf_print_bp((w + 1)/2); pdf_print(" "); pdf_print_bp(h); + pdf_print_ln(" l"); + pdf_print_ln("S"); + pdf_print_ln("Q"); + end + else begin + pdf_print_bp(pdf_x(x)); pdf_out(" "); + pdf_print_bp(pdf_y(y)); pdf_out(" "); + pdf_print_bp(w); pdf_out(" "); + pdf_print_bp(h); pdf_print_ln(" re f"); + end; +end; + + +procedure pdf_rectangle(left, top, right, bottom: scaled); {output a +rectangle specification to PDF file} +begin + prepare_mag; + pdf_print("/Rect ["); + pdf_print_mag_bp(pdf_x(left)); pdf_out(" "); + pdf_print_mag_bp(pdf_y(bottom)); pdf_out(" "); + pdf_print_mag_bp(pdf_x(right)); pdf_out(" "); + pdf_print_mag_bp(pdf_y(top)); + pdf_print_ln("]"); +end; + +@* \[32d] The cross-reference table. + +The cross-reference table |obj_tab| is an array of |obj_tab_size| of +|tab_entry|. Each entry contains four 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. + +@<Types...@>= +@!obj_entry = record@;@/ + int0, int1, int2, int3: integer; +end; + +@ 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 in linked in a list. + +The third field holds the byte offset of the object in the output PDF file. +Objects that have been not written yet have this field set to zero. However +sometimes we have to use this field to store some info before the object is +written out. + +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. + +@d obj_info(#) == obj_tab[#].int0 {information representing identifier of this object} +@d obj_link(#) == obj_tab[#].int1 {link to the next entry in linked list} +@d obj_offset(#) == obj_tab[#].int2 {byte offset of this object in PDF output file} +@d obj_aux(#) == obj_tab[#].int3 {auxiliary pointer} +@d is_obj_written(#) == (obj_offset(#) <> 0) + +@# {types of objects} +@d obj_type_others == 0 {objects which are not linked in any list} +@d obj_type_page == 1 {index of linked list of Page objects} +@d obj_type_pages == 2 {index of linked list of Pages objects} +@d obj_type_font == 3 {index of linked list of Fonts objects} +@d obj_type_outline == 4 {index of linked list of outline objects} +@d obj_type_dest == 5 {index of linked list of destination objects} +@d obj_type_obj == 6 {index of linked list of raw objects} +@d obj_type_xform == 7 {index of linked list of XObject forms} +@d obj_type_ximage == 8 {index of linked list of XObject image} +@d obj_type_thread == 9 {index of linked list of num article threads} +@d head_tab_max == obj_type_thread {max index of |head_tab|} + +@# {max number of kids for balanced trees} +@d pages_tree_kids_max == 6 {max number of kids of Pages tree node} +@d name_tree_kids_max == @'100000 {max number of kids of node of name tree for +name destinations} + +@# {when a whatsit node representing annotation is created, words |1..3| are +width, height and depth of this annotation; after shipping out words |1..4| +are rectangle specification of annotation. For whatsit node representing +destination |pdf_left| and |pdf_top| are used for some types of destinations} + +@# {coordinates of destinations/threads/annotations (in whatsit node)} +@d pdf_left(#) == mem[# + 1].sc +@d pdf_top(#) == mem[# + 2].sc +@d pdf_right(#) == mem[# + 3].sc +@d pdf_bottom(#) == mem[# + 4].sc + +@# {dimesion of destinations/threads/annotations (in whatsit node)} +@d pdf_width(#) == mem[# + 1].sc +@d pdf_height(#) == mem[# + 2].sc +@d pdf_depth(#) == mem[# + 3].sc + +@# {data structure for \.{\\pdfliteral}} +@d pdf_literal_data(#) == link(#+1) {data} +@d pdf_literal_mode(#) == info(#+1) {mode of resetting the text matrix + while writing data to the page stream} +@# {modes of resetting the text matrix} +@d reset_origin == 0 {end text (ET) if needed, reset text matrix} +@d direct_page == 1 {end text (ET) if needed, don't reset text matrix} +@d direct_always == 2 {don't reset text matrix} +@d scan_special == 3 {look into special text} + +@# {data structure for \.{\\pdfobj} and \.{\\pdfrefobj}} +@d pdf_refobj_node_size == 2 {size of whatsit node representing the raw object} +@d pdf_obj_objnum(#) == info(# + 1) {number of the raw object} +@d obj_data_ptr == obj_aux {pointer to |pdf_mem|} +@d pdfmem_obj_size == 4 {size of memory in |pdf_mem| which + |obj_data_ptr| holds} +@d obj_obj_data(#) == pdf_mem[obj_data_ptr(#) + 0] {object data} +@d obj_obj_is_stream(#) == pdf_mem[obj_data_ptr(#) + 1] {will this object + be written as a stream instead of a dictionary?} +@d obj_obj_stream_attr(#) == pdf_mem[obj_data_ptr(#) + 2] {additional + object attributes for streams} +@d obj_obj_is_file(#) == pdf_mem[obj_data_ptr(#) + 3] {data should be + read from an external file?} + +@# {data structure for \.{\\pdfxform} and \.{\\pdfrefxform}} +@d pdf_refxform_node_size == 5 {size of whatsit node for xform; words 1..3 are + form dimensions} +@d pdf_xform_objnum(#) == info(# + 4) {object number} +@d pdfmem_xform_size == 6 {size of memory in |pdf_mem| which + |obj_data_ptr| holds} +@d obj_xform_width(#) == pdf_mem[obj_data_ptr(#) + 0] +@d obj_xform_height(#) == pdf_mem[obj_data_ptr(#) + 1] +@d obj_xform_depth(#) == pdf_mem[obj_data_ptr(#) + 2] +@d obj_xform_box(#) == pdf_mem[obj_data_ptr(#) + 3] {this field holds + pointer to the corresponding box} +@d obj_xform_attr(#) == pdf_mem[obj_data_ptr(#) + 4] {additional xform + attributes} +@d obj_xform_resources(#) == pdf_mem[obj_data_ptr(#) + 5] {additional xform + Resources} + +@# {data structure for \.{\\pdfximage} and \.{\\pdfrefximage}} +@d pdf_refximage_node_size == 5 {size of whatsit node for ximage; words 1..3 + are image dimensions} +@d pdf_ximage_objnum(#) == info(# + 4) {object number} +@d pdfmem_ximage_size == 5 {size of memory in |pdf_mem| which + |obj_data_ptr| holds} +@d obj_ximage_width(#) == pdf_mem[obj_data_ptr(#) + 0] +@d obj_ximage_height(#) == pdf_mem[obj_data_ptr(#) + 1] +@d obj_ximage_depth(#) == pdf_mem[obj_data_ptr(#) + 2] +@d obj_ximage_attr(#) == pdf_mem[obj_data_ptr(#) + 3] {additional ximage attributes} +@d obj_ximage_data(#) == pdf_mem[obj_data_ptr(#) + 4] {pointer to image data} + +@# {data structure of annotations; words 1..4 represent the coordinates of + the annotation} +@d obj_annot_ptr == obj_aux {pointer to corresponding whatsit node} +@d pdf_annot_node_size == 7 {size of whatsit node representing annotation} +@d pdf_annot_data(#) == info(# + 5) {raw data of general annotations} +@d pdf_link_attr(#) == info(# + 5) {attributes of link annotations} +@d pdf_link_action(#) == link(# + 5) {pointer to action structure} +@d pdf_annot_objnum(#) == mem[# + 6].int {object number of corresponding object} + +@# {types of actions} +@d pdf_action_page == 0 {Goto action} +@d pdf_action_goto == 1 {Goto action} +@d pdf_action_thread == 2 {Thread action} +@d pdf_action_user == 3 {user-defined action} + +@# {data structure of actions} +@d pdf_action_size == 3 {size of action structure in |mem|} +@d pdf_action_type == type {action type} +@d pdf_action_named_id == subtype {identifier is type of name} +@d pdf_action_id == link {destination/thread name identifier} +@d pdf_action_file(#) == info(# + 1) {file name for external action} +@d pdf_action_new_window(#)== link(# + 1) {open a new window?} +@d pdf_action_page_tokens(#) == info(# + 2) {specification of goto page action} +@d pdf_action_user_tokens(#) == info(# + 2) {user-defined action string} +@d pdf_action_refcount(#) == link(# + 2) {counter of references to this action} + +@# {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|} + +@d pdfmem_outline_size == 8 {size of memory in |pdf_mem| which +|obj_outline_ptr| points to} +@d obj_outline_count == obj_info{count of all opened children} +@d obj_outline_ptr == obj_aux {pointer to |pdf_mem|} +@d obj_outline_title(#) == pdf_mem[obj_outline_ptr(#)] +@d obj_outline_parent(#) == pdf_mem[obj_outline_ptr(#) + 1] +@d obj_outline_prev(#) == pdf_mem[obj_outline_ptr(#) + 2] +@d obj_outline_next(#) == pdf_mem[obj_outline_ptr(#) + 3] +@d obj_outline_first(#) == pdf_mem[obj_outline_ptr(#) + 4] +@d obj_outline_last(#) == pdf_mem[obj_outline_ptr(#) + 5] +@d obj_outline_action_objnum(#) == pdf_mem[obj_outline_ptr(#) + 6] {object number of +action} +@d obj_outline_attr(#) == pdf_mem[obj_outline_ptr(#) + 7] + +@# {types of destinations} +@d pdf_dest_xyz == 0 +@d pdf_dest_fit == 1 +@d pdf_dest_fith == 2 +@d pdf_dest_fitv == 3 +@d pdf_dest_fitb == 4 +@d pdf_dest_fitbh == 5 +@d pdf_dest_fitbv == 6 +@d pdf_dest_fitr == 7 + +@# {data structure of destinations} +@d obj_dest_ptr == obj_aux {pointer to |pdf_dest_node|} +@d pdf_dest_node_size == 7 {size of whatsit node for destination; +words |1..4| hold dest dimensions, word |6| identifier type, subtype +and identifier of destination, word |6| the corresponding object number} +@d pdf_dest_type(#) == type(# + 5) {type of destination} +@d pdf_dest_named_id(#) == subtype(# + 5) {is named identifier?} +@d pdf_dest_id(#) == link(# + 5) {destination identifier} +@d pdf_dest_xyz_zoom(#) == info(# + 6) {zoom factor for |destxyz| destination} +@d pdf_dest_objnum(#) == link(# + 6) {object number of corresponding +object} + +@# {data structure of threads; words 1..4 represent the coordinates of the + corners} +@d pdf_thread_node_size == 7 +@d pdf_thread_named_id(#) == subtype(# + 5) {is a named identifier} +@d pdf_thread_id(#) == link(# + 5) {thread identifier} +@d pdf_thread_attr(#) == info(# + 6) {attributes of thread} +@d obj_thread_first == obj_aux {pointer to the first bead} + +@# {data structure of beads} +@d pdfmem_bead_size == 5 {size of memory in |pdf_mem| which + |obj_bead_ptr| points to} +@d obj_bead_ptr == obj_aux {pointer to |pdf_mem|} +@d obj_bead_rect(#) == pdf_mem[obj_bead_ptr(#)] +@d obj_bead_page(#) == pdf_mem[obj_bead_ptr(#) + 1] +@d obj_bead_next(#) == pdf_mem[obj_bead_ptr(#) + 2] +@d obj_bead_prev(#) == pdf_mem[obj_bead_ptr(#) + 3] +@d obj_bead_attr(#) == pdf_mem[obj_bead_ptr(#) + 4] +@d obj_bead_data == obj_bead_rect {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} + +@<Constants...@>= +@!inf_obj_tab_size = 32000; {min size of the cross-reference table for PDF output} +@!sup_obj_tab_size = 8388607; {max size of the cross-reference table for PDF output} +@!inf_dest_names_size = 10000; {min size of the destination names table for PDF output} +@!sup_dest_names_size = 131072; {max size of the destination names table for PDF output} +@!pdf_objtype_max = head_tab_max; +@!pdf_pdf_box_spec_media = 0; +@!pdf_pdf_box_spec_crop = 1; +@!pdf_pdf_box_spec_bleed = 2; +@!pdf_pdf_box_spec_trim = 3; +@!pdf_pdf_box_spec_art = 4; + +@ @<Glob...@>= +@!obj_tab_size:integer; +@!obj_tab:^obj_entry; +@!head_tab: array[1..head_tab_max] of integer; +@!obj_ptr: integer; {objects counter} +@!pdf_last_pages: integer; {pointer to most recently generated pages object} +@!pdf_last_page: integer; {pointer to most recently generated page object} +@!pdf_last_stream: integer; {pointer to most recently generated stream} +@!pdf_stream_length: integer; {length of most recently generated stream} +@!pdf_stream_length_offset: integer; {file offset of the last stream length} +@!pdf_append_list_arg: integer; {for use with |pdf_append_list|} +@!ff: integer; {for use with |set_ff|} + +@ @<Set init...@>= +obj_ptr := 0; +for k := 1 to head_tab_max do + head_tab[k] := 0; + +@ 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. + +@d pdf_append_list_end(#) == # := append_ptr(#, pdf_append_list_arg); end +@d pdf_append_list(#) == begin pdf_append_list_arg := #; pdf_append_list_end +@d set_ff(#) == begin + if pdf_font_num[#] < 0 then + ff := -pdf_font_num[#] + else + ff := #; +end + +@<Declare procedures that need to be declared forward for pdftex@>= +procedure append_dest_name(s: str_number; n: integer); +begin + if pdf_dest_names_ptr = dest_names_size then + overflow("number of destination names", dest_names_size); + dest_names[pdf_dest_names_ptr].objname := s; + dest_names[pdf_dest_names_ptr].objnum := n; + incr(pdf_dest_names_ptr); +end; + +procedure pdf_create_obj(t, i: integer); {create an object with type |t| and +identifier |i|} +label done; +var p, q: integer; +begin + if obj_ptr = obj_tab_size then + overflow("indirect objects table size", obj_tab_size); + incr(obj_ptr); + obj_info(obj_ptr) := i; + obj_offset(obj_ptr) := 0; + obj_aux(obj_ptr) := 0; + avl_put_obj(obj_ptr, t); + if t = obj_type_page then begin + p := head_tab[t]; + {find the right position to insert newly created object}@/ + if (p = 0) or (obj_info(p) < i) then begin + obj_link(obj_ptr) := p; + head_tab[t] := obj_ptr; + end + else begin + while p <> 0 do begin + if obj_info(p) < i then + goto done; + q := p; + p := obj_link(p); + end; +done: + obj_link(q) := obj_ptr; + obj_link(obj_ptr) := p; + end; + end + else if t <> obj_type_others then begin + obj_link(obj_ptr) := head_tab[t]; + head_tab[t] := obj_ptr; + if (t = obj_type_dest) and (i < 0) then + append_dest_name(-obj_info(obj_ptr), obj_ptr); + end; +end; + +function pdf_new_objnum: integer; {create a new object and return its number} +begin + pdf_create_obj(obj_type_others, 0); + pdf_new_objnum := obj_ptr; +end; + +procedure pdf_begin_obj(i: integer); {begin a PDF object} +begin + ensure_pdf_open; + check_pdfminorversion; + obj_offset(i) := pdf_offset; + pdf_print_int(i); + pdf_print_ln(" 0 obj"); +end; + +procedure pdf_end_obj; +begin + pdf_print_ln("endobj"); {end a PDF object} +end; + +procedure pdf_begin_dict(i: integer); {begin a PDF dictionary object} +begin + obj_offset(i) := pdf_offset; + pdf_print_int(i); + pdf_print_ln(" 0 obj <<"); +end; + +procedure pdf_end_dict; {end a PDF object of type dictionary} +begin + pdf_print_ln(">> endobj"); +end; + +procedure pdf_new_obj(t, i: integer); {begin to a new object} +begin + pdf_create_obj(t, i); + pdf_begin_obj(obj_ptr); +end; + +procedure pdf_new_dict(t, i: integer); {begin a new object with type dictionary} +begin + pdf_create_obj(t, i); + pdf_begin_dict(obj_ptr); +end; + +function append_ptr(p: pointer; i: integer): pointer; {appends a pointer with +info |i| to the end of linked list with head |p|} +var q: pointer; +begin + append_ptr := p; + fast_get_avail(q); + info(q) := i; + link(q) := null; + if p = null then begin + append_ptr := q; + return; + end; + while link(p) <> null do + p := link(p); + link(p) := q; +end; + +function pdf_lookup_list(p: pointer; i: integer): pointer; {looks up for pointer +with info |i| in list |p|} +begin + pdf_lookup_list := null; + while p <> null do begin + if info(p) = i then begin + pdf_lookup_list := p; + return; + end; + p := link(p); + end; +end; + +@ @<Glob...@>= +@!pdf_image_procset: integer; {collection of image types used in current page/form} +@!pdf_text_procset: boolean; {mask of used ProcSet's in the current page/form} + +@ Subroutines to print out various PDF objects + +@d is_hex_char(#) == (((# >= '0') and (# <= '9')) or + ((# >= 'A') and (# <= 'F')) or + ((# >= 'a') and (# <= 'f'))) + +@p procedure pdf_print_fw_int(n, w: integer); {print out an integer with +fixed width; used for outputting cross-reference table} +var k:integer; {$0\le k\le23$} +begin + k:=0; + repeat dig[k]:=n mod 10; n:=n div 10; incr(k); + until k = w; + pdf_room(k); + while k>0 do begin + decr(k); + pdf_quick_out("0"+dig[k]); + end; +end; + +procedure pdf_int_entry(s: str_number; v: integer); {print out an entry in +dictionary with integer value to PDF buffer} +begin + pdf_out("/"); + pdf_print(s); + pdf_out(" "); + pdf_print_int(v); +end; + +procedure pdf_int_entry_ln(s: str_number; v: integer); +begin + pdf_int_entry(s, v); + pdf_print_nl; +end; + +procedure pdf_indirect(s: str_number; o: integer); {print out an indirect +entry in dictionary} +begin + pdf_out("/"); + pdf_print(s); + pdf_out(" "); + pdf_print_int(o); + pdf_print(" 0 R"); +end; + +procedure pdf_indirect_ln(s: str_number; o: integer); +begin + pdf_indirect(s, o); + pdf_print_nl; +end; + +procedure pdf_print_str(s: str_number); {print out |s| as string in PDF +output} +label done; +var i, j, k: pool_pointer; + is_hex_string: boolean; +begin + i := str_start[s]; + j := i + length(s) - 1; + if i > j then begin + pdf_print("()"); {null string} + return; + end; + if (str_pool[i] = '(') and (str_pool[j] = ')') then begin + pdf_print(s); + return; + end; + is_hex_string := false; + if (str_pool[i] <> '<') or (str_pool[j] <> '>') or odd(length(s)) then + goto done; + incr(i); + decr(j); + while i < j do begin + if is_hex_char(str_pool[i]) and is_hex_char(str_pool[i + 1]) then + i := i + 2 + else + goto done; + end; + is_hex_string := true; +done: + if is_hex_string then + pdf_print(s) + else begin + pdf_out("("); + pdf_print(s); + pdf_out(")"); + end; +end; + +procedure pdf_print_str_ln(s: str_number); {print out |s| as string in PDF +output} +begin + pdf_print_str(s); + pdf_print_nl; +end; + +procedure pdf_str_entry(s, v: str_number); {print out an entry in +dictionary with string value to PDF buffer} +begin + if v = 0 then + return; + pdf_out("/"); + pdf_print(s); + pdf_out(" "); + pdf_print_str(v); +end; + +procedure pdf_str_entry_ln(s, v: str_number); +begin + if v = 0 then + return; + pdf_str_entry(s, v); + pdf_print_nl; +end; + +@* \[32e] Font processing. + +As pdfTeX should also act as a back-end driver, it needs to support virtual +font too. Information about virtual font can be found in 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 font is new font (has not been used yet), +virtual font or real font. The array |pdf_font_type| holds flag of each used +font. After initialization flag of each font is set to |new_font_type|. +The first time when a character of a font is written out, pdfTeX looks for +the corresponding virtual font. If the corresponding virtual font exists, then +the font type is set to |virtual_font_type|; otherwise it will be set to +|real_font_type|. |subst_font_type| indicates fonts that have been substituted +during adjusting spacing. Such fonts are linked via the |pdf_font_elink| array. + +@d new_font_type = 0 {new font (has not been used yet)} +@d virtual_font_type = 1 {virtual font} +@d real_font_type = 2 {real font} +@d subst_font_type = 3 {substituted font} +@d pdf_init_font(#) == begin tmp_f := #; pdf_create_font_obj; end +@d pdf_check_vf(#) == begin + tmp_f := #; + do_vf; + if pdf_font_type[#] = virtual_font_type then + pdf_error("font", "command cannot be used with virtual font"); +end + +@d pdf_check_new_font(#) == + if pdf_font_type[#] = new_font_type then begin + tmp_f := #; + do_vf; + end + +@<Declare procedures that need to be declared forward...@>= +procedure pdf_create_font_obj; forward; +procedure do_vf; forward; +procedure scan_pdf_ext_toks; forward; + +@ @<Glob...@>= +@!pdf_font_type: ^eight_bits; {the type of font} +@!pdf_font_attr: ^str_number; {pointer to additional attributes} +@!tmp_f: internal_font_number; {for use with |pdf_init_font|} + +@ 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 +whose internal number is the absolute value of the entry. For partial +downloading we also need to hold flags indicating which characters in particular +font are used in array |pdf_char_used|. + +@d pdf_print_resname_prefix == +if pdf_resname_prefix <> 0 then + pdf_print(pdf_resname_prefix) + +@p procedure pdf_use_font(f: internal_font_number; fontnum: integer); +begin + call_func(divide_scaled(font_size[f], one_hundred_bp, + fixed_decimal_digits + 2)); + pdf_font_size[f] := scaled_out; + font_used[f] := true; + pdf_font_num[f] := fontnum; + if pdf_move_chars > 0 then begin + pdf_warning(0,"Primitive \pdfmovechars is obsolete.",true); + pdf_move_chars := 0; {warn only once} + end; +end; + +procedure pdf_create_font_obj; +var f, k: internal_font_number; +begin + f := tmp_f; + if not font_used[f] then begin + if hasfmentry(f) then begin + {this font is scaleable, so different sizes can share a single font object} + k := tfm_of_fm(pdf_font_map[f]); + if (k <> f) and str_eq_str(font_name[k], font_name[f]) then begin + pdf_use_font(f, -k); + return; + end; + end; + pdf_create_obj(obj_type_font, f); + pdf_use_font(f, obj_ptr); + end; +end; + +@ We need to hold information about used characters in each font for partial +downloading. + +@<Types...@>= +char_used_array = array[0..31] of eight_bits; +char_map_array = array[0..32] of eight_bits; {move chars in range 0..32} +fm_entry_ptr = ^integer; + +@ @<Glob...@>= +@!pdf_char_used: ^char_used_array; {to mark used chars} +@!pdf_char_map: ^char_map_array; {where to map chars 0..32} +@!pdf_font_size: ^scaled; {used size of font in PDF file} +@!pdf_font_num: ^integer; {mapping between internal font number in \TeX\ and + font name defined in resources in PDF file} +@!pdf_font_map: ^fm_entry_ptr; {pointer into AVL tree of font mappings} +@!pdf_font_list: pointer; {list of used fonts in current page} +@!pdf_resname_prefix: str_number; {global prefix of resources name} +@!last_tokens_string: str_number; {the number of the most recently string +created by |tokens_to_string|} + +@ @<Set init...@>= +pdf_resname_prefix := 0; +last_tokens_string := 0; + + +@ Here we implement reading information from \.{VF} file. + +@d vf_max_packet_length = 10000 {max length of character packet in \.{VF} file} + +@# +@d vf_error = 61 {label to go to when an error occur} +@d do_char = 70 {label to go to typesetting a character of virtual font} +@# +@d long_char = 242 {\.{VF} command for general character packet} +@d vf_id = 202 {identifies \.{VF} files} +@d put1=133 {typeset a character} + +@# +@d vf_byte == getc(vf_file) {get a byte from\.{VF} file} +@d vf_packet(#) == vf_packet_start[vf_packet_base[#] + vf_packet_end +@d vf_packet_end(#) == #] + +@# +@d bad_vf(#) == begin vf_err_str := #; goto vf_error; end {go out \.{VF} +processing with an error message} +@d four_cases(#) == #,#+1,#+2,#+3 + +@# +@d tmp_b0 == tmp_w.qqqq.b0 +@d tmp_b1 == tmp_w.qqqq.b1 +@d tmp_b2 == tmp_w.qqqq.b2 +@d tmp_b3 == tmp_w.qqqq.b3 +@d tmp_int == tmp_w.int + +@# +@d scaled3u == {convert |tmp_b1..tmp_b3| to an unsigned scaled dimension} +(((((tmp_b3*vf_z)div@'400)+(tmp_b2*vf_z))div@'400)+(tmp_b1*vf_z))div vf_beta +@d scaled4(#) == {convert |tmp_b0..tmp_b3| to a scaled dimension} + #:=scaled3u; + if tmp_b0>0 then if tmp_b0=255 then # := # - vf_alpha +@d scaled3(#) == {convert |tmp_b1..tmp_b3| to a scaled dimension} + #:=scaled3u; @+ if tmp_b1>127 then # := # - vf_alpha +@d scaled2 == {convert |tmp_b2..tmp_b3| to a scaled dimension} + if tmp_b2>127 then tmp_b1:=255 else tmp_b1:=0; + scaled3 +@d scaled1 == {convert |tmp_b3| to a scaled dimension} + if tmp_b3>127 then tmp_b1:=255 else tmp_b1:=0; + tmp_b2:=tmp_b1; scaled3 + +@<Glob...@>= +@!vf_packet_base: ^integer; {base addresses of character packets from virtual fonts} +@!vf_default_font: ^internal_font_number; {default font in a \.{VF} file} +@!vf_local_font_num: ^internal_font_number; {number of local fonts in a \.{VF} file} +@!vf_packet_length: integer; {length of the current packet} +@!vf_file: byte_file; +@!vf_nf: internal_font_number; {the local fonts counter} +@!vf_e_fnts: ^integer; {external font numbers} +@!vf_i_fnts: ^internal_font_number; {corresponding internal font numbers} +@!tmp_w: memory_word; {accumulator} +@!vf_z: integer; {multiplier} +@!vf_alpha: integer; {correction for negative values} +@!vf_beta: 1..16; {divisor} + +@ @<Set init...@>= +vf_nf := 0; + +@ The |do_vf| procedure attempts to read the \.{VF} file for a font, and sets +|pdf_font_type| to |real_font_type| if the \.{VF} file could not be found +or loaded, otherwise sets |pdf_font_type| to |virtual_font_type|. At this +time, |tmp_f| is the internal font number of the current \.{TFM} font. To +process font definitions in virtual font we call |vf_def_font|. + +@p procedure vf_replace_z; +begin + vf_alpha:=16; + while vf_z>=@'40000000 do begin + vf_z:=vf_z div 2; + vf_alpha:=vf_alpha+vf_alpha; + end; + vf_beta:=256 div vf_alpha; + vf_alpha:=vf_alpha*vf_z; +end; + +function vf_read(k: integer): integer; {read |k| bytes as an integer from \.{VF} file} +var i: integer; +begin + i := 0; + while k > 0 do begin + i := i*256 + vf_byte; + decr(k); + end; + vf_read := i; +end; + +procedure vf_local_font_warning(f, k: internal_font_number; s: str_number); +{print a warning message if an error ocurrs during processing local fonts in +\.{VF} file} +begin + print_nl(s); + print(" in local font "); + print(font_name[k]); + print(" in virtual font "); + print(font_name[f]); + print(".vf ignored."); +end; + +function vf_def_font(f: internal_font_number): internal_font_number; +{process a local font in \.{VF} file} +var k: internal_font_number; + s: str_number; + ds, fs: scaled; + cs: four_quarters; + c: integer; +begin + cs.b0 := vf_byte; cs.b1 := vf_byte; cs.b2 := vf_byte; cs.b3 := vf_byte; + tmp_b0 := vf_byte; tmp_b1 := vf_byte; tmp_b2 := vf_byte; tmp_b3 := vf_byte; + scaled4(fs); + ds := vf_read(4) div @'20; + tmp_b0 := vf_byte; + tmp_b1 := vf_byte; + while tmp_b0 > 0 do begin + decr(tmp_b0); + if vf_byte > 0 then + do_nothing; {skip the font path} + end; + str_room(tmp_b1); + while tmp_b1 > 0 do begin + decr(tmp_b1); + append_char(vf_byte); + end; + s := make_string; + k := tfm_lookup(s, fs); + if k = null_font then + k := read_font_info(null_cs, s, "", fs); + if k <> null_font then begin + if ((cs.b0 <> 0) or (cs.b1 <> 0) or (cs.b2 <> 0) or (cs.b3 <> 0)) and + ((font_check[k].b0 <> 0) or (font_check[k].b1 <> 0) or + (font_check[k].b2 <> 0) or (font_check[k].b3 <> 0)) and + ((cs.b0 <> font_check[k].b0) or (cs.b1 <> font_check[k].b1) or + (cs.b2 <> font_check[k].b2) or (cs.b3 <> font_check[k].b3)) then + vf_local_font_warning(f, k, "checksum mismatch"); + if ds <> font_dsize[k] then + vf_local_font_warning(f, k, "design size mismatch"); + end; + if pdf_font_expand_ratio[f] <> 0 then + set_expand_param(k, f, pdf_font_expand_ratio[f]); + vf_def_font := k; +end; + +procedure do_vf; {process \.{VF} file with font internal number |f|} +label vf_error; +var cmd, k, n: integer; + cc, cmd_length: integer; + tfm_width: scaled; + vf_err_str, s: str_number; + stack_level: vf_stack_index; + save_vf_nf: internal_font_number; + f: internal_font_number; + +begin + f := tmp_f; + pdf_font_type[f] := real_font_type; + if auto_expand_vf(f) then + return; {auto-expanded virtual font} + stack_level := 0; + @<Open |vf_file|, return if not found@>; + @<Process the preamble@>;@/ + @<Process the font definitions@>;@/ + @<Allocate memory for the new virtual font@>;@/ + while cmd <= long_char do begin@/ + @<Build a character packet@>;@/ + end; + if cmd <> post then + bad_vf("POST command expected"); + b_close(vf_file); + pdf_font_type[f] := virtual_font_type; + return; +vf_error: + print_nl("Error in processing VF font ("); + print(font_name[f]); + print(".vf): "); + print(vf_err_str); + print(", virtual font will be ignored"); + print_ln; + b_close(vf_file); + update_terminal; +end; + +@ @<Open |vf_file|, return if not found@>= +pack_file_name(font_name[f], "", ".vf"); +if not vf_b_open_in(vf_file) then + return + +@ @<Process the preamble@>= +if vf_byte <> pre then + bad_vf("PRE command expected"); +if vf_byte <> vf_id then + bad_vf("wrong id byte"); +cmd_length := vf_byte; +for k := 1 to cmd_length do + tmp_int := vf_byte; +tmp_b0 := vf_byte; tmp_b1 := vf_byte; tmp_b2 := vf_byte; tmp_b3 := vf_byte; +if ((tmp_b0 <> 0) or (tmp_b1 <> 0) or (tmp_b2 <> 0) or (tmp_b3 <> 0)) and + ((font_check[f].b0 <> 0) or (font_check[f].b1 <> 0) or + (font_check[f].b2 <> 0) or (font_check[f].b3 <> 0)) and + ((tmp_b0 <> font_check[f].b0) or (tmp_b1 <> font_check[f].b1) or + (tmp_b2 <> font_check[f].b2) or (tmp_b3 <> font_check[f].b3)) then begin + print_nl("checksum mismatch in font "); + print(font_name[f]); + print(".vf ignored"); +end; +if vf_read(4) div @'20 <> font_dsize[f] then begin + print_nl("design size mismatch in font "); + print(font_name[f]); + print(".vf ignored"); +end; +update_terminal; +vf_z := font_size[f]; +vf_replace_z + +@ @<Process the font definitions@>= +cmd := vf_byte; +save_vf_nf := vf_nf; +while (cmd >= fnt_def1) and (cmd <= fnt_def1 + 3) do begin + vf_e_fnts[vf_nf] := vf_read(cmd - fnt_def1 + 1); + vf_i_fnts[vf_nf] := vf_def_font(f); + incr(vf_nf); + cmd := vf_byte; +end; +vf_default_font[f] := save_vf_nf; +vf_local_font_num[f] := vf_nf - save_vf_nf; + +@ @<Allocate memory for the new virtual font@>= + vf_packet_base[f] := new_vf_packet(f) + +@ @<Build a character packet@>= +if cmd = long_char then begin + vf_packet_length := vf_read(4); + cc := vf_read(4); + if not is_valid_char(cc) then + bad_vf("invalid character code"); + tmp_b0 := vf_byte; tmp_b1 := vf_byte; tmp_b2 := vf_byte; tmp_b3 := vf_byte; + scaled4(tfm_width); +end +else begin + vf_packet_length := cmd; + cc := vf_byte; + if not is_valid_char(cc) then + bad_vf("invalid character code"); + tmp_b1 := vf_byte; tmp_b2 := vf_byte; tmp_b3 := vf_byte; + scaled3(tfm_width); +end; +if vf_packet_length < 0 then + bad_vf("negative packet length"); +if vf_packet_length > vf_max_packet_length then + bad_vf("packet length too long"); +if (tfm_width <> char_width(f)(char_info(f)(cc))) then begin + print_nl("character width mismatch in font "); + print(font_name[f]); + print(".vf ignored"); +end; +str_room(vf_packet_length); +while vf_packet_length > 0 do begin + cmd := vf_byte; + decr(vf_packet_length); + @<Cases of \.{DVI} commands that can appear in character packet@>; + if cmd <> nop then + append_char(cmd); + vf_packet_length := vf_packet_length - cmd_length; + while cmd_length > 0 do begin + decr(cmd_length); + append_char(vf_byte); + end; +end; +if stack_level <> 0 then + bad_vf("more PUSHs than POPs in character packet"); +if vf_packet_length <> 0 then + bad_vf("invalid packet length or DVI command in packet"); +@<Store the packet being built@>; +cmd := vf_byte + +@ @<Store the packet being built@>= +s := make_string; +storepacket(f, cc, s); +flush_str(s) + +@ @<Cases of \.{DVI} commands that can appear in character packet@>= +if (cmd >= set_char_0) and (cmd <= set_char_0 + 127) then + cmd_length := 0 +else if ((fnt_num_0 <= cmd) and (cmd <= fnt_num_0 + 63)) or + ((fnt1 <= cmd) and (cmd <= fnt1 + 3)) then begin + if cmd >= fnt1 then begin + k := vf_read(cmd - fnt1 + 1); + vf_packet_length := vf_packet_length - (cmd - fnt1 + 1); + end + else + k := cmd - fnt_num_0; + if k >= 256 then + bad_vf("too many local fonts"); + n := 0; + while (n < vf_local_font_num[f]) and + (vf_e_fnts[vf_default_font[f] + n] <> k) do + incr(n); + if n = vf_local_font_num[f] then + bad_vf("undefined local font"); + if k <= 63 then + append_char(fnt_num_0 + k) + else begin + append_char(fnt1); + append_char(k); + end; + cmd_length := 0; + cmd := nop; +end +else case cmd of +set_rule, put_rule: cmd_length := 8; +four_cases(set1): cmd_length := cmd - set1 + 1; +four_cases(put1): cmd_length := cmd - put1 + 1; +four_cases(right1): cmd_length := cmd - right1 + 1; +four_cases(w1): cmd_length := cmd - w1 + 1; +four_cases(x1): cmd_length := cmd - x1 + 1; +four_cases(down1): cmd_length := cmd - down1 + 1; +four_cases(y1): cmd_length := cmd - y1 + 1; +four_cases(z1): cmd_length := cmd - z1 + 1; +four_cases(xxx1): begin + cmd_length := vf_read(cmd - xxx1 + 1); + vf_packet_length := vf_packet_length - (cmd - xxx1 + 1); + if cmd_length > vf_max_packet_length then + bad_vf("packet length too long"); + if cmd_length < 0 then + bad_vf("string of negative length"); + append_char(xxx1); + append_char(cmd_length); + cmd := nop; {|cmd| has been already stored above as |xxx1|} +end; +w0, x0, y0, z0, nop: + cmd_length := 0; +push, pop: begin + cmd_length := 0; + if cmd = push then + if stack_level = vf_stack_size then + overflow("virtual font stack size", vf_stack_size) + else + incr(stack_level) + else + if stack_level = 0 then + bad_vf("more POPs than PUSHs in character") + else + decr(stack_level); +end; +othercases + bad_vf("improver DVI command"); +endcases + +@ The |do_vf_packet| procedure is called in order to interpret the +character packet for a virtual character. Such a packet may contain the +instruction to typeset a character from the same or an other virtual +font; in such cases |do_vf_packet| calls itself recursively. The +recursion level, i.e., the number of times this has happened, is kept +in the global variable |vf_cur_s| and should not exceed |vf_max_recursion|. + +@<Constants...@>= +@!vf_max_recursion=10; {\.{VF} files shouldn't recurse beyond this level} +@!vf_stack_size=100; {\.{DVI} files shouldn't |push| beyond this depth} + +@ @<Types...@>= +@!vf_stack_index=0..vf_stack_size; {an index into the stack} +@!vf_stack_record=record + stack_h, stack_v, stack_w, stack_x, stack_y, stack_z: scaled; +end; + +@ @<Glob...@>= +@!vf_cur_s: 0..vf_max_recursion; {current recursion level} +@!vf_stack: array [vf_stack_index] of vf_stack_record; +@!vf_stack_ptr: vf_stack_index; {pointer into |vf_stack|} + +@ @<Set init...@>= +vf_cur_s := 0; +vf_stack_ptr := 0; + +@ Some functions for processing character packets. + +@p function packet_read(k: integer): integer; {read |k| bytes as an integer from +character packet} +var i: integer; +begin + i := 0; + while k > 0 do begin + i := i*256 + packet_byte; + decr(k); + end; + packet_read := i; +end; + +function packet_scaled(k: integer): integer; {get |k| bytes from packet as a +scaled} +var s: scaled; +begin + case k of + 1: begin + tmp_b3 := packet_byte; + scaled1(s); + end; + 2: begin + tmp_b2 := packet_byte; + tmp_b3 := packet_byte; + scaled2(s); + end; + 3: begin + tmp_b1 := packet_byte; + tmp_b2 := packet_byte; + tmp_b3 := packet_byte; + scaled3(s); + end; + 4: begin + tmp_b0 := packet_byte; + tmp_b1 := packet_byte; + tmp_b2 := packet_byte; + tmp_b3 := packet_byte; + scaled4(s); + end; + othercases pdf_error("vf", "invalid number size"); + endcases; + packet_scaled := s; +end; + +procedure do_vf_packet(f: internal_font_number; c: eight_bits); {typeset the \.{DVI} commands in the +character packet for character |c| in current font |f|} +label do_char, continue; +var save_packet_ptr, save_packet_length: pool_pointer; + save_vf, k, n: internal_font_number; + base_line, save_h, save_v: scaled; + cmd: integer; + char_move: boolean; + w, x, y, z: scaled; + s: str_number; +begin + incr(vf_cur_s); + if vf_cur_s > vf_max_recursion then + overflow("max level recursion of virtual fonts", vf_max_recursion); + push_packet_state; + start_packet(f, c); + vf_z := font_size[f]; + vf_replace_z; + save_vf := f; + f := vf_i_fnts[vf_default_font[save_vf]]; + save_v := cur_v; + save_h := cur_h; + w := 0; x := 0; y := 0; z := 0; + while vf_packet_length > 0 do begin + cmd := packet_byte; + @<Do typesetting the \.{DVI} commands in virtual character packet@>; +continue: + end; + cur_h := save_h; + cur_v := save_v; + pop_packet_state; + vf_z := font_size[f]; + vf_replace_z; + decr(vf_cur_s); +end; + +@ The following code typesets a character to PDF output. + +@d output_one_char(#)==begin + pdf_check_new_font(f); + if pdf_font_type[f] = virtual_font_type then + do_vf_packet(f, #) + else begin + pdf_begin_string(f); + pdf_print_char(f, #); + adv_char_width(f, char_width(f)(char_info(f)(#))); + end; +end + + +@<Do typesetting the \.{DVI} commands in virtual character packet@>= +if (cmd >= set_char_0) and (cmd <= set_char_0 + 127) then begin + if not is_valid_char(cmd) then begin + char_warning(f, cmd); + goto continue; + end; + c := cmd; + char_move := true; + goto do_char; +end +else if ((fnt_num_0 <= cmd) and (cmd <= fnt_num_0 + 63)) or (cmd = fnt1) then begin + if cmd = fnt1 then + k := packet_byte + else + k := cmd - fnt_num_0; + n := 0; + while (n < vf_local_font_num[save_vf]) and + (vf_e_fnts[vf_default_font[save_vf] + n] <> k) do + incr(n); + if (n = vf_local_font_num[save_vf]) then + f := null_font + else + f := vf_i_fnts[vf_default_font[save_vf] + n]; +end +else case cmd of +push: begin + vf_stack[vf_stack_ptr].stack_h := cur_h; + vf_stack[vf_stack_ptr].stack_v := cur_v; + vf_stack[vf_stack_ptr].stack_w := w; + vf_stack[vf_stack_ptr].stack_x := x; + vf_stack[vf_stack_ptr].stack_y := y; + vf_stack[vf_stack_ptr].stack_z := z; + incr(vf_stack_ptr); +end; +pop: begin + decr(vf_stack_ptr); + cur_h := vf_stack[vf_stack_ptr].stack_h; + cur_v := vf_stack[vf_stack_ptr].stack_v; + w := vf_stack[vf_stack_ptr].stack_w; + x := vf_stack[vf_stack_ptr].stack_x; + y := vf_stack[vf_stack_ptr].stack_y; + z := vf_stack[vf_stack_ptr].stack_z; +end; +four_cases(set1), four_cases(put1): begin + if (set1 <= cmd) and (cmd <= set1 + 3) then begin + tmp_int := packet_read(cmd - set1 + 1); + char_move := true; + end + else begin + tmp_int := packet_read(cmd - put1 + 1); + char_move := false; + end; + if not is_valid_char(tmp_int) then begin + char_warning(f, tmp_int); + goto continue; + end; + c := tmp_int; + goto do_char; +end; +set_rule, put_rule: begin + rule_ht := packet_scaled(4); + rule_wd := packet_scaled(4); + if (rule_wd > 0) and (rule_ht > 0) then begin + pdf_set_rule(cur_h, cur_v, rule_wd, rule_ht); + if cmd = set_rule then + cur_h := cur_h + rule_wd; + end; +end; +four_cases(right1): + cur_h := cur_h + packet_scaled(cmd - right1 + 1); +w0, four_cases(w1): begin + if cmd > w0 then + w := packet_scaled(cmd - w0); + cur_h := cur_h + w; +end; +x0, four_cases(x1): begin + if cmd > x0 then + x := packet_scaled(cmd - x0); + cur_h := cur_h + x; +end; +four_cases(down1): + cur_v := cur_v + packet_scaled(cmd - down1 + 1); +y0, four_cases(y1): begin + if cmd > y0 then + y := packet_scaled(cmd - y0); + cur_v := cur_v + y; +end; +z0, four_cases(z1): begin + if cmd > z0 then + z := packet_scaled(cmd - z0); + cur_v := cur_v + z; +end; +four_cases(xxx1): begin + tmp_int := packet_read(cmd - xxx1 + 1); + str_room(tmp_int); + while tmp_int > 0 do begin + decr(tmp_int); + append_char(packet_byte); + end; + s := make_string; + literal(s, scan_special, false); + flush_str(s); +end; +othercases pdf_error("vf", "invalid DVI command"); +endcases; +goto continue; +do_char: +if is_valid_char(c) then + output_one_char(c) +else + char_warning(f, c); +if char_move then + cur_h := cur_h + char_width(f)(char_info(f)(c)) + +@* \[32f] PDF shipping out. +To ship out a \TeX\ box to PDF page description we need to implement +|pdf_hlist_out|, |pdf_vlist_out| and |pdf_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 |pdf_hlist_out| and |pdf_vlist_out|. + +@<Declare procedures needed in |pdf_hlist_out|, |pdf_vlist_out|@>= +procedure pdf_out_literal(p:pointer); +var old_setting:0..max_selector; {holds print |selector|} + s: str_number; +begin + old_setting:=selector; selector:=new_string; + show_token_list(link(pdf_literal_data(p)),null,pool_size-pool_ptr); + selector:=old_setting; + s := make_string; + literal(s, pdf_literal_mode(p), false); + flush_str(s); +end; + +procedure pdf_special(p: pointer); +var old_setting:0..max_selector; {holds print |selector|} + s: str_number; +begin + old_setting:=selector; selector:=new_string; + show_token_list(link(write_tokens(p)),null,pool_size-pool_ptr); + selector:=old_setting; + s := make_string; + literal(s, scan_special, true); + flush_str(s); +end; + +procedure pdf_print_toks(p: pointer); {print tokens list |p|} +var s: str_number; +begin + s := tokens_to_string(p); + if length(s) > 0 then + pdf_print(s); + flush_str(s); +end; + +procedure pdf_print_toks_ln(p: pointer); {print tokens list |p|} +var s: str_number; +begin + s := tokens_to_string(p); + if length(s) > 0 then begin + pdf_print(s); + pdf_print_nl; + end; + flush_str(s); +end; + +@ Similiar to |vlist_out|, |pdf_vlist_out| needs to be declared forward + +@p procedure@?pdf_vlist_out; forward; + +@ The implementation of procedure |pdf_hlist_out| is similiar to |hlist_out| + +@p @t\4@>@<Declare procedures needed in |pdf_hlist_out|, |pdf_vlist_out|@>@t@>@/ + +procedure pdf_hlist_out; {output an |hlist_node| box} +label reswitch, move_past, fin_rule, next_p; +var base_line: scaled; {the baseline coordinate for this box} +@!left_edge: scaled; {the left coordinate for this box} +@!save_h: scaled; {what |cur_h| should pop to} +@!this_box: pointer; {pointer to containing box} +@!g_order: glue_ord; {applicable order of infinity for glue} +@!g_sign: normal..shrinking; {selects type of glue} +@!p:pointer; {current position in the hlist} +@!leader_box:pointer; {the leader box being replicated} +@!leader_wd:scaled; {width of leader box being replicated} +@!lx:scaled; {extra space between leader boxes} +@!outer_doing_leaders:boolean; {were we doing leaders?} +@!edge:scaled; {left edge of sub-box, or right edge of leader space} +@!running_link: pointer; {pointer to `running' link if exists} +@!glue_temp:real; {glue value before rounding} +@!cur_glue:real; {glue seen so far} +@!cur_g:scaled; {rounded equivalent of |cur_glue| times the glue ratio} +begin cur_g:=0; cur_glue:=float_constant(0); +this_box:=temp_ptr; g_order:=glue_order(this_box); +g_sign:=glue_sign(this_box); p:=list_ptr(this_box); +incr(cur_s); +base_line:=cur_v; left_edge:=cur_h; +running_link := null; +@<Create link annotation for the current hbox if needed@>; +while p<>null do + @<Output node |p| for |pdf_hlist_out| and move to the next node, + maintaining the condition |cur_v=base_line|@>; +decr(cur_s); +end; + +@ @<Create link annotation for the current hbox if needed@>= +if running_link = null then begin + if is_running(pdf_link_wd) and (pdf_link_level = cur_s) then begin + append_link(this_box, left_edge, base_line); + running_link := last_link; + end; +end +else + last_link := running_link + +@ @<Output node |p| for |pdf_hlist_out|...@>= +reswitch: if is_char_node(p) then + begin + repeat f:=font(p); c:=character(p); + if is_valid_char(c) then + output_one_char(c) + else + char_warning(f, c); + cur_h:=cur_h+char_width(f)(char_info(f)(c)); + p:=link(p); + until not is_char_node(p); + end +else @<Output the non-|char_node| |p| for |pdf_hlist_out| + and move to the next node@> + +@ @<Output the non-|char_node| |p| for |pdf_hlist_out|...@>= +begin case type(p) of +hlist_node,vlist_node:@<(\pdfTeX) Output a box in an hlist@>; +rule_node: begin rule_ht:=height(p); rule_dp:=depth(p); rule_wd:=width(p); + goto fin_rule; + end; +whatsit_node: @<Output the whatsit node |p| in |pdf_hlist_out|@>; +glue_node: @<(\pdfTeX) Move right or output leaders@>; +kern_node,math_node:cur_h:=cur_h+width(p); +ligature_node: @<Make node |p| look like a |char_node| and |goto reswitch|@>; +othercases do_nothing +endcases;@/ +goto next_p; +fin_rule: @<(\pdfTeX) Output a rule in an hlist@>; +move_past: cur_h:=cur_h+rule_wd; +next_p:p:=link(p); +end + +@ @<(\pdfTeX) Output a box in an hlist@>= +if list_ptr(p)=null then cur_h:=cur_h+width(p) +else begin + cur_v:=base_line+shift_amount(p); {shift the box down} + temp_ptr:=p; edge:=cur_h; + if type(p)=vlist_node then pdf_vlist_out@+else pdf_hlist_out; + cur_h:=edge+width(p); cur_v:=base_line; + end + +@ @<(\pdfTeX) Output a rule in an hlist@>= +if is_running(rule_ht) then rule_ht:=height(this_box); +if is_running(rule_dp) then rule_dp:=depth(this_box); +rule_ht:=rule_ht+rule_dp; {this is the rule thickness} +if (rule_ht>0)and(rule_wd>0) then {we don't output empty rules} + begin cur_v:=base_line+rule_dp; + pdf_set_rule(cur_h, cur_v, rule_wd, rule_ht); + cur_v:=base_line; + end + +@ @<(\pdfTeX) Move right or output leaders@>= +begin g:=glue_ptr(p); rule_wd:=width(g)-cur_g; +if g_sign<>normal then + begin if g_sign=stretching then + begin if stretch_order(g)=g_order then + begin cur_glue:=cur_glue+stretch(g); + vet_glue(float(glue_set(this_box))*cur_glue); +@^real multiplication@> + cur_g:=round(glue_temp); + end; + end + else if shrink_order(g)=g_order then + begin cur_glue:=cur_glue-shrink(g); + vet_glue(float(glue_set(this_box))*cur_glue); + cur_g:=round(glue_temp); + end; + end; +rule_wd:=rule_wd+cur_g; +if subtype(p)>=a_leaders then + @<(\pdfTeX) Output leaders in an hlist, |goto fin_rule| if a rule + or to |next_p| if done@>; +goto move_past; +end + +@ @<(\pdfTeX) Output leaders in an hlist...@>= +begin leader_box:=leader_ptr(p); +if type(leader_box)=rule_node then + begin rule_ht:=height(leader_box); rule_dp:=depth(leader_box); + goto fin_rule; + end; +leader_wd:=width(leader_box); +if (leader_wd>0)and(rule_wd>0) then + begin 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@>; + while cur_h+leader_wd<=edge do + @<(\pdfTeX) Output a leader box at |cur_h|, + then advance |cur_h| by |leader_wd+lx|@>; + cur_h:=edge-10; goto next_p; + end; +end + +@ @<(\pdfTeX) Output a leader box at |cur_h|, ...@>= +begin cur_v:=base_line+shift_amount(leader_box);@/ +save_h:=cur_h; temp_ptr:=leader_box; +outer_doing_leaders:=doing_leaders; doing_leaders:=true; +if type(leader_box)=vlist_node then pdf_vlist_out@+else pdf_hlist_out; +doing_leaders:=outer_doing_leaders; +cur_v:=base_line; +cur_h:=save_h+leader_wd+lx; +end + +@ The |pdf_vlist_out| routine is similar to |pdf_hlist_out|, but a bit simpler. +@p procedure pdf_vlist_out; {output a |pdf_vlist_node| box} +label move_past, fin_rule, next_p; +var left_edge: scaled; {the left coordinate for this box} +@!top_edge: scaled; {the top coordinate for this box} +@!save_v: scaled; {what |cur_v| should pop to} +@!this_box: pointer; {pointer to containing box} +@!g_order: glue_ord; {applicable order of infinity for glue} +@!g_sign: normal..shrinking; {selects type of glue} +@!p:pointer; {current position in the vlist} +@!leader_box:pointer; {the leader box being replicated} +@!leader_ht:scaled; {height of leader box being replicated} +@!lx:scaled; {extra space between leader boxes} +@!outer_doing_leaders:boolean; {were we doing leaders?} +@!edge:scaled; {bottom boundary of leader space} +@!glue_temp:real; {glue value before rounding} +@!cur_glue:real; {glue seen so far} +@!cur_g:scaled; {rounded equivalent of |cur_glue| times the glue ratio} +begin cur_g:=0; cur_glue:=float_constant(0); +this_box:=temp_ptr; g_order:=glue_order(this_box); +g_sign:=glue_sign(this_box); p:=list_ptr(this_box); +incr(cur_s); +left_edge:=cur_h; cur_v:=cur_v-height(this_box); top_edge:=cur_v; +@<Create thread for the current vbox if needed@>; +while p<>null do + @<Output node |p| for |pdf_vlist_out| and move to the next node, + maintaining the condition |cur_h=left_edge|@>; +decr(cur_s); +end; + +@ @<Create thread for the current vbox if needed@>= +if (last_thread <> null) and is_running(pdf_thread_dp) and + (pdf_thread_level = cur_s) then + append_thread(this_box, left_edge, top_edge + height(this_box)) + +@ @<Output node |p| for |pdf_vlist_out|...@>= +begin if is_char_node(p) then confusion("pdfvlistout") +@:this can't happen pdfvlistout}{\quad pdfvlistout@> +else @<Output the non-|char_node| |p| for |pdf_vlist_out|@>; +next_p:p:=link(p); +end + +@ @<Output the non-|char_node| |p| for |pdf_vlist_out|@>= +begin case type(p) of +hlist_node,vlist_node:@<(\pdfTeX) Output a box in a vlist@>; +rule_node: begin rule_ht:=height(p); rule_dp:=depth(p); rule_wd:=width(p); + goto fin_rule; + end; +whatsit_node: @<Output the whatsit node |p| in |pdf_vlist_out|@>; +glue_node: @<(\pdfTeX) Move down or output leaders@>; +kern_node:cur_v:=cur_v+width(p); +othercases do_nothing +endcases;@/ +goto next_p; +fin_rule: @<(\pdfTeX) Output a rule in a vlist, |goto next_p|@>; +move_past: cur_v:=cur_v+rule_ht; +end + +@ @<(\pdfTeX) Output a box in a vlist@>= +if list_ptr(p)=null then cur_v:=cur_v+height(p)+depth(p) +else begin cur_v:=cur_v+height(p); save_v:=cur_v; + cur_h:=left_edge+shift_amount(p); {shift the box right} + temp_ptr:=p; + if type(p)=vlist_node then pdf_vlist_out@+else pdf_hlist_out; + cur_v:=save_v+depth(p); cur_h:=left_edge; + end + +@ @<(\pdfTeX) Output a rule in a vlist...@>= +if is_running(rule_wd) then rule_wd:=width(this_box); +rule_ht:=rule_ht+rule_dp; {this is the rule thickness} +cur_v:=cur_v+rule_ht; +if (rule_ht>0)and(rule_wd>0) then {we don't output empty rules} + pdf_set_rule(cur_h, cur_v, rule_wd, rule_ht); +goto next_p + +@ @<(\pdfTeX) Move down or output leaders@>= +begin g:=glue_ptr(p); rule_ht:=width(g)-cur_g; +if g_sign<>normal then + begin if g_sign=stretching then + begin if stretch_order(g)=g_order then + begin cur_glue:=cur_glue+stretch(g); + vet_glue(float(glue_set(this_box))*cur_glue); +@^real multiplication@> + cur_g:=round(glue_temp); + end; + end + else if shrink_order(g)=g_order then + begin cur_glue:=cur_glue-shrink(g); + vet_glue(float(glue_set(this_box))*cur_glue); + cur_g:=round(glue_temp); + end; + end; +rule_ht:=rule_ht+cur_g; +if subtype(p)>=a_leaders then + @<(\pdfTeX) Output leaders in a vlist, |goto fin_rule| if a rule + or to |next_p| if done@>; +goto move_past; +end + +@ @<(\pdfTeX) Output leaders in a vlist...@>= +begin leader_box:=leader_ptr(p); +if type(leader_box)=rule_node then + begin rule_wd:=width(leader_box); rule_dp:=0; + goto fin_rule; + end; +leader_ht:=height(leader_box)+depth(leader_box); +if (leader_ht>0)and(rule_ht>0) then + begin 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@>; + while cur_v+leader_ht<=edge do + @<(\pdfTeX) Output a leader box at |cur_v|, + then advance |cur_v| by |leader_ht+lx|@>; + cur_v:=edge-10; goto next_p; + end; +end + +@ @<(\pdfTeX) Output a leader box at |cur_v|, ...@>= +begin cur_h:=left_edge+shift_amount(leader_box);@/ +cur_v:=cur_v+height(leader_box); save_v:=cur_v; +temp_ptr:=leader_box; +outer_doing_leaders:=doing_leaders; doing_leaders:=true; +if type(leader_box)=vlist_node then pdf_vlist_out@+else pdf_hlist_out; +doing_leaders:=outer_doing_leaders; +cur_h:=left_edge; +cur_v:=save_v-height(leader_box)+leader_ht+lx; +end + +@ |fix_pdfoutput| freezes |pdfoutput| when something has been written to +the output. + +@p procedure fix_pdfoutput; +begin + if not fixed_pdfoutput_set then begin + fixed_pdfoutput := pdf_output; + fixed_pdfoutput_set := true; + end + else if fixed_pdfoutput <> pdf_output then + pdf_error("setup", + "\pdfoutput can only be changed before anything is written to the output"); +end; + + +@ |pdf_ship_out| is used instead of |ship_out| to shipout a box to PDF +output. If |shipping_page| is not set then the output will be a Form object, +otherwise it will be a Page object. + +@p procedure pdf_ship_out(p: pointer; shipping_page: boolean); {output the box |p|} +label done, done1; +var i,j,k:integer; {general purpose accumulators} +r: integer; {accumulator to copy node for pending link annotation} +save_font_list: pointer; {to save |pdf_font_list| during flushing pending forms} +save_obj_list: pointer; {to save |pdf_obj_list|} +save_ximage_list: pointer; {to save |pdf_ximage_list|} +save_xform_list: pointer; {to save |pdf_xform_list|} +save_image_procset: integer; {to save |pdf_image_procset|} +save_text_procset: integer; {to save |pdf_text_procset|} +pdf_last_resources: integer; {pointer to most recently generated Resources object} +s:str_number; +old_setting:0..max_selector; {saved |selector| setting} +begin if tracing_output>0 then + begin print_nl(""); print_ln; + print("Completed box being shipped out"); +@.Completed box...@> + end; +if not init_pdf_output then begin + @<Initialize variables for \.{PDF} output@>; + init_pdf_output := true; +end; +is_shipping_page := shipping_page; +if shipping_page then begin + if term_offset>max_print_line-9 then print_ln + else if (term_offset>0)or(file_offset>0) then print_char(" "); + print_char("["); j:=9; + while (count(j)=0)and(j>0) do decr(j); + for k:=0 to j do + begin print_int(count(k)); + if k<j then print_char("."); + end; + update_terminal; +end; +if tracing_output>0 then + begin if shipping_page then print_char("]"); + begin_diagnostic; show_box(p); end_diagnostic(true); + end; +@<(\pdfTeX) Ship box |p| out@>; +if (tracing_output<=0) and shipping_page then print_char("]"); +dead_cycles:=0; +update_terminal; {progress report} +@<Flush the box from memory, showing statistics if requested@>; +end; + +@ @<(\pdfTeX) Ship box |p| out@>= +@<Update the values of |max_h| and |max_v|; but if the page is too large, + |goto done|@>; +@<Initialize variables as |pdf_ship_out| begins@>; +if type(p)=vlist_node then pdf_vlist_out@+else pdf_hlist_out; +if shipping_page then + incr(total_pages); +cur_s:=-1; +@<Finish shipping@>; +done: + +@ @<Initialize variables as |pdf_ship_out| begins@>= +fix_pdfoutput; +temp_ptr:=p; +prepare_mag; +pdf_last_resources := pdf_new_objnum; +@<Reset resources lists@>; +if not shipping_page then begin + pdf_xform_width := width(p); + pdf_xform_height := height(p); + pdf_xform_depth := depth(p); + pdf_begin_dict(pdf_cur_form); + pdf_last_stream := pdf_cur_form; + cur_v := height(p); + cur_h := 0; + pdf_origin_h := 0; + pdf_origin_v := pdf_xform_height + pdf_xform_depth; +end +else begin + @<Calculate page dimensions and margins@>; + pdf_last_page := get_obj(obj_type_page, total_pages + 1, 0); + obj_aux(pdf_last_page) := 1; {mark that this page has beed created} + pdf_new_dict(obj_type_others, 0); + pdf_last_stream := obj_ptr; + cur_h := cur_h_offset; + cur_v := height(p) + cur_v_offset; + pdf_origin_h := 0; + pdf_origin_v := cur_page_height; + @<Reset PDF mark lists@>; +end; +if not shipping_page then begin + @<Write out Form stream header@>; +end; +@<Start stream of page/form contents@> + +@ @<Reset resources lists@>= +pdf_font_list := null; +pdf_obj_list := null; +pdf_xform_list := null; +pdf_ximage_list := null; +pdf_text_procset := false; +pdf_image_procset := 0 + +@ @<Reset PDF mark lists@>= +pdf_annot_list := null; +pdf_link_list := null; +pdf_dest_list := null; +pdf_bead_list := null; +last_link := null; +last_thread := null + +@ @<Calculate page dimensions and margins@>= +cur_h_offset := pdf_h_origin + h_offset; +cur_v_offset := pdf_v_origin + v_offset; +if pdf_page_width <> 0 then + cur_page_width := pdf_page_width +else + cur_page_width := width(p) + 2*cur_h_offset; +if pdf_page_height <> 0 then + cur_page_height := pdf_page_height +else + cur_page_height := height(p) + depth(p) + 2*cur_v_offset + +@ Here we write out the header for Form. + +@<Write out Form stream header@>= +pdf_print_ln("/Type /XObject"); +pdf_print_ln("/Subtype /Form"); +if obj_xform_attr(pdf_cur_form) <> null then begin + pdf_print_toks_ln(obj_xform_attr(pdf_cur_form)); + delete_toks(obj_xform_attr(pdf_cur_form)); +end; +pdf_print("/BBox ["); +pdf_print("0 0 "); +pdf_print_bp(pdf_xform_width); pdf_out(" "); +pdf_print_bp(pdf_xform_height + pdf_xform_depth); pdf_print_ln("]"); +pdf_print_ln("/FormType 1"); +pdf_print_ln("/Matrix [1 0 0 1 0 0]"); +pdf_indirect_ln("Resources", pdf_last_resources) + +@ @<Start stream of page/form contents@>= +pdf_begin_stream; +if shipping_page then begin + @<Adjust transformation matrix for the magnification ratio@>; +end + +@ @<Adjust transformation matrix for the magnification ratio@>= +prepare_mag; +if mag <> 1000 then begin + pdf_print_real(mag, 3); + pdf_print(" 0 0 "); + pdf_print_real(mag, 3); + pdf_print_ln(" 0 0 cm"); +end + +@ @<Finish shipping@>= +@<Finish stream of page/form contents@>; +if shipping_page then begin + @<Write out page object@>; +end; +@<Flush out pending raw objects@>; +@<Flush out pending forms@>; +@<Flush out pending images@>; +if shipping_page then begin + @<Flush out pending PDF marks@>; +end; +@<Write out resources dictionary@>; +@<Flush resources lists@>; +if shipping_page then begin + @<Flush PDF mark lists@>; +end + +@ @<Finish stream of page/form contents@>= +pdf_end_text; +pdf_end_stream + +@ @<Write out resources dictionary@>= +pdf_begin_dict(pdf_last_resources); +@<Print additional resources@>; +@<Generate font resources@>; +@<Generate XObject resources@>; +@<Generate ProcSet@>; +pdf_end_dict + +@ @<Print additional resources@>= +if shipping_page then begin + if pdf_page_resources <> null then + pdf_print_toks_ln(pdf_page_resources); +end +else begin + if obj_xform_resources(pdf_cur_form) <> null then begin + pdf_print_toks_ln(obj_xform_resources(pdf_cur_form)); + delete_toks(obj_xform_resources(pdf_cur_form)); + end; +end + +@ In the end of shipping out a page we reset all the lists holding objects +have been created during the page shipping. + +@d delete_toks(#) == begin delete_token_ref(#); # := null; end + +@<Flush resources lists@>= +flush_list(pdf_font_list); +flush_list(pdf_obj_list); +flush_list(pdf_xform_list); +flush_list(pdf_ximage_list) + +@ @<Flush PDF mark lists@>= +flush_list(pdf_annot_list); +flush_list(pdf_link_list); +flush_list(pdf_dest_list); +flush_list(pdf_bead_list) + +@ @<Generate font resources@>= +if pdf_font_list <> null then begin + pdf_print("/Font << "); + k := pdf_font_list; + while k <> null do begin + pdf_print("/F"); + set_ff(info(k)); + pdf_print_int(ff); + pdf_print_font_tag(info(k)); + pdf_print_resname_prefix; + pdf_out(" "); + pdf_print_int(pdf_font_num[ff]); + pdf_print(" 0 R "); + k := link(k); + end; + pdf_print_ln(">>"); + pdf_text_procset := true; +end + +@ @<Generate XObject resources@>= +if (pdf_xform_list <> null) or (pdf_ximage_list <> null) then begin + pdf_print("/XObject << "); + k := pdf_xform_list; + while k <> null do begin + pdf_print("/Fm"); + pdf_print_int(obj_info(info(k))); + pdf_print_resname_prefix; + pdf_out(" "); + pdf_print_int(info(k)); + pdf_print(" 0 R "); + k := link(k); + end; + k := pdf_ximage_list; + while k <> null do begin + pdf_print("/Im"); + pdf_print_int(obj_info(info(k))); + pdf_print_resname_prefix; + pdf_out(" "); + pdf_print_int(info(k)); + pdf_print(" 0 R "); + update_image_procset(obj_ximage_data(info(k))); + k := link(k); + end; + pdf_print_ln(">>"); +end + +@ @<Generate ProcSet@>= +pdf_print("/ProcSet [ /PDF"); +if pdf_text_procset then + pdf_print(" /Text"); +if check_image_b(pdf_image_procset) then + pdf_print(" /ImageB"); +if check_image_c(pdf_image_procset) then + pdf_print(" /ImageC"); +if check_image_i(pdf_image_procset) then + pdf_print(" /ImageI"); +pdf_print_ln(" ]") + +@ @<Write out page object@>= +pdf_begin_dict(pdf_last_page); +pdf_print_ln("/Type /Page"); +pdf_indirect_ln("Contents", pdf_last_stream); +pdf_indirect_ln("Resources", pdf_last_resources); +pdf_print("/MediaBox [0 0 "); +pdf_print_mag_bp(cur_page_width); pdf_out(" "); +pdf_print_mag_bp(cur_page_height); +pdf_print_ln("]"); +if pdf_page_attr <> null then + pdf_print_toks_ln(pdf_page_attr); +@<Generate parent pages object@>; +@<Generate array of annotations or beads in page@>; +pdf_end_dict + +@ @<Generate parent pages object@>= +if total_pages mod pages_tree_kids_max = 1 then begin + pdf_create_obj(obj_type_pages, pages_tree_kids_max); + pdf_last_pages := obj_ptr; +end; +pdf_indirect_ln("Parent", pdf_last_pages) + +@ @<Generate array of annotations or beads in page@>= +if (pdf_annot_list <> null) or (pdf_link_list <> null) then begin + pdf_print("/Annots [ "); + k := pdf_annot_list; + while k <> null do begin + pdf_print_int(info(k)); + pdf_print(" 0 R "); + k := link(k); + end; + k := pdf_link_list; + while k <> null do begin + pdf_print_int(info(k)); + pdf_print(" 0 R "); + k := link(k); + end; + pdf_print_ln("]"); +end; +if pdf_bead_list <> null then begin + k := pdf_bead_list; + pdf_print("/B [ "); + while k <> null do begin + pdf_print_int(info(k)); + pdf_print(" 0 R "); + k := link(k); + end; + pdf_print_ln("]"); +end + +@ @<Declare procedures needed in |pdf_hlist_out|, |pdf_vlist_out|@>= +procedure pdf_write_obj(n: integer); {write a raw PDF object} +var s: str_number; + f: byte_file; +begin + s := tokens_to_string(obj_obj_data(n)); + delete_toks(obj_obj_data(n)); + if obj_obj_is_stream(n) > 0 then begin + pdf_begin_dict(n); + if obj_obj_stream_attr(n) <> null then begin + pdf_print_toks_ln(obj_obj_stream_attr(n)); + delete_toks(obj_obj_stream_attr(n)); + end; + pdf_begin_stream; + end + else + pdf_begin_obj(n); + if obj_obj_is_file(n) > 0 then begin + cur_name := s; + cur_area := ""; + cur_ext := ""; + pack_cur_name; + if not tex_b_openin(f) then + pdf_error("ext5", "cannot open file for embedding"); + print("<<"); + print(s); + while not eof(f) do + pdf_out(getc(f)); + print(">>"); + b_close(f); + end + else if obj_obj_is_stream(n) > 0 then + pdf_print(s) + else + pdf_print_ln(s); + if obj_obj_is_stream(n) > 0 then + pdf_end_stream + else + pdf_end_obj; + flush_str(s); +end; + +procedure flush_whatsit_node(p: pointer; s: small_number); +begin + type(p) := whatsit_node; + subtype(p) := s; + if link(p) <> null then + pdf_error("flush_whatsit_node", "link(p) is not null"); + flush_node_list(p); +end; + +@ @<Flush out pending raw objects@>= +if pdf_obj_list <> null then begin + k := pdf_obj_list; + while k <> null do begin + if not is_obj_written(info(k)) then + pdf_write_obj(info(k)); + k := link(k); + end; +end + +@ When flushing pending forms we need to save and restore resources lists + (|pdf_font_list|, |pdf_obj_list|, |pdf_xform_list| and |pdf_ximage_list|), + which are also used by page shipping. + +@<Flush out pending forms@>= +if pdf_xform_list <> null then begin + k := pdf_xform_list; + while k <> null do begin + if not is_obj_written(info(k)) then begin + pdf_cur_form := info(k); + @<Save resources lists@>; + @<Reset resources lists@>; + pdf_ship_out(obj_xform_box(pdf_cur_form), false); + @<Restore resources lists@>; + end; + k := link(k); + end; +end + +@ @<Save resources lists@>= +save_font_list := pdf_font_list; +save_obj_list := pdf_obj_list; +save_xform_list := pdf_xform_list; +save_ximage_list := pdf_ximage_list; +save_text_procset := pdf_text_procset; +save_image_procset := pdf_image_procset + +@ @<Restore resources lists@>= +pdf_font_list := save_font_list; +pdf_obj_list := save_obj_list; +pdf_xform_list := save_xform_list; +pdf_ximage_list := save_ximage_list; +pdf_text_procset := save_text_procset; +pdf_image_procset := save_image_procset + +@ @<Declare procedures needed in |pdf_hlist_out|, |pdf_vlist_out|@>= +procedure pdf_write_image(n: integer); {write an image} +begin + pdf_begin_dict(n); + if obj_ximage_attr(n) <> null then begin + pdf_print_toks_ln(obj_ximage_attr(n)); + delete_toks(obj_ximage_attr(n)); + end; + write_image(obj_ximage_data(n)); + delete_image(obj_ximage_data(n)); +end; + +@ @<Flush out pending images@>= +if pdf_ximage_list <> null then begin + k := pdf_ximage_list; + while k <> null do begin + if not is_obj_written(info(k)) then + pdf_write_image(info(k)); + k := link(k); + end; +end + +@ @<Flush out pending PDF marks@>= +pdf_origin_h := 0; +pdf_origin_v := cur_page_height; +@<Flush out PDF annotations@>; +@<Flush out PDF link annotations@>; +@<Flush out PDF mark destinations@>; +@<Flush out PDF bead rectangle specifications@> + +@ @<Flush out PDF annotations@>= +if pdf_annot_list <> null then begin + k := pdf_annot_list; + while k <> null do begin + i := obj_annot_ptr(info(k)); {|i| points to |pdf_annot_node|} + pdf_begin_dict(info(k)); + pdf_print_ln("/Type /Annot"); + pdf_print_toks_ln(pdf_annot_data(i)); + pdf_rectangle(pdf_left(i), pdf_top(i), pdf_right(i), pdf_bottom(i)); + pdf_end_dict; + k := link(k); + end; +end + +@ @<Flush out PDF link annotations@>= +if pdf_link_list <> null then begin + @<Write out PDF link annotations@>; + @<Free PDF link annotations@>; +end + +@ @<Write out PDF link annotations@>= +k := pdf_link_list; +while k <> null do begin + i := obj_annot_ptr(info(k)); + pdf_begin_dict(info(k)); + pdf_print_ln("/Type /Annot"); + if pdf_link_attr(i) <> null then + pdf_print_toks_ln(pdf_link_attr(i)); + pdf_rectangle(pdf_left(i), pdf_top(i), pdf_right(i), pdf_bottom(i)); + if pdf_action_type(pdf_link_action(i)) <> pdf_action_user + then begin + pdf_print_ln("/Subtype /Link"); + pdf_print("/A "); + end; + write_action(pdf_link_action(i)); + pdf_end_dict; + k := link(k); +end + +@ @<Free PDF link annotations@>= +k := pdf_link_list; +while k <> null do begin + i := obj_annot_ptr(info(k)); + {nodes with |info = null| were created by |append_link| and + must be flushed here, as they are not linked in any list} + if info(i) = max_halfword then + flush_whatsit_node(i, pdf_start_link_node); + k := link(k); +end + +@ @<Flush out PDF mark destinations@>= +if pdf_dest_list <> null then begin + k := pdf_dest_list; + while k <> null do begin + if is_obj_written(info(k)) then + pdf_error("ext5", + "destination has been already written (this shouldn't happen)") + else begin + i := obj_dest_ptr(info(k)); + if pdf_dest_named_id(i) > 0 then begin + pdf_begin_dict(info(k)); + pdf_print("/D "); + end + else + pdf_begin_obj(info(k)); + pdf_out("["); pdf_print_int(pdf_last_page); pdf_print(" 0 R "); + case pdf_dest_type(i) of + pdf_dest_xyz: begin + pdf_print("/XYZ "); + pdf_print_mag_bp(pdf_x(pdf_left(i))); pdf_out(" "); + pdf_print_mag_bp(pdf_y(pdf_top(i))); pdf_out(" "); + if pdf_dest_xyz_zoom(i) = null then + pdf_print("null") + else begin + pdf_print_int(pdf_dest_xyz_zoom(i) div 1000); + pdf_out("."); + pdf_print_int((pdf_dest_xyz_zoom(i) mod 1000)); + end; + end; + pdf_dest_fit: + pdf_print("/Fit"); + pdf_dest_fith: begin + pdf_print("/FitH "); + pdf_print_mag_bp(pdf_y(pdf_top(i))); + end; + pdf_dest_fitv: begin + pdf_print("/FitV "); + pdf_print_mag_bp(pdf_x(pdf_left(i))); + end; + pdf_dest_fitb: + pdf_print("/FitB"); + pdf_dest_fitbh: begin + pdf_print("/FitBH "); + pdf_print_mag_bp(pdf_y(pdf_top(i))); + end; + pdf_dest_fitbv: begin + pdf_print("/FitBV "); + pdf_print_mag_bp(pdf_x(pdf_left(i))); + end; + pdf_dest_fitr: begin + pdf_print("/FitR "); + pdf_print_rect_spec(i); + end; + othercases pdf_error("ext5", "unknown dest type"); + endcases; + pdf_print_ln("]"); + if pdf_dest_named_id(i) > 0 then + pdf_end_dict + else + pdf_end_obj; + end; + k := link(k); + end; +end + +@ @<Declare procedures needed in |pdf_hlist_out|, |pdf_vlist_out|@>= +procedure pdf_print_rect_spec(r: pointer); {prints a rect spec} +begin + pdf_print_mag_bp(pdf_x(pdf_left(r))); + pdf_out(" "); + pdf_print_mag_bp(pdf_y(pdf_bottom(r))); + pdf_out(" "); + pdf_print_mag_bp(pdf_x(pdf_right(r))); + pdf_out(" "); + pdf_print_mag_bp(pdf_y(pdf_top(r))); +end; + +@ @<Flush out PDF bead rectangle specifications@>= +if pdf_bead_list <> null then begin + k := pdf_bead_list; + while k <> null do begin + pdf_new_obj(obj_type_others, 0); + pdf_out("["); + i := obj_bead_data(info(k)); {pointer to a whatsit or whatsit-like node} + pdf_print_rect_spec(i); + if info(i) = max_halfword then {not a whatsit node, so must be destroyed here} + flush_whatsit_node(i, pdf_start_thread_node); + pdf_print_ln("]"); + obj_bead_rect(info(k)) := obj_ptr; {rewrite |obj_bead_data|} + pdf_end_obj; + k := link(k); + end; +end + +@ In the end we must flush PDF objects that cannot be written out +immediately after shipping out pages. + +@ @<Output outlines@>= +if pdf_first_outline <> 0 then begin + pdf_new_dict(obj_type_others, 0); + outlines := obj_ptr; + l := pdf_first_outline; k := 0; + repeat + incr(k); + a := open_subentries(l); + if obj_outline_count(l) > 0 then + k := k + a; + obj_outline_parent(l) := obj_ptr; + l := obj_outline_next(l); + until l = 0; + pdf_print_ln("/Type /Outlines"); + pdf_indirect_ln("First", pdf_first_outline); + pdf_indirect_ln("Last", pdf_last_outline); + pdf_int_entry_ln("Count", k); + pdf_end_dict; + @<Output PDF outline entries@>; +end +else + outlines := 0 + +@ @<Output PDF outline entries@>= +k := head_tab[obj_type_outline]; +while k <> 0 do begin + if obj_outline_parent(k) = pdf_parent_outline then begin + if obj_outline_prev(k) = 0 then + pdf_first_outline := k; + if obj_outline_next(k) = 0 then + pdf_last_outline := k; + end; + pdf_begin_dict(k); + pdf_indirect_ln("Title", obj_outline_title(k)); + pdf_indirect_ln("A", obj_outline_action_objnum(k)); + if obj_outline_parent(k) <> 0 then + pdf_indirect_ln("Parent", obj_outline_parent(k)); + if obj_outline_prev(k) <> 0 then + pdf_indirect_ln("Prev", obj_outline_prev(k)); + if obj_outline_next(k) <> 0 then + pdf_indirect_ln("Next", obj_outline_next(k)); + if obj_outline_first(k) <> 0 then + pdf_indirect_ln("First", obj_outline_first(k)); + if obj_outline_last(k) <> 0 then + pdf_indirect_ln("Last", obj_outline_last(k)); + if obj_outline_count(k) <> 0 then + pdf_int_entry_ln("Count", obj_outline_count(k)); + if obj_outline_attr(k) <> 0 then begin + pdf_print_toks_ln(obj_outline_attr(k)); + delete_toks(obj_outline_attr(k)); + end; + pdf_end_dict; + k := obj_link(k); +end + +@ @<Output article threads@>= +if head_tab[obj_type_thread] <> 0 then begin + pdf_new_obj(obj_type_others, 0); + threads := obj_ptr; + pdf_out("["); + k := head_tab[obj_type_thread]; + while k <> 0 do begin + pdf_print_int(k); + pdf_print(" 0 R "); + k := obj_link(k); + end; + remove_last_space; + pdf_print_ln("]"); + pdf_end_obj; + k := head_tab[obj_type_thread]; + while k <> 0 do begin + out_thread(k); + k := obj_link(k); + end; +end +else + threads := 0 + +@ Now we are ready to declare our new procedure |ship_out|. It will call +|pdf_ship_out| if the integer parameter |pdf_output| is positive; otherwise it +will call |dvi_ship_out|, which is the \TeX\ original |ship_out|. + +@p procedure ship_out(p:pointer); {output the box |p|} +begin + fix_pdfoutput; + if pdf_output > 0 then + pdf_ship_out(p, true) + else + dvi_ship_out(p); +end; + +@ @<Initialize variables for \.{PDF} output@>= +ensure_pdf_open; +check_pdfminorversion; +prepare_mag; +fixed_decimal_digits := fix_int(pdf_decimal_digits, 0, 4); +min_bp_val := + divide_scaled(one_hundred_bp, ten_pow[fixed_decimal_digits + 2], 0); +fixed_pk_resolution := fix_int(pdf_pk_resolution, 72, 2400); +pk_scale_factor := + divide_scaled(72, fixed_pk_resolution, 5 + fixed_decimal_digits); +if pdf_pk_mode <> null then begin + kpse_init_prog('PDFTEX', fixed_pk_resolution, + make_cstring(tokens_to_string(pdf_pk_mode)), nil); + flush_string; +end else + kpse_init_prog('PDFTEX', fixed_pk_resolution, nil, nil); +if not kpse_var_value('MKTEXPK') then + kpse_set_program_enabled (kpse_pk_format, 1, kpse_src_cmdline); +set_job_id(year, month, day, time, pdftex_version, pdftex_revision); +if (pdf_unique_resname > 0) and (pdf_resname_prefix = 0) then + pdf_resname_prefix := get_resname_prefix + +@ Finishing the PDF output file. + +The following procedures sort the table of destination names +@p function str_less_str(s1, s2: str_number): boolean; {compare two strings} +var j1, j2: pool_pointer; + l, i: integer; +begin + j1 := str_start[s1]; + j2 := str_start[s2]; + if length(s1) < length(s2) then + l := length(s1) + else + l := length(s2); + i := 0; + while (i < l) and (str_pool[j1 + i] = str_pool[j2 + i]) do + incr(i); + if ((i < l) and (str_pool[j1 + i] < str_pool[j2 + i])) or + ((i = l) and (length(s1) < length(s2))) then + str_less_str := true + else + str_less_str := false; +end; + +procedure sort_dest_names(l, r: integer); {sorts |dest_names| by names} +var i, j: integer; + s: str_number; + x, y: integer; + e: dest_name_entry; +begin + i := l; + j := r; + s := dest_names[(l + r) div 2].objname; + repeat + while str_less_str(dest_names[i].objname, s) do + incr(i); + while str_less_str(s, dest_names[j].objname) do + decr(j); + if i <= j then begin + e := dest_names[i]; + dest_names[i] := dest_names[j]; + dest_names[j] := e; + incr(i); + decr(j); + end; + until i > j; + if l < j then + sort_dest_names(l, j); + if i < r then + sort_dest_names(i, r); +end; + +@ Now the finish of PDF output file. At this moment all Page objects +are already written completely to PDF output file. + +@<Finish the PDF file@>= +if total_pages=0 then print_nl("No pages of output.") +@.No pages of output@> +else begin + pdf_flush; {to make sure that the output file name has been already + created} + if total_pages mod pages_tree_kids_max <> 0 then + obj_info(pdf_last_pages) := total_pages mod pages_tree_kids_max; + {last pages object may have less than |pages_tree_kids_max| chilrend} + @<Check for non-existing pages@>; + @<Reverse the linked list of Page and Pages objects@>; + @<Check for non-existing destinations@>; + @<Output fonts definition@>; + @<Output pages tree@>; + @<Output outlines@>; + @<Output name tree@>; + @<Output article threads@>; + @<Output the catalog object@>; + pdf_print_info; + @<Output the |obj_tab|@>; + @<Output the trailer@>; + pdf_flush; + print_nl("Output written on "); print_file_name(0, output_file_name, 0); + @.Output written on x@> + print(" ("); print_int(total_pages); print(" page"); + if total_pages<>1 then print_char("s"); + print(", "); print_int(pdf_offset); print(" bytes)."); + libpdffinish; + b_close(pdf_file); +end + +@ 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. + +@p procedure pdf_fix_dest(k: integer); +begin + if obj_dest_ptr(k) <> null then + return; + pdf_warning("dest", "", false); + if obj_info(k) < 0 then begin + print("name{"); + print(-obj_info(k)); + print("}"); + end + else begin + print("num"); + print_int(obj_info(k)); + end; + print(" has been referenced but does not exist, replaced by a fixed one"); + print_ln; print_ln; + pdf_begin_obj(k); + pdf_out("["); + pdf_print_int(head_tab[obj_type_page]); + pdf_print_ln(" 0 R /Fit]"); + pdf_end_obj; +end; + +@ @<Check for non-existing destinations@>= +k := head_tab[obj_type_dest]; +while k <> 0 do begin + pdf_fix_dest(k); + k := obj_link(k); +end + +@ @<Check for non-existing pages@>= +k := head_tab[obj_type_page]; +while obj_aux(k) = 0 do begin + pdf_warning("dest", "Page ", false); + print_int(obj_info(k)); + print(" has been referenced but does not exist!"); + print_ln; print_ln; + k := obj_link(k); +end; +head_tab[obj_type_page] := k + +@ @<Reverse the linked list of Page and Pages objects@>= +k := head_tab[obj_type_page]; +l := 0; +repeat + i := obj_link(k); + obj_link(k) := l; + l := k; + k := i; +until k = 0; +head_tab[obj_type_page] := l; +k := head_tab[obj_type_pages]; +l := 0; +repeat + i := obj_link(k); + obj_link(k) := l; + l := k; + k := i; +until k = 0; +head_tab[obj_type_pages] := l + +@ @<Output fonts definition@>= +for k := font_base + 1 to font_ptr do + if font_used[k] and hasfmentry(k) then begin + if pdf_font_num[k] < 0 then + i := -pdf_font_num[k] + else + i := tfm_of_fm(pdf_font_map[k]); + if i <> k then + for j := 0 to 255 do + if pdf_char_marked(k, j) then + pdf_mark_char(i, j); + end; +k := head_tab[obj_type_font]; +while k <> 0 do begin + f := obj_info(k); + do_pdf_font(k, f); + k := obj_link(k); +end + +@ We will generate in each single step the parents of all Pages/Page objects in +the previous level. These new generated Pages object will create a new level of +Pages tree. We will repeat this until search only one Pages object. This one +will be the Root object. + +@<Output pages tree@>= +a := obj_ptr + 1; {all Pages objects whose children are not Page objects +should have index greater than |a|} +l := head_tab[obj_type_pages]; {|l| is the index of current Pages object which is +being output} +k := head_tab[obj_type_page]; {|k| is the index of current child of |l|} +if obj_link(l) = 0 then + is_root := true {only Pages object; total pages is not greater than + |pages_tree_kids_max|} +else + is_root := false; +b := obj_ptr + 1; {to init |c| in next step} +repeat + i := 0; {counter of Pages object in current level} + c := b; {first Pages object in previous level} + b := obj_ptr + 1; {succcesor of last created object} + repeat + if not is_root then begin + if i mod pages_tree_kids_max = 0 then begin {create a new Pages object for next level} + pdf_last_pages := pdf_new_objnum; + obj_info(pdf_last_pages) := obj_info(l); + end + else + obj_info(pdf_last_pages) := obj_info(pdf_last_pages) + + obj_info(l); + end; + @<Output the current Pages object in this level@>; + incr(i); + if l < a then + l := obj_link(l) + else + incr(l); + until (l = 0) or (l = b); + if l = 0 then + l := a; + if b = obj_ptr then + is_root := true; +until false; +done: + +@ @<Output the current Pages object in this level@>= +pdf_begin_dict(l); +pdf_print_ln("/Type /Pages"); +pdf_int_entry_ln("Count", obj_info(l)); +if not is_root then + pdf_indirect_ln("Parent", pdf_last_pages); +pdf_print("/Kids ["); +j := 0; +repeat + pdf_print_int(k); + pdf_print(" 0 R "); + if k < a then {the next Pages/Page object must be |obj_link(k)|} + k := obj_link(k) + else {|k >= a|, the next Pages object is |k + 1|} + incr(k); + incr(j); +until ((l < a) and (j = obj_info(l))) or + (k = 0) or (k = c) or + (j = pages_tree_kids_max); +remove_last_space; +pdf_print_ln("]"); +if k = 0 then begin + if head_tab[obj_type_pages] <> 0 then begin {we are in Page objects list} + k := head_tab[obj_type_pages]; + head_tab[obj_type_pages] := 0; + end + else {we are in Pages objects list} + k := a; +end; +if is_root and (pdf_pages_attr <> null) then + pdf_print_toks_ln(pdf_pages_attr); +pdf_end_dict; +if is_root then + goto done + +@ 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. + +@<Output name tree@>= +if pdf_dest_names_ptr = 0 then begin + dests := 0; + goto done1; +end; +sort_dest_names(0, pdf_dest_names_ptr - 1); +a := obj_ptr + 1; {first intermediate node of name tree} +l := a; {index of node being output} +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) } +repeat + c := obj_ptr + 1; {first node in current level} + repeat + pdf_create_obj(obj_type_others, 0); {create a new node for next level} + @<Output the current node in this level@>; + incr(l); + incr(i); + until k = c; +until false; +done1: +if (dests <> 0) or (pdf_names_toks <> null) then begin + pdf_new_dict(obj_type_others, 0); + if (dests <> 0) then + pdf_indirect_ln("Dests", dests); + if pdf_names_toks <> null then begin + pdf_print_toks_ln(pdf_names_toks); + delete_toks(pdf_names_toks); + end; + pdf_end_dict; + names_tree := obj_ptr; +end +else + names_tree := 0 + +@ @<Output the current node in this level@>= +pdf_begin_dict(l); +j := 0; +if k < pdf_dest_names_ptr then begin + obj_info(l) := dest_names[k].objname; + pdf_print("/Names ["); + repeat + pdf_print_str(dest_names[k].objname); + pdf_out(" "); + pdf_print_int(dest_names[k].objnum); + pdf_print(" 0 R "); + incr(j); + incr(k); + until (j = name_tree_kids_max) or (k = pdf_dest_names_ptr); + remove_last_space; + pdf_print_ln("]"); + obj_link(l) := dest_names[k - 1].objname; + if k = pdf_dest_names_ptr then + k := a; +end +else begin + obj_info(l) := obj_info(k); + pdf_print("/Kids ["); + repeat + pdf_print_int(k); + pdf_print(" 0 R "); + incr(j); + incr(k); + until (j = name_tree_kids_max) or (k = c); + remove_last_space; + pdf_print_ln("]"); + obj_link(l) := obj_link(k - 1); +end; +if (l > k) or (l = a) then begin + pdf_print("/Limits ["); + pdf_print_str(obj_info(l)); + pdf_out(" "); + pdf_print_str(obj_link(l)); + pdf_print_ln("]"); + pdf_end_dict; +end +else begin + pdf_end_dict; + dests := l; + goto done1; +end + +@ @<Output the catalog object@>= +pdf_new_dict(obj_type_others, 0); +root := obj_ptr; +pdf_print_ln("/Type /Catalog"); +pdf_indirect_ln("Pages", pdf_last_pages); +if threads <> 0 then + pdf_indirect_ln("Threads", threads); +if outlines <> 0 then + pdf_indirect_ln("Outlines", outlines); +if names_tree <> 0 then + pdf_indirect_ln("Names", names_tree); +if pdf_catalog_toks <> null then begin + pdf_print_toks_ln(pdf_catalog_toks); + delete_toks(pdf_catalog_toks); +end; +if pdf_catalog_openaction <> 0 then + pdf_indirect_ln("OpenAction", pdf_catalog_openaction); +pdf_end_dict + +@ 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. + +@p function substr_of_str(s, t: str_number):boolean; +label continue,exit; +var j, k, kk: pool_pointer; {running indices} +begin + k:=str_start[t]; + while (k < str_start[t+1] - length(s)) do begin + j:=str_start[s]; + kk:=k; + while (j < str_start[s+1]) do begin + if str_pool[j] <> str_pool[kk] then + goto continue; + incr(j); + incr(kk); + end; + substr_of_str:=true; + return; + continue: incr(k); + end; + substr_of_str:=false; +end; + +procedure pdf_print_info; {print info object} +var s: str_number; + creator_given, producer_given, creationdate_given: boolean; +begin + pdf_new_dict(obj_type_others, 0); + creator_given:=false; + producer_given:=false; + creationdate_given:=false; + if pdf_info_toks <> null then begin + s:=tokens_to_string(pdf_info_toks); + creator_given:=substr_of_str("/Creator", s); + producer_given:=substr_of_str("/Producer", s); + creationdate_given:=substr_of_str("/CreationDate", s); + end; + if not producer_given then begin + @<Print the Producer key@>; + end; + if pdf_info_toks <> null then begin + if length(s) > 0 then begin + pdf_print(s); + pdf_print_nl; + end; + flush_str(s); + delete_toks(pdf_info_toks); + end; + if not creator_given then + pdf_str_entry_ln("Creator", "TeX"); + if not creationdate_given then begin + @<Print the CreationDate key@>; + end; + pdf_str_entry_ln("PTEX.Fullbanner", pdftex_banner); + pdf_end_dict; +end; + +@ @<Print the Producer key@>= +pdf_print("/Producer (pdfTeX-"); +pdf_print_int(pdftex_version div 100); +pdf_out("."); +pdf_print_int(pdftex_version mod 100); +pdf_out("."); +pdf_print(pdftex_revision); +pdf_print_ln(")") + +@ @<Print the CreationDate key@>= +print_creation_date; + +@ @<Glob...@>= +@!pdftex_banner: str_number; {the complete banner} + +@ @<Output the |obj_tab|@>= +l := 0; +for k := 1 to obj_ptr do + if obj_offset(k) = 0 then begin + obj_link(l) := k; + l := k; + end; +obj_link(l) := 0; +pdf_save_offset := pdf_offset; +pdf_print_ln("xref"); +pdf_print("0 "); pdf_print_int_ln(obj_ptr + 1); +pdf_print_fw_int(obj_link(0), 10); +pdf_print_ln(" 65535 f "); +for k := 1 to obj_ptr do begin + if obj_offset(k) = 0 then begin + pdf_print_fw_int(obj_link(k), 10); + pdf_print_ln(" 00000 f "); + end + else begin + pdf_print_fw_int(obj_offset(k), 10); + pdf_print_ln(" 00000 n "); + end; +end + +@ @<Output the trailer@>= +pdf_print_ln("trailer"); +pdf_print("<< "); +pdf_int_entry_ln("Size", obj_ptr + 1); +pdf_indirect_ln("Root", root); +pdf_indirect_ln("Info", obj_ptr); +if pdf_trailer_toks <> null then begin + pdf_print_toks_ln(pdf_trailer_toks); + delete_toks(pdf_trailer_toks); +end; +print_ID(output_file_name); +pdf_print_ln(" >>"); +pdf_print_ln("startxref"); +pdf_print_int_ln(pdf_save_offset); +pdf_print_ln("%%EOF") + +@* \[33] Packaging. +@z + +@x [649] +exit: hpack:=r; +@y +exit: {|hpack|} +hpack:=r; +@z + +@x [651] + kern_node,math_node: x:=x+width(p); +@y + kern_node: x:=x+width(p); + math_node: x:=x+width(p); +@z + +@x [888] - fixlinedimen +append_to_vlist(just_box); +@y +if pdf_each_line_height <> 0 then + height(just_box) := pdf_each_line_height; +if pdf_each_line_depth <> 0 then + depth(just_box) := pdf_each_line_depth; +if (pdf_first_line_height <> 0) and (cur_line = prev_graf + 1) then + height(just_box) := pdf_first_line_height; +if (pdf_last_line_depth <> 0) and (cur_line + 1 = best_line) then + depth(just_box) := pdf_last_line_depth; +append_to_vlist(just_box); +@z + +@x [889] +adjust_tail:=adjust_head; just_box:=hpack(q,cur_width,exactly); +@y +adjust_tail:=adjust_head; +just_box:=hpack(q,cur_width,exactly); +@z + +@x [1088] - quitvmode +@ A paragraph begins when horizontal-mode material occurs in vertical mode, +or when the paragraph is explicitly started by `\.{\\indent}' or +`\.{\\noindent}'. + +@<Put each...@>= +primitive("indent",start_par,1); +@!@:indent_}{\.{\\indent} primitive@> +primitive("noindent",start_par,0); +@!@:no_indent_}{\.{\\noindent} primitive@> +@y +@ Here is a really small patch to add a new primitive called +\.{\\quitvmode}. In vertical modes, it is identical to \.{\\indent}, +but in horizontal and math modes it is really a no-op (as opposed to +\.{\\indent}, which executes the |indent_in_hmode| procedure). + +A paragraph begins when horizontal-mode material occurs in vertical mode, +or when the paragraph is explicitly started by `\.{\\quitvmode}', +`\.{\\indent}' or `\.{\\noindent}'. + +@<Put each...@>= +primitive("indent",start_par,1); +@!@:indent_}{\.{\\indent} primitive@> +primitive("noindent",start_par,0); +@!@:no_indent_}{\.{\\noindent} primitive@> +primitive("quitvmode",start_par,2); +@!@:quit_vmode_}{\.{\\quitvmode} primitive@> +@z + +@x [1089] - quitvmode +start_par: if chr_code=0 then print_esc("noindent")@+ else print_esc("indent"); +@y +start_par: if chr_code=0 then print_esc("noindent")@+ else if chr_code=1 then print_esc("indent")@+ else print_esc("quitvmode"); +@z + +@x [1092] - quitvmode +hmode+start_par,mmode+start_par: indent_in_hmode; +@y +hmode+start_par,mmode+start_par: if cur_chr<>2 then indent_in_hmode; +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Declare the necessary variables for finishing PDF file +% Close PDF output if necessary +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x [1333] +procedure close_files_and_terminate; +var k:integer; {all-purpose index} +begin @<Finish the extensions@>; +@!stat if tracing_stats>0 then @<Output statistics about this job@>;@;@+tats@/ +wake_up_terminal; @<Finish the \.{DVI} file@>; +@y +procedure close_files_and_terminate; +label done, done1; +var a, b, c, i, j, k, l: integer; {all-purpose index} + is_root: boolean; {|pdf_last_pages| is root of Pages tree?} + root, outlines, threads, names_tree, dests, fixed_dest: integer; +begin @<Finish the extensions@>; +@!stat if tracing_stats>0 then @<Output statistics about this job@>;@;@+tats@/ +wake_up_terminal; +if fixed_pdfoutput > 0 then begin + if history = fatal_error_stop then + print_err(" ==> Fatal error occurred, the output PDF file is not finished!") + else begin + @<Finish the PDF file@>; + end; +end +else begin + @<Finish the \.{DVI} file@>; +end; +@z + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Output statistics about the pdftex specific sizes only in PDF mode. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x [1334] + wlog_ln(' ',max_in_stack:1,'i,',max_nest_stack:1,'n,',@| + max_param_stack:1,'p,',@| + max_buf_stack+1:1,'b,',@| + max_save_stack+6:1,'s stack positions out of ',@| + stack_size:1,'i,', + nest_size:1,'n,', + param_size:1,'p,', + buf_size:1,'b,', + save_size:1,'s'); + end +@y + wlog_ln(' ',max_in_stack:1,'i,',max_nest_stack:1,'n,',@| + max_param_stack:1,'p,',@| + max_buf_stack+1:1,'b,',@| + max_save_stack+6:1,'s stack positions out of ',@| + stack_size:1,'i,', + nest_size:1,'n,', + param_size:1,'p,', + buf_size:1,'b,', + save_size:1,'s'); + if (pdf_output > 0) then begin + wlog_ln('PDF statistics:'); + wlog_ln(' ',obj_ptr:1,' PDF objects out of ',obj_tab_size:1); + wlog_ln(' ',pdf_dest_names_ptr:1,' named destinations out of ',dest_names_size:1); + wlog_ln(' ',pdf_mem_ptr:1,' words of extra memory for PDF output out of ',pdf_mem_size:1); + end; + end +@z + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Override pdf_output value from format file with command line option +% and initialize other options +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x + while (loc<limit)and(buffer[loc]=" ") do incr(loc); + end; +@y + while (loc<limit)and(buffer[loc]=" ") do incr(loc); + end; +if (pdf_output_option <> 0) then pdf_output := pdf_output_value; +pdf_init_map_file('pdftex.map'); +@z + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% PDF-speficic extensions that don't fall to any previous category +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +@x [1344] +@d set_language_code=5 {command modifier for \.{\\setlanguage}} +@y +@d set_language_code=5 {command modifier for \.{\\setlanguage}} +@d pdftex_first_extension_code = 6 +@d pdf_literal_node == pdftex_first_extension_code + 0 +@d pdf_obj_code == pdftex_first_extension_code + 1 +@d pdf_refobj_node == pdftex_first_extension_code + 2 +@d pdf_xform_code == pdftex_first_extension_code + 3 +@d pdf_refxform_node == pdftex_first_extension_code + 4 +@d pdf_ximage_code == pdftex_first_extension_code + 5 +@d pdf_refximage_node == pdftex_first_extension_code + 6 +@d pdf_annot_node == pdftex_first_extension_code + 7 +@d pdf_start_link_node == pdftex_first_extension_code + 8 +@d pdf_end_link_node == pdftex_first_extension_code + 9 +@d pdf_outline_code == pdftex_first_extension_code + 10 +@d pdf_dest_node == pdftex_first_extension_code + 11 +@d pdf_thread_node == pdftex_first_extension_code + 12 +@d pdf_start_thread_node == pdftex_first_extension_code + 13 +@d pdf_end_thread_node == pdftex_first_extension_code + 14 +@d pdf_save_pos_node == pdftex_first_extension_code + 15 +@d pdf_info_code == pdftex_first_extension_code + 16 +@d pdf_catalog_code == pdftex_first_extension_code + 17 +@d pdf_names_code == pdftex_first_extension_code + 18 +@d pdf_font_attr_code == pdftex_first_extension_code + 19 +@d pdf_include_chars_code == pdftex_first_extension_code + 20 +@d pdf_map_file_code == pdftex_first_extension_code + 21 +@d pdf_map_line_code == pdftex_first_extension_code + 22 +@d pdf_trailer_code == pdftex_first_extension_code + 23 +@d pdf_strcmp_code == pdftex_first_extension_code + 24 +@d pdf_escape_string_code == pdftex_first_extension_code + 25 +@d pdf_escape_name_code == pdftex_first_extension_code + 26 +@d reset_timer_code == pdftex_first_extension_code + 27 +@d pdftex_last_extension_code == pdftex_first_extension_code + 27 +@z + +@x [1344] +primitive("setlanguage",extension,set_language_code);@/ +@!@:set_language_}{\.{\\setlanguage} primitive@> +@y +primitive("setlanguage",extension,set_language_code);@/ +@!@:set_language_}{\.{\\setlanguage} primitive@> +primitive("pdfliteral",extension,pdf_literal_node);@/ +@!@:pdf_literal_}{\.{\\pdfliteral} primitive@> +primitive("pdfobj",extension,pdf_obj_code);@/ +@!@:pdf_obj_}{\.{\\pdfobj} primitive@> +primitive("pdfrefobj",extension,pdf_refobj_node);@/ +@!@:pdf_refobj_}{\.{\\pdfrefobj} primitive@> +primitive("pdfxform",extension,pdf_xform_code);@/ +@!@:pdf_xform_}{\.{\\pdfxform} primitive@> +primitive("pdfrefxform",extension,pdf_refxform_node);@/ +@!@:pdf_refxform_}{\.{\\pdfrefxform} primitive@> +primitive("pdfximage",extension,pdf_ximage_code);@/ +@!@:pdf_ximage_}{\.{\\pdfximage} primitive@> +primitive("pdfrefximage",extension,pdf_refximage_node);@/ +@!@:pdf_refximage_}{\.{\\pdfrefximage} primitive@> +primitive("pdfannot",extension,pdf_annot_node);@/ +@!@:pdf_annot_}{\.{\\pdfannot} primitive@> +primitive("pdfstartlink",extension,pdf_start_link_node);@/ +@!@:pdf_start_link_}{\.{\\pdfstartlink} primitive@> +primitive("pdfendlink",extension,pdf_end_link_node);@/ +@!@:pdf_end_link_}{\.{\\pdfendlink} primitive@> +primitive("pdfoutline",extension,pdf_outline_code);@/ +@!@:pdf_outline_}{\.{\\pdfoutline} primitive@> +primitive("pdfdest",extension,pdf_dest_node);@/ +@!@:pdf_dest_}{\.{\\pdfdest} primitive@> +primitive("pdfthread",extension,pdf_thread_node);@/ +@!@:pdf_thread_}{\.{\\pdfthread} primitive@> +primitive("pdfstartthread",extension,pdf_start_thread_node);@/ +@!@:pdf_start_thread_}{\.{\\pdfstartthread} primitive@> +primitive("pdfendthread",extension,pdf_end_thread_node);@/ +@!@:pdf_end_thread_}{\.{\\pdfendthread} primitive@> +primitive("pdfsavepos",extension,pdf_save_pos_node);@/ +@!@:pdf_save_pos_}{\.{\\pdfsavepos} primitive@> +primitive("pdfinfo",extension,pdf_info_code);@/ +@!@:pdf_info_}{\.{\\pdfinfo} primitive@> +primitive("pdfcatalog",extension,pdf_catalog_code);@/ +@!@:pdf_catalog_}{\.{\\pdfcatalog} primitive@> +primitive("pdfnames",extension,pdf_names_code);@/ +@!@:pdf_names_}{\.{\\pdfnames} primitive@> +primitive("pdfincludechars",extension,pdf_include_chars_code);@/ +@!@:pdf_include_chars_}{\.{\\pdfincludechars} primitive@> +primitive("pdffontattr",extension,pdf_font_attr_code);@/ +@!@:pdf_font_attr_}{\.{\\pdffontattr} primitive@> +primitive("pdfmapfile",extension,pdf_map_file_code);@/ +@!@:pdf_map_file_}{\.{\\pdfmapfile} primitive@> +primitive("pdfmapline",extension,pdf_map_line_code);@/ +@!@:pdf_map_line_}{\.{\\pdfmapline} primitive@> +primitive("pdftrailer",extension,pdf_trailer_code);@/ +@!@:pdf_trailer_}{\.{\\pdftrailer} primitive@> +primitive("pdfstrcmp",extension,pdf_strcmp_code);@/ +@!@:pdf_strcmp_}{\.{\\pdfstrcmp} primitive@> +primitive("pdfescapestring",extension,pdf_escape_string_code);@/ +@!@:pdf_escape_string_}{\.{\\pdfescapestring} primitive@> +primitive("pdfescapename",extension,pdf_escape_name_code);@/ +@!@:pdf_escape_name_}{\.{\\pdfescapename} primitive@> +primitive("pdfresettimer",extension,reset_timer_code);@/ +@!@:reset_timer_}{\.{\\pdfresettimer} primitive@> +@z + +@x [1346] + set_language_code:print_esc("setlanguage"); +@y + set_language_code:print_esc("setlanguage"); + pdf_literal_node: print_esc("pdfliteral"); + pdf_obj_code: print_esc("pdfobj"); + pdf_refobj_node: print_esc("pdfrefobj"); + pdf_xform_code: print_esc("pdfxform"); + pdf_refxform_node: print_esc("pdfrefxform"); + pdf_ximage_code: print_esc("pdfximage"); + pdf_refximage_node: print_esc("pdfrefximage"); + pdf_annot_node: print_esc("pdfannot"); + pdf_start_link_node: print_esc("pdfstartlink"); + pdf_end_link_node: print_esc("pdfendlink"); + pdf_outline_code: print_esc("pdfoutline"); + pdf_dest_node: print_esc("pdfdest"); + pdf_thread_node: print_esc("pdfthread"); + pdf_start_thread_node: print_esc("pdfstartthread"); + pdf_end_thread_node: print_esc("pdfendthread"); + pdf_save_pos_node: print_esc("pdfsavepos"); + pdf_info_code: print_esc("pdfinfo"); + pdf_catalog_code: print_esc("pdfcatalog"); + pdf_names_code: print_esc("pdfnames"); + pdf_include_chars_code: print_esc("pdfincludechars"); + pdf_font_attr_code: print_esc("pdffontattr"); + pdf_map_file_code: print_esc("pdfmapfile"); + pdf_map_line_code: print_esc("pdfmapline"); + pdf_trailer_code: print_esc("pdftrailer"); + pdf_strcmp_code: print_esc("pdfstrcmp"); + pdf_escape_string_code: print_esc("pdfescapestring"); + pdf_escape_name_code: print_esc("pdfescapename"); + reset_timer_code: print_esc("pdfresettimer"); +@z + +@x [1348] +immediate_code:@<Implement \.{\\immediate}@>; +set_language_code:@<Implement \.{\\setlanguage}@>; +@y +immediate_code:@<Implement \.{\\immediate}@>; +set_language_code:@<Implement \.{\\setlanguage}@>; +pdf_literal_node: @<Implement \.{\\pdfliteral}@>; +pdf_obj_code: @<Implement \.{\\pdfobj}@>; +pdf_refobj_node: @<Implement \.{\\pdfrefobj}@>; +pdf_xform_code: @<Implement \.{\\pdfxform}@>; +pdf_refxform_node: @<Implement \.{\\pdfrefxform}@>; +pdf_ximage_code: @<Implement \.{\\pdfximage}@>; +pdf_refximage_node: @<Implement \.{\\pdfrefximage}@>; +pdf_annot_node: @<Implement \.{\\pdfannot}@>; +pdf_start_link_node: @<Implement \.{\\pdfstartlink}@>; +pdf_end_link_node: @<Implement \.{\\pdfendlink}@>; +pdf_outline_code: @<Implement \.{\\pdfoutline}@>; +pdf_dest_node: @<Implement \.{\\pdfdest}@>; +pdf_thread_node: @<Implement \.{\\pdfthread}@>; +pdf_start_thread_node: @<Implement \.{\\pdfstartthread}@>; +pdf_end_thread_node: @<Implement \.{\\pdfendthread}@>; +pdf_save_pos_node: @<Implement \.{\\pdfsavepos}@>; +pdf_info_code: @<Implement \.{\\pdfinfo}@>; +pdf_catalog_code: @<Implement \.{\\pdfcatalog}@>; +pdf_names_code: @<Implement \.{\\pdfnames}@>; +pdf_include_chars_code: @<Implement \.{\\pdfincludechars}@>; +pdf_font_attr_code: @<Implement \.{\\pdffontattr}@>; +pdf_map_file_code: @<Implement \.{\\pdfmapfile}@>; +pdf_map_line_code: @<Implement \.{\\pdfmapline}@>; +pdf_trailer_code: @<Implement \.{\\pdftrailer}@>; +pdf_strcmp_code: @<Implement \.{\\pdfstrcmp}@>; +pdf_escape_string_code: @<Implement \.{\\pdfescapestring}@>; +pdf_escape_name_code: @<Implement \.{\\pdfescapename}@>; +reset_timer_code: @<Implement \.{\\pdfresettimer}@>; +@z + +@x [1354] +@<Implement \.{\\special}@>= +begin new_whatsit(special_node,write_node_size); write_stream(tail):=null; +p:=scan_toks(false,true); write_tokens(tail):=def_ref; +end +@y +@<Implement \.{\\special}@>= +begin new_whatsit(special_node,write_node_size); write_stream(tail):=null; +p:=scan_toks(false,true); write_tokens(tail):=def_ref; +end + +@ The following macros are needed for further manipulation with whatsit nodes +for \pdfTeX{} extensions (copying, destroying etc.) + +@d add_action_ref(#) == incr(pdf_action_refcount(#)) {increase count of +references to this action} + +@d delete_action_ref(#) == {decrease count of references to this +action; free it if there is no reference to this action} +begin + if pdf_action_refcount(#) = null then begin + if pdf_action_type(#) = pdf_action_user then + delete_token_ref(pdf_action_user_tokens(#)) + else begin + if pdf_action_file(#) <> null then + delete_token_ref(pdf_action_file(#)); + if pdf_action_type(#) = pdf_action_page then + delete_token_ref(pdf_action_page_tokens(#)) + else if pdf_action_named_id(#) > 0 then + delete_token_ref(pdf_action_id(#)); + end; + free_node(#, pdf_action_size); + end + else + decr(pdf_action_refcount(#)); +end + +@ We have to check whether \.{\\pdfoutput} is set for using \pdfTeX{} + extensions. +@<Declare procedures needed in |do_ext...@>= +procedure check_pdfoutput(s: str_number; is_error : boolean); +begin + if pdf_output <= 0 then + if is_error then + pdf_error(s, "used while \pdfoutput is not set") + else + pdf_warning(s, "used while \pdfoutput is not set; ignoring it", true); +end; + +procedure scan_pdf_ext_toks; +begin + call_func(scan_toks(false, true)); {like \.{\\special}} +end; + +procedure compare_strings; {to implement \.{\\pdfstrcmp}} +label done; +var s1, s2: str_number; + i1, i2, j1, j2: pool_pointer; + result: integer; +begin + call_func(scan_toks(false, true)); + s1 := tokens_to_string(def_ref); + delete_token_ref(def_ref); + call_func(scan_toks(false, true)); + s2 := tokens_to_string(def_ref); + delete_token_ref(def_ref); + i1 := str_start[s1]; + j1 := str_start[s1 + 1]; + i2 := str_start[s2]; + j2 := str_start[s2 + 1]; + while (i1 < j1) and (i2 < j2) do begin + if str_pool[i1] < str_pool[i2] then begin + result := -1; + goto done; + end; + if str_pool[i1] > str_pool[i2] then begin + result := 1; + goto done; + end; + incr(i1); + incr(i2); + end; + if (i1 = j1) and (i2 = j2) then + result := 0 + else if i1 < j1 then + result := 1 + else + result := -1; +done: + pdf_retval := result; + flush_str(s2); + flush_str(s1); +end; + +@ @<Implement \.{\\pdfliteral}@>= +begin + check_pdfoutput("\pdfliteral", true); + new_whatsit(pdf_literal_node, write_node_size); + if scan_keyword("direct") then + pdf_literal_mode(tail) := direct_always + else if scan_keyword("page") then + pdf_literal_mode(tail) := direct_page + else + pdf_literal_mode(tail) := reset_origin; + scan_pdf_ext_toks; + pdf_literal_data(tail) := def_ref; +end + +@ 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|. + +@<Glob...@>= +@!pdf_last_obj: integer; + +@ @<Implement \.{\\pdfobj}@>= +begin + check_pdfoutput("\pdfobj", true); + if scan_keyword("reserveobjnum") then begin + @<Scan an optional space@>; + incr(pdf_obj_count); + pdf_create_obj(obj_type_obj, pdf_obj_count); + pdf_last_obj := obj_ptr; + end + else begin + k := -1; + if scan_keyword("useobjnum") then begin + scan_int; + k := cur_val; + if (k <= 0) or (k > obj_ptr) or (obj_data_ptr(k) <> 0) then begin + pdf_warning("\pdfobj", "invalid object number being ignored", true); + pdf_retval := -1; {signal the problem} + k := -1; {will be generated again} + end; + end; + if k < 0 then begin + incr(pdf_obj_count); + pdf_create_obj(obj_type_obj, pdf_obj_count); + k := obj_ptr; + end; + obj_data_ptr(k) := pdf_get_mem(pdfmem_obj_size); + if scan_keyword("stream") then begin + obj_obj_is_stream(k) := 1; + if scan_keyword("attr") then begin + scan_pdf_ext_toks; + obj_obj_stream_attr(k) := def_ref; + end + else + obj_obj_stream_attr(k) := null; + end + else + obj_obj_is_stream(k) := 0; + if scan_keyword("file") then + obj_obj_is_file(k) := 1 + else + obj_obj_is_file(k) := 0; + scan_pdf_ext_toks; + obj_obj_data(k) := def_ref; + pdf_last_obj := k; + end; +end + +@ We need to check whether the referenced object exists. + +@<Declare procedures that need to be declared forward for pdftex@>= +procedure pdf_check_obj(t, n: integer); +var k: integer; +begin + k := head_tab[t]; + while (k <> 0) and (k <> n) do + k := obj_link(k); + if k = 0 then + pdf_error("ext1", "cannot find referenced object"); +end; + +@ @<Implement \.{\\pdfrefobj}@>= +begin + check_pdfoutput("\pdfrefobj", true); + scan_int; + pdf_check_obj(obj_type_obj, cur_val); + new_whatsit(pdf_refobj_node, pdf_refobj_node_size); + pdf_obj_objnum(tail) := cur_val; +end + +@ \.{\\pdfxform} and \.{\\pdfrefxform} are similiar to \.{\\pdfobj} and + \.{\\pdfrefobj} + +@<Glob...@>= +@!pdf_last_xform: integer; + +@ @<Implement \.{\\pdfxform}@>= +begin + check_pdfoutput("\pdfxform", true); + incr(pdf_xform_count); + pdf_create_obj(obj_type_xform, pdf_xform_count); + k := obj_ptr; + obj_data_ptr(k) := pdf_get_mem(pdfmem_xform_size); + if scan_keyword("attr") then begin + scan_pdf_ext_toks; + obj_xform_attr(k) := def_ref; + end + else + obj_xform_attr(k) := null; + if scan_keyword("resources") then begin + scan_pdf_ext_toks; + obj_xform_resources(k) := def_ref; + end + else + obj_xform_resources(k) := null; + scan_int; + if box(cur_val) = null then + pdf_error("ext1", "\pdfxform cannot be used with a void box"); + obj_xform_width(k) := width(box(cur_val)); + obj_xform_height(k) := height(box(cur_val)); + obj_xform_depth(k) := depth(box(cur_val)); + obj_xform_box(k) := box(cur_val); {save pointer to the box} + box(cur_val) := null; + pdf_last_xform := k; +end + +@ @<Implement \.{\\pdfrefxform}@>= +begin + check_pdfoutput("\pdfrefxform", true); + scan_int; + pdf_check_obj(obj_type_xform, cur_val); + new_whatsit(pdf_refxform_node, pdf_refxform_node_size); + pdf_xform_objnum(tail) := cur_val; + pdf_width(tail) := obj_xform_width(cur_val); + pdf_height(tail) := obj_xform_height(cur_val); + pdf_depth(tail) := obj_xform_depth(cur_val); +end + +@ \.{\\pdfximage} and \.{\\pdfrefximage} are similiar to \.{\\pdfxform} and + \.{\\pdfrefxform}. As we have to scan |<rule spec>| quite often, it is better + have a |rule_node| that holds the most recently scanned |<rule spec>|. + +@<Glob...@>= +@!pdf_last_ximage: integer; +@!pdf_last_ximage_pages: integer; +@!pdf_last_ximage_colordepth: integer; +@!alt_rule: pointer; +@!pdf_last_pdf_box_spec: integer; + +@ @<Set init...@>= +alt_rule := null; + +@ @<Declare procedures needed in |do_ext...@>= +procedure scale_image(n: integer); +var x, y, xr, yr: integer; {size and resolution of image} + w, h: scaled; {indeed size corresponds to image resolution} + default_res: integer; +begin + x := image_width(obj_ximage_data(n)); + y := image_height(obj_ximage_data(n)); + xr := image_x_res(obj_ximage_data(n)); + yr := image_y_res(obj_ximage_data(n)); + if (xr > 65535) or (yr > 65535) then begin + xr := 0; + yr := 0; + pdf_warning("ext1", "too large image resolution ignored", true); + end; + if (x <= 0) or (y <= 0) or (xr < 0) or (yr < 0) then + pdf_error("ext1", "invalid image dimensions"); + if is_pdf_image(obj_ximage_data(n)) then begin + w := x; + h := y; + end + else begin + default_res := fix_int(pdf_image_resolution, 0, 65535); + if (default_res > 0) and ((xr = 0) or (yr = 0)) then begin + xr := default_res; + yr := default_res; + end; + if is_running(obj_ximage_width(n)) and + is_running(obj_ximage_height(n)) then + begin + if (xr > 0) and (yr > 0) then begin + w := ext_xn_over_d(one_hundred_inch, x, 100*xr); + h := ext_xn_over_d(one_hundred_inch, y, 100*yr); + end + else begin + w := ext_xn_over_d(one_hundred_inch, x, 7200); + h := ext_xn_over_d(one_hundred_inch, y, 7200); + end; + end; + end; + if is_running(obj_ximage_width(n)) and is_running(obj_ximage_height(n)) and + is_running(obj_ximage_depth(n)) then begin + obj_ximage_width(n) := w; + obj_ximage_height(n) := h; + obj_ximage_depth(n) := 0; + end + else if is_running(obj_ximage_width(n)) then begin + {image depth or height is explicitly specified} + if is_running(obj_ximage_height(n)) then begin + {image depth is explicitly specified} + obj_ximage_width(n) := ext_xn_over_d(h, x, y); + obj_ximage_height(n) := h - obj_ximage_depth(n); + end + else if is_running(obj_ximage_depth(n)) then begin + {image height is explicitly specified} + obj_ximage_width(n) := ext_xn_over_d(obj_ximage_height(n), x, y); + obj_ximage_depth(n) := 0; + end + else begin + {both image depth and height are explicitly specified} + obj_ximage_width(n) := ext_xn_over_d(obj_ximage_height(n) + + obj_ximage_depth(n), x, y); + end; + end + else begin + {image width is explicitly specified} + if is_running(obj_ximage_height(n)) and + is_running(obj_ximage_depth(n)) then begin + {both image depth and height are not specified} + obj_ximage_height(n) := ext_xn_over_d(obj_ximage_width(n), y, x); + obj_ximage_depth(n) := 0; + end + {image depth is explicitly specified} + else if is_running(obj_ximage_height(n)) then begin + obj_ximage_height(n) := + ext_xn_over_d(obj_ximage_width(n), y, x) - obj_ximage_depth(n); + end + {image height is explicitly specified} + else if is_running(obj_ximage_depth(n)) then begin + obj_ximage_depth(n) := 0; + end + {both image depth and height are explicitly specified} + else + do_nothing; + end; +end; + +procedure scan_pdf_box_spec; {scans pdf-box-spec to |pdf_last_pdf_box_spec|} +begin + pdf_last_pdf_box_spec := pdf_pdf_box_spec_crop; + + if scan_keyword("mediabox") then + pdf_last_pdf_box_spec := pdf_pdf_box_spec_media + else if scan_keyword("cropbox") then + pdf_last_pdf_box_spec := pdf_pdf_box_spec_crop + else if scan_keyword("bleedbox") then + pdf_last_pdf_box_spec := pdf_pdf_box_spec_bleed + else if scan_keyword("trimbox") then + pdf_last_pdf_box_spec := pdf_pdf_box_spec_trim + else if scan_keyword("artbox") then + pdf_last_pdf_box_spec := pdf_pdf_box_spec_art +end; + +procedure scan_alt_rule; {scans rule spec to |alt_rule|} +label reswitch; +begin + if alt_rule = null then + alt_rule := new_rule; + width(alt_rule) := null_flag; + height(alt_rule) := null_flag; + depth(alt_rule) := null_flag; +reswitch: + if scan_keyword("width") then begin + scan_normal_dimen; + width(alt_rule) := cur_val; + goto reswitch; + end; + if scan_keyword("height") then begin + scan_normal_dimen; + height(alt_rule) := cur_val; + goto reswitch; + end; + if scan_keyword("depth") then begin + scan_normal_dimen; + depth(alt_rule) := cur_val; + goto reswitch; + end; +end; + +procedure scan_image; +label reswitch; +var p: pointer; + k: integer; + named: str_number; + s: str_number; + page, colorspace: integer; +begin + incr(pdf_ximage_count); + pdf_create_obj(obj_type_ximage, pdf_ximage_count); + k := obj_ptr; + obj_data_ptr(k) := pdf_get_mem(pdfmem_ximage_size); + scan_alt_rule; {scans |<rule spec>| to |alt_rule|} + obj_ximage_width(k) := width(alt_rule); + obj_ximage_height(k) := height(alt_rule); + obj_ximage_depth(k) := depth(alt_rule); + if scan_keyword("attr") then begin + scan_pdf_ext_toks; + obj_ximage_attr(k) := def_ref; + end + else + obj_ximage_attr(k) := null; + named := 0; + if scan_keyword("named") then begin + scan_pdf_ext_toks; + named := tokens_to_string(def_ref); + delete_token_ref(def_ref); + end + else if scan_keyword("page") then begin + scan_int; + page := cur_val; + end + else + page := 1; + if scan_keyword("colorspace") then begin + scan_int; + colorspace := cur_val; + end + else + colorspace := 0; + scan_pdf_box_spec; {scans pdf-box-spec to |pdf_last_pdf_box_spec|} + scan_pdf_ext_toks; + s := tokens_to_string(def_ref); + delete_token_ref(def_ref); + if pdf_option_always_use_pdfpagebox <> 0 then begin + pdf_warning(0,"Primitive \pdfoptionalwaysusepdfpagebox is obsolete; use \pdfforcepagebox instead.",true); + pdf_force_pagebox := pdf_option_always_use_pdfpagebox; + pdf_option_always_use_pdfpagebox := 0; {warn once} + end; + if pdf_option_pdf_inclusion_errorlevel <> 0 then begin + pdf_warning(0,"Primitive \pdfoptionpdfinclusionerrorlevel is obsolete; use \pdfinclusionerrorlevel instead.",true); + pdf_inclusion_errorlevel := pdf_option_pdf_inclusion_errorlevel; + pdf_option_pdf_inclusion_errorlevel := 0; {warn once} + end; + if pdf_force_pagebox > 0 then begin + print_err("pdfTeX warning (image inclusion): "); + print ("\pdfforcepagebox is in use ("); + print_int (pdf_force_pagebox); + print (")"); + print_ln; + end; + obj_ximage_data(k) := read_image(s, page, named, colorspace, + pdf_minor_version, + pdf_force_pagebox, + pdf_inclusion_errorlevel); + if named <> 0 then flush_str(named); + flush_str(s); + scale_image(k); + pdf_last_ximage := k; + pdf_last_ximage_pages := image_pages(obj_ximage_data(k)); + pdf_last_ximage_colordepth := image_colordepth(obj_ximage_data(k)); +end; + +@ @<Implement \.{\\pdfximage}@>= +begin + check_pdfoutput("\pdfximage", true); + check_pdfminorversion; + scan_image; +end + +@ @<Implement \.{\\pdfrefximage}@>= +begin + check_pdfoutput("\pdfrefximage", true); + scan_int; + pdf_check_obj(obj_type_ximage, cur_val); + new_whatsit(pdf_refximage_node, pdf_refximage_node_size); + pdf_ximage_objnum(tail) := cur_val; + pdf_width(tail) := obj_ximage_width(cur_val); + pdf_height(tail) := obj_ximage_height(cur_val); + pdf_depth(tail) := obj_ximage_depth(cur_val); +end + +@ The following function finds object with identifier |i| and type |t|. + |i < 0| indicates that |-i| should be treated as a string number. 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 |pdf_ship_out| (to check whether a Page object already exists) so we need + to declare it together with subroutines needed in |pdf_hlist_out| and + |pdf_vlist_out|. + +@<Declare procedures that need to be declared forward for pdftex@>= +function find_obj(t, i: integer; byname: boolean): integer; +begin + find_obj := avl_find_obj(t, i, byname); +end; + +procedure flush_str(s: str_number); {flush a string if possible} +begin + if flushable(s) then + flush_string; +end; + +function get_obj(t, i: integer; byname: boolean): integer; +var r: integer; + s: str_number; +begin + if byname > 0 then begin + s := tokens_to_string(i); + r := find_obj(t, s, true); + end + else begin + s := 0; + r := find_obj(t, i, false); + end; + if r = 0 then begin + if byname > 0 then begin + pdf_create_obj(t, -s); + s := 0; + end + else + pdf_create_obj(t, i); + r := obj_ptr; + if t = obj_type_dest then + obj_dest_ptr(r) := null; + end; + if s <> 0 then + flush_str(s); + get_obj := r; +end; + +function get_microinterval:integer; +var s,@!m:integer; {seconds and microseconds} +begin + seconds_and_micros(s,m); + if (s-epochseconds)>32767 then + get_microinterval := max_integer + else if (microseconds>m) then + get_microinterval := ((s-1-epochseconds)*65536)+ (((m+1000000-microseconds)/100)*65536)/10000 + else + get_microinterval := ((s-epochseconds)*65536) + (((m-microseconds)/100)*65536)/10000; +end; + + +@ @<Declare procedures needed in |do_ext...@>= +function scan_action: pointer; {read an action specification} +var p, t: integer; + s: str_number; +begin + p := get_node(pdf_action_size); + scan_action := p; + pdf_action_file(p) := null; + pdf_action_refcount(p) := null; + if scan_keyword("user") then + pdf_action_type(p) := pdf_action_user + else if scan_keyword("goto") then + pdf_action_type(p) := pdf_action_goto + else if scan_keyword("thread") then + pdf_action_type(p) := pdf_action_thread + else + pdf_error("ext1", "action type missing"); + if pdf_action_type(p) = pdf_action_user then begin + scan_pdf_ext_toks; + pdf_action_user_tokens(p) := def_ref; + return; + end; + if scan_keyword("file") then begin + scan_pdf_ext_toks; + pdf_action_file(p) := def_ref; + end; + if scan_keyword("page") then begin + if pdf_action_type(p) <> pdf_action_goto then + pdf_error("ext1", "only GoTo action can be used with `page'"); + pdf_action_type(p) := pdf_action_page; + scan_int; + if cur_val <= 0 then + pdf_error("ext1", "page number must be positive"); + pdf_action_id(p) := cur_val; + pdf_action_named_id(p) := 0; + scan_pdf_ext_toks; + pdf_action_page_tokens(p) := def_ref; + end + else if scan_keyword("name") then begin + scan_pdf_ext_toks; + pdf_action_named_id(p) := 1; + pdf_action_id(p) := def_ref; + end + else if scan_keyword("num") then begin + if (pdf_action_type(p) = pdf_action_goto) and + (pdf_action_file(p) <> null) then + pdf_error("ext1", + "`goto' option cannot be used with both `file' and `num'"); + scan_int; + if cur_val <= 0 then + pdf_error("ext1", "num identifier must be positive"); + pdf_action_named_id(p) := 0; + pdf_action_id(p) := cur_val; + end + else + pdf_error("ext1", "identifier type missing"); + if scan_keyword("newwindow") then begin + pdf_action_new_window(p) := 1; + @<Scan an optional space@>; end + else if scan_keyword("nonewwindow") then begin + pdf_action_new_window(p) := 2; + @<Scan an optional space@>; end + else + pdf_action_new_window(p) := 0; + if (pdf_action_new_window(p) > 0) and + (((pdf_action_type(p) <> pdf_action_goto) and + (pdf_action_type(p) <> pdf_action_page)) or + (pdf_action_file(p) = null)) then + pdf_error("ext1", + "`newwindow'/`nonewwindow' must be used with `goto' and `file' option"); +end; + +procedure new_annot_whatsit(w, s: small_number); {create a new whatsit node for +annotation} +var p: pointer; +begin + new_whatsit(w, s); + scan_alt_rule; {scans |<rule spec>| to |alt_rule|} + pdf_width(tail) := width(alt_rule); + pdf_height(tail) := height(alt_rule); + pdf_depth(tail) := depth(alt_rule); + if (w = pdf_start_link_node) then begin + if scan_keyword("attr") then begin + scan_pdf_ext_toks; + pdf_link_attr(tail) := def_ref; + end + else + pdf_link_attr(tail) := null; + end; + if (w = pdf_thread_node) or (w = pdf_start_thread_node) then begin + if scan_keyword("attr") then begin + scan_pdf_ext_toks; + pdf_thread_attr(tail) := def_ref; + end + else + pdf_thread_attr(tail) := null; + end; +end; + +@ @<Glob...@>= +@!pdf_last_annot: integer; + +@ @<Implement \.{\\pdfannot}@>= +begin + check_pdfoutput("\pdfannot", true); + if scan_keyword("reserveobjnum") then begin + pdf_last_annot := pdf_new_objnum; + @<Scan an optional space@>; end + else begin + if scan_keyword("useobjnum") then begin + scan_int; + k := cur_val; + if (k <= 0) or (k > obj_ptr) or (obj_annot_ptr(k) <> 0) then + pdf_error("ext1", "invalid object number"); + end + else + k := pdf_new_objnum; + new_annot_whatsit(pdf_annot_node, pdf_annot_node_size); + pdf_annot_objnum(tail) := k; + scan_pdf_ext_toks; + pdf_annot_data(tail) := def_ref; + pdf_last_annot := k; + end +end + +@ @<Implement \.{\\pdfstartlink}@>= +begin + check_pdfoutput("\pdfstartlink", true); + if abs(mode) = vmode then + pdf_error("ext1", "\pdfstartlink cannot be used in vertical mode"); + new_annot_whatsit(pdf_start_link_node, pdf_annot_node_size); + pdf_link_action(tail) := scan_action; +end + +@ @<Implement \.{\\pdfendlink}@>= +begin + check_pdfoutput("\pdfendlink", true); + if abs(mode) = vmode then + pdf_error("ext1", "\pdfendlink cannot be used in vertical mode"); + new_whatsit(pdf_end_link_node, small_node_size); +end + +@ @<Declare procedures needed in |do_ext...@>= +function outline_list_count(p: pointer): integer; {return number of outline +entries in the same level with |p|} +var k: integer; +begin + k := 1; + while obj_outline_prev(p) <> 0 do begin + incr(k); + p := obj_outline_prev(p); + end; + outline_list_count := k; +end; + +@ @<Implement \.{\\pdfoutline}@>= +begin + check_pdfoutput("\pdfoutline", true); + if scan_keyword("attr") then begin + scan_pdf_ext_toks; + r := def_ref; + end + else + r := 0; + p := scan_action; + if scan_keyword("count") then begin + scan_int; + i := cur_val; + end + else + i := 0; + scan_pdf_ext_toks; + q := def_ref; + pdf_new_obj(obj_type_others, 0); + j := obj_ptr; + write_action(p); + pdf_end_obj; + delete_action_ref(p); + pdf_create_obj(obj_type_outline, 0); + k := obj_ptr; + obj_outline_ptr(k) := pdf_get_mem(pdfmem_outline_size); + obj_outline_action_objnum(k) := j; + obj_outline_count(k) := i; + pdf_new_obj(obj_type_others, 0); + pdf_print_str_ln(tokens_to_string(q)); + flush_str(last_tokens_string); + delete_token_ref(q); + pdf_end_obj; + obj_outline_title(k) := obj_ptr; + obj_outline_prev(k) := 0; + obj_outline_next(k) := 0; + obj_outline_first(k) := 0; + obj_outline_last(k) := 0; + obj_outline_parent(k) := pdf_parent_outline; + obj_outline_attr(k) := r; + if pdf_first_outline = 0 then + pdf_first_outline := k; + if pdf_last_outline = 0 then begin + if pdf_parent_outline <> 0 then + obj_outline_first(pdf_parent_outline) := k; + end + else begin + obj_outline_next(pdf_last_outline) := k; + obj_outline_prev(k) := pdf_last_outline; + end; + pdf_last_outline := k; + if obj_outline_count(k) <> 0 then begin + pdf_parent_outline := k; + pdf_last_outline := 0; + end + else if (pdf_parent_outline <> 0) and + (outline_list_count(k) = abs(obj_outline_count(pdf_parent_outline))) then + begin + j := pdf_last_outline; + repeat + obj_outline_last(pdf_parent_outline) := j; + j := pdf_parent_outline; + pdf_parent_outline := obj_outline_parent(pdf_parent_outline); + until (pdf_parent_outline = 0) or + (outline_list_count(j) < abs(obj_outline_count(pdf_parent_outline))); + if pdf_parent_outline = 0 then + pdf_last_outline := pdf_first_outline + else + pdf_last_outline := obj_outline_first(pdf_parent_outline); + while obj_outline_next(pdf_last_outline) <> 0 do + pdf_last_outline := obj_outline_next(pdf_last_outline); + end; +end + +@ When a destination is created we need to check whether another destination +with the same identifier already exists and give a warning if needed. + +@<Declare procedures needed in |pdf_hlist_out|, |pdf_vlist_out|@>= +procedure warn_dest_dup(id: integer; byname: small_number; s1, s2: str_number); +begin + pdf_warning(s1, "destination with the same identifier (", false); + if byname > 0 then begin + print("name"); + print_mark(id); + end + else begin + print("num"); + print_int(id); + end; + print(") "); + print(s2); + print_ln; + show_context; +end; + +@ Notice that |scan_keyword| doesn't care if two words have same prefix; so +we should be careful when scan keywords with same prefix. The main rule: if +there are two or more keywords with the same prefix, then always test in +order from the longest one to the shortest one. + +@<Implement \.{\\pdfdest}@>= +begin + check_pdfoutput("\pdfdest", true); + q := tail; + new_whatsit(pdf_dest_node, pdf_dest_node_size); + if scan_keyword("num") then begin + scan_int; + if cur_val <= 0 then + pdf_error("ext1", "num identifier must be positive"); + if cur_val > max_halfword then + pdf_error("ext1", "number too big"); + pdf_dest_id(tail) := cur_val; + pdf_dest_named_id(tail) := 0; + end + else if scan_keyword("name") then begin + scan_pdf_ext_toks; + pdf_dest_id(tail) := def_ref; + pdf_dest_named_id(tail) := 1; + end + else + pdf_error("ext1", "identifier type missing"); + if scan_keyword("xyz") then begin + pdf_dest_type(tail) := pdf_dest_xyz; + if scan_keyword("zoom") then begin + scan_int; + if cur_val > max_halfword then + pdf_error("ext1", "number too big"); + pdf_dest_xyz_zoom(tail) := cur_val; + end + else + pdf_dest_xyz_zoom(tail) := null; + end + else if scan_keyword("fitbh") then + pdf_dest_type(tail) := pdf_dest_fitbh + else if scan_keyword("fitbv") then + pdf_dest_type(tail) := pdf_dest_fitbv + else if scan_keyword("fitb") then + pdf_dest_type(tail) := pdf_dest_fitb + else if scan_keyword("fith") then + pdf_dest_type(tail) := pdf_dest_fith + else if scan_keyword("fitv") then + pdf_dest_type(tail) := pdf_dest_fitv + else if scan_keyword("fitr") then + pdf_dest_type(tail) := pdf_dest_fitr + else if scan_keyword("fit") then + pdf_dest_type(tail) := pdf_dest_fit + else + pdf_error("ext1", "destination type missing"); + @<Scan an optional space@>; + if pdf_dest_type(tail) = pdf_dest_fitr then begin + scan_alt_rule; {scans |<rule spec>| to |alt_rule|} + pdf_width(tail) := width(alt_rule); + pdf_height(tail) := height(alt_rule); + pdf_depth(tail) := depth(alt_rule); + end; + if pdf_dest_named_id(tail) <> 0 then begin + i := tokens_to_string(pdf_dest_id(tail)); + k := find_obj(obj_type_dest, i, true); + flush_str(i); + end + else + k := find_obj(obj_type_dest, pdf_dest_id(tail), false); + if (k <> 0) and (obj_dest_ptr(k) <> null) then begin + warn_dest_dup(pdf_dest_id(tail), pdf_dest_named_id(tail), + "ext4", "has been already used, duplicate ignored"); + flush_node_list(tail); + tail := q; + link(q) := null; + end; +end + +@ @<Declare procedures needed in |do_ext...@>= +procedure scan_thread_id; +begin + if scan_keyword("num") then begin + scan_int; + if cur_val <= 0 then + pdf_error("ext1", "num identifier must be positive"); + if cur_val > max_halfword then + pdf_error("ext1", "number too big"); + pdf_thread_id(tail) := cur_val; + pdf_thread_named_id(tail) := 0; + end + else if scan_keyword("name") then begin + scan_pdf_ext_toks; + pdf_thread_id(tail) := def_ref; + pdf_thread_named_id(tail) := 1; + end + else + pdf_error("ext1", "identifier type missing"); +end; + +@ @<Implement \.{\\pdfthread}@>= +begin + check_pdfoutput("\pdfthread", true); + new_annot_whatsit(pdf_thread_node, pdf_thread_node_size); + scan_thread_id; +end + +@ @<Implement \.{\\pdfstartthread}@>= +begin + check_pdfoutput("\pdfstartthread", true); + new_annot_whatsit(pdf_start_thread_node, pdf_thread_node_size); + scan_thread_id; +end + +@ @<Implement \.{\\pdfendthread}@>= +begin + check_pdfoutput("\pdfendthread", true); + new_whatsit(pdf_end_thread_node, small_node_size); +end + +@ @<Glob...@>= +@!pdf_last_x_pos: integer; +@!pdf_last_y_pos: integer; + +@ @<Implement \.{\\pdfsavepos}@>= +begin + check_pdfoutput("\pdfsavepos", true); + new_whatsit(pdf_save_pos_node, small_node_size); +end + +@ To implement primitives as \.{\\pdfinfo}, \.{\\pdfcatalog} or +\.{\\pdfnames} we need to concatenate tokens lists. + +@<Declare procedures needed in |do_ext...@>= +function concat_tokens(q, r: pointer): pointer; {concat |q| and |r| and +returns the result tokens list} +var p: pointer; +begin + if q = null then begin + concat_tokens := r; + return; + end; + p := q; + while link(p) <> null do + p := link(p); + link(p) := link(r); + free_avail(r); + concat_tokens := q; +end; + +@ @<Implement \.{\\pdfinfo}@>= +begin + check_pdfoutput("\pdfinfo", false); + scan_pdf_ext_toks; + if pdf_output > 0 then + pdf_info_toks := concat_tokens(pdf_info_toks, def_ref); +end + +@ @<Implement \.{\\pdfcatalog}@>= +begin + check_pdfoutput("\pdfcatalog", false); + scan_pdf_ext_toks; + if pdf_output > 0 then + pdf_catalog_toks := concat_tokens(pdf_catalog_toks, def_ref); + if scan_keyword("openaction") then + if pdf_catalog_openaction <> 0 then + pdf_error("ext1", "duplicate of openaction") + else begin + p := scan_action; + pdf_new_obj(obj_type_others, 0); + if pdf_output > 0 then + pdf_catalog_openaction := obj_ptr; + write_action(p); + pdf_end_obj; + delete_action_ref(p); + end; +end + +@ @<Implement \.{\\pdfnames}@>= +begin + check_pdfoutput("\pdfnames", true); + scan_pdf_ext_toks; + pdf_names_toks := concat_tokens(pdf_names_toks, def_ref); +end + +@ @<Implement \.{\\pdftrailer}@>= +begin + check_pdfoutput("\pdftrailer", false); + scan_pdf_ext_toks; + if pdf_output > 0 then + pdf_trailer_toks := concat_tokens(pdf_trailer_toks, def_ref); +end + +@ @<Implement \.{\\pdfescapestring}@>= +begin + scan_pdf_ext_toks; + escapestr(tokens_to_string(def_ref)); + flush_str(last_tokens_string); + delete_token_ref(def_ref); +end + +@ @<Implement \.{\\pdfescapename}@>= +begin + scan_pdf_ext_toks; + escapename(tokens_to_string(def_ref)); + flush_str(last_tokens_string); + delete_token_ref(def_ref); +end + +@ @<Glob...@>= +@!pdf_retval: integer; {global multi-purpose return value} + +@ @<Implement \.{\\pdfstrcmp}@>= +compare_strings + +@ @<Set initial values of key variables@>= + seconds_and_micros(epochseconds,microseconds); + +@ @<Implement \.{\\pdfresettimer}@>= +begin + seconds_and_micros(epochseconds,microseconds); +end + + +@ The following subroutines are about PDF-specific font issues. + +@<Declare procedures needed in |do_ext...@>= +procedure pdf_include_chars; +var s: str_number; + k: pool_pointer; {running indices} + f: internal_font_number; +begin + scan_font_ident; + f := cur_val; + if f = null_font then + pdf_error("font", "invalid font identifier"); + pdf_check_vf(f); + if not font_used[f] then + pdf_init_font(f); + scan_pdf_ext_toks; + s := tokens_to_string(def_ref); + delete_token_ref(def_ref); + k := str_start[s]; + while k < str_start[s + 1] do begin + pdf_mark_char(f, str_pool[k]); + incr(k); + end; + flush_str(s); +end; + + +@ @<Implement \.{\\pdfincludechars}@>= +begin + check_pdfoutput("\pdfincludechars", true); + pdf_include_chars; +end + +@ @<Implement \.{\\pdffontattr}@>= +begin + check_pdfoutput("\pdffontattr", true); + scan_font_ident; + k := cur_val; + if k = null_font then + pdf_error("font", "invalid font identifier"); + scan_pdf_ext_toks; + pdf_font_attr[k] := tokens_to_string(def_ref); +end + +@ @<Implement \.{\\pdfmapfile}@>= +begin + check_pdfoutput("\pdfmapfile", true); + scan_pdf_ext_toks; + pdfmapfile(def_ref); + delete_token_ref(def_ref); +end + +@ @<Implement \.{\\pdfmapline}@>= +begin + check_pdfoutput("\pdfmapline", true); + scan_pdf_ext_toks; + pdfmapline(def_ref); + delete_token_ref(def_ref); +end + +@ The following function are needed for outputing article thread. + +@<Declare procedures needed in |do_ext...@>= +procedure thread_title(thread: integer); +begin + pdf_print("/Title ("); + if obj_info(thread) < 0 then + pdf_print(-obj_info(thread)) + else + pdf_print_int(obj_info(thread)); + pdf_print_ln(")"); +end; + +procedure pdf_fix_thread(thread: integer); +var a: pointer; +begin + pdf_warning("thread", "destination ", false); + if obj_info(thread) < 0 then begin + print("name{"); + print(-obj_info(thread)); + print("}"); + end + else begin + print("num"); + print_int(obj_info(thread)); + end; + print(" has been referenced but does not exist, replaced by a fixed one"); + print_ln; print_ln; + pdf_new_dict(obj_type_others, 0); + a := obj_ptr; + pdf_indirect_ln("T", thread); + pdf_indirect_ln("V", a); + pdf_indirect_ln("N", a); + pdf_indirect_ln("P", head_tab[obj_type_page]); + pdf_print("/R [0 0 "); + pdf_print_bp(pdf_page_width); pdf_out(" "); + pdf_print_bp(pdf_page_height); + pdf_print_ln("]"); + pdf_end_dict; + pdf_begin_dict(thread); + pdf_print_ln("/I << "); + thread_title(thread); + pdf_print_ln(">>"); + pdf_indirect_ln("F", a); + pdf_end_dict; +end; + +procedure out_thread(thread: integer); +var a, b, c: pointer; + last_attr: integer; +begin + if obj_thread_first(thread) = 0 then begin + pdf_fix_thread(thread); + return; + end; + pdf_begin_dict(thread); + a := obj_thread_first(thread); + b := a; + last_attr := 0; + repeat + if obj_bead_attr(a) <> 0 then + last_attr := obj_bead_attr(a); + a := obj_bead_next(a); + until a = b; + if last_attr <> 0 then + pdf_print_ln(last_attr) + else begin + pdf_print_ln("/I << "); + thread_title(thread); + pdf_print_ln(">>"); + end; + pdf_indirect_ln("F", a); + pdf_end_dict; + repeat + pdf_begin_dict(a); + if a = b then + pdf_indirect_ln("T", thread); + pdf_indirect_ln("V", obj_bead_prev(a)); + pdf_indirect_ln("N", obj_bead_next(a)); + pdf_indirect_ln("P", obj_bead_page(a)); + pdf_indirect_ln("R", obj_bead_rect(a)); + pdf_end_dict; + a := obj_bead_next(a); + until a = b; +end; + +@ @<Display <rule spec> for whatsit node created by \pdfTeX@>= +print("("); +print_rule_dimen(pdf_height(p)); +print_char("+"); +print_rule_dimen(pdf_depth(p)); +print(")x"); +print_rule_dimen(pdf_width(p)) +@z + +@x [1356] +othercases print("whatsit?") +@y +pdf_literal_node: begin + print_esc("pdfliteral"); + case pdf_literal_mode(p) of + reset_origin: + do_nothing; + direct_page: + print(" page"); + direct_always: + print(" direct"); + othercases confusion("literal2") + endcases; + print_mark(pdf_literal_data(p)); +end; +pdf_refobj_node: begin + print_esc("pdfrefobj"); + if obj_obj_is_stream(pdf_obj_objnum(p)) > 0 then begin + if obj_obj_stream_attr(pdf_obj_objnum(p)) <> null then begin + print(" attr"); + print_mark(obj_obj_stream_attr(pdf_obj_objnum(p))); + end; + print(" stream"); + end; + if obj_obj_is_file(pdf_obj_objnum(p)) > 0 then + print(" file"); + print_mark(obj_obj_data(pdf_obj_objnum(p))); +end; +pdf_refxform_node: begin + print_esc("pdfrefxform"); + print("("); + print_scaled(obj_xform_height(pdf_xform_objnum(p))); + print_char("+"); + print_scaled(obj_xform_depth(pdf_xform_objnum(p))); + print(")x"); + print_scaled(obj_xform_width(pdf_xform_objnum(p))); +end; +pdf_refximage_node: begin + print_esc("pdfrefximage"); + print("("); + print_scaled(obj_ximage_height(pdf_ximage_objnum(p))); + print_char("+"); + print_scaled(obj_ximage_depth(pdf_ximage_objnum(p))); + print(")x"); + print_scaled(obj_ximage_width(pdf_ximage_objnum(p))); +end; +pdf_annot_node: begin + print_esc("pdfannot"); + @<Display <rule spec> for whatsit node created by \pdfTeX@>; + print_mark(pdf_annot_data(p)); +end; +pdf_start_link_node: begin + print_esc("pdflink"); + @<Display <rule spec> for whatsit node created by \pdfTeX@>; + if pdf_link_attr(p) <> null then begin + print(" attr"); + print_mark(pdf_link_attr(p)); + end; + print(" action"); + if pdf_action_type(pdf_link_action(p)) = pdf_action_user then begin + print(" user"); + print_mark(pdf_action_user_tokens(pdf_link_action(p))); + return; + end; + if pdf_action_file(pdf_link_action(p)) <> null then begin + print(" file"); + print_mark(pdf_action_file(pdf_link_action(p))); + end; + case pdf_action_type(pdf_link_action(p)) of + pdf_action_goto: begin + if pdf_action_named_id(pdf_link_action(p)) > 0 then begin + print(" goto name"); + print_mark(pdf_action_id(pdf_link_action(p))); + end + else begin + print(" goto num"); + print_int(pdf_action_id(pdf_link_action(p))) + end; + end; + pdf_action_page: begin + print(" page"); + print_int(pdf_action_id(pdf_link_action(p))); + print_mark(pdf_action_page_tokens(pdf_link_action(p))); + end; + pdf_action_thread: begin + if pdf_action_named_id(pdf_link_action(p)) > 0 then begin + print(" thread name"); + print_mark(pdf_action_id(pdf_link_action(p))); + end + else begin + print(" thread num"); + print_int(pdf_action_id(pdf_link_action(p))); + end; + end; + othercases pdf_error("displaying", "unknown action type"); + endcases; +end; +pdf_end_link_node: print_esc("pdfendlink"); +pdf_dest_node: begin + print_esc("pdfdest"); + if pdf_dest_named_id(p) > 0 then begin + print(" name"); + print_mark(pdf_dest_id(p)); + end + else begin + print(" num"); + print_int(pdf_dest_id(p)); + end; + print(" "); + case pdf_dest_type(p) of + pdf_dest_xyz: begin + print("xyz"); + if pdf_dest_xyz_zoom(p) <> null then begin + print(" zoom"); + print_int(pdf_dest_xyz_zoom(p)); + end; + end; + pdf_dest_fitbh: print("fitbh"); + pdf_dest_fitbv: print("fitbv"); + pdf_dest_fitb: print("fitb"); + pdf_dest_fith: print("fith"); + pdf_dest_fitv: print("fitv"); + pdf_dest_fitr: begin + print("fitr"); + @<Display <rule spec> for whatsit node created by \pdfTeX@>; + end; + pdf_dest_fit: print("fit"); + othercases print("unknown!"); + endcases; +end; +pdf_thread_node, +pdf_start_thread_node: begin + if subtype(p) = pdf_thread_node then + print_esc("pdfthread") + else + print_esc("pdfstartthread"); + print("("); print_rule_dimen(pdf_height(p)); print_char("+"); + print_rule_dimen(pdf_depth(p)); print(")x"); + print_rule_dimen(pdf_width(p)); + if pdf_thread_attr(p) <> null then begin + print(" attr"); + print_mark(pdf_thread_attr(p)); + end; + if pdf_thread_named_id(p) > 0 then begin + print(" name"); + print_mark(pdf_thread_id(p)); + end + else begin + print(" num"); + print_int(pdf_thread_id(p)); + end; +end; +pdf_end_thread_node: print_esc("pdfendthread"); +pdf_save_pos_node: print_esc("pdfsavepos"); +othercases print("whatsit?") +@z + +@x [1357] +othercases confusion("ext2") +@y +pdf_literal_node: begin + r := get_node(write_node_size); + add_token_ref(pdf_literal_data(p)); + words := write_node_size; +end; +pdf_refobj_node: begin + r := get_node(pdf_refobj_node_size); + words := pdf_refobj_node_size; +end; +pdf_refxform_node: begin + r := get_node(pdf_refxform_node_size); + words := pdf_refxform_node_size; +end; +pdf_refximage_node: begin + r := get_node(pdf_refximage_node_size); + words := pdf_refximage_node_size; +end; +pdf_annot_node: begin + r := get_node(pdf_annot_node_size); + add_token_ref(pdf_annot_data(p)); + words := pdf_annot_node_size; +end; +pdf_start_link_node: begin + r := get_node(pdf_annot_node_size); + pdf_height(r) := pdf_height(p); + pdf_depth(r) := pdf_depth(p); + pdf_width(r) := pdf_width(p); + pdf_link_attr(r) := pdf_link_attr(p); + if pdf_link_attr(r) <> null then + add_token_ref(pdf_link_attr(r)); + pdf_link_action(r) := pdf_link_action(p); + add_action_ref(pdf_link_action(r)); +end; +pdf_end_link_node: + r := get_node(small_node_size); +pdf_dest_node: begin + r := get_node(pdf_dest_node_size); + if pdf_dest_named_id(p) > 0 then + add_token_ref(pdf_dest_id(p)); + words := pdf_dest_node_size; +end; +pdf_thread_node, +pdf_start_thread_node: begin + r := get_node(pdf_thread_node_size); + if pdf_thread_named_id(p) > 0 then + add_token_ref(pdf_thread_id(p)); + if pdf_thread_attr(p) <> null then + add_token_ref(pdf_thread_attr(p)); + words := pdf_thread_node_size; +end; +pdf_end_thread_node: + r := get_node(small_node_size); +pdf_save_pos_node: + r := get_node(small_node_size); +othercases confusion("ext2") +@z + +@x [1358] +othercases confusion("ext3") +@y +pdf_literal_node: begin + delete_token_ref(pdf_literal_data(p)); + free_node(p, write_node_size); +end; +pdf_refobj_node: + free_node(p, pdf_refobj_node_size); +pdf_refxform_node: + free_node(p, pdf_refxform_node_size); +pdf_refximage_node: + free_node(p, pdf_refximage_node_size); +pdf_annot_node: begin + delete_token_ref(pdf_annot_data(p)); + free_node(p, pdf_annot_node_size); +end; +pdf_start_link_node: begin + if pdf_link_attr(p) <> null then + delete_token_ref(pdf_link_attr(p)); + delete_action_ref(pdf_link_action(p)); + free_node(p, pdf_annot_node_size); +end; +pdf_end_link_node: + free_node(p, small_node_size); +pdf_dest_node: begin + if pdf_dest_named_id(p) > 0 then + delete_token_ref(pdf_dest_id(p)); + free_node(p, pdf_dest_node_size); +end; +pdf_thread_node, +pdf_start_thread_node: begin + if pdf_thread_named_id(p) > 0 then + delete_token_ref(pdf_thread_id(p)); + if pdf_thread_attr(p) <> null then + delete_token_ref(pdf_thread_attr(p)); + free_node(p, pdf_thread_node_size); +end; +pdf_end_thread_node: + free_node(p, small_node_size); +pdf_save_pos_node: + free_node(p, small_node_size); +othercases confusion("ext3") +@z + +@x [1359] +@ @<Incorporate a whatsit node into a vbox@>=do_nothing +@y +@ @<Incorporate a whatsit node into a vbox@>= +if (subtype(p) = pdf_refxform_node) or (subtype(p) = pdf_refximage_node) then +begin x:=x+d+pdf_height(p); d:=pdf_depth(p); +s:=0; +if pdf_width(p)+s>w then w:=pdf_width(p)+s; +end +@z + +@x [1360] +@ @<Incorporate a whatsit node into an hbox@>=do_nothing +@y +@ @<Incorporate a whatsit node into an hbox@>= +if (subtype(p) = pdf_refxform_node) or (subtype(p) = pdf_refximage_node) then +begin x:=x+pdf_width(p); +s:=0; +if pdf_height(p)-s>h then h:=pdf_height(p)-s; +if pdf_depth(p)+s>d then d:=pdf_depth(p)+s; +end +@z + +@x [1361] +@ @<Let |d| be the width of the whatsit |p|@>=d:=0 +@y +@ @<Let |d| be the width of the whatsit |p|@>= +if (subtype(p) = pdf_refxform_node) or (subtype(p) = pdf_refximage_node) then + d := pdf_width(p) +else + d := 0 +@z + +@x [1362] +@<Advance \(p)past a whatsit node in the \(l)|line_break| loop@>=@+ +adv_past(cur_p) +@y +@<Advance \(p)past a whatsit node in the \(l)|line_break| loop@>=@+ +begin +adv_past(cur_p); +if (subtype(cur_p) = pdf_refxform_node) or (subtype(cur_p) = pdf_refximage_node) then + act_width:=act_width+pdf_width(cur_p); +end +@z + +@x [1364] +@ @<Prepare to move whatsit |p| to the current page, then |goto contribute|@>= +goto contribute +@y +@ @<Prepare to move whatsit |p| to the current page, then |goto contribute|@>= +begin + if (subtype(p) = pdf_refxform_node) or (subtype(p) = pdf_refximage_node) then + begin page_total:=page_total+page_depth+pdf_height(p); + page_depth:=pdf_depth(p); + end; + goto contribute; +end +@z + +@x [1365] +@ @<Process whatsit |p| in |vert_break| loop, |goto not_found|@>= +goto not_found +@y +@ @<Process whatsit |p| in |vert_break| loop, |goto not_found|@>= +begin + if (subtype(p) = pdf_refxform_node) or (subtype(p) = pdf_refximage_node) then + begin cur_height:=cur_height+prev_dp+pdf_height(p); prev_dp:=pdf_depth(p); + end; + goto not_found; +end +@z + +@x [1375] +@<Implement \.{\\immediate}@>= +begin get_x_token; +if (cur_cmd=extension)and(cur_chr<=close_node) then + begin p:=tail; do_extension; {append a whatsit node} + out_what(tail); {do the action immediately} + flush_node_list(tail); tail:=p; link(p):=null; + end +else back_input; +end +@y +@<Implement \.{\\immediate}@>= +begin get_x_token; +if cur_cmd=extension then begin + if cur_chr<=close_node then + begin p:=tail; do_extension; {append a whatsit node} + out_what(tail); {do the action immediately} + flush_node_list(tail); tail:=p; link(p):=null; + end + else case cur_chr of + pdf_obj_code: begin + do_extension; {scan object and set |pdf_last_obj|} + if obj_data_ptr(pdf_last_obj) = 0 then {this object has not been initialized yet} + pdf_error("ext1", "`\pdfobj reserveobjnum' cannot be used with \immediate"); + pdf_write_obj(pdf_last_obj); + end; + pdf_xform_code: begin + do_extension; {scan form and set |pdf_last_xform|} + pdf_cur_form := pdf_last_xform; + pdf_ship_out(obj_xform_box(pdf_last_xform), false); + end; + pdf_ximage_code: begin + do_extension; {scan image and set |pdf_last_ximage|} + pdf_write_image(pdf_last_ximage); + end; + othercases back_input + endcases; +end +else + back_input; +end +@z + +@x [1378] +@ @<Finish the extensions@>= +for k:=0 to 15 do if write_open[k] then a_close(write_file[k]) +@y +@ @<Finish the extensions@>= +for k:=0 to 15 do if write_open[k] then a_close(write_file[k]) + +@ Shipping out PDF marks. + +@<Types...@>= +dest_name_entry = record + objname: str_number; {destination name} + objnum: integer; {destination object number} +end; + +@ @<Glob...@>= +@!cur_page_width: scaled; {width of page being shipped} +@!cur_page_height: scaled; {height of page being shipped} +@!cur_h_offset: scaled; {horizontal offset of page being shipped} +@!cur_v_offset: scaled; {vertical offset of page being shipped} +@!pdf_obj_list: pointer; {list of objects in the current page} +@!pdf_xform_list: pointer; {list of forms in the current page} +@!pdf_ximage_list: pointer; {list of images in the current page} +@!pdf_link_level: integer; {depth of nesting of box containing link annotation} +@!last_link: pointer; {pointer to the last link annotation} +@!pdf_link_ht, pdf_link_dp, pdf_link_wd: scaled; {dimensions of the last link +annotation} +@!last_thread: pointer; {pointer to the last thread} +@!pdf_thread_ht, pdf_thread_dp, pdf_thread_wd: scaled; {dimensions of the last +thread} +@!pdf_last_thread_id: halfword; {identifier of the last thread} +@!pdf_last_thread_named_id: boolean; {is identifier of the last thread named} +@!pdf_thread_level: integer; {depth of nesting of box containing the last thread} +@!pdf_annot_list: pointer; {list of annotations in the current page} +@!pdf_link_list: pointer; {list of link annotations in the current page} +@!pdf_dest_list: pointer; {list of destinations in the current page} +@!pdf_bead_list: pointer; {list of thread beads in the current page} +@!pdf_obj_count: integer; {counter of objects} +@!pdf_xform_count: integer; {counter of forms} +@!pdf_ximage_count: integer; {counter of images} +@!pdf_cur_form: integer; {the form being output} +@!pdf_first_outline, pdf_last_outline, pdf_parent_outline: integer; +@!pdf_xform_width, +@!pdf_xform_height, +@!pdf_xform_depth: scaled; {dimension of the current form} +@!pdf_info_toks: pointer; {additional keys of Info dictionary} +@!pdf_catalog_toks: pointer; {additional keys of Catalog dictionary} +@!pdf_catalog_openaction: integer; +@!pdf_names_toks: pointer; {additional keys of Names dictionary} +@!pdf_dest_names_ptr: integer; {first unused position in |dest_names|} +@!dest_names_size: integer; {maximum number of names in name tree of PDF output file} +@!dest_names: ^dest_name_entry; +@!image_orig_x, image_orig_y: integer; {origin of cropped pdf images} +@!link_level_stack: pointer; {stack to save |pdf_link_level|} +@!pdf_trailer_toks: pointer; {additional keys of Trailer dictionary} + +@ @<Set init...@>= +pdf_link_level := -1; +link_level_stack := null; +pdf_first_outline:= 0; +pdf_last_outline:= 0; +pdf_parent_outline:= 0; +pdf_obj_count := 0; +pdf_xform_count := 0; +pdf_ximage_count := 0; +pdf_dest_names_ptr := 0; +pdf_info_toks := null; +pdf_catalog_toks := null; +pdf_names_toks := null; +pdf_catalog_openaction := 0; +pdf_trailer_toks := null; + +@ The following procedures are needed for outputing whatsit nodes for +pdfTeX. + +@<Declare procedures needed in |pdf_hlist_out|, |pdf_vlist_out|@>= +procedure write_action(p: pointer); {write an action specification} +var s: str_number; + d: integer; +begin + if pdf_action_type(p) = pdf_action_user then begin + pdf_print_toks_ln(pdf_action_user_tokens(p)); + return; + end; + pdf_print("<< "); + if pdf_action_file(p) <> null then begin + pdf_print("/F "); + s := tokens_to_string(pdf_action_file(p)); + if (str_pool[str_start[s]] = 40) and + (str_pool[str_start[s] + length(s) - 1] = 41) then + pdf_print(s) + else begin + pdf_print_str(s); + end; + flush_str(s); + pdf_print(" "); + if pdf_action_new_window(p) > 0 then begin + pdf_print("/NewWindow "); + if pdf_action_new_window(p) = 1 then + pdf_print("true ") + else + pdf_print("false "); + end; + end; + case pdf_action_type(p) of + pdf_action_page: begin + if pdf_action_file(p) = null then begin + pdf_print("/S /GoTo /D ["); + pdf_print_int(get_obj(obj_type_page, pdf_action_id(p), false)); + pdf_print(" 0 R"); + end + else begin + pdf_print("/S /GoToR /D ["); + pdf_print_int(pdf_action_id(p) - 1); + end; + pdf_out(" "); + pdf_print(tokens_to_string(pdf_action_page_tokens(p))); + flush_str(last_tokens_string); + pdf_out("]"); + end; + pdf_action_goto: begin + if pdf_action_file(p) = null then begin + pdf_print("/S /GoTo "); + d := get_obj(obj_type_dest, pdf_action_id(p), + pdf_action_named_id(p)); + end + else + pdf_print("/S /GoToR "); + if pdf_action_named_id(p) > 0 then begin + pdf_str_entry("D", tokens_to_string(pdf_action_id(p))); + flush_str(last_tokens_string); + end + else if pdf_action_file(p) = null then + pdf_indirect("D", d) + else + pdf_error("ext4", "`goto' option cannot be used with both `file' and `num'"); + end; + pdf_action_thread: begin + pdf_print("/S /Thread "); + if pdf_action_file(p) = null then + d := get_obj(obj_type_thread, pdf_action_id(p), + pdf_action_named_id(p)); + if pdf_action_named_id(p) > 0 then begin + pdf_str_entry("D", tokens_to_string(pdf_action_id(p))); + flush_str(last_tokens_string); + end + else if pdf_action_file(p) = null then + pdf_indirect("D", d) + else + pdf_int_entry("D", pdf_action_id(p)); + end; + endcases; + pdf_print_ln(" >>"); +end; + +procedure set_rect_dimens(p, parent_box: pointer; x, y, w, h, d, margin: scaled); +begin + pdf_left(p) := cur_h; + if is_running(w) then + pdf_right(p) := x + width(parent_box) + else + pdf_right(p) := cur_h + w; + if is_running(h) then + pdf_top(p) := y - height(parent_box) + else + pdf_top(p) := cur_v - h; + if is_running(d) then + pdf_bottom(p) := y + depth(parent_box) + else + pdf_bottom(p) := cur_v + d; + pdf_left(p) := pdf_left(p) - margin; + pdf_top(p) := pdf_top(p) - margin; + pdf_right(p) := pdf_right(p) + margin; + pdf_bottom(p) := pdf_bottom(p) + margin; +end; + +procedure do_annot(p, parent_box: pointer; x, y: scaled); +begin + if not is_shipping_page then + pdf_error("ext4", "annotations cannot be inside an XForm"); + if doing_leaders then + return; + set_rect_dimens(p, parent_box, x, y, + pdf_width(p), pdf_height(p), pdf_depth(p), 0); + obj_annot_ptr(pdf_annot_objnum(p)) := p; + pdf_append_list(pdf_annot_objnum(p))(pdf_annot_list); +end; + +@ To implement nesting link annotations, we need a stack to save box testing +level of each link that has been broken. Each stack entry holds the +box nesting level and pointer the whatsit node created for +corresponding \.{\\pdfstartlink}. + +@d link_level(#) == info(#) +@d link_ptr(#) == info(# + 1) + +@<Declare procedures needed in |pdf_hlist_out|, |pdf_vlist_out|@>= +procedure save_link_level(l: pointer); +var p, r: pointer; +begin + pdf_link_level := cur_s; + r := copy_node_list(l); + pdf_link_wd := pdf_width(r); + pdf_link_ht := pdf_height(r); + pdf_link_dp := pdf_depth(r); + p := get_node(small_node_size); + link_level(p) := pdf_link_level; + link_ptr(p) := r; + link(p) := link_level_stack; + link_level_stack := p; +end; + +procedure do_link(p, parent_box: pointer; x, y: scaled); +begin + if not is_shipping_page then + pdf_error("ext4", "link annotations cannot be inside an XForm"); + if type(parent_box) <> hlist_node then + pdf_error("ext4", "link annotations can be inside hbox only"); + save_link_level(p); + set_rect_dimens(p, parent_box, x, y, + pdf_link_wd, pdf_link_ht, pdf_link_dp, pdf_link_margin); + last_link := p; + pdf_create_obj(obj_type_others, 0); + obj_annot_ptr(obj_ptr) := p; + pdf_append_list(obj_ptr)(pdf_link_list); +end; + +procedure restore_link_level; +var p, r: pointer; +begin + if link_level_stack = null then + pdf_error("ext4", "invalid stack of link nesting level"); + p := link_level_stack; + link_level_stack := link(p); + r := link_ptr(p); + flush_node_list(r); + free_node(p, small_node_size); + p := link_level_stack; + if p = null then + pdf_link_level := -1 + else begin + pdf_link_level := link_level(p); + r := link_ptr(p); + pdf_link_wd := pdf_width(r); + pdf_link_ht := pdf_height(r); + pdf_link_dp := pdf_depth(r); + end; +end; + +procedure end_link; +begin + if pdf_link_level <> cur_s then + pdf_error("ext4", "\pdfendlink ended up in different nesting level than \pdfstartlink"); + if is_running(pdf_link_wd) and (last_link <> null) then + pdf_right(last_link) := cur_h + pdf_link_margin; + restore_link_level; + last_link := null; +end; + +@ 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 |null|. We set |info| field just before destroying the node, in +order to use |flush_node_list| to do the job. + +@<Declare procedures needed in |pdf_hlist_out|, |pdf_vlist_out|@>= +procedure append_link(parent_box: pointer; x, y: scaled); {append a new +|pdf_start_link_node| to |pdf_link_list| and update |last_link|} +var p, r: integer; +begin + if type(parent_box) <> hlist_node then + pdf_error("ext4", "link annotations can be inside hbox only"); + r := copy_node_list(link_ptr(link_level_stack)); {copy link node to |r|} + info(r) := max_halfword; {mark that this node is not a whatsit node} + link(r) := null; {this node will be destroyed separately} + set_rect_dimens(r, parent_box, x, y, + pdf_link_wd, pdf_link_ht, pdf_link_dp, pdf_link_margin); + pdf_create_obj(obj_type_others, 0); + obj_annot_ptr(obj_ptr) := r; + last_link := r; + pdf_append_list(obj_ptr)(pdf_link_list); +end; + +@ Threads are handled in similar way as link annotations. + +@<Declare procedures needed in |pdf_hlist_out|, |pdf_vlist_out|@>= +procedure append_bead(p: pointer); +var a, b, c, t: integer; +begin + if not is_shipping_page then + pdf_error("ext4", "threads cannot be inside an XForm"); + t := get_obj(obj_type_thread, pdf_thread_id(p), pdf_thread_named_id(p)); + b := pdf_new_objnum; + obj_bead_ptr(b) := pdf_get_mem(pdfmem_bead_size); + obj_bead_page(b) := pdf_last_page; + obj_bead_data(b) := p; + if pdf_thread_attr(p) <> null then + obj_bead_attr(b) := tokens_to_string(pdf_thread_attr(p)) + else + obj_bead_attr(b) := 0; + if obj_thread_first(t) = 0 then begin + obj_thread_first(t) := b; + obj_bead_next(b) := b; + obj_bead_prev(b) := b; + end + else begin + a := obj_thread_first(t); + c := obj_bead_prev(a); + obj_bead_prev(b) := c; + obj_bead_next(b) := a; + obj_bead_prev(a) := b; + obj_bead_next(c) := b; + end; + pdf_append_list(b)(pdf_bead_list); +end; + +procedure do_thread(p, parent_box: pointer; x, y: scaled); +begin + if doing_leaders then + return; + if subtype(p) = pdf_start_thread_node then begin + pdf_thread_wd := pdf_width(p); + pdf_thread_ht := pdf_height(p); + pdf_thread_dp := pdf_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 then + add_token_ref(pdf_thread_id(p)); + pdf_thread_level := cur_s; + end; + set_rect_dimens(p, parent_box, x, y, + pdf_width(p), pdf_height(p), pdf_depth(p), + pdf_thread_margin); + append_bead(p); + last_thread := p; +end; + +procedure append_thread(parent_box: pointer; x, y: scaled); +var p: pointer; +begin + p := get_node(pdf_thread_node_size); + info(p) := max_halfword; {this is not a whatsit node} + link(p) := null; {this node will be destroyed separately} + pdf_width(p) := pdf_thread_wd; + pdf_height(p) := pdf_thread_ht; + pdf_depth(p) := pdf_thread_dp; + pdf_thread_attr(p) := null; + pdf_thread_id(p) := pdf_last_thread_id; + if pdf_last_thread_named_id then begin + add_token_ref(pdf_thread_id(p)); + pdf_thread_named_id(p) := 1; + end + else + pdf_thread_named_id(p) := 0; + set_rect_dimens(p, parent_box, x, y, + pdf_width(p), pdf_height(p), pdf_depth(p), + pdf_thread_margin); + append_bead(p); + last_thread := p; +end; + +procedure end_thread; +begin + if pdf_thread_level <> cur_s then + pdf_error("ext4", "\pdfendthread ended up in different nesting level than \pdfstartthread"); + if is_running(pdf_thread_dp) and (last_thread <> null) then + pdf_bottom(last_thread) := cur_v + pdf_thread_margin; + if pdf_last_thread_named_id then + delete_token_ref(pdf_last_thread_id); + last_thread := null; +end; + +function open_subentries(p: pointer): integer; +var k, c: integer; + l, r: integer; +begin + k := 0; + if obj_outline_first(p) <> 0 then begin + l := obj_outline_first(p); + repeat + incr(k); + c := open_subentries(l); + if obj_outline_count(l) > 0 then + k := k + c; + obj_outline_parent(l) := p; + r := obj_outline_next(l); + if r = 0 then + obj_outline_last(p) := l; + l := r; + until l = 0; + end; + if obj_outline_count(p) > 0 then + obj_outline_count(p) := k + else + obj_outline_count(p) := -k; + open_subentries := k; +end; + +procedure do_dest(p, parent_box: pointer; x, y: scaled); +var k: integer; +begin + if not is_shipping_page then + pdf_error("ext4", "destinations cannot be inside an XForm"); + if doing_leaders then + return; + k := get_obj(obj_type_dest, pdf_dest_id(p), pdf_dest_named_id(p)); + if obj_dest_ptr(k) <> null then begin + warn_dest_dup(pdf_dest_id(p), pdf_dest_named_id(p), + "ext4", "has been already used, duplicate ignored"); + return; + end; + obj_dest_ptr(k) := p; + pdf_append_list(k)(pdf_dest_list); + case pdf_dest_type(p) of + pdf_dest_xyz: begin + pdf_left(p) := cur_h; + pdf_top(p) := cur_v; + end; + pdf_dest_fith, + pdf_dest_fitbh: + pdf_top(p) := cur_v; + pdf_dest_fitv, + pdf_dest_fitbv: + pdf_left(p) := cur_h; + pdf_dest_fit, + pdf_dest_fitb: + do_nothing; + pdf_dest_fitr: + set_rect_dimens(p, parent_box, x, y, + pdf_width(p), pdf_height(p), pdf_depth(p), + pdf_dest_margin); + endcases; +end; + +procedure out_form(p: pointer); +begin + pdf_end_text; + pdf_print_ln("q"); + if pdf_lookup_list(pdf_xform_list, pdf_xform_objnum(p)) = null then + pdf_append_list(pdf_xform_objnum(p))(pdf_xform_list); + cur_v := cur_v + obj_xform_depth(pdf_xform_objnum(p)); + pdf_print("1 0 0 1 "); + pdf_print_bp(pdf_x(cur_h)); pdf_out(" "); + pdf_print_bp(pdf_y(cur_v)); + pdf_print_ln(" cm"); + pdf_print("/Fm"); + pdf_print_int(obj_info(pdf_xform_objnum(p))); + pdf_print_resname_prefix; + pdf_print_ln(" Do"); + pdf_print_ln("Q"); +end; + +procedure out_image(p: pointer); +var image: integer; +begin + image := obj_ximage_data(pdf_ximage_objnum(p)); + pdf_end_text; + pdf_print_ln("q"); + if pdf_lookup_list(pdf_ximage_list, pdf_ximage_objnum(p)) = null then + pdf_append_list(pdf_ximage_objnum(p))(pdf_ximage_list); + if not is_pdf_image(image) then begin + pdf_print_real(ext_xn_over_d(pdf_width(p), + ten_pow[6], one_hundred_bp), 4); + pdf_print(" 0 0 "); + pdf_print_real(ext_xn_over_d(pdf_height(p) + pdf_depth(p), + ten_pow[6], one_hundred_bp), 4); + pdf_out(" "); + pdf_print_bp(pdf_x(cur_h)); pdf_out(" "); + pdf_print_bp(pdf_y(cur_v)); + end + else begin + pdf_print_real(ext_xn_over_d(pdf_width(p), + ten_pow[6], image_width(image)), 6); + pdf_print(" 0 0 "); + pdf_print_real(ext_xn_over_d(pdf_height(p) + pdf_depth(p), + ten_pow[6], image_height(image)), 6); + pdf_out(" "); + pdf_print_bp(pdf_x(cur_h) - + ext_xn_over_d(pdf_width(p), epdf_orig_x(image), + image_width(image))); + pdf_out(" "); + pdf_print_bp(pdf_y(cur_v) - + ext_xn_over_d(pdf_height(p), epdf_orig_y(image), + image_height(image))); + end; + pdf_print_ln(" cm"); + pdf_print("/Im"); + pdf_print_int(obj_info(pdf_ximage_objnum(p))); + pdf_print_resname_prefix; + pdf_print_ln(" Do"); + pdf_print_ln("Q"); +end; + + +@ @<Output the whatsit node |p| in |pdf_vlist_out|@>= +case subtype(p) of +pdf_literal_node: + pdf_out_literal(p); +pdf_refobj_node: + pdf_append_list(pdf_obj_objnum(p))(pdf_obj_list); +pdf_refxform_node: + @<Output a Form node in a vlist@>; +pdf_refximage_node: + @<Output a Image node in a vlist@>; +pdf_annot_node: + do_annot(p, this_box, left_edge, top_edge + height(this_box)); +pdf_start_link_node: + pdf_error("ext4", "\pdfstartlink ended up in vlist"); +pdf_end_link_node: + pdf_error("ext4", "\pdfendlink ended up in vlist"); +pdf_dest_node: + do_dest(p, this_box, left_edge, top_edge + height(this_box)); +pdf_thread_node, +pdf_start_thread_node: + do_thread(p, this_box, left_edge, top_edge + height(this_box)); +pdf_end_thread_node: + end_thread; +pdf_save_pos_node: + @<Save current position to |pdf_last_x_pos|, |pdf_last_y_pos|@>; +special_node: + pdf_special(p); +othercases out_what(p); +endcases + +@ @<Glob...@>= +@!is_shipping_page: boolean; {set to |shipping_page| when |pdf_ship_out| starts} + +@ @<Save current position to |pdf_last_x_pos|, |pdf_last_y_pos|@>= +begin + pdf_last_x_pos := cur_h; + if is_shipping_page then + pdf_last_y_pos := cur_page_height - cur_v + else + pdf_last_y_pos := pdf_xform_height + pdf_xform_depth - cur_v; +end + +@ @<Output a Image node in a vlist@>= +begin cur_v:=cur_v+pdf_height(p)+pdf_depth(p); save_v:=cur_v; + cur_h:=left_edge; + out_image(p); + cur_v:=save_v; cur_h:=left_edge; + end + +@ @<Output a Form node in a vlist@>= +begin cur_v:=cur_v+pdf_height(p); save_v:=cur_v; + cur_h:=left_edge; + out_form(p); + cur_v:=save_v+pdf_depth(p); cur_h:=left_edge; + end + +@ @<Output the whatsit node |p| in |pdf_hlist_out|@>= +case subtype(p) of +pdf_literal_node: + pdf_out_literal(p); +pdf_refobj_node: + pdf_append_list(pdf_obj_objnum(p))(pdf_obj_list); +pdf_refxform_node: + @<Output a Form node in a hlist@>; +pdf_refximage_node: + @<Output a Image node in a hlist@>; +pdf_annot_node: + do_annot(p, this_box, left_edge, base_line); +pdf_start_link_node: + do_link(p, this_box, left_edge, base_line); +pdf_end_link_node: begin + end_link; + @<Create link annotation for the current hbox if needed@>; +end; +pdf_dest_node: + do_dest(p, this_box, left_edge, base_line); +pdf_thread_node: + do_thread(p, this_box, left_edge, base_line); +pdf_start_thread_node: + pdf_error("ext4", "\pdfstartthread ended up in hlist"); +pdf_end_thread_node: + pdf_error("ext4", "\pdfendthread ended up in hlist"); +pdf_save_pos_node: + @<Save current position to |pdf_last_x_pos|, |pdf_last_y_pos|@>; +special_node: + pdf_special(p); +othercases out_what(p); +endcases + +@ @<Output a Image node in a hlist@>= +begin + cur_v:=base_line+pdf_depth(p); + edge:=cur_h; + out_image(p); + cur_h:=edge+pdf_width(p); cur_v:=base_line; + end + +@ @<Output a Form node in a hlist@>= +begin + cur_v:=base_line; + edge:=cur_h; + out_form(p); + cur_h:=edge+pdf_width(p); cur_v:=base_line; + end +@z diff --git a/Build/source/texk/web2c/pdftexdir/pdftex.defines b/Build/source/texk/web2c/pdftexdir/pdftex.defines new file mode 100644 index 00000000000..2bd9ef1fefa --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/pdftex.defines @@ -0,0 +1,105 @@ +{ +Copyright (c) 1996-2005 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/pdftex.defines#15 $ +} + +{ pdftex.defines: additions for pdfTeX } + +{ macros from pdftex.h } +@define function pdfcharmarked(); +@define function getlpcode(); +@define function getrpcode(); +@define function getefcode(); +@define function texbopenin(); +@define function vfbopenin (); +@define procedure pdfmarkchar(); +@define procedure writepdf(); + +{ functions from mapfile.c } +@define function hasfmentry(); +@define function tfmoffm(); +@define procedure checkextfm(); +@define procedure pdfmapfile(); +@define procedure pdfmapline(); +@define procedure pdfinitmapfile(); + +{ functions from utils.c } +@define procedure escapehex(); +@define procedure escapename(); +@define procedure escapestring(); +@define function extxnoverd(); +@define procedure getcreationdate; +@define procedure getfiledump(); +@define procedure getfilemoddate(); +@define procedure getfilesize(); +@define procedure getmatch(); +@define procedure getmd5sum(); +@define function getresnameprefix; +@define procedure initstarttime; +@define function isquotebad; +@define function makecstring(); +@define procedure matchstrings(); +@define procedure libpdffinish; +@define procedure makepdftexbanner; +@define procedure printcreationdate; +@define procedure printID(); +@define procedure setjobid(); +@define procedure unescapehex(); +@define procedure writestreamlength(); + + +{ functions from vfpacket.c } +@define function newvfpacket(); +@define function packetbyte; +@define procedure startpacket(); +@define procedure storepacket(); + +{ functions from writefont.c } +@define procedure dopdffont(); + +{ functions from writeimg.c } +@define function checkimageb(); +@define function checkimagec(); +@define function checkimagei(); +@define function epdforigx(); +@define function epdforigy(); +@define function imageheight(); +@define function imagepages(); +@define function imagecolordepth(); +@define function imagewidth(); +@define function imagexres(); +@define function imageyres(); +@define function ispdfimage(); +@define function readimage(); +@define procedure deleteimage(); +@define procedure updateimageprocset(); +@define procedure writeimage(); + +{ functions from writet3.c } +@define function getpkcharwidth(); + +{ functions from writezip.c } +@define procedure writezip(); + +{ functions from avlstuff.c } +@define procedure avlputobj(); +@define function avlfindobj(); + +{ end of pdftex.defines } diff --git a/Build/source/texk/web2c/pdftexdir/pdftex.h b/Build/source/texk/web2c/pdftexdir/pdftex.h new file mode 100644 index 00000000000..837d3f5a2e9 --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/pdftex.h @@ -0,0 +1,50 @@ +/* +Copyright (c) 1996-2002 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/pdftex.h#4 $ +*/ + +/* Additions to texmfmp.h for pdfTeX */ + +/* mark a char in font */ +#define pdfmarkchar(f, c) pdfcharused[f][c/8] |= (1<<(c%8)) + +/* test whether a char in font is marked */ +#define pdfcharmarked(f, c) (boolean)(pdfcharused[f][c/8] & (1<<(c%8))) + +/* writepdf() always writes by fwrite() */ +#define writepdf(a, b) \ + (void) fwrite ((char *) &pdfbuf[a], sizeof (pdfbuf[a]), \ + (int) ((b) - (a) + 1), pdffile) + +#define getlpcode(f, c) \ + (pdffontlpbase[f] == 0 ? 0 : pdfmem[pdffontlpbase[f] + c]) + +#define getrpcode(f, c) \ + (pdffontrpbase[f] == 0 ? 0 : pdfmem[pdffontrpbase[f] + c]) + +#define getefcode(f, c) \ + (pdffontefbase[f] == 0 ? 1000 : pdfmem[pdffontefbase[f] + c]) + +#define texbopenin(f) \ + open_input (&(f), kpse_tex_format, FOPEN_RBIN_MODE) +#define vfbopenin(f) \ + open_input (&(f), kpse_vf_format, FOPEN_RBIN_MODE) + +#include <pdftexdir/ptexlib.h> diff --git a/Build/source/texk/web2c/pdftexdir/pdftex.mak b/Build/source/texk/web2c/pdftexdir/pdftex.mak new file mode 100644 index 00000000000..1acfb87c4e9 --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/pdftex.mak @@ -0,0 +1,199 @@ +################################################################################ +# +# Makefile : pdftex, web2c win32.mak fragment to build pdfTeX +# Author : Fabrice Popineau <Fabrice.Popineau@supelec.fr> +# Platform : Win32, Microsoft VC++ 6.0, depends upon fpTeX 0.5 sources +# Time-stamp: <04/03/20 16:40:35 popineau> +# +################################################################################ + +# The libraries are not mentioned. As the matter stands, a change in their +# number or how they are configured requires changes to the main distribution +# anyway. + +Makefile: pdftexdir\pdftex.mk + +pdftex_bin = $(objdir)\pdftex.exe $(objdir)\pdfetex.exe $(objdir)\ttf2afm.exe $(objdir)\pdftosrc.exe +# pdftex_exe = pdftex.exe pdfetex.exe ttf2afm.exe pdftosrc.exe +pdftex_pool = pdftex.pool pdfetex.pool +# linux_build_dir = $(HOME)\pdftex\build\linux\texk\web2c + +# We build pdftex +pdftex = $(objdir)\pdftex.exe +!ifdef TEX_DLL +pdftex = $(pdftex) $(objdir)\$(library_prefix)pdftex.dll +!endif + +# The C sources. +pdftex_c = pdftex.c +pdftex_o = $(objdir)\pdftex.obj + +# Making pdftex +!ifdef TEX_DLL +$(objdir)\$(library_prefix)pdftex.exp: $(objdir)\$(library_prefix)pdftex.lib + +$(objdir)\$(library_prefix)pdftex.lib: $(pdftex_o) + $(archive) /DEF $(pdftex_o) + +$(objdir)\$(library_prefix)pdftex.dll: $(pdftex_o) $(objdir)\$(library_prefix)pdftex.exp $(objdir)\pdftex.res $(pdftexlibs) $(kpathsealib) $(proglib) + $(link_dll) $(**) $(socketlibs) $(conlibs) + +$(objdir)\pdftex.exe: $(objdir)\win32main.obj $(objdir)\$(library_prefix)pdftex.lib $(kpathsealib) $(proglib) + $(link) $(**) $(conlibs) +!else +$(objdir)\pdftex.exe: $(pdftex_o) $(objdir)\win32main.obj $(objdir)\pdftex.res $(pdftexlibs) $(kpathsealib) $(proglib) + $(link) $(**) $(socketlibs) $(conlibs) +!endif + +# C file dependencies. +$(pdftex_c) pdftexcoerce.h pdftexd.h: pdftex.p $(web2c_texmf) + $(web2c) pdftex + +# Tangling. +pdftex.p pdftex.pool: .\$(objdir)\tangle.exe pdftex.web pdftex.ch + .\$(objdir)\tangle pdftex.web pdftex.ch + +# Generation of the web and ch files. +pdftex.web: $(objdir)\tie.exe \ + tex.web \ + pdftexdir/pdftex.ch \ + pdftexdir/hz.ch \ + pdftexdir/misc.ch \ + # pdftexdir\pdftex.mak + .\$(objdir)\tie -m pdftex.web tex.web \ + pdftexdir\pdftex.ch \ + $(srcdir)/pdftexdir/hz.ch \ + $(srcdir)/pdftexdir/misc.ch + +pdftex.ch: $(objdir)\tie.exe pdftex.web \ + pdftexdir\tex.ch0 \ + tex.ch \ + tex-supp-w32.ch \ + pdftexdir\tex.ch1 \ + pdftexdir\tex.pch \ + pdftexdir\tex.ch2 +# pdftexdir\pdftex.mak + .\$(objdir)\tie -c pdftex.ch \ + pdftex.web \ + $(srcdir)\pdftexdir\tex.ch0 \ + tex.ch \ + tex-supp-w32.ch \ + $(srcdir)\pdftexdir\tex.ch1 \ + $(srcdir)\pdftexdir\tex.pch \ + $(srcdir)\pdftexdir\tex.ch2 + +# Tests... +check: pdftex-check +pdftex-check: pdftex pdftex.fmt + +# Cleaning up. +clean:: pdftex-clean +pdftex-clean: +# $(LIBTOOL) --mode=clean $(RM) pdftex + -@echo $(verbose) & ( \ + for %%i in ($(pdftex_o) $(pdftex_c) pdftexextra.c pdftexcoerce.h \ + pdftexd.h pdftex.p pdftex.pool pdftex.web pdftex.ch \ + pdftex.fmt pdftex.log) do $(del) %%i $(redir_stderr) \ + ) + +# Dumps. +# all_pdffmts = pdftex.fmt $(pdffmts) + +# dumps: pdffmts +# pdffmts: $(all_pdffmts) +# pdftex.fmt: $(pdftex) +# $(dumpenv) $(make) progname=pdftex files="plain.tex cmr10.tfm" prereq-check +# $(dumpenv) .\$(objdir)\pdftex --progname=pdftex --jobname=pdftex --ini "\pdfoutput=1 \input plain \dump" <nul +# +# pdfolatex.fmt: $(pdftex) +# $(dumpenv) $(make) progname=pdfolatex files="latex.ltx" prereq-check +# $(dumpenv) .\$(objdir)\pdftex --progname=pdfolatex --jobname=pdfolatex --ini "\pdfoutput=1 \input latex.ltx" <nul +# +# pdflatex.fmt: $(pdftex) +# $(dumpenv) $(make) progname=pdflatex files="latex.ltx" prereq-check +# $(dumpenv) .\$(objdir)\pdftex --progname=pdflatex --jobname=pdflatex --ini "\pdfoutput=1 \input latex.ltx" <nul +# +# +# Installation. +install-pdftex: install-pdftex-exec install-pdftex-data +install-pdftex-exec: install-pdftex-links +# install-pdftex-data: install-pdftex-dumps +install-pdftex-dumps: install-pdftex-fmts + +# The actual binary executables and pool files. +install-programs: install-pdftex-programs +install-pdftex-programs: $(pdftex) $(bindir) + -@echo $(verbose) & ( \ + for %%p in ($(pdftex)) do $(copy) %%p $(bindir) \ + ) $(redir_stdout) + +# install-links: install-pdftex-links +install-pdftex-links: install-pdftex-programs +# -@echo $(verbose) & ( \ +# pushd $(bindir) & \ +# $(del) .\pdfinitex.exe .\pdfvirtex.exe & \ +# $(lnexe) .\pdftex.exe $(bindir)\pdfinitex.exe & \ +# $(lnexe) .\pdftex.exe $(bindir)\pdfvirtex.exe & \ +# popd \ +# ) $(redir_stdout) + -@echo $(verbose) & ( \ + if not "$(pdffmts)"=="" \ + for %%i in ($(pdffmts)) do \ + pushd $(bindir) & \ + $(del) .\%%~ni.exe & \ + $(lnexe) .\pdftex.exe $(bindir)\%%~ni.exe & \ + popd \ + ) $(redir_stdout) + +# install-fmts: install-pdftex-fmts +install-pdftex-fmts: pdffmts $(fmtdir) + -@echo $(verbose) & ( \ + for %%f in ($(all_pdffmts)) \ + do $(copy) %%f $(fmtdir)\%%f \ + ) $(redir_stdout) + +# Auxiliary files. +install-data:: install-pdftex-data +install-pdftex-data: $(texpooldir) + @$(copy) pdftex.pool $(texpooldir)\pdftex.pool $(redir_stdout) + +# +# ttf2afm +ttf2afm = $(objdir)\ttf2afm.exe + +$(objdir)\ttf2afm.exe: $(objdir)\ttf2afm.obj + $(link) $(**) $(kpathsealib) $(proglib) $(conlibs) + +$(objdir)\ttf2afm.obj: pdftexdir\ttf2afm.c pdftexdir\macnames.c + $(compile) -I.\pdftexdir pdftexdir\ttf2afm.c +check: ttf2afm-check +ttf2afm-check: $(objdir)\ttf2afm.exe +clean:: ttf2afm-clean +ttf2afm-clean: +# $(LIBTOOL) --mode=clean $(RM) ttf2afm + -@echo $(verbose) & ( \ + for %%i in ($(objdir)\ttf2afm.obj $(objdir)\macnames.obj \ + ttf2afm.c macnames.c) do $(del) %%i $(redir_stderr) \ + ) +# +# pdftosrc +pdftosrc = $(objdir)\pdftosrc.exe + +$(objdir)\pdftosrc.exe: $(objdir)\pdftosrc.obj $(xpdflib) + $(link) $(objdir)\pdftosrc.obj $(xpdflib) $(kpathsealib) $(proglib) $(conlibs) + +$(objdir)\pdftosrc.obj: pdftexdir\pdftosrc.cc + $(compile) /Tp $(**) +check: pdftosrc-check +pdftosrc-check: $(objdir)\pdftosrc.exe +clean:: pdftosrc-clean +pdftosrc-clean: +# $(LIBTOOL) --mode=clean $(RM) pdftosrc + -@$(del) $(objdir)\pdftosrc.obj $(redir_stderr) + +# end of pdftex.mak +# +# Local variables: +# page-delimiter: "^# \f" +# mode: Makefile +# End: diff --git a/Build/source/texk/web2c/pdftexdir/pdftex.mk b/Build/source/texk/web2c/pdftexdir/pdftex.mk new file mode 100644 index 00000000000..56a770546cf --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/pdftex.mk @@ -0,0 +1,201 @@ +# Makefile fragment for pdfTeX and web2c. --infovore@xs4all.nl. Public domain. +# This fragment contains the parts of the makefile that are most likely to +# differ between releases of pdfTeX. + +# The libraries are not mentioned. As the matter stands, a change in their +# number or how they are configured requires changes to the main distribution +# anyway. + +# $Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/pdftex.mk#38 $ + +Makefile: pdftexdir/pdftex.mk + +pdftex_bin = pdftex pdfetex ttf2afm pdftosrc +linux_build_dir = $(HOME)/pdftex/build/linux/texk/web2c + +# We build pdftex +pdftex = @PTEX@ pdftex +pdftexdir = pdftexdir + +# Extract pdftex version +pdftexdir/pdftex.version: pdftexdir/pdftex.ch + grep '^@d pdftex_version_string==' $(srcdir)/pdftexdir/pdftex.ch \ + | sed "s/^.*'-//;s/'.*$$//" \ + >pdftexdir/pdftex.version + +# The C sources. +pdftex_c = pdftexini.c pdftex0.c pdftex1.c pdftex2.c pdftex3.c +pdftex_o = pdftexini.o pdftex0.o pdftex1.o pdftex2.o pdftex3.o pdftexextra.o + +# Making pdftex +pdftex: $(pdftex_o) $(pdftexextra_o) $(pdftexlibsdep) + @CXXHACKLINK@ $(pdftex_o) $(pdftexextra_o) $(pdftexlibs) $(socketlibs) @CXXHACKLDLIBS@ @CXXLDEXTRA@ + +# C file dependencies. +$(pdftex_c) pdftexcoerce.h pdftexd.h: pdftex.p $(web2c_texmf) + $(web2c) pdftex +pdftexextra.c: pdftexdir/pdftexextra.h lib/texmfmp.c + sed s/TEX-OR-MF-OR-MP/pdftex/ $(srcdir)/lib/texmfmp.c >$@ +pdftexdir/pdftexextra.h: pdftexdir/pdftexextra.in pdftexdir/pdftex.version + sed s/PDFTEX-VERSION/`cat pdftexdir/pdftex.version`/ \ + $(srcdir)/pdftexdir/pdftexextra.in >$@ + +# Tangling. +pdftex.p pdftex.pool: tangle pdftex.web pdftex.ch + $(TANGLE) pdftex.web pdftex.ch + +# Generation of the web and ch files. +# Sources for pdftex.web: +pdftex_web_srcs = $(srcdir)/tex.web \ + $(srcdir)/pdftexdir/pdftex.ch \ + $(srcdir)/pdftexdir/hz.ch \ + $(srcdir)/pdftexdir/misc.ch \ + $(srcdir)/pdftexdir/vadjust.ch \ + $(srcdir)/pdftexdir/pdftex2.ch +# Sources for etex.ch: +pdftex_ch_srcs = pdftex.web \ + $(srcdir)/pdftexdir/tex.ch0 \ + $(srcdir)/tex.ch \ + $(srcdir)/pdftexdir/tex.ch1 \ + $(srcdir)/pdftexdir/tex.pch \ + $(srcdir)/pdftexdir/noligatures.ch \ + $(srcdir)/pdftexdir/pdfstrcmp.ch \ + $(srcdir)/pdftexdir/randoms.ch +# Rules: +pdftex.web: tie pdftexdir/pdftex.mk $(pdftex_web_srcs) + $(TIE) -m pdftex.web $(pdftex_web_srcs) +pdftex.ch: $(pdftex_ch_srcs) + $(TIE) -c pdftex.ch $(pdftex_ch_srcs) + +# for developing only +pdftex-org.web: $(pdftex_ch_srcs_org) + $(TIE) -m $@ $(pdftex_ch_srcs_org) +pdftex-all.web: pdftex.web pdftex.ch + $(TIE) -m $@ pdftex.web pdftex.ch + +# Tests... +check: @PTEX@ pdftex-check +pdftex-check: pdftex pdftex.fmt + +# Cleaning up. +clean:: pdftex-clean +pdftex-clean: + $(LIBTOOL) --mode=clean $(RM) pdftex + rm -f $(pdftex_o) $(pdftex_c) pdftexextra.c pdftexcoerce.h + rm -f pdftexdir/pdftexextra.h pdftexdir/pdftex.version + rm -f pdftexd.h pdftex.p pdftex.pool pdftex.web pdftex.ch + rm -f pdftex.fmt pdftex.log + +# Dumps. +all_pdffmts = @FMU@ pdftex.fmt $(pdffmts) + +dumps: @PTEX@ pdffmts +pdffmts: $(all_pdffmts) + +pdffmtdir = $(web2cdir)/pdftex +$(pdffmtdir):: + $(SHELL) $(top_srcdir)/../mkinstalldirs $(pdffmtdir) + +pdftex.fmt: pdftex + $(dumpenv) $(MAKE) progname=pdftex files="plain.tex cmr10.tfm" prereq-check + $(dumpenv) ./pdftex --progname=pdftex --jobname=pdftex --ini \\pdfoutput=1 \\input plain \\dump </dev/null + +pdfolatex.fmt: pdftex + $(dumpenv) $(MAKE) progname=pdfolatex files="latex.ltx" prereq-check + $(dumpenv) ./pdftex --progname=pdfolatex --jobname=pdfolatex --ini \\pdfoutput=1 \\input latex.ltx </dev/null + +#pdflatex.fmt: pdftex +# $(dumpenv) $(MAKE) progname=pdflatex files="latex.ltx" prereq-check +# $(dumpenv) ./pdftex --progname=pdflatex --jobname=pdflatex --ini \\pdfoutput=1 \\input latex.ltx </dev/null + +# +# Installation. +install-pdftex: install-pdftex-exec install-pdftex-data +install-pdftex-exec: install-pdftex-links +install-pdftex-data: install-pdftex-pool @FMU@ install-pdftex-dumps +install-pdftex-dumps: install-pdftex-fmts + +# The actual binary executables and pool files. +install-programs: @PTEX@ install-pdftex-programs +install-pdftex-programs: pdftex $(bindir) + for p in pdftex; do $(INSTALL_LIBTOOL_PROG) $$p $(bindir); done + +install-links: @PTEX@ install-pdftex-links +install-pdftex-links: install-pdftex-programs + #cd $(bindir) && (rm -f pdfinitex pdfinitex; \ + # $(LN) pdftex pdfinitex; $(LN) pdftex pdfvirtex) + +install-fmts: @PTEX@ install-pdftex-fmts +install-pdftex-fmts: pdffmts $(pdffmtdir) + pdffmts="$(all_pdffmts)"; \ + for f in $$pdffmts; do $(INSTALL_DATA) $$f $(pdffmtdir)/$$f; done + pdffmts="$(pdffmts)"; \ + for f in $$pdffmts; do base=`basename $$f .fmt`; \ + (cd $(bindir) && (rm -f $$base; $(LN) pdftex $$base)); done + +# Auxiliary files. +install-data:: @PTEX@ install-pdftex-data +install-pdftex-pool: pdftex.pool $(texpooldir) + $(INSTALL_DATA) pdftex.pool $(texpooldir)/pdftex.pool + + +# +# ttf2afm +ttf2afm = ttf2afm + +ttf2afm: ttf2afm.o + $(kpathsea_link) ttf2afm.o $(kpathsea) +ttf2afm.o: ttf2afm.c macnames.c + $(compile) -c $< -o $@ +ttf2afm.c: + cp $(srcdir)/pdftexdir/ttf2afm.c . +macnames.c: + cp $(srcdir)/pdftexdir/macnames.c . +check: ttf2afm-check +ttf2afm-check: ttf2afm +clean:: ttf2afm-clean +ttf2afm-clean: + $(LIBTOOL) --mode=clean $(RM) ttf2afm + rm -f ttf2afm.o macnames.o + rm -f ttf2afm.c macnames.c +# +# pdftosrc +pdftosrc = pdftosrc + +pdftosrc: pdftexdir/pdftosrc.o $(LIBXPDFDEP) + @CXXHACKLINK@ pdftexdir/pdftosrc.o $(LDLIBXPDF) -lm @CXXLDEXTRA@ +pdftexdir/pdftosrc.o:$(srcdir)/pdftexdir/pdftosrc.cc + cd pdftexdir && $(MAKE) pdftosrc.o +check: pdftosrc-check +pdftosrc-check: pdftosrc +clean:: pdftosrc-clean +pdftosrc-clean: + $(LIBTOOL) --mode=clean $(RM) pdftosrc +# +# pdftex binaries archive +pdftexbin: + $(MAKE) $(pdftex_bin) + +pdftex-cross: + $(MAKE) web2c-cross + $(MAKE) pdftexbin + +web2c-cross: $(web2c_programs) + @if test ! -x $(linux_build_dir)/tangle; then echo Error: linux_build_dir not ready; exit -1; fi + rm -f web2c/fixwrites web2c/splitup web2c/web2c + cp -f $(linux_build_dir)/web2c/fixwrites web2c + cp -f $(linux_build_dir)/web2c/splitup web2c + cp -f $(linux_build_dir)/web2c/web2c web2c + touch web2c/fixwrites web2c/splitup web2c/web2c + $(MAKE) tangleboot && rm -f tangleboot && \ + cp -f $(linux_build_dir)/tangleboot . && touch tangleboot + $(MAKE) ctangleboot && rm -f ctangleboot && \ + cp -f $(linux_build_dir)/ctangleboot . && touch ctangleboot + $(MAKE) ctangle && rm -f ctangle && \ + cp -f $(linux_build_dir)/ctangle . && touch ctangle + $(MAKE) tie && rm -f tie && \ + cp -f $(linux_build_dir)/tie . && touch tie + $(MAKE) tangle && rm -f tangle && \ + cp -f $(linux_build_dir)/tangle . && touch tangle + +# end of pdftex.mk diff --git a/Build/source/texk/web2c/pdftexdir/pdftex2.ch b/Build/source/texk/web2c/pdftexdir/pdftex2.ch new file mode 100644 index 00000000000..227cb474242 --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/pdftex2.ch @@ -0,0 +1,89 @@ +% WEB change file containing pdftex codes that are conveninent to be here +% instead of pdftex.ch due to changes files coming after pdftex.ch (hz.ch & +% vadjust.ch) +% +% Copyright (c) 1996-2005 Han Th\^e\llap{\raise 0.5ex\hbox{\'{}}} Th\`anh, <thanh@pdftex.org> +% +% This file is part of pdfTeX. +% +% pdfTeX 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. +% +% pdfTeX 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 General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with pdfTeX; if not, write to the Free Software +% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +% +% $Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/pdftex2.ch#5 $ + +@x [230] - tagcode +@d ef_code_base == 4 +@y +@d ef_code_base == 4 +@d tag_code == 5 +@z + +@x [230] - tagcode + ef_code_base: scanned_result(get_ef_code(n, k))(int_val); +@y + ef_code_base: scanned_result(get_ef_code(n, k))(int_val); + tag_code: scanned_result(get_tag_code(n, k))(int_val); +@z + +@x [???] - tagcode +function init_font_base(v: integer): integer; +@y +procedure set_tag_code(f: internal_font_number; c: eight_bits; i: integer); +var fixedi:integer; +begin + if is_valid_char(c) then + begin fixedi := abs(fix_int(i,-7,0)); + if fixedi >= 4 then begin + if char_tag(char_info(f)(c)) = ext_tag then + op_byte(char_info(f)(c)) := (op_byte(char_info(f)(c))) - ext_tag; + fixedi := fixedi - 4; + end; + if fixedi >= 2 then begin + if char_tag(char_info(f)(c)) = list_tag then + op_byte(char_info(f)(c)) := (op_byte(char_info(f)(c))) - list_tag; + fixedi := fixedi - 2; + end; + if fixedi >= 1 then begin + if char_tag(char_info(f)(c)) = lig_tag then + op_byte(char_info(f)(c)) := (op_byte(char_info(f)(c))) - lig_tag; + end; + end; +end; + +function init_font_base(v: integer): integer; +@z + +@x [1253] - tagcode + ef_code_base: set_ef_code(f, p, cur_val); +@y + ef_code_base: set_ef_code(f, p, cur_val); + tag_code: set_tag_code(f, p, cur_val); +@z + +@x [1254] - tagcode +primitive("efcode",assign_font_int,ef_code_base); +@!@:ef_code_}{\.{\\efcode} primitive@> +@y +primitive("efcode",assign_font_int,ef_code_base); +@!@:ef_code_}{\.{\\efcode} primitive@> +primitive("tagcode",assign_font_int,tag_code); +@!@:tag_code_}{\.{\\tagcode} primitive@> +@z + +@x [1255] +ef_code_base: print_esc("efcode"); +@y +ef_code_base: print_esc("efcode"); +tag_code: print_esc("tagcode"); +@z diff --git a/Build/source/texk/web2c/pdftexdir/pdftexextra.in b/Build/source/texk/web2c/pdftexdir/pdftexextra.in new file mode 100644 index 00000000000..cd81871bec9 --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/pdftexextra.in @@ -0,0 +1,40 @@ +/* +Copyright (c) 1996-2004 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: pdftexextra.in,v 1.4 2004/08/26 18:14:18 olaf Exp $ +*/ + +/* pdftexextra.in: banner etc. for pdfTeX. + + This is included by pdfTeX, from ../etexextra.c + (generated from ../lib/texmfmp.c). +*/ + +#define BANNER "This is pdfTeX, Version 3.141592-PDFTEX-VERSION" +#define COPYRIGHT_HOLDER "Han The Thanh" +#define AUTHOR NULL +#define PROGRAM_HELP PDFTEXHELP +#define BUG_ADDRESS "pdftex@tug.org" +#define DUMP_VAR TEXformatdefault +#define DUMP_LENGTH_VAR formatdefaultlength +#define DUMP_OPTION "fmt" +#define DUMP_EXT ".fmt" +#define INPUT_FORMAT kpse_tex_format +#define INI_PROGRAM "pdfinitex" +#define VIR_PROGRAM "pdfvirtex" diff --git a/Build/source/texk/web2c/pdftexdir/pdftexlib.mk b/Build/source/texk/web2c/pdftexdir/pdftexlib.mk new file mode 100644 index 00000000000..5b3f745385c --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/pdftexlib.mk @@ -0,0 +1,76 @@ +## pdftexlib.mk - Makefile fragment for libraries used by pdf[ex]tex. +# Public domain. + +# The pdf*tex programs depend on a number of libraries. +# Include dependencies to get the built if we don't do make +# from the top-level directory. + +Makefile: pdftexdir/pdftexlib.mk + +# libz + +ZLIBDIR=../../libs/zlib +ZLIBSRCDIR=$(srcdir)/$(ZLIBDIR) +ZLIBDEP = @ZLIBDEP@ +LDZLIB = @LDZLIB@ + +$(ZLIBDIR)/libz.a: $(ZLIBSRCDIR) + cd $(ZLIBDIR) && $(MAKE) $(common_makeargs) libz.a + + +# libpng + +LIBPNGDIR=../../libs/libpng +LIBPNGSRCDIR=$(srcdir)/$(LIBPNGDIR) +LIBPNGDEP = @LIBPNGDEP@ +LDLIBPNG = @LDLIBPNG@ + +$(LIBPNGDIR)/libpng.a: $(LIBPNGSRCDIR)/*.c + cd $(LIBPNGDIR) && $(MAKE) $(common_makeargs) libpng.a + + +# libxpdf + +LIBXPDFDIR=../../libs/xpdf +LIBXPDFSRCDIR=$(srcdir)/$(LIBXPDFDIR) +LIBXPDFDEP = @LIBXPDFDEP@ +LDLIBXPDF = @LDLIBXPDF@ + +$(LIBXPDFDIR)/fofi/libfofi.a: $(LIBXPDFSRCDIR)/fofi/*.cc \ + $(LIBXPDFSRCDIR)/fofi/*.h + cd $(LIBXPDFDIR)/fofi; $(MAKE) $(common_makeargs) libfofi.a +$(LIBXPDFDIR)/goo/libGoo.a: $(LIBXPDFSRCDIR)/goo/*.cc \ + $(LIBXPDFSRCDIR)/goo/*.c $(LIBXPDFSRCDIR)/goo/*.h + cd $(LIBXPDFDIR)/goo; $(MAKE) $(common_makeargs) libGoo.a +$(LIBXPDFDIR)/xpdf/libxpdf.a: $(LIBXPDFSRCDIR)/xpdf/*.cc \ + $(LIBXPDFSRCDIR)/xpdf/*.h + cd $(LIBXPDFDIR)/xpdf; $(MAKE) $(common_makeargs) libxpdf.a + + +# md5 + +LIBMD5DIR=../../libs/md5 +LIBMD5SRCDIR=$(srcdir)/$(LIBMD5DIR) +LIBMD5DEP=$(LIBMD5DIR)/md5.o + +$(LIBMD5DEP): $(LIBMD5SRCDIR)/md5.c $(LIBMD5SRCDIR)/md5.h +clean:: md5lib-clean +md5lib-clean: + rm -f $(LIBMD5DEP) + + +# libpdf itself +pdflib = pdftexdir/libpdf.a +pdflib_sources = $(srcdir)/pdftexdir/*.c $(srcdir)/pdftexdir/*.cc \ + $(srcdir)/pdftexdir/*.h + +pdftexdir/libpdf.a: $(pdflib_sources) pdftexdir/pdftexextra.h + cd pdftexdir && $(MAKE) $(common_makeargs) libpdf.a + + +# Convenience variables. + +pdftexlibs = $(pdflib) $(LDLIBPNG) $(LDZLIB) $(LDLIBXPDF) $(LIBMD5DEP) +pdftexlibsdep = $(pdflib) $(LIBPNGDEP) $(ZLIBDEP) $(LIBXPDFDEP) $(LIBMD5DEP) + +## end of pdftexlib.mk - Makefile fragment for libraries used by pdf[ex]tex. diff --git a/Build/source/texk/web2c/pdftexdir/pdftoepdf.cc b/Build/source/texk/web2c/pdftexdir/pdftoepdf.cc new file mode 100644 index 00000000000..ef52a356763 --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/pdftoepdf.cc @@ -0,0 +1,1072 @@ +/* +Copyright 1996-2004 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/pdftoepdf.cc#53 $ +*/ + +#include <stdlib.h> +#include <math.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <aconf.h> +#include <GString.h> +#include <gmem.h> +#include <gfile.h> +#include <config.h> +#include "Object.h" +#include "Stream.h" +#include "Array.h" +#include "Dict.h" +#include "XRef.h" +#include "Catalog.h" +#include "Link.h" +#include "Page.h" +#include "GfxFont.h" +#include "PDFDoc.h" +#include "GlobalParams.h" +#include "Error.h" + +#include "epdf.h" + +static const char perforce_id[] = + "$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/pdftoepdf.cc#53 $"; + +/* we avoid reading all necessary kpathsea headers, but we need xstrdup */ +#ifdef __cplusplus +extern "C" { + extern KPSEDLL char *xstrdup (const char *); +} +#else + extern KPSEDLL char *xstrdup (const char *); +#endif + +#ifdef __cplusplus +extern "C" { +// FIXME: This definition is a duplicate from ../pdftexcoerce.h, which is +// not usable here because of different macro definitions. +extern integer pdflastpdfboxspec ; +} +#endif + +/* + * Used flags below: + * PDFTEX_COPY_PAGEGROUP + * if pdfTeX should copy a page group (a new feature in pdf1.4 for + * transparency) of an included file. The current support for this is + * most likely broken. pdfTeX will at least give a warning if this flag + * is not set. Surprisingly Acrobat and Jaws display files without a + * page group correctly, so it might be safe to not set the flag. + * See also PDFTEX_COPY_PAGEGROUP_NOFAIL + * PDFTEX_COPY_PAGEGROUP_NOFAIL + * if set to false pdfTeX will treat a page group in an included file as + * an error and abort gracefully. This is only evaluated if + * PDFTEX_COPY_PAGEGROUP is set. + */ + +// FIXME: These definitions are duplicates from pdftexd.h +/* #define PDF_PDF_BOX_SPEC_MEDIA 0 */ +/* #define PDF_PDF_BOX_SPEC_CROP 1 */ +/* #define PDF_PDF_BOX_SPEC_BLEED 2 */ +/* #define PDF_PDF_BOX_SPEC_TRIM 3 */ +/* #define PDF_PDF_BOX_SPEC_ART 4 */ +#define pdfpdfboxspecmedia ( 0 ) +#define pdfpdfboxspeccrop ( 1 ) +#define pdfpdfboxspecbleed ( 2 ) +#define pdfpdfboxspectrim ( 3 ) +#define pdfpdfboxspecart ( 4 ) + +// The prefix for the PDF keys special to pdfTeX +// This has been registered with Adobe by Hans Hagen +#define pdfkeyprefix "PTEX" + +// PdfObject encapsulates the xpdf Object type, and properly +// frees its resources on destruction. +// Use obj-> to access members of the Object, and +// &obj to get a pointer to the object. +// It is no longer necessary to call Object::free explicitely. + +class PdfObject { +public: + PdfObject() { /* nothing */ } + ~PdfObject() { iObject.free(); } + Object* operator->() { return &iObject; } + Object* operator&() { return &iObject; } +private: // no copying or assigning + PdfObject(const PdfObject &); + void operator=(const PdfObject &); +public: + Object iObject; +}; + +// when copying the Resources of the selected page, all objects are copied +// recusively top-down. Indirect objects however are not fetched during +// copying, but get a new object number from pdftex and then will be +// appended into a linked list. Duplicates are checked and removed from the +// list of indirect objects during appending. + +enum InObjType { + objFont, + objFontDesc, + objOther +}; + +struct InObj { + Ref ref; // ref in original PDF + InObjType type; // object type + InObj *next; // next entry in list of indirect objects + integer num; // new object number in output PDF + fm_entry * fontmap; // pointer to font map entry + integer enc_objnum; // Encoding for objFont + int written; // has it been written to output PDF? +}; + +struct UsedEncoding { + integer enc_objnum; + GfxFont *font; + UsedEncoding *next; +}; + +static InObj *inObjList; +static UsedEncoding *encodingList; +static GBool isInit = gFalse; + +// -------------------------------------------------------------------- +// Maintain list of open embedded PDF files +// -------------------------------------------------------------------- + +struct PdfDocument { + char *file_name; + PDFDoc *doc; + XRef *xref; + InObj *inObjList; + int occurences; // number of references to the document; the doc can be + // deleted when this is negative + PdfDocument *next; +}; + +static PdfDocument *pdfDocuments = 0; + +static XRef *xref = 0; + +// Returns pointer to PdfDocument record for PDF file. +// Creates a new record if it doesn't exist yet. +// xref is made current for the document. + +static PdfDocument *find_add_document(char *file_name) +{ + PdfDocument *p = pdfDocuments; + while (p && strcmp(p->file_name, file_name) != 0) + p = p->next; + if (p) { + xref = p->xref; + (p->occurences)++; +#ifdef DEBUG + fprintf(stderr, "\nIncrementing %s (%d)\n", p->file_name, p->occurences); +#endif + return p; + } + p = new PdfDocument; + p->file_name = xstrdup(file_name); + p->xref = xref = 0; + p->occurences = 0; +#ifdef DEBUG + fprintf(stderr, "\nCreating %s (%d)\n", p->file_name, p->occurences); +#endif + GString *docName = new GString(p->file_name); + p->doc = new PDFDoc(docName); // takes ownership of docName + if (!p->doc->isOk() || !p->doc->okToPrint()) { + pdftex_fail("xpdf: reading PDF image failed"); + } + p->inObjList = 0; + p->next = pdfDocuments; + pdfDocuments = p; + return p; +} + +// Deallocate a PdfDocument with all its resources +static void delete_document(PdfDocument *pdf_doc) +{ + PdfDocument **p = &pdfDocuments; + while (*p && *p != pdf_doc) + p = &((*p)->next); + // should not happen: + if (!*p) + return; + // unlink from list + *p = pdf_doc->next; + // free pdf_doc's resources + InObj *r, *n; + for (r = pdf_doc->inObjList; r != 0; r = n) { + n = r->next; + delete r; + } + xref = pdf_doc->xref; + delete pdf_doc->doc; + xfree(pdf_doc->file_name); + delete pdf_doc; +} + +// Replacement for +// Object *initDict(Dict *dict1){ initObj(objDict); dict = dict1; return this; } +static void initDictFromDict (PdfObject &obj, Dict *dict) +{ + obj->initDict(xref); + for (int i = 0, + l = dict->getLength(); + i < l; + i++) { + Object obj1; + obj->dictAdd(copyString(dict->getKey(i)), dict->getValNF(i, &obj1)); + } +} + +// -------------------------------------------------------------------- + +static int addEncoding(GfxFont *gfont) +{ + UsedEncoding *n; + n = new UsedEncoding; + n->next = encodingList; + encodingList = n; + n->font = gfont; + n->enc_objnum = pdfnewobjnum(); + return n->enc_objnum; +} + +#define addFont(ref, fontmap, enc_objnum) \ + addInObj(objFont, ref, fontmap, enc_objnum) + +#define addFontDesc(ref, fontmap) \ + addInObj(objFontDesc, ref, fontmap, 0) + +#define addOther(ref) \ + addInObj(objOther, ref, 0, 0) + +static int addInObj(InObjType type, Ref ref, fm_entry *f, integer e) +{ + InObj *p, *q, *n = new InObj; + if (ref.num == 0) + pdftex_fail("pdf inclusion: invalid reference"); + n->ref = ref; + n->type = type; + n->next = 0; + n->fontmap = f; + n->enc_objnum = e; + n->written = 0; + if (inObjList == 0) + inObjList = n; + else { + for (p = inObjList; p != 0; p = p->next) { + if (p->ref.num == ref.num && p->ref.gen == ref.gen) { + delete n; + return p->num; + } + q = p; + } + // it is important to add new objects at the end of the list, + // because new objects are being added while the list is being + // written out. + q->next = n; + } + n->num = pdfnewobjnum(); + return n->num; +} + +static void copyObject(Object *); + +static void copyName(char *s) +{ + pdf_puts("/"); + for (; *s != 0; s++) { + if (isdigit(*s) || isupper(*s) || islower(*s) || *s == '_' || + *s == '.' || *s == '-' ) + pdfout(*s); + else + pdf_printf("#%.2X", *s & 0xFF); + } +} + +static void copyDictEntry(Object *obj, int i) +{ + PdfObject obj1; + copyName(obj->dictGetKey(i)); + pdf_puts(" "); + obj->dictGetValNF(i, &obj1); + copyObject(&obj1); + pdf_puts("\n"); +} + +static void copyDict(Object *obj) +{ + int i, l; + if (!obj->isDict()) + pdftex_fail("pdf inclusion: invalid dict type <%s>", + obj->getTypeName()); + for (i = 0, l = obj->dictGetLength(); i < l; ++i) + copyDictEntry(obj, i); +} + +static void copyFontDict(Object *obj, InObj *r) +{ + int i, l; + char *key; + if (!obj->isDict()) + pdftex_fail("pdf inclusion: invalid dict type <%s>", + obj->getTypeName()); + pdf_puts("<<\n"); + if (r->type == objFont) { // Font dict + for (i = 0, l = obj->dictGetLength(); i < l; ++i) { + key = obj->dictGetKey(i); + if (strcmp("BaseFont", key) == 0 || + strcmp("Encoding", key) == 0) + continue; // skip original values + copyDictEntry(obj, i); + } + // write new BaseFont and Encoding + pdf_printf("/BaseFont %i 0 R\n", (int)get_fontname(r->fontmap)); + pdf_printf("/Encoding %i 0 R\n", (int)r->enc_objnum); + } + else { // FontDescriptor dict + for (i = 0, l = obj->dictGetLength(); i < l; ++i) { + key = obj->dictGetKey(i); + if (strcmp("FontName", key) == 0 || + strncmp("FontFile", key, strlen("FontFile")) == 0) + continue; // ignore original FontFile/FontName + if (strcmp("CharSet", key) == 0) + continue; // ignore CharSet + copyDictEntry(obj, i); + } + // write new FontName and FontFile + pdf_printf("/FontName %i 0 R\n", (int)get_fontname(r->fontmap)); + pdf_printf("/FontFile %i 0 R\n", (int)get_fontfile(r->fontmap)); + } + pdf_puts(">>"); +} + +static void copyStream(Stream *str) +{ + int c; + str->reset(); + while ((c = str->getChar()) != EOF) + pdfout(c); +} + +static void copyProcSet(Object *obj) +{ + int i, l; + PdfObject procset; + if (!obj->isArray()) + pdftex_fail("pdf inclusion: invalid ProcSet array type <%s>", + obj->getTypeName()); + pdf_puts("/ProcSet [ "); + for (i = 0, l = obj->arrayGetLength(); i < l; ++i) { + obj->arrayGetNF(i, &procset); + if (!procset->isName()) + pdftex_fail("pdf inclusion: invalid ProcSet entry type <%s>", + procset->getTypeName()); + copyName(procset->getName()); + pdf_puts(" "); + } + pdf_puts("]\n"); +} + +static void copyFont(char *tag, Object *fontRef) +{ + PdfObject fontdict, subtype, basefont, fontdescRef, fontdesc, charset, fontfile; + GfxFont *gfont; + fm_entry *fontmap; + // Check whether the font has already been embedded before analysing it. + InObj *p; + Ref ref = fontRef->getRef(); + for (p = inObjList; p; p = p->next) { + if (p->ref.num == ref.num && p->ref.gen == ref.gen) { + copyName(tag); + pdf_printf(" %d 0 R ", p->num); + return; + } + } + /* only handle included Type1 fonts; anything else will be copied */ + if (fontRef->fetch(xref, &fontdict) && + fontdict->isDict() && + fontdict->dictLookup("Subtype", &subtype) && + subtype->isName() && + fontdict->dictLookup("BaseFont", &basefont) && + basefont->isName() && + fontdict->dictLookupNF("FontDescriptor", &fontdescRef) && + fontdescRef->isRef() && + fontdescRef->fetch(xref, &fontdesc) && + fontdesc->isDict() && + fontdesc->dictLookupNF("FontDescriptor", &fontdescRef) && + ((strcmp(subtype->getName(), "Type1") == 0 && + fontdesc->dictLookup("FontFile", &fontfile)) || + (strcmp(subtype->getName(), "Type1C") == 0 && + fontdesc->dictLookup("FontFile3", &fontfile))) && + fontfile->isStream() + ) { + fontmap = lookup_fontmap(basefont->getName()); + if (fontmap != NULL) { + if (fontdesc->dictLookup("CharSet", &charset) && + charset->isString() && is_subsetable(fontmap)) + mark_glyphs(fontmap, charset->getString()->getCString()); + else + embed_whole_font(fontmap); + addFontDesc(fontdescRef->getRef(), fontmap); + copyName(tag); + gfont = GfxFont::makeFont(xref, tag, fontRef->getRef(), + fontdict->getDict()); + pdf_printf(" %d 0 R ", addFont(fontRef->getRef(), fontmap, + addEncoding(gfont))); + return; + } + } + copyName(tag); + pdf_puts(" "); + copyObject(fontRef); +} + +static void copyFontResources(Object *obj) +{ + PdfObject fontRef; + int i, l; + if (!obj->isDict()) + pdftex_fail("pdf inclusion: invalid font resources dict type <%s>", + obj->getTypeName()); + pdf_puts("/Font << "); + for (i = 0, l = obj->dictGetLength(); i < l; ++i) { + obj->dictGetValNF(i, &fontRef); + if (fontRef->isRef()) + copyFont(obj->dictGetKey(i), &fontRef); + else + pdftex_fail("pdf inclusion: invalid font in reference type <%s>", + fontRef->getTypeName()); + } + pdf_puts(">>\n"); +} + +static void copyOtherResources(Object *obj, char *key) +{ + /* copies all other resources (write_epdf handles Fonts and ProcSets), + * but gives a warning if an object is not a dictionary. + */ + if (!obj->isDict()) + //FIXME: Write the message only to the log file + pdftex_warn("pdf inclusion: invalid other resource which is no dict" + " (key '%s', type <%s>); copying it anyway.", + key, + obj->getTypeName()); + copyName(key); + pdf_puts(" "); + copyObject(obj); +} + +/* converts double to string; very small and very large numbers are NOT + * converted to scientific notation. + * n must be a number or real confirming to the implementation limits of PDF as + * specified in appendix C.1 of the pdf ref. + * These are: + * maximum value of ints is +2^32 + * maximum value of reals is +2^15 + * smalles values of reals is 1/(2^16) + */ +static char * +convertNumToPDF(double n) +{ + static const int precision = 6; + static const int fact = (int) 1E6; /* must be 10^precision */ + static const double epsilon = 0.5E-6; /* 2epsilon must be 10^-precision */ + static char buf[64]; + // handle very small values: return 0 + if (fabs(n) < epsilon) {buf[0] = '0'; buf[1] = '\0';} + else { + char ints[64]; + int bindex = 0, sindex = 0; + int ival, fval; + // handle the sign part if n is negative + if (n < 0) { + buf[bindex++] = '-'; + n = -n; + } + n += epsilon; // for rounding + // handle the integer part, simply with sprintf + ival = (int)floor(n); + n -= ival; + sprintf(ints, "%d", ival); + while (ints[sindex] != 0) buf[bindex++] = ints[sindex++]; + // handle the fractional part up to 'precision' digits + fval = (int)floor(n*fact); + if (fval) { + // set a dot + buf[bindex++] = '.'; + sindex = bindex + precision; + buf[sindex--] = '\0'; + // fill up trailing zeros with the string terminator NULL + while (((fval % 10) == 0) && (sindex >= bindex)) { + buf[sindex--] = '\0'; + fval /= 10; + } + // fill up the fractional part back to front + while (sindex >= bindex) { + buf[sindex--] = (fval % 10) + '0'; + fval /= 10; + } + } else buf[bindex++] = 0; + } + return (char *)buf; +} + +static void copyObject(Object *obj) +{ + PdfObject obj1; + int i, l, c; + Ref ref; + char *p; + GString *s; + if (obj->isBool()) { + pdf_printf("%s", obj->getBool() ? "true" : "false"); + } + else if (obj->isInt()) { + pdf_printf("%i", obj->getInt()); + } + else if (obj->isReal()) { + pdf_printf("%s", convertNumToPDF(obj->getReal())); + } + else if (obj->isNum()) { + pdf_printf("%s", convertNumToPDF(obj->getNum())); + } + else if (obj->isString()) { + s = obj->getString(); + p = s->getCString(); + l = s->getLength(); + if (strlen(p) == (unsigned int)l) { + pdf_puts("("); + for (; *p != 0; p++) { + c = (unsigned char)*p; + if (c == '(' || c == ')' || c == '\\') + pdf_printf("\\%c", c); + else if (c < 0x20 || c > 0x7F) + pdf_printf("\\%03o", c); + else + pdfout(c); + } + pdf_puts(")"); + } + else { + pdf_puts("<"); + for (i = 0; i < l; i++) { + c = s->getChar(i) & 0xFF; + pdf_printf("%.2x", c); + } + pdf_puts(">"); + } + } + else if (obj->isName()) { + copyName(obj->getName()); + } + else if (obj->isNull()) { + pdf_puts("null"); + } + else if (obj->isArray()) { + pdf_puts("["); + for (i = 0, l = obj->arrayGetLength(); i < l; ++i) { + obj->arrayGetNF(i, &obj1); + if (!obj1->isName()) + pdf_puts(" "); + copyObject(&obj1); + } + pdf_puts("]"); + } + else if (obj->isDict()) { + pdf_puts("<<\n"); + copyDict(obj); + pdf_puts(">>"); + } + else if (obj->isStream()) { + initDictFromDict (obj1, obj->streamGetDict()); + obj->streamGetDict()->incRef(); + pdf_puts("<<\n"); + copyDict(&obj1); + pdf_puts(">>\n"); + pdf_puts("stream\n"); + copyStream(obj->getStream()->getBaseStream()); + pdf_puts("endstream"); + } + else if (obj->isRef()) { + ref = obj->getRef(); + if (ref.num == 0) { + pdftex_warn("pdf inclusion: reference to invalid object was replaced by <null>"); + pdf_puts("null"); + } + else + pdf_printf("%d 0 R", addOther(ref)); + } + else { + pdftex_fail("pdf inclusion: type <%s> cannot be copied", + obj->getTypeName()); + } +} + +static void writeRefs() +{ + InObj *r; + for (r = inObjList; r != 0; r = r->next) { + if (!r->written) { + Object obj1; + r->written = 1; + zpdfbeginobj(r->num); + xref->fetch(r->ref.num, r->ref.gen, &obj1); + if (r->type == objFont || r->type == objFontDesc) + copyFontDict(&obj1, r); + else + copyObject(&obj1); + pdf_puts("\n"); + pdfendobj(); + obj1.free(); + } + } +} + +static void writeEncodings() +{ + UsedEncoding *r, *n; + char *glyphNames[MAX_CHAR_CODE + 1], *s; + int i; + for (r = encodingList; r != 0; r = r->next) { + for (i = 0; i <= MAX_CHAR_CODE; i++) { + if (r->font->isCIDFont()) { + pdftex_warn("pdf inclusion: CID font included, encoding maybe wrong"); + } + if ((s = ((Gfx8BitFont *)r->font)->getCharName(i)) != 0) + glyphNames[i] = s; + else + glyphNames[i] = notdef; + } + write_enc(glyphNames, NULL, r->enc_objnum); + } + for (r = encodingList; r != 0; r = n) { + n = r->next; + delete r->font; + delete r; + } +} + +/* Reads various information about the pdf and sets it up for later inclusion. + * This will fail if the pdf version of the pdf is higher than + * minor_pdf_version_wanted or page_name is given and can not be found. + * It makes no sense to give page_name _and_ page_num. + * Returns the page number. + */ +integer +read_pdf_info(char *image_name, char *page_name, integer page_num, + integer minor_pdf_version_wanted, integer always_use_pdf_pagebox, + integer pdf_inclusion_errorlevel) +{ + PdfDocument *pdf_doc; + Page *page; + int rotate; + PDFRectangle *pagebox; + float pdf_version_found, pdf_version_wanted; + // initialize + if (!isInit) { + globalParams = new GlobalParams(); + globalParams->setErrQuiet(gFalse); + isInit = gTrue; + } + // open PDF file + pdf_doc = find_add_document(image_name); + epdf_doc = (void *) pdf_doc; +#ifdef DEBUG + fprintf(stderr, "\nReading information on %s\n", pdf_doc->file_name); +#endif + // check pdf version + // this works only for pdf 1.x -- but since any versions of pdf newer + // than 1.x will not be backwards compatible to pdf 1.x, pdfTeX will + // then have to changed drastically anyway. + pdf_version_found = pdf_doc->doc->getPDFVersion(); + pdf_version_wanted = 1 + (minor_pdf_version_wanted * 0.1); + if (pdf_version_found > pdf_version_wanted) { + char msg[] = "pdf inclusion: found pdf version <%.1f>, but at most version <%.1f> allowed"; + if (pdf_inclusion_errorlevel > 0) { + pdftex_fail(msg, pdf_version_found, pdf_version_wanted); + } else { + pdftex_warn(msg, pdf_version_found, pdf_version_wanted); + } + } + epdf_num_pages = pdf_doc->doc->getCatalog()->getNumPages(); + if (page_name) { + // get page by name + GString name(page_name); + LinkDest *link = pdf_doc->doc->findDest(&name); + if (link == 0 || !link->isOk()) + pdftex_fail("pdf inclusion: invalid destination <%s>", + page_name); + Ref ref = link->getPageRef(); + page_num = pdf_doc->doc->getCatalog()->findPage(ref.num, ref.gen); + if (page_num == 0) + pdftex_fail("pdf inclusion: destination is not a page <%s>", + page_name); + delete link; + } else { + // get page by number + if (page_num <= 0 || page_num > epdf_num_pages) + pdftex_fail("pdf inclusion: required page does not exist <%i>", + epdf_num_pages); + } + // get the required page + page = pdf_doc->doc->getCatalog()->getPage(page_num); + + // get the pagebox (media, crop...) to use. + // always_use_pdf_pagebox can set in the config file to override the + // setting through pdfximage. + if (always_use_pdf_pagebox < 1) { + switch (pdflastpdfboxspec) { + case pdfpdfboxspeccrop: + pagebox = page->getCropBox(); + break; + + case pdfpdfboxspecbleed: + pagebox = page->getBleedBox(); + break; + + case pdfpdfboxspectrim: + pagebox = page->getTrimBox(); + break; + + case pdfpdfboxspecart: + pagebox = page->getArtBox(); + break; + + default: + pagebox = page->getMediaBox(); + } + } + else { + switch (always_use_pdf_pagebox) { + case 1 : + pagebox = page->getMediaBox(); + break; + case 2 : + pagebox = page->getCropBox(); + break; + case 3 : + pagebox = page->getBleedBox(); + break; + case 4 : + pagebox = page->getTrimBox(); + break; + default : // 5 and larger + pagebox = page->getArtBox(); + } + } +#ifdef DEBUG + fprintf(stderr, + "\npagebox->x1: %.8f, pagebox->x2: %.8f, pagebox->y1: %.8f, pagebox->y2: %.8f\n", + pagebox->x1, pagebox->x2, pagebox->y1, pagebox->y2); +#endif + epdf_width = pagebox->x2 - pagebox->x1; + epdf_height = pagebox->y2 - pagebox->y1; + epdf_orig_x = pagebox->x1; + epdf_orig_y = pagebox->y1; + + rotate = page->getRotate(); + // handle page rotation and adjust dimens as needed + if (rotate != 0) { + if (rotate % 90 == 0) { + // handle only the simple case: multiple of 90s. + // these are the only values allowed according to the + // reference (v1.3, p.78). + // 180 needs no special treatment here + register float f; + switch (rotate) { + case 90: f = epdf_height; epdf_height = epdf_width; epdf_width = f; break; + case 270: f = epdf_height; epdf_height = epdf_width; epdf_width = f; break; + } + } + } + pdf_doc->xref = pdf_doc->doc->getXRef(); + return page_num; +} + +/* writes the current epf_doc. + * Here the included pdf is copied, so most errors that can happen during pdf + * inclusion will arise here. + */ +void +write_epdf(void) +{ + Page *page; + PdfObject contents, obj1, obj2; + PdfObject group, metadata, pieceinfo, separationInfo; + Object info; + char *key; + int i, l; + int rotate; + double scale[6] = {0, 0, 0, 0, 0, 0}; + bool writematrix = false; + PdfDocument *pdf_doc = (PdfDocument *) epdf_doc; + (pdf_doc->occurences)--; +#ifdef DEBUG + fprintf(stderr, "\nDecrementing %s (%d)\n", pdf_doc->file_name, pdf_doc->occurences); +#endif + xref = pdf_doc->xref; + inObjList = pdf_doc->inObjList; + encodingList = 0; + page = pdf_doc->doc->getCatalog()->getPage(epdf_selected_page); + rotate = page->getRotate(); + PDFRectangle *pagebox; + // write the Page header + pdf_puts("/Type /XObject\n"); + pdf_puts("/Subtype /Form\n"); + pdf_puts("/FormType 1\n"); + + // write additional information + pdf_printf("/%s.FileName (%s)\n", pdfkeyprefix, + convertStringToPDFString(pdf_doc->file_name, + strlen(pdf_doc->file_name))); + pdf_printf("/%s.PageNumber %i\n", pdfkeyprefix, epdf_selected_page); + pdf_doc->doc->getDocInfoNF(&info); + if (info.isRef()) { + // the info dict must be indirect (pdf ref p.61) + pdf_printf("/%s.InfoDict ", pdfkeyprefix); + pdf_printf("%d 0 R \n", addOther(info.getRef())); + } + + // get the pagebox (media, crop...) to use. + // epdf_always_use_pdf_pagebox is a copy of always_use_pdf_pagebox which + // can set in the config file to override the setting through pdfximage. + if (epdf_always_use_pdf_pagebox < 1) { + switch (epdf_page_box) { + case pdfpdfboxspeccrop: + pagebox = page->getCropBox(); + break; + + case pdfpdfboxspecbleed: + pagebox = page->getBleedBox(); + break; + + case pdfpdfboxspectrim: + pagebox = page->getTrimBox(); + break; + + case pdfpdfboxspecart: + pagebox = page->getArtBox(); + break; + + default: + pagebox = page->getMediaBox(); + } + } + else { + switch (epdf_always_use_pdf_pagebox) { + case 1 : + pagebox = page->getMediaBox(); + break; + case 2 : + pagebox = page->getCropBox(); + break; + case 3 : + pagebox = page->getBleedBox(); + break; + case 4 : + pagebox = page->getTrimBox(); + break; + default : // 5 and larger + pagebox = page->getArtBox(); + } + } +#ifdef DEBUG + fprintf(stderr, + "\npagebox->x1: %.8f, pagebox->x2: %.8f, pagebox->y1: %.8f, pagebox->y2: %.8f\n", + pagebox->x1, pagebox->x2, pagebox->y1, pagebox->y2); +#endif + + // handle page rotation + if (rotate != 0) { + if (rotate % 90 == 0) { + // this handles only the simple case: multiple of 90s but these + // are the only values allowed according to the reference + // (v1.3, p.78). + // the image is rotated around its center. + // the /Rotate key is clockwise while the matrix is + // counterclockwise :-% + tex_printf (", page is rotated %d degrees", rotate); + switch (rotate) { + case 90: scale[1] = -1; scale[2] = 1; scale[4] = pagebox->x1 - pagebox->y1; scale[5] = pagebox->y1 + pagebox->x2; writematrix = true; break; + case 180: scale[0] = scale[3] = -1; scale[4] = pagebox->x1 + pagebox->x2; scale[5] = pagebox->y1 + pagebox->y2; writematrix = true; break; // width and height are exchanged + case 270: scale[1] = 1; scale[2] = -1; scale[4] = pagebox->x1 + pagebox->y2; scale[5] = pagebox->y1 - pagebox->x1; writematrix = true; break; + } + if (writematrix) { // The matrix is only written if the image is rotated. + pdf_printf("/Matrix [%.8f %.8f %.8f %.8f %.8f %.8f]\n", + scale[0], + scale[1], + scale[2], + scale[3], + scale[4], + scale[5]); + } + } + } + + pdf_printf("/BBox [%.8f %.8f %.8f %.8f]\n", + pagebox->x1, + pagebox->y1, + pagebox->x2, + pagebox->y2); + + // write the page Group if it's there + if (page->getGroup() != NULL) { +#if PDFTEX_COPY_PAGEGROUP +# if PDFTEX_COPY_PAGEGROUP_NOFAIL + // FIXME: This will most likely produce incorrect PDFs :-( + initDictFromDict(group, page->getGroup()); + if (group->dictGetLength() > 0) { + pdf_puts("/Group "); + copyObject (&group); + pdf_puts("\n"); + } +# else + // FIXME: currently we don't know how to handle Page Groups so we abort gracefully :-( + pdftex_fail("pdf inclusion: Page Group detected which pdfTeX can't handle. Sorry."); +# endif +#else + // FIXME: currently we don't know how to handle Page Groups so we at least give a warning :-( + pdftex_warn("pdf inclusion: Page Group detected which pdfTeX can't handle. Ignoring it."); +#endif + } + + // write the page Metadata if it's there + if (page->getMetadata() != NULL) { + metadata->initStream(page->getMetadata()); + pdf_puts("/Metadata "); + copyObject (&metadata); + pdf_puts("\n"); + } + + // write the page PieceInfo if it's there + if (page->getPieceInfo() != NULL) { + initDictFromDict (pieceinfo, page->getPieceInfo()); + if (pieceinfo->dictGetLength() > 0) { + pdf_puts("/PieceInfo "); + copyObject (&pieceinfo); + pdf_puts("\n"); + } + } + + // write the page SeparationInfo if it's there + if (page->getSeparationInfo() != NULL) { + initDictFromDict (separationInfo, page->getSeparationInfo()); + if (separationInfo->dictGetLength() > 0) { + pdf_puts("/SeparationInfo "); + copyObject (&separationInfo); + pdf_puts("\n"); + } + } + + // write the Resources dictionary + if (page->getResourceDict() == NULL) { + // Resources can be missing (files without them have been spotted + // in the wild). This violates the pdf spec, which claims they are + // required, but all RIPs accept them. + // We "replace" them with empty Resources. + pdftex_warn("pdf inclusion: no /Resources detected. Replacing with empty /Resources."); + pdf_puts("/Resources <<>>\n"); + } + else { + initDictFromDict (obj1, page->getResourceDict()); + page->getResourceDict()->incRef(); + if (!obj1->isDict()) + pdftex_fail("pdf inclusion: invalid resources dict type <%s>", + obj1->getTypeName()); + pdf_puts("/Resources <<\n"); + for (i = 0, l = obj1->dictGetLength(); i < l; ++i) { + obj1->dictGetVal(i, &obj2); + key = obj1->dictGetKey(i); + if (strcmp("Font", key) == 0) + copyFontResources(&obj2); + else if (strcmp("ProcSet", key) == 0) + copyProcSet(&obj2); + else + copyOtherResources(&obj2, key); + } + pdf_puts(">>\n"); + } + // write the page contents + page->getContents(&contents); + if (contents->isStream()) { + initDictFromDict (obj1, contents->streamGetDict()); + contents->streamGetDict()->incRef(); + copyDict(&obj1); + pdf_puts(">>\nstream\n"); + copyStream(contents->getStream()->getBaseStream()); + pdf_puts("endstream\n"); + pdfendobj(); + } + else if (contents->isArray()) { + pdfbeginstream(); + for (i = 0, l = contents->arrayGetLength(); i < l; ++i) { + Object contentsobj; + copyStream((contents->arrayGet(i, &contentsobj))->getStream()); + contentsobj.free(); + } + pdfendstream(); + } + else {// the contents are optional, but we need to include an empty stream + pdfbeginstream(); + pdfendstream(); + } + // write out all indirect objects + writeRefs(); + // write out all used encodings (and delete list) + writeEncodings(); + // save object list, xref + pdf_doc->inObjList = inObjList; + pdf_doc->xref = xref; +} + +// Called when an image has been written and it's resources in image_tab are +// freed and it's not referenced anymore. +void +epdf_delete() +{ + PdfDocument *pdf_doc = (PdfDocument *) epdf_doc; + xref = pdf_doc->xref; + if (pdf_doc->occurences < 0) { +#ifdef DEBUG + fprintf(stderr, "\nDeleting %s\n", pdf_doc->file_name); +#endif + delete_document(pdf_doc); + } +} + +// Called when PDF embedding system is finalized. +// Now deallocate all remaining PdfDocuments. +void epdf_check_mem() +{ + if (isInit) { + PdfDocument *p, *n; + for (p = pdfDocuments; p; p = n) { + n = p->next; + delete_document(p); + } + // see above for globalParams + delete globalParams; + } +} +// vi:ts=4:tw=79:expandtab:ai: diff --git a/Build/source/texk/web2c/pdftexdir/pdftosrc.cc b/Build/source/texk/web2c/pdftexdir/pdftosrc.cc new file mode 100644 index 00000000000..ec83aca7b94 --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/pdftosrc.cc @@ -0,0 +1,130 @@ +/* +Copyright (c) 1996-2002 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/pdftosrc.cc#10 $ +*/ + +#include <stdlib.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <aconf.h> +#include <GString.h> +#include <gmem.h> +#include <gfile.h> +#include "Object.h" +#include "Stream.h" +#include "Array.h" +#include "Dict.h" +#include "XRef.h" +#include "Catalog.h" +#include "Page.h" +#include "GfxFont.h" +#include "PDFDoc.h" +#include "GlobalParams.h" +#include "Error.h" + +static XRef *xref = 0; + +int main(int argc, char *argv[]) +{ + char *p, buf[1024]; + PDFDoc *doc; + GString *fileName; + Stream *s; + Object srcStream, srcName, catalogDict; + FILE *outfile; + char *outname; + int objnum = 0, objgen = 0; + int c; + fprintf(stderr, "pdftosrc version %s\n", xpdfVersion); + if (argc < 2) { + fprintf(stderr, "Usage: pdftosrc <PDF-file> [<stream-object-number>]\n"); + exit(1); + } + fileName = new GString(argv[1]); + globalParams = new GlobalParams(); + doc = new PDFDoc(fileName); + if (!doc->isOk()) { + fprintf(stderr, "Invalid PDF file\n"); + exit(1); + } + if (argc >= 3) { + objnum = atoi(argv[2]); + if (argc >= 4) + objgen = atoi(argv[3]); + } + xref = doc->getXRef(); + catalogDict.initNull(); + xref->getCatalog(&catalogDict); + if (!catalogDict.isDict("Catalog")) { + fprintf(stderr, "No Catalog found\n"); + exit(1); + } + srcStream.initNull(); + if (objnum == 0) { + catalogDict.dictLookup("SourceObject", &srcStream); + if (!srcStream.isStream("SourceFile")) { + fprintf(stderr, "No SourceObject found\n"); + exit(1); + } + srcName.initNull(); + srcStream.getStream()->getDict()->lookup("SourceName", &srcName); + if (!srcName.isString()) { + fprintf(stderr, "No SourceName found\n"); + exit(1); + } + outname = srcName.getString()->getCString(); + // We cannot free srcName, as objname shares its string. + // srcName.free(); + } + else { + xref->fetch(objnum, objgen, &srcStream); + if (!srcStream.isStream()) { + fprintf(stderr, "Not a Stream object\n"); + exit(1); + } + sprintf(buf, "%s", fileName->getCString()); + if ((p = strrchr(buf, '.')) == 0) + p = strchr(buf, 0); + if (objgen == 0) + sprintf(p, ".%i", objnum); + else + sprintf(p, ".%i+%i", objnum, objgen); + outname = buf; + } + if (!(outfile = fopen(outname, "wb"))) { + fprintf(stderr, "Cannot open file \"%s\" for writing\n", outname); + exit(1); + } + s = srcStream.getStream(); + s->reset(); + while ((c = s->getChar()) != EOF) + fputc(c, outfile); + if (objnum == 0) + fprintf(stderr, "Source file extracted to %s\n", outname); + else + fprintf(stderr, "Stream object extracted to %s\n", outname); + fclose(outfile); + catalogDict.free(); + srcStream.free(); + delete doc; + delete globalParams; +} diff --git a/Build/source/texk/web2c/pdftexdir/pdftosrc.rc b/Build/source/texk/web2c/pdftexdir/pdftosrc.rc new file mode 100644 index 00000000000..6929fbade24 --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/pdftosrc.rc @@ -0,0 +1,35 @@ +/* pdftosrc.rc: pdftosrc resources -*- C++ -*- + + Copyright (C) 1996-2003 Fabrice Popineau <fabrice.popineau@supelec.fr> + + This file 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, or (at your + option) any later version. + + This file 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this file; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#include <texlive-version.h> + +#define VER_FILEVERSION TEXLIVE_MAJOR_VERSION,TEXLIVE_MINOR_VERSION,TEXLIVE_BETA_NUMBER,TEXLIVE_ALPHA_NUMBER +#define VER_FILEVERSION_STR TEXLIVE_PRODUCTVERSION_STR " pdftosrc 2.01" + +#define VER_INTERNALNAME_STR "pdftosrc" +#define VER_ORIGINALFILENAME_STR "pdftosrc.exe" + +#define VER_FILEDESCRIPTION_STR "PDF Source Extractor" + +#define VER_COMPANYNAME_STR "" +#define VER_LEGALCOPYRIGHT_STR "" + +#include <texlive.version> + +/* pdftosrc.rc ends here */ diff --git a/Build/source/texk/web2c/pdftexdir/pkin.c b/Build/source/texk/web2c/pdftexdir/pkin.c new file mode 100644 index 00000000000..3bece2124ad --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/pkin.c @@ -0,0 +1,427 @@ +/* +Copyright (c) 1996-2002 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/pkin.c#4 $ +*/ + +/* + * NAME + * pkin.c - implementation of readchar() + * DESCRIPTION + * This implementation of readchar() uses parts of the program dvips + * written by Tomas Rokicki--the inventor of the pkformat--(loadfont.c, + * download.c and unpack.c). Dvips in turn is derived from pktype. + * Pktype(TeX) is described in debt in ``The PKtype processor'', + * which is available as pktype.weave as part of the METAFONTware. + * What was needed to implement readchar() is rearranged in pkfile.c to + * get more modularity in the style of MODULA2. + * BUGFIXES + * May 1997: Eric Delaunay <delaunay@lix.polytechnique.fr> reports a + * problem with huge fonts (greater than 1008 DPI). The code for + * handling PK characters in `extended format' was wrongly derived + * from dvips. Made some minor improvements regarding error handling. + * REDESIGN + * Piet Tutelaers + * rcpt@urc.tue.nl + * + * Modified for use with pdftex by Han The Thanh <thanh@fi.muni.cz>. + */ + +#include "ptexlib.h" + +/* + * Now we have some routines to get stuff from the pk file. pkbyte returns + * the next byte from the pk file. + */ + + +/* +static FILE *pkfile ; +*/ + +extern FILE *t3_file; +#define pkfile t3_file + +static shalfword pkbyte(void) +{ + register shalfword i ; + + if ((i=xgetc(pkfile))==EOF) + pdftex_fail("unexpected eof in pk file") ; + return(i) ; +} + +static integer pkduo(void) +{ + register integer i ; + + i = pkbyte() ; + if (i > 127) + i -= 256 ; + i = i * 256 + pkbyte() ; + return(i) ; +} + +static integer pktrio(void) +{ + register integer i ; + + i = pkbyte() ; + if (i > 127) + i -= 256 ; + i = i * 256 + pkbyte() ; + i = i * 256 + pkbyte() ; + return(i) ; +} + +static integer pkquad(void) +{ + register integer i ; + + i = pkbyte() ; + if (i > 127) + i -= 256 ; + i = i * 256 + pkbyte() ; + i = i * 256 + pkbyte() ; + i = i * 256 + pkbyte() ; + return(i) ; +} + +/* + * The next part is devoted to unpacking the character data. + */ + +/* + * We need procedures to get a nybble, bit, and packed word from the + * packed data structure. + */ + +static halfword inputbyte, flagbyte ; +static halfword bitweight ; +static halfword dynf ; +static halfword repeatcount ; + +static shalfword getnyb(void) +{ halfword temp; + if ( bitweight == 0 ) + { bitweight = 16 ; + inputbyte = pkbyte(); + temp = inputbyte >> 4 ; + } else { + bitweight = 0 ; + temp = inputbyte & 15 ; + } + return(temp); +} + +static boolean getbit(void) +{ + bitweight >>= 1 ; + if ( bitweight == 0 ) + { inputbyte = pkbyte(); + bitweight = 128 ; + } + return(inputbyte & bitweight) ; +} + +static halfword (*realfunc)(void) ; +long pk_remainder ; +static halfword handlehuge(halfword i, halfword k); + +static halfword pkpackednum(void) { +register halfword i, j ; + i = getnyb () ; + if ( i == 0 ) + { do { j = getnyb () ; + i++ ; + } while ( ! ( j != 0 ) ) ; + if ( i > 3 ) { +/* + * Damn, we got a huge count! We *fake* it by giving an artificially + * large repeat count. + */ + return(handlehuge(i, j)) ; + } else { + while ( i > 0 ) + { j = j * 16 + getnyb () ; + i-- ; + } + return ( j - 15 + ( 13 - dynf ) * 16 + dynf ) ; + } + } + else if ( i <= dynf ) return ( i ) ; + else if ( i < 14 ) return ( ( i - dynf - 1 ) * 16 + getnyb () + dynf + 1 + ) ; + else + { if ( i == 14 ) repeatcount = pkpackednum () ; + else repeatcount = 1 ; +#ifdef DEBUG + printf("[%d]", repeatcount); +#endif + return ( (*realfunc)() ) ; + } + } + +static halfword rest(void) +{ + halfword i ; + + if (pk_remainder < 0) { + pk_remainder = - pk_remainder ; + return ( 0 ) ; + } else if (pk_remainder > 0) { + if (pk_remainder > 4000) { + pk_remainder = 4000 - pk_remainder ; + return ( 4000 ) ; + } else { + i = pk_remainder ; + pk_remainder = 0 ; + realfunc = pkpackednum ; + return ( i ) ; + } + } else { + pdftex_fail("shouldn't happen") ; + return 0; /*NOTREACHED*/ + } +} + +static halfword handlehuge(halfword i, halfword k) +{ + register long j = k ; + + while (i) { + j = (j << 4L) + getnyb() ; + i-- ; + } + pk_remainder = j - 15 + ( 13 - dynf ) * 16 + dynf ; + realfunc = rest ; + return ( rest() ) ; +} + +/* + * And now we have our unpacking routine. + */ + +static halfword gpower[17] = { 0, 1, 3, 7, 15, 31, 63, 127, + 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535 } ; + +static void unpack(chardesc *cd) +{ + register integer i, j ; + register halfword word, wordweight ; + halfword *raster; + shalfword rowsleft ; + boolean turnon ; + shalfword hbit ; + halfword count ; + shalfword wordwidth ; + + wordwidth = (cd->cwidth + 15) / 16 ; + i = 2 * cd->cheight * (long)wordwidth ; + if (i <= 0) + i = 2 ; + if (i > cd->rastersize) { + xfree(cd->raster); + cd->rastersize = i; + cd->raster = xtalloc(cd->rastersize, halfword); + } + raster = cd->raster; + realfunc = pkpackednum ; + dynf = flagbyte / 16 ; + turnon = flagbyte & 8 ; + if ( dynf == 14 ) + { bitweight = 0 ; + for ( i = 1 ; i <= cd->cheight ; i ++ ) + { word = 0 ; + wordweight = 32768 ; + for ( j = 1 ; j <= cd->cwidth ; j ++ ) + { if ( getbit () ) word += wordweight ; + wordweight >>= 1 ; + if ( wordweight == 0 ) + { *raster++ = word ; + word = 0 ; + wordweight = 32768 ; + } + } + if ( wordweight != 32768 ) + *raster++ = word ; + } + } else { + rowsleft = cd->cheight ; + hbit = cd->cwidth ; + repeatcount = 0 ; + wordweight = 16 ; + word = 0 ; + bitweight = 0 ; + while ( rowsleft > 0 ) + { count = (*realfunc)() ; +#ifdef DEBUG + if (turnon) printf("(%d) ",count); + else printf("%d ",count); +#endif + while ( count != 0 ) + { if ( ( count < wordweight ) && ( count < hbit ) ) + { if ( turnon ) word += gpower [ wordweight ] - gpower + [ wordweight - count ] ; + hbit -= count ; + wordweight -= count ; + count = 0 ; + } + else if ( ( count >= hbit ) && ( hbit <= wordweight ) ) + { if ( turnon ) + word += gpower [ wordweight ] - gpower + [ wordweight - hbit ] ; + *raster++ = word ; + for ( i = 1 ; i <= repeatcount ; i ++ ) { + for ( j = 1 ; j <= wordwidth ; j ++ ) { + *raster = *(raster - wordwidth) ; + raster++ ; + } + } + rowsleft -= repeatcount + 1 ; + repeatcount = 0 ; + word = 0 ; + wordweight = 16 ; + count -= hbit ; + hbit = cd->cwidth ; + } + else + { if ( turnon ) word += gpower [ wordweight ] ; + *raster++ = word ; + word = 0 ; + count -= wordweight ; + hbit -= wordweight ; + wordweight = 16 ; + } + } + turnon = ! turnon ; + } + if ( ( rowsleft != 0 ) || ( (integer)hbit != cd->cwidth ) ) + pdftex_fail("error while unpacking; more bits than required"); + } +} + +/* + * readchar(): the main routine + * Reads the character definition of character `c' into `cd' if available, + * return FALSE (0) otherwise. + */ + +/* + * readchar(): the main routine + * check pk preamble if necessary, + * read the next character definition into `cd', + * return EOF if no character definition is available + */ + +int readchar(boolean check_preamble, chardesc *cd) +{ + register shalfword i ; + register integer k ; + register integer length=0 ; + +/* + * Check the preamble of the pkfile + */ + if (check_preamble) { + if (pkbyte()!=247) + pdftex_fail("bad pk file, expected pre") ; + if (pkbyte()!=89) + pdftex_fail("bad version of pk file") ; + for(i=pkbyte(); i>0; i--) /* creator of pkfile */ + (void)pkbyte() ; + (void)pkquad(); /* design size */ + k = pkquad() ; /* checksum */ + k = pkquad() ; /* hppp */ + k = pkquad() ; /* vppp */ + } +/* + * Now we skip to the desired character definition + */ + while ((flagbyte=pkbyte())!=245) { + if (flagbyte < 240) { + switch (flagbyte & 7) { +case 0: case 1: case 2: case 3: + length = (flagbyte & 7) * 256 + pkbyte() - 3; + cd->charcode = pkbyte() ; + (void) pktrio() ; /* TFMwidth */ + cd->xescape = pkbyte() ; /* pixel width */ + cd->cwidth = pkbyte() ; + cd->cheight = pkbyte() ; + cd->xoff = pkbyte() ; + cd->yoff = pkbyte() ; + if (cd->xoff > 127) + cd->xoff -= 256 ; + if (cd->yoff > 127) + cd->yoff -= 256 ; + break ; +case 4: case 5: case 6: + length = (flagbyte & 3) * 65536L + pkbyte() * 256L ; + length = length + pkbyte() - 4L ; + cd->charcode = pkbyte() ; + (void) pktrio() ; /* TFMwidth */ + cd->xescape = pkduo() ; /* pixelwidth */ + cd->cwidth = pkduo() ; + cd->cheight = pkduo() ; + cd->xoff = pkduo() ; + cd->yoff = pkduo() ; + break ; +case 7: + length = pkquad() - 9L; + cd->charcode = pkquad(); + (void) pkquad() ; /* TFMwidth */ + cd->xescape = pkquad(); /* pixelwidth */ + k = pkquad() ; + cd->cwidth = pkquad(); + cd->cheight = pkquad(); + cd->xoff = pkquad(); + cd->yoff = pkquad(); + } + if (length <= 0) + pdftex_fail("packet length (%i) too small", (int)length) ; + unpack(cd); + return 1; + } else { + k = 0 ; + switch (flagbyte) { +case 243: + k = pkbyte() ; + if (k > 127) + k -= 256 ; +case 242: + k = k * 256 + pkbyte() ; +case 241: + k = k * 256 + pkbyte() ; +case 240: + k = k * 256 + pkbyte() ; + while (k-- > 0) + i = pkbyte() ; + break ; +case 244: + k = pkquad() ; + break ; +case 246: + break ; +default: + pdftex_fail("unexpected command (%i)", (int)flagbyte) ; + } + } + } + return 0; /* character not found */ +} diff --git a/Build/source/texk/web2c/pdftexdir/ptexlib.h b/Build/source/texk/web2c/pdftexdir/ptexlib.h new file mode 100644 index 00000000000..90159001e39 --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/ptexlib.h @@ -0,0 +1,219 @@ +/* +Copyright (c) 1996-2002 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/ptexlib.h#26 $ +*/ + +#ifndef PDFTEXLIB +#define PDFTEXLIB + +/* WEB2C macros and prototypes */ +#if !defined(PDFTEXCOERCE) && !defined(PDFETEXCOERCE) +#ifdef pdfTeX +#undef pdfTeX /* to avoid warning about redefining pdfTeX in pdftexd.h */ +#endif /* pdfTeX */ +#define EXTERN extern +#include "pdftexd.h" +#endif + +/* pdftexlib macros */ +#include "ptexmac.h" + +/* pdftexlib type declarations */ +typedef struct { + const char *pdfname; + const char *t1name; + float value; + boolean valid; +} key_entry; + +typedef struct { + boolean loaded; /* the encoding has been loaded? */ + char *name; /* encoding file name */ + integer objnum; /* object number */ + char **glyph_names; +} enc_entry; + +typedef struct { + char *tfm_name; /* TFM file name */ + char *ps_name; /* PostScript name */ + integer flags; /* font flags */ + char *ff_name; /* font file name */ + char *subset_tag; /* pseudoUniqueTag for subsetted font */ + enc_entry *encoding; /* pointer to corresponding encoding */ + internalfontnumber tfm_num; /* number of the TFM refering this entry */ + unsigned short type; /* font type (T1/TTF/...) */ + short slant; /* SlantFont */ + short extend; /* ExtendFont */ + integer ff_objnum; /* FontFile object number */ + integer fn_objnum; /* FontName/BaseName object number */ + integer fd_objnum; /* FontDescriptor object number */ + char *charset; /* string containing used glyphs */ + boolean all_glyphs; /* embed all glyphs? */ + unsigned short links; /* link flags from tfm_tree and ps_tree */ + short tfm_avail; /* flags whether a tfm is available */ +} fm_entry; + +typedef struct { + char *ff_name; /* base name of font file */ + char *ff_path; /* full path to font file */ +} ff_entry; + +typedef short shalfword ; +typedef struct { + integer charcode, + cwidth, + cheight, + xoff, + yoff, + xescape, + rastersize; + halfword *raster; +} chardesc; + +/* pdftexlib variable declarations */ +extern boolean fontfile_found; +extern boolean is_otf_font; +extern boolean true_dimen; +extern boolean write_ttf_glyph_names; +extern char **t1_glyph_names, *t1_builtin_glyph_names[]; +extern char *cur_file_name; +extern const char notdef[]; +extern fm_entry *fm_cur; +extern integer t1_length1, t1_length2, t1_length3; +extern integer ttf_length; +extern internalfontnumber tex_font; +extern key_entry font_keys[]; +extern strnumber last_tex_string; +extern size_t last_ptr_index; +extern char fontname_buf[]; + +/* pdftexlib function prototypes */ + +/* epdf.c */ +extern integer get_fontfile_num(int); +extern integer get_fontname_num(int); +extern void epdf_free(void); + +/* mapfile.c */ +extern char *mk_basename(char *); +extern char *mk_exname(char *, int); +extern fm_entry * lookup_fontmap(char *); +extern boolean hasfmentry(internalfontnumber); +extern internalfontnumber tfmoffm(fmentryptr); +extern void checkextfm(strnumber, integer); +extern void fm_free(void); +extern void fm_read_info(void); +extern ff_entry * check_ff_exist(fm_entry *); +extern void pdfmapfile(integer); +extern void pdfmapline(integer); + +/* papersiz.c */ +extern integer myatodim(char **); +extern integer myatol(char **); + +/* pkin.c */ +extern int readchar(boolean, chardesc *); + +/* utils.c */ +extern boolean str_eq_cstr(strnumber, char *); +extern char *makecstring(integer); +extern int xfflush(FILE *); +extern int xgetc(FILE *); +extern int xputc(int, FILE *); +extern scaled extxnoverd(scaled, scaled, scaled); +extern size_t xfwrite(void *, size_t size, size_t nmemb, FILE *); +extern strnumber getresnameprefix(void); +extern strnumber maketexstring(const char *); +extern integer fb_offset(void); +extern void fb_flush(void); +extern void fb_putchar(eightbits b); +extern void fb_seek(integer); +extern void libpdffinish(void); +extern char *makecfilename(strnumber s); +extern void make_subset_tag(fm_entry *, char **); +extern void pdf_printf(const char *,...); +extern void pdf_puts(const char *); +extern void pdftex_fail(const char *,...); +extern void pdftex_warn(const char *,...); +extern void setjobid(int, int, int, int, int, int); +extern void tex_printf(const char *, ...); +extern void writestreamlength(integer, integer); +extern char *convertStringToPDFString(char *in, int len); +extern void printID(strnumber); + +/* vfpacket.c */ +extern eightbits packetbyte(void); +extern integer newvfpacket(internalfontnumber); +extern void poppacketstate(void); +extern void pushpacketstate(void); +extern void startpacket(internalfontnumber, integer); +extern void storepacket(integer, integer, integer); +extern void vf_free(void); + +/* writeenc.c */ +extern boolean indexed_enc(fm_entry *); +extern enc_entry *add_enc(char *); +extern void enc_free(void); +extern void read_enc(enc_entry *); +extern void write_enc(char **, enc_entry *, integer); + +/* writefont.c */ +extern void dopdffont(integer, internalfontnumber); + +/* writeimg.c */ +extern boolean checkimageb(integer); +extern boolean checkimagec(integer); +extern boolean checkimagei(integer); +extern boolean ispdfimage(integer); +extern integer epdforigx(integer); +extern integer epdforigy(integer); +extern integer imageheight(integer); +extern integer imagepages(integer); +extern integer imagewidth(integer); +extern integer imagexres(integer); +extern integer imageyres(integer); +extern integer readimage(strnumber, integer, strnumber, integer, integer, integer, integer); +extern void deleteimage(integer); +extern void img_free(void) ; +extern void updateimageprocset(integer); +extern void writeimage(integer); + +/* writet1.c */ +extern boolean t1_subset(char *, char *, unsigned char *); +extern void load_enc(char *, char **); +extern void writet1(void); +extern void t1_free(void); + +/* writet3.c */ +extern void writet3(int, internalfontnumber); +extern scaled getpkcharwidth(internalfontnumber, scaled); + +/* writettf.c */ +extern void writettf(void); +extern void writeotf(void); + +/* writezip.c */ +extern void writezip(boolean); + +/* avlstuff.c */ +extern void avlputobj(integer, integer); +extern integer avlfindobj(integer, integer, integer); + +#endif /* PDFTEXLIB */ diff --git a/Build/source/texk/web2c/pdftexdir/ptexmac.h b/Build/source/texk/web2c/pdftexdir/ptexmac.h new file mode 100644 index 00000000000..ed6ebe7d9be --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/ptexmac.h @@ -0,0 +1,196 @@ +/* +Copyright (c) 1996-2004 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/ptexmac.h#18 $ +*/ + +#ifndef PDFTEXMAC +#define PDFTEXMAC + +/* Not all systems define it. */ +#ifndef M_PI +#define M_PI 3.14159265358979323846 /* pi */ +#define M_PI_2 1.5707963267948966192E0 /*Hex 2^ 0 * 1.921FB54442D18 */ +#define M_PI_4 7.8539816339744830962E-1 /*Hex 2^-1 * 1.921FB54442D18 */ +#endif + +#ifdef WIN32 +// Why relying on gmalloc() ??? +#define gmalloc(n) xmalloc(n) +#define gfree(p) free(p) +#define inline __inline +#define srandom(n) srand(n) +#define random() rand() +#endif + +/* Pascal WEB macros */ +#define maxinteger 0x7FFFFFFF +#define maxdimen 0x3FFFFFFF + +#define objinfo(n) objtab[n].int0 + +#define pdfroom(n) do { \ + if (pdfbufsize < n) \ + pdftex_fail("PDF output buffer overflowed"); \ + if (pdfptr + n > pdfbufsize) \ + pdfflush(); \ +} while (0) + +#define pdfout(c) do { \ + if (pdfptr > pdfbufsize) \ + pdfflush(); \ + pdfbuf[pdfptr++] = c; \ +} while (0) + +#define pdfoffset() (pdfgone + pdfptr) +#define pdfinitfont(f) {tmpf = f; pdfcreatefontobj();} + +#define MAX_CHAR_CODE 255 + +#define PRINTF_BUF_SIZE 1024 +#define MAX_CSTRING_LEN 1024 +#define MAX_PSTRING_LEN 1024 +#define SMALL_BUF_SIZE 256 +#define SMALL_ARRAY_SIZE 256 +#define FONTNAME_BUF_SIZE 128 /* a PDF name can be maximum 127 chars long */ + +#define check_buf(size, buf_size) \ + if ((size) > (buf_size)) \ + pdftex_fail("buffer overflow", (buf_size)) + +#define append_char_to_buf(c, p, buf, buf_size) do { \ + if (c == 9) \ + c = 32; \ + if (c == 13 || c == EOF) \ + c = 10; \ + if (c != ' ' || (p > buf && p[-1] != 32)) { \ + check_buf(p - buf + 1, (buf_size)); \ + *p++ = c; \ + } \ +} while (0) + +#define append_eol(p, buf, buf_size) do { \ + check_buf(p - buf + 2, (buf_size)); \ + if (p - buf > 1 && p[-1] != 10) \ + *p++ = 10; \ + if (p - buf > 2 && p[-2] == 32) { \ + p[-2] = 10; \ + p--; \ + } \ + *p = 0; \ +} while (0) + +#define remove_eol(p, buf) do { \ + p = strend(buf) - 1; \ + if (*p == 10) \ + *p = 0; \ +} while (0) + +#define skip(p, c) if (*p == c) p++ + +#define alloc_array(T, n, s) do { \ + if (T##_array == NULL) { \ + T##_limit = (s); \ + if ((n) > T##_limit) \ + T##_limit = (n); \ + T##_array = xtalloc(T##_limit, T##_entry); \ + T##_ptr = T##_array; \ + } \ + else if (T##_ptr - T##_array + (n) > T##_limit) { \ + last_ptr_index = T##_ptr - T##_array; \ + T##_limit *= 2; \ + if (T##_ptr - T##_array + (n) > T##_limit) \ + T##_limit = T##_ptr - T##_array + (n); \ + xretalloc(T##_array, T##_limit, T##_entry); \ + T##_ptr = T##_array + last_ptr_index; \ + } \ +} while (0) + +#define is_cfg_comment(c) \ + (c == 10 || c == '*' || c == '#' || c == ';' || c == '%') + +#define define_array(T) \ +T##_entry *T##_ptr, *T##_array = NULL; \ +size_t T##_limit + +#define xfree(p) do { if (p != NULL) free(p); p = NULL; } while (0) +#define strend(s) strchr(s, 0) +#define xtalloc XTALLOC +#define xretalloc XRETALLOC + +#define ASCENT_CODE 0 +#define CAPHEIGHT_CODE 1 +#define DESCENT_CODE 2 +#define FONTNAME_CODE 3 +#define ITALIC_ANGLE_CODE 4 +#define STEMV_CODE 5 +#define XHEIGHT_CODE 6 +#define FONTBBOX1_CODE 7 +#define FONTBBOX2_CODE 8 +#define FONTBBOX3_CODE 9 +#define FONTBBOX4_CODE 10 +#define MAX_KEY_CODE (FONTBBOX1_CODE + 1) +#define FONT_KEYS_NUM (FONTBBOX4_CODE + 1) + +#define F_INCLUDED 0x01 +#define F_SUBSETTED 0x02 +#define F_TRUETYPE 0x04 +#define F_BASEFONT 0x08 + +#define set_included(fm) ((fm)->type |= F_INCLUDED) +#define set_subsetted(fm) ((fm)->type |= F_SUBSETTED) +#define set_truetype(fm) ((fm)->type |= F_TRUETYPE) +#define set_basefont(fm) ((fm)->type |= F_BASEFONT) + +#define unset_included(fm) ((fm)->type &= ~F_INCLUDED) +#define unset_subsetted(fm) ((fm)->type &= ~F_SUBSETTED) +#define unset_truetype(fm) ((fm)->type &= ~F_TRUETYPE) +#define unset_basefont(fm) ((fm)->type &= ~F_BASEFONT) + +#define unset_fontfile(fm) xfree((fm)->ff_name) + +#define is_included(fm) ((fm)->type & F_INCLUDED) +#define is_subsetted(fm) ((fm)->type & F_SUBSETTED) +#define is_truetype(fm) ((fm)->type & F_TRUETYPE) +#define is_basefont(fm) ((fm)->type & F_BASEFONT) +#define no_font_desc(fm) (is_basefont(fm) && !is_included(fm)) + +#define fm_slant(fm) (fm)->slant +#define fm_extend(fm) (fm)->extend +#define fm_fontfile(fm) (fm)->ff_name + +#define is_reencoded(fm) ((fm)->encoding != NULL) +#define is_fontfile(fm) (fm_fontfile(fm) != NULL) +#define is_t1fontfile(fm) (is_fontfile(fm) && !is_truetype(fm)) + +#define LINK_TFM 0x01 +#define LINK_PS 0x02 +#define set_tfmlink(fm) ((fm)->links |= LINK_TFM) +#define set_pslink(fm) ((fm)->links |= LINK_PS) +#define unset_tfmlink(fm) ((fm)->links &= ~LINK_TFM) +#define unset_pslink(fm) ((fm)->links &= ~LINK_PS) +#define has_tfmlink(fm) ((fm)->links & LINK_TFM) +#define has_pslink(fm) ((fm)->links & LINK_PS) + + +#define set_cur_file_name(s) \ + cur_file_name = s; \ + packfilename(maketexstring(cur_file_name), getnullstr(), getnullstr()) + +#endif /* PDFTEXMAC */ diff --git a/Build/source/texk/web2c/pdftexdir/randoms.ch b/Build/source/texk/web2c/pdftexdir/randoms.ch new file mode 100644 index 00000000000..2268143406d --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/randoms.ch @@ -0,0 +1,569 @@ +% randoms.ch +% Copyright (c) 2005 Han Th\^e\llap{\raise 0.5ex\hbox{\'{}}} Th\`anh, <thanh@pdftex.org> +% +% This file is part of pdfTeX. +% +% pdfTeX 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. +% +% pdfTeX 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 General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with pdfTeX; if not, write to the Free Software +% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +% +% $Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/pdftex.ch#163 $ +% +% This is a WEB change file for pseudo-random numbers in pdftex 1.30 and above. +% +% There are four new primitives: +% +% \pdfuniformdeviate <count> +% Generates a uniformly distributed random integer value +% between 0 (inclusive) and <count> (exclusive). +% This primitive expands to a list of tokens. +% +% \pdfnormaldeviate +% Expands to a random integer value with a mean of 0 and a +% unit of 65536. +% This primitive expands to a list of tokens. +% +% \pdfrandomseed +% You can use \the\pdfrandomseed to query the current seed value, +% so you can e.g. the value to the log file. +% +% The initial value of the seed is derived from the system time, +% and is not more than 1,000,999,999 (this ensures that the value +% can be used with commands like \count). +% +% \pdfsetrandomseed <count> +% This sets the random seed to a specific value, allowing you +% to re-play sequences of semi-randoms at a later moment. +% +% Most of the actual code is taken from metapost, and originally +% written by Knuth, for Metafont. Glue to make it work in TeX is +% by me. If you find an error, it is bound to be in my code, +% not Knuth's :-) +% +% Taco Hoekwater (taco@metatex.org), june 27, 2005. No restrictions. + +@x +@* \[8] Packed data. +@y +@* \[7b] Random numbers. + +\font\tenlogo=logo10 % font used for the METAFONT logo +\def\MP{{\tenlogo META}\-{\tenlogo POST}} + +This section is (almost) straight from MetaPost. I had to change +the types (use |integer| instead of |fraction|), but that should +not have any influence on the actual calculations (the original +comments refer to quantities like |fraction_four| ($2^{30}$), and +that is the same as the numeric representation of |maxdimen|). + +I've copied the low-level variables and routines that are needed, but +only those (e.g. |m_log|), not the accompanying ones like |m_exp|. Most +of the following low-level numeric routines are only needed within the +calculation of |norm_rand|. I've been forced to rename |make_fraction| +to |make_frac| because TeX already has a routine by that name with +a wholly different function (it creates a |fraction_noad| for math +typesetting) -- Taco + +And now let's complete our collection of numeric utility routines +by considering random number generation. +\MP\ generates pseudo-random numbers with the additive scheme recommended +in Section 3.6 of {\sl The Art of Computer Programming}; however, the +results are random fractions between 0 and |fraction_one-1|, inclusive. + +There's an auxiliary array |randoms| that contains 55 pseudo-random +fractions. Using the recurrence $x_n=(x_{n-55}-x_{n-31})\bmod 2^{28}$, +we generate batches of 55 new $x_n$'s at a time by calling |new_randoms|. +The global variable |j_random| tells which element has most recently +been consumed. + +@<Glob...@>= +@!randoms:array[0..54] of integer; {the last 55 random values generated} +@!j_random:0..54; {the number of unused |randoms|} +@!random_seed:scaled; {the default random seed} + +@ A small bit of metafont is needed. + +@d fraction_half==@'1000000000 {$2^{27}$, represents 0.50000000} +@d fraction_one==@'2000000000 {$2^{28}$, represents 1.00000000} +@d fraction_four==@'10000000000 {$2^{30}$, represents 4.00000000} +@d el_gordo == @'17777777777 {$2^{31}-1$, the largest value that \MP\ likes} +@d halfp(#)==(#) div 2 +@d double(#) == #:=#+# {multiply a variable by two} + +@ The |make_frac| routine produces the |fraction| equivalent of +|p/q|, given integers |p| and~|q|; it computes the integer +$f=\lfloor2^{28}p/q+{1\over2}\rfloor$, when $p$ and $q$ are +positive. If |p| and |q| are both of the same scaled type |t|, +the ``type relation'' |make_frac(t,t)=fraction| is valid; +and it's also possible to use the subroutine ``backwards,'' using +the relation |make_frac(t,fraction)=t| between scaled types. + +If the result would have magnitude $2^{31}$ or more, |make_frac| +sets |arith_error:=true|. Most of \MP's internal computations have +been designed to avoid this sort of error. + +If this subroutine were programmed in assembly language on a typical +machine, we could simply compute |(@t$2^{28}$@>*p)div q|, since a +double-precision product can often be input to a fixed-point division +instruction. But when we are restricted to \PASCAL\ arithmetic it +is necessary either to resort to multiple-precision maneuvering +or to use a simple but slow iteration. The multiple-precision technique +would be about three times faster than the code adopted here, but it +would be comparatively long and tricky, involving about sixteen +additional multiplications and divisions. + +This operation is part of \MP's ``inner loop''; indeed, it will +consume nearly 10\pct! of the running time (exclusive of input and output) +if the code below is left unchanged. A machine-dependent recoding +will therefore make \MP\ run faster. The present implementation +is highly portable, but slow; it avoids multiplication and division +except in the initial stage. System wizards should be careful to +replace it with a routine that is guaranteed to produce identical +results in all cases. +@^system dependencies@> + +As noted below, a few more routines should also be replaced by machine-dependent +code, for efficiency. But when a procedure is not part of the ``inner loop,'' +such changes aren't advisable; simplicity and robustness are +preferable to trickery, unless the cost is too high. +@^inner loop@> + +@p function make_frac(@!p,@!q:integer):integer; +var @!f:integer; {the fraction bits, with a leading 1 bit} +@!n:integer; {the integer part of $\vert p/q\vert$} +@!negative:boolean; {should the result be negated?} +@!be_careful:integer; {disables certain compiler optimizations} +begin if p>=0 then negative:=false +else begin negate(p); negative:=true; + end; +if q<=0 then + begin debug if q=0 then confusion("/");@;@+gubed@;@/ +@:this can't happen /}{\quad \./@> + negate(q); negative:=not negative; + end; +n:=p div q; p:=p mod q; +if n>=8 then + begin arith_error:=true; + if negative then make_frac:=-el_gordo@+else make_frac:=el_gordo; + end +else begin n:=(n-1)*fraction_one; + @<Compute $f=\lfloor 2^{28}(1+p/q)+{1\over2}\rfloor$@>; + if negative then make_frac:=-(f+n)@+else make_frac:=f+n; + end; +end; + +@ The |repeat| loop here preserves the following invariant relations +between |f|, |p|, and~|q|: +(i)~|0<=p<q|; (ii)~$fq+p=2^k(q+p_0)$, where $k$ is an integer and +$p_0$ is the original value of~$p$. + +Notice that the computation specifies +|(p-q)+p| instead of |(p+p)-q|, because the latter could overflow. +Let us hope that optimizing compilers do not miss this point; a +special variable |be_careful| is used to emphasize the necessary +order of computation. Optimizing compilers should keep |be_careful| +in a register, not store it in memory. +@^inner loop@> + +@<Compute $f=\lfloor 2^{28}(1+p/q)+{1\over2}\rfloor$@>= +f:=1; +repeat be_careful:=p-q; p:=be_careful+p; +if p>=0 then f:=f+f+1 +else begin double(f); p:=p+q; + end; +until f>=fraction_one; +be_careful:=p-q; +if be_careful+p>=0 then incr(f) + +@ + +@p function take_frac(@!q:integer;@!f:integer):integer; +var @!p:integer; {the fraction so far} +@!negative:boolean; {should the result be negated?} +@!n:integer; {additional multiple of $q$} +@!be_careful:integer; {disables certain compiler optimizations} +begin @<Reduce to the case that |f>=0| and |q>0|@>; +if f<fraction_one then n:=0 +else begin n:=f div fraction_one; f:=f mod fraction_one; + if q<=el_gordo div n then n:=n*q + else begin arith_error:=true; n:=el_gordo; + end; + end; +f:=f+fraction_one; +@<Compute $p=\lfloor qf/2^{28}+{1\over2}\rfloor-q$@>; +be_careful:=n-el_gordo; +if be_careful+p>0 then + begin arith_error:=true; n:=el_gordo-p; + end; +if negative then take_frac:=-(n+p) +else take_frac:=n+p; +end; + +@ @<Reduce to the case that |f>=0| and |q>0|@>= +if f>=0 then negative:=false +else begin negate(f); negative:=true; + end; +if q<0 then + begin negate(q); negative:=not negative; + end; + +@ The invariant relations in this case are (i)~$\lfloor(qf+p)/2^k\rfloor +=\lfloor qf_0/2^{28}+{1\over2}\rfloor$, where $k$ is an integer and +$f_0$ is the original value of~$f$; (ii)~$2^k\L f<2^{k+1}$. +@^inner loop@> + +@<Compute $p=\lfloor qf/2^{28}+{1\over2}\rfloor-q$@>= +p:=fraction_half; {that's $2^{27}$; the invariants hold now with $k=28$} +if q<fraction_four then + repeat if odd(f) then p:=halfp(p+q)@+else p:=halfp(p); + f:=halfp(f); + until f=1 +else repeat if odd(f) then p:=p+halfp(q-p)@+else p:=halfp(p); + f:=halfp(f); + until f=1 + +@ The subroutines for logarithm and exponential involve two tables. +The first is simple: |two_to_the[k]| equals $2^k$. The second involves +a bit more calculation, which the author claims to have done correctly: +|spec_log[k]| is $2^{27}$ times $\ln\bigl(1/(1-2^{-k})\bigr)= +2^{-k}+{1\over2}2^{-2k}+{1\over3}2^{-3k}+\cdots\,$, rounded to the +nearest integer. + +@<Glob...@>= +@!two_to_the:array[0..30] of integer; {powers of two} +@!spec_log:array[1..28] of integer; {special logarithms} + + +@ @<Set init...@>= +two_to_the[0]:=1; +for k:=1 to 30 do two_to_the[k]:=2*two_to_the[k-1]; +spec_log[1]:=93032640; +spec_log[2]:=38612034; +spec_log[3]:=17922280; +spec_log[4]:=8662214; +spec_log[5]:=4261238; +spec_log[6]:=2113709; +spec_log[7]:=1052693; +spec_log[8]:=525315; +spec_log[9]:=262400; +spec_log[10]:=131136; +spec_log[11]:=65552; +spec_log[12]:=32772; +spec_log[13]:=16385; +for k:=14 to 27 do spec_log[k]:=two_to_the[27-k]; +spec_log[28]:=1; + +@ + +@p function m_log(@!x:integer):integer; +var @!y,@!z:integer; {auxiliary registers} +@!k:integer; {iteration counter} +begin if x<=0 then @<Handle non-positive logarithm@> +else begin y:=1302456956+4-100; {$14\times2^{27}\ln2\approx1302456956.421063$} + z:=27595+6553600; {and $2^{16}\times .421063\approx 27595$} + while x<fraction_four do + begin double(x); y:=y-93032639; z:=z-48782; + end; {$2^{27}\ln2\approx 93032639.74436163$ + and $2^{16}\times.74436163\approx 48782$} + y:=y+(z div unity); k:=2; + while x>fraction_four+4 do + @<Increase |k| until |x| can be multiplied by a + factor of $2^{-k}$, and adjust $y$ accordingly@>; + m_log:=y div 8; + end; +end; + +@ @<Increase |k| until |x| can...@>= +begin z:=((x-1) div two_to_the[k])+1; {$z=\lceil x/2^k\rceil$} +while x<fraction_four+z do + begin z:=halfp(z+1); k:=k+1; + end; +y:=y+spec_log[k]; x:=x-z; +end + +@ @<Handle non-positive logarithm@>= +begin print_err("Logarithm of "); +@.Logarithm...replaced by 0@> +print_scaled(x); print(" has been replaced by 0"); +help2("Since I don't take logs of non-positive numbers,")@/ + ("I'm zeroing this one. Proceed, with fingers crossed."); +error; m_log:=0; +end + +@ The following somewhat different subroutine tests rigorously if $ab$ is +greater than, equal to, or less than~$cd$, +given integers $(a,b,c,d)$. In most cases a quick decision is reached. +The result is $+1$, 0, or~$-1$ in the three respective cases. + +@d return_sign(#)==begin ab_vs_cd:=#; return; + end + +@p function ab_vs_cd(@!a,b,c,d:integer):integer; +label exit; +var @!q,@!r:integer; {temporary registers} +begin @<Reduce to the case that |a,c>=0|, |b,d>0|@>; +loop@+ begin q := a div d; r := c div b; + if q<>r then + if q>r then return_sign(1)@+else return_sign(-1); + q := a mod d; r := c mod b; + if r=0 then + if q=0 then return_sign(0)@+else return_sign(1); + if q=0 then return_sign(-1); + a:=b; b:=q; c:=d; d:=r; + end; {now |a>d>0| and |c>b>0|} +exit:end; + +@ @<Reduce to the case that |a...@>= +if a<0 then + begin negate(a); negate(b); + end; +if c<0 then + begin negate(c); negate(d); + end; +if d<=0 then + begin if b>=0 then + if ((a=0)or(b=0))and((c=0)or(d=0)) then return_sign(0) + else return_sign(1); + if d=0 then + if a=0 then return_sign(0)@+else return_sign(-1); + q:=a; a:=c; c:=q; q:=-b; b:=-d; d:=q; + end +else if b<=0 then + begin if b<0 then if a>0 then return_sign(-1); + if c=0 then return_sign(0) else return_sign(-1); + end + +@ To consume a random integer, the program below will say `|next_random|' +and then it will fetch |randoms[j_random]|. + +@d next_random==if j_random=0 then new_randoms + else decr(j_random) + +@p procedure new_randoms; +var @!k:0..54; {index into |randoms|} +@!x:integer; {accumulator} +begin for k:=0 to 23 do + begin x:=randoms[k]-randoms[k+31]; + if x<0 then x:=x+fraction_one; + randoms[k]:=x; + end; +for k:=24 to 54 do + begin x:=randoms[k]-randoms[k-24]; + if x<0 then x:=x+fraction_one; + randoms[k]:=x; + end; +j_random:=54; +end; + +@ To initialize the |randoms| table, we call the following routine. + +@p procedure init_randoms(@!seed:integer); +var @!j,@!jj,@!k:integer; {more or less random integers} +@!i:0..54; {index into |randoms|} +begin j:=abs(seed); +while j>=fraction_one do j:=halfp(j); +k:=1; +for i:=0 to 54 do + begin jj:=k; k:=j-k; j:=jj; + if k<0 then k:=k+fraction_one; + randoms[(i*21)mod 55]:=j; + end; +new_randoms; new_randoms; new_randoms; {``warm up'' the array} +end; + +@ To produce a uniform random number in the range |0<=u<x| or |0>=u>x| +or |0=u=x|, given a |scaled| value~|x|, we proceed as shown here. + +Note that the call of |take_frac| will produce the values 0 and~|x| +with about half the probability that it will produce any other particular +values between 0 and~|x|, because it rounds its answers. + +@p function unif_rand(@!x:integer):integer; +var @!y:integer; {trial value} +begin next_random; y:=take_frac(abs(x),randoms[j_random]); +if y=abs(x) then unif_rand:=0 +else if x>0 then unif_rand:=y +else unif_rand:=-y; +end; + +@ Finally, a normal deviate with mean zero and unit standard deviation +can readily be obtained with the ratio method (Algorithm 3.4.1R in +{\sl The Art of Computer Programming\/}). + +@p function norm_rand:integer; +var @!x,@!u,@!l:integer; {what the book would call $2^{16}X$, $2^{28}U$, + and $-2^{24}\ln U$} +begin repeat + repeat next_random; + x:=take_frac(112429,randoms[j_random]-fraction_half); + {$2^{16}\sqrt{8/e}\approx 112428.82793$} + next_random; u:=randoms[j_random]; + until abs(x)<u; +x:=make_frac(x,u); +l:=139548960-m_log(u); {$2^{24}\cdot12\ln2\approx139548959.6165$} +until ab_vs_cd(1024,l,x,x)>=0; +norm_rand:=x; +end; + +@* \[8] Packed data. +@z + +@x l.388 +@d pdftex_last_item_codes = pdftex_first_rint_code + 11 {end of \pdfTeX's command codes} +@y +@d random_seed_code = pdftex_first_rint_code + 12 {code for \.{\\pdfrandomseed}} +@d pdftex_last_item_codes = pdftex_first_rint_code + 12 {end of \pdfTeX's command codes} +@z + +@x l.417 +primitive("pdfelapsedtime",last_item,elapsed_time_code); +@!@:elapsed_time_}{\.{\\pdfelapsedtime} primitive@> +@y +primitive("pdfelapsedtime",last_item,elapsed_time_code); +@!@:elapsed_time_}{\.{\\pdfelapsedtime} primitive@> +primitive("pdfrandomseed",last_item,random_seed_code); +@!@:random_seed_}{\.{\\pdfrandomseed} primitive@> +@z + +@x l.434 + elapsed_time_code: print_esc("pdfelapsedtime"); +@y + elapsed_time_code: print_esc("pdfelapsedtime"); + random_seed_code: print_esc("pdfrandomseed"); +@z + +@x l.461 + elapsed_time_code: cur_val := get_microinterval; +@y + elapsed_time_code: cur_val := get_microinterval; + random_seed_code: cur_val := random_seed; +@z + +@x +@d pdftex_convert_codes = pdftex_first_expand_code + 21 {end of \pdfTeX's command codes} +@y +@d uniform_deviate_code = pdftex_first_expand_code + 21 {end of \pdfTeX's command codes} +@d normal_deviate_code = pdftex_first_expand_code + 22 {end of \pdfTeX's command codes} +@d pdftex_convert_codes = pdftex_first_expand_code + 23 {end of \pdfTeX's command codes} +@z + +@x +primitive("jobname",convert,job_name_code);@/ +@y +primitive("pdfuniformdeviate",convert,uniform_deviate_code);@/ +@!@:uniform_deviate_}{\.{\\pdfuniformdeviate} primitive@> +primitive("pdfnormaldeviate",convert,normal_deviate_code);@/ +@!@:normal_deviate_}{\.{\\pdfnormaldeviate} primitive@> +primitive("jobname",convert,job_name_code);@/ +@z + +@x + othercases print_esc("jobname") +@y + uniform_deviate_code: print_esc("pdfuniformdeviate"); + normal_deviate_code: print_esc("pdfnormaldeviate"); + othercases print_esc("jobname") +@z + +@x +pdf_strcmp_code: + begin + save_scanner_status := scanner_status; + save_warning_index := warning_index; + save_def_ref := def_ref; + compare_strings; + def_ref := save_def_ref; + warning_index := save_warning_index; + scanner_status := save_scanner_status; + end; +job_name_code: if job_name=0 then open_log_file; +@y +pdf_strcmp_code: + begin + save_scanner_status := scanner_status; + save_warning_index := warning_index; + save_def_ref := def_ref; + compare_strings; + def_ref := save_def_ref; + warning_index := save_warning_index; + scanner_status := save_scanner_status; + end; +job_name_code: if job_name=0 then open_log_file; +uniform_deviate_code: scan_int; +normal_deviate_code: do_nothing; +@z + +@x +job_name_code: print(job_name); +@y +uniform_deviate_code: print_int(unif_rand(cur_val)); +normal_deviate_code: print_int(norm_rand); +job_name_code: print(job_name); +@z + + +@x +@<Compute the magic offset@>; +@y +random_seed :=(microseconds*1000)+(epochseconds mod 1000000);@/ +init_randoms(random_seed);@/ +@<Compute the magic offset@>; +@z + +@x l. 4562 +@d pdftex_last_extension_code == pdftex_first_extension_code + 25 +@y +@d set_random_seed_code == pdftex_first_extension_code + 26 +@d pdftex_last_extension_code == pdftex_first_extension_code + 26 +@z + +@x l.4625 +primitive("pdfresettimer",extension,reset_timer_code);@/ +@!@:reset_timer_}{\.{\\pdfresettimer} primitive@> +@y +primitive("pdfresettimer",extension,reset_timer_code);@/ +@!@:reset_timer_}{\.{\\pdfresettimer} primitive@> +primitive("pdfsetrandomseed",extension,set_random_seed_code);@/ +@!@:set_random_seed_code}{\.{\\pdfsetrandomseed} primitive@> +@z + +@x + reset_timer_code: print_esc("pdfresettimer"); +@y + reset_timer_code: print_esc("pdfresettimer"); + set_random_seed_code: print_esc("pdfsetrandomseed"); +@z + +@x +reset_timer_code: @<Implement \.{\\pdfresettimer}@>; +@y +reset_timer_code: @<Implement \.{\\pdfresettimer}@>; +set_random_seed_code: @<Implement \.{\\pdfsetrandomseed}@>; +@z + +@x +@ @<Implement \.{\\pdfresettimer}@>= +@y +@ Negative random seed values are silently converted to positive ones + +@<Implement \.{\\pdfsetrandomseed}@>= +begin + scan_int; + if cur_val<0 then negate(cur_val); + random_seed := cur_val; + init_randoms(random_seed); +end + +@ @<Implement \.{\\pdfresettimer}@>= +@z + diff --git a/Build/source/texk/web2c/pdftexdir/tex.ch0 b/Build/source/texk/web2c/pdftexdir/tex.ch0 new file mode 100644 index 00000000000..f3c0b93fa80 --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/tex.ch0 @@ -0,0 +1,42 @@ +% +% Copyright (c) 1996-2002 Han The Thanh, <thanh@pdftex.org> +% +% This file is part of pdfTeX. +% +% pdfTeX 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. +% +% pdfTeX 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 General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with pdfTeX; if not, write to the Free Software +% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +% +% $Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/tex.ch0#10 $ +% +% Change file to assist in creating the web2c-specific change file. +% This one comes first, resolves inconsistencies between the generated +% pdftex.web and tex.ch + +@x [1.2] l.188 +@d TeX_banner=='This is TeX, Version 3.141592' {printed when \TeX\ starts} +@# +@d banner==pdfTeX_banner +@y +@d banner=='This is TeX, Version 3.141592' {printed when \TeX\ starts} +@z + +@x [17.236] l.4960 - first web2c, then pdfTeX additional integer parameters +@d tex_int_pars=55 {total number of \TeX's integer parameters} +@# +@d pdftex_first_integer_code = tex_int_pars {base for \pdfTeX's integer parameters} +@y +@d int_pars=55 {total number of integer parameters} +@# +@d pdftex_first_integer_code = tex_int_pars {base for \pdfTeX's integer parameters} +@z diff --git a/Build/source/texk/web2c/pdftexdir/tex.ch1 b/Build/source/texk/web2c/pdftexdir/tex.ch1 new file mode 100644 index 00000000000..172e2a6668b --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/tex.ch1 @@ -0,0 +1,39 @@ +% +% Copyright (c) 1996-2002 Han The Thanh, <thanh@pdftex.org> +% +% This file is part of pdfTeX. +% +% pdfTeX 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. +% +% pdfTeX 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 General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with pdfTeX; if not, write to the Free Software +% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +% +% $Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/tex.ch1#11 $ +% +% Change file to assist in creating the web2c-specific change file. +% This one resolves inconsistencies between tex.ch and tex.pch. + +@x [1] m.2 l.188 - banner +@d banner==TeX_banner +@d banner_k==TeX_banner_k +@y +@d banner==pdfTeX_banner +@d banner_k==pdfTeX_banner_k +@z + +@x [17.236] l.4960 - first web2c, then pdfTeX additional integer parameters +@d int_pars=web2c_int_pars {total number of integer parameters} +@# +@d pdftex_first_integer_code = tex_int_pars {base for \pdfTeX's integer parameters} +@y +@d pdftex_first_integer_code = web2c_int_pars {base for \pdfTeX's integer parameters} +@z diff --git a/Build/source/texk/web2c/pdftexdir/tex.pch b/Build/source/texk/web2c/pdftexdir/tex.pch new file mode 100644 index 00000000000..ca78e387dd5 --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/tex.pch @@ -0,0 +1,355 @@ +% Copyright (c) 1996-2005 Han Th\^e\llap{\raise 0.5ex\hbox{\'{}}} Th\`anh, <thanh@pdftex.org> +% +% Note: This file, pdftexdir/tex.pch, contains the web2c changes for the +% pdfTeX specific part of pdftex.web (defined in pdftexdir/pdftex.ch) +% and is used as follows to construct the web2c change file for pdfTeX: +% +% pdftexdir/tex.ch0 ) +% + ) +% tex.ch ) +% + ) => tie -c ... => pdftex.ch +% pdftexdir/tex.ch1 ) +% + ) +% pdftexdir/tex.pch ) +% +% In addition, this file is used to construct the web2c change file +% for pdfeTeX: +% +% pdfetexdir/tex.ch0 ) +% + ) +% tex.ch ) +% + ) +% etexdir/tex.ch1 ) +% + ) => tie -c ... => pdfetex.ch +% etexdir/tex.ech ) +% + ) +% pdfetexdir/tex.ch1 ) +% + ) +% pdftexdir/tex.pch ) +% +% where the four (small) files pdf{,e}texdir/tex.ch[01] take care +% of interferences between web2c, e-Tex, pdfTeX changes. +% Consequently, changes in all these files have to be coordinated. + +% This file is part of pdfTeX. +% +% pdfTeX 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. +% +% pdfTeX 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 General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with pdfTeX; if not, write to the Free Software +% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +% +% $Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/tex.pch#26 $ +% Change file containing web2c-specific or system-dependent changes to +% pdftex + +@x [1] m.2 l.188 - Web2C: extensions imply we're not pdfTeX +@d pdfTeX_banner=='This is pdfTeX, Version 3.141592',pdftex_version_string +@y +@d pdfTeX_banner_k=='This is pdfTeXk, Version 3.141592',pdftex_version_string +@d pdfTeX_banner=='This is pdfTeX, Version 3.141592',pdftex_version_string +@z + +@x (MLTeX) + begin i := char_tag(char_info(f)(c)); +@y + begin i := char_tag(orig_char_info(f)(c)); +@z + +@x (MLTeX) +@d is_valid_char(#)==((font_bc[f] <= #) and (# <= font_ec[f]) and + char_exists(char_info(f)(#))) +@y +@d is_valid_char(#)==((font_bc[f] <= #) and (# <= font_ec[f]) and + char_exists(orig_char_info(f)(#))) +@z + +@x (MLTeX) +function get_charwidth(f: internal_font_number; c: eight_bits): scaled; +begin + if is_valid_char(c) then + get_charwidth := char_width(f)(char_info(f)(c)) + else + get_charwidth := 0; +end; + +function get_charheight(f: internal_font_number; c: eight_bits): scaled; +begin + if is_valid_char(c) then + get_charheight := char_height(f)(height_depth(char_info(f)(c))) + else + get_charheight := 0; +end; + +function get_chardepth(f: internal_font_number; c: eight_bits): scaled; +begin + if is_valid_char(c) then + get_chardepth := char_depth(f)(height_depth(char_info(f)(c))) + else + get_chardepth := 0; +end; +@y +function get_charwidth(f: internal_font_number; c: eight_bits): scaled; +begin + if is_valid_char(c) then + get_charwidth := char_width(f)(orig_char_info(f)(c)) + else + get_charwidth := 0; +end; + +function get_charheight(f: internal_font_number; c: eight_bits): scaled; +begin + if is_valid_char(c) then + get_charheight := char_height(f)(height_depth(orig_char_info(f)(c))) + else + get_charheight := 0; +end; + +function get_chardepth(f: internal_font_number; c: eight_bits): scaled; +begin + if is_valid_char(c) then + get_chardepth := char_depth(f)(height_depth(orig_char_info(f)(c))) + else + get_chardepth := 0; +end; +@z + +@x (MLTeX) +label reswitch, move_past, fin_rule, next_p; +@y +label reswitch, move_past, fin_rule, next_p, found, continue; +@z + +@x (MLTeX) + if is_valid_char(c) then + output_one_char(c) + else + char_warning(f, c); + cur_h:=cur_h+char_width(f)(char_info(f)(c)); +@y + if is_valid_char(c) then begin + output_one_char(c); + cur_h:=cur_h+char_width(f)(char_info(f)(c)); + goto continue; + end; + if mltex_enabled_p then + @<(\pdfTeX) Output a substitution, |goto continue| if not possible@>; +continue: +@z + +@x +@ The |pdf_vlist_out| routine is similar to |pdf_hlist_out|, but a bit simpler. +@y +@ @<(\pdfTeX) Output a substitution, |goto continue| if not possible@>= + begin + @<Get substitution information, check it, goto |found| + if all is ok, otherwise goto |continue|@>; +found: @<Print character substition tracing log@>; + @<(\pdfTeX) Rebuild character using substitution information@>; + end + +@ @<(\pdfTeX) Rebuild character using substitution information@>= + base_x_height:=x_height(f); + base_slant:=slant(f)/float_constant(65536); +@^real division@> + accent_slant:=base_slant; {slant of accent character font} + base_width:=char_width(f)(ib_c); + base_height:=char_height(f)(height_depth(ib_c)); + accent_width:=char_width(f)(ia_c); + accent_height:=char_height(f)(height_depth(ia_c)); + @/{compute necessary horizontal shift (don't forget slant)}@/ + delta:=round((base_width-accent_width)/float_constant(2)+ + base_height*base_slant-base_x_height*accent_slant); +@^real multiplication@> +@^real addition@> + @/{1. For centering/horizontal shifting insert a kern node.}@/ + cur_h:=cur_h+delta; + @/{2. Then insert the accent character possibly shifted up or down.}@/ + if ((base_height<>base_x_height) and (accent_height>0)) then + begin {the accent must be shifted up or down} + cur_v:=base_line+(base_x_height-base_height); + output_one_char(accent_c); + cur_v:=base_line; + end + else begin + output_one_char(accent_c); + end; + cur_h:=cur_h+accent_width; + @/{3. For centering/horizontal shifting insert another kern node.}@/ + cur_h:=cur_h+(-accent_width-delta); + @/{4. Output the base character.}@/ + output_one_char(base_c); + cur_h:=cur_h+base_width; + +@ The |pdf_vlist_out| routine is similar to |pdf_hlist_out|, but a bit simpler. +@z + +@x [49.1259] + begin if s>0 then + begin if s=font_size[f] then goto common_ending; + end + else if font_size[f]=xn_over_d(font_dsize[f],-s,1000) then + goto common_ending; + end +@y + begin + if pdf_font_step[f] = 0 then begin + if s>0 then + begin if s=font_size[f] then goto common_ending; + end + else if font_size[f]=xn_over_d(font_dsize[f],-s,1000) then + goto common_ending; + end + end +@z + +@x (WEB2C!) +param_base:=xmalloc_array(integer, font_max); + +undump_things(font_check[null_font], font_ptr+1-null_font); +@y +param_base:=xmalloc_array(integer, font_max); + +pdf_char_used:=xmalloc_array(char_used_array, font_max); +pdf_char_map:=xmalloc_array(char_map_array, font_max); +pdf_font_size:=xmalloc_array(scaled, font_max); +pdf_font_num:=xmalloc_array(integer, font_max); +pdf_font_map:=xmalloc_array(fm_entry_ptr, font_max); +pdf_font_type:=xmalloc_array(eight_bits, font_max); +pdf_font_attr:=xmalloc_array(str_number, font_max); +pdf_font_blink:=xmalloc_array(internal_font_number, font_max); +pdf_font_elink:=xmalloc_array(internal_font_number, font_max); +pdf_font_stretch:=xmalloc_array(integer, font_max); +pdf_font_shrink:=xmalloc_array(integer, font_max); +pdf_font_step:=xmalloc_array(integer, font_max); +pdf_font_expand_ratio:=xmalloc_array(integer, font_max); +pdf_font_auto_expand:=xmalloc_array(boolean, font_max); +pdf_font_lp_base:=xmalloc_array(integer, font_max); +pdf_font_rp_base:=xmalloc_array(integer, font_max); +pdf_font_ef_base:=xmalloc_array(integer, font_max); +vf_packet_base:=xmalloc_array(integer, font_max); +vf_default_font:=xmalloc_array(internal_font_number, font_max); +vf_local_font_num:=xmalloc_array(internal_font_number, font_max); +vf_e_fnts:=xmalloc_array(integer, font_max); +vf_i_fnts:=xmalloc_array(internal_font_number, font_max); + +for font_k := font_base to font_max do begin + for k := 0 to 31 do begin + pdf_char_used[font_k, k] := 0; + pdf_char_map[font_k, k] := k; + end; + pdf_char_map[font_k, 32] := 32; + pdf_font_size[font_k] := 0; + pdf_font_num[font_k] := 0; + pdf_font_map[font_k] := 0; + pdf_font_type[font_k] := new_font_type; + pdf_font_attr[font_k] := ""; + pdf_font_blink[font_k] := null_font; + pdf_font_elink[font_k] := null_font; + pdf_font_stretch[font_k] := null_font; + pdf_font_shrink[font_k] := null_font; + pdf_font_step[font_k] := 0; + pdf_font_expand_ratio[font_k] := 0; + pdf_font_auto_expand[font_k] := false; + pdf_font_lp_base[font_k] := 0; + pdf_font_rp_base[font_k] := 0; + pdf_font_ef_base[font_k] := 0; +end; + +make_pdftex_banner; +undump_things(font_check[null_font], font_ptr+1-null_font); +@z + +@x [51.1] + setup_bound_var (0)('hash_extra')(hash_extra); + +@y + setup_bound_var (0)('hash_extra')(hash_extra); + setup_bound_var (65536)('obj_tab_size')(obj_tab_size); + setup_bound_var (20000)('dest_names_size')(dest_names_size); +@z + +@x [51.2] + const_chk (hash_extra); + if error_line > ssup_error_line then error_line := ssup_error_line; +@y + const_chk (hash_extra); + const_chk (obj_tab_size); + const_chk (pdf_mem_size); + const_chk (dest_names_size); + if error_line > ssup_error_line then error_line := ssup_error_line; +@z + +@x [51.3] + hyph_link :=xmalloc_array (hyph_pointer, hyph_size); +@y + hyph_link :=xmalloc_array (hyph_pointer, hyph_size); + obj_tab:=xmalloc_array (obj_entry, obj_tab_size); + pdf_mem:=xmalloc_array (integer, inf_pdf_mem_size); {will grow dynamically} + dest_names:=xmalloc_array (dest_name_entry, dest_names_size); +@z + +@x (WEB2C!) + param_base:=xmalloc_array(integer, font_max); + + font_ptr:=null_font; fmem_ptr:=7; +@y +param_base:=xmalloc_array(integer, font_max); + +pdf_char_used:=xmalloc_array(char_used_array,font_max); +pdf_char_map:=xmalloc_array(char_map_array,font_max); +pdf_font_size:=xmalloc_array(scaled,font_max); +pdf_font_num:=xmalloc_array(integer,font_max); +pdf_font_map:=xmalloc_array(fm_entry_ptr,font_max); +pdf_font_type:=xmalloc_array(eight_bits,font_max); +pdf_font_attr:=xmalloc_array(str_number,font_max); +pdf_font_blink:=xmalloc_array(internal_font_number,font_max); +pdf_font_elink:=xmalloc_array(internal_font_number,font_max); +pdf_font_stretch:=xmalloc_array(integer,font_max); +pdf_font_shrink:=xmalloc_array(integer,font_max); +pdf_font_step:=xmalloc_array(integer,font_max); +pdf_font_expand_ratio:=xmalloc_array(integer,font_max); +pdf_font_auto_expand:=xmalloc_array(boolean,font_max); +pdf_font_lp_base:=xmalloc_array(integer,font_max); +pdf_font_rp_base:=xmalloc_array(integer,font_max); +pdf_font_ef_base:=xmalloc_array(integer,font_max); +vf_packet_base:=xmalloc_array(integer,font_max); +vf_default_font:=xmalloc_array(internal_font_number,font_max); +vf_local_font_num:=xmalloc_array(internal_font_number,font_max); +vf_e_fnts:=xmalloc_array(integer,font_max); +vf_i_fnts:=xmalloc_array(internal_font_number,font_max); + +for font_k := font_base to font_max do begin + for k := 0 to 31 do begin + pdf_char_used[font_k, k] := 0; + pdf_char_map[font_k, k] := k; + end; + pdf_char_map[font_k, 32] := 32; + pdf_font_size[font_k] := 0; + pdf_font_num[font_k] := 0; + pdf_font_map[font_k] := 0; + pdf_font_type[font_k] := new_font_type; + pdf_font_attr[font_k] := ""; + pdf_font_blink[font_k] := null_font; + pdf_font_elink[font_k] := null_font; + pdf_font_stretch[font_k] := null_font; + pdf_font_shrink[font_k] := null_font; + pdf_font_step[font_k] := 0; + pdf_font_expand_ratio[font_k] := 0; + pdf_font_auto_expand[font_k] := false; + pdf_font_lp_base[font_k] := 0; + pdf_font_rp_base[font_k] := 0; + pdf_font_ef_base[font_k] := 0; +end; + +font_ptr:=null_font; fmem_ptr:=7; +make_pdftex_banner; +@z diff --git a/Build/source/texk/web2c/pdftexdir/ttf2afm.c b/Build/source/texk/web2c/pdftexdir/ttf2afm.c new file mode 100644 index 00000000000..d3aa7051339 --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/ttf2afm.c @@ -0,0 +1,998 @@ +/* +Copyright (c) 1996-2005 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/ttf2afm.c#21 $ +*/ + +/* +#include <kpathsea/c-auto.h> +#include <kpathsea/c-fopen.h> +#include <kpathsea/c-limits.h> +#include <kpathsea/c-memstr.h> +#include <kpathsea/c-proto.h> +#include <kpathsea/c-std.h> +#include <kpathsea/c-unistd.h> +#include <kpathsea/c-vararg.h> +#include <kpathsea/getopt.h> +*/ +#include <kpathsea/kpathsea.h> +#include <time.h> +#include <libgen.h> +#include <pdftexdir/ptexmac.h> +#include <pdftexdir/writettf.h> + +static const char perforce_id[] = + "$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/ttf2afm.c#21 $"; + +/* constants used for print_glyph */ +#define AS_NAME 0 +#define AS_INDEX 1 +#define AS_UNICODE 2 + +#define VERSION "1.0" + +#define enc_getchar() xgetc(encfile) +#define enc_eof() feof(encfile) +#define pdftex_fail ttf_fail + +#define print_str(S) if (S != NULL) fprintf(outfile, #S " %s\n", S) +#define print_dimen(N) if (N != 0) fprintf(outfile, #N " %i\n", (int)get_ttf_funit(N)) + +#define get_ttf_funit(n) \ + (n < 0 ? -((-n/upem)*1000 + ((-n%upem)*1000)/upem) :\ + ((n/upem)*1000 + ((n%upem)*1000)/upem)) + +typedef struct _unicode_entry { + TTF_USHORT code; + struct _unicode_entry *next; +} unicode_entry; + +typedef struct { + TTF_ULONG wx; + const char *name; + TTF_USHORT index; + TTF_LONG bbox[4]; + TTF_LONG offset; + char found; + unicode_entry *unicode_list; +} mtx_entry; + +typedef struct _kern_entry { + TTF_FWORD value; + TTF_USHORT adjacent; + struct _kern_entry *next; +} kern_entry; + + +char *FontName = NULL; +char *FullName = NULL; +char *FamilyName = NULL; +char *Notice = NULL; +char *Version = NULL; +char *Weight = NULL; +TTF_LONG ItalicAngle = 0; +TTF_LONG IsFixedPitch = 0; +TTF_LONG FontBBox1 = 0; +TTF_LONG FontBBox2 = 0; +TTF_LONG FontBBox3 = 0; +TTF_LONG FontBBox4 = 0; +TTF_LONG UnderlinePosition = 0; +TTF_LONG UnderlineThickness = 0; +TTF_LONG CapHeight = 0; +TTF_LONG XHeight = 0; +TTF_LONG Ascender = 0; +TTF_LONG Descender = 0; + +char *cur_file_name = NULL; +char *bname = NULL; +FILE *fontfile, *encfile, *outfile = NULL; +char enc_line[ENC_BUF_SIZE]; +int print_glyph = AS_NAME; /* print glyph as names by default*/ +int print_cmap = 0; +int use_ext_enc = 0; /* use external encoding? */ +int select_unicode = 1; /* use the first unicode mapping by default */ +int printing_enc = 0; /* set to 1 while printing encodings */ + + +TTF_USHORT upem; +TTF_USHORT ntabs; +int nhmtx; +int post_format; +int loca_format; +int nglyphs; +int nkernpairs = 0; +int names_count = 0; +char *ps_glyphs_buf = NULL; +dirtab_entry *dir_tab; +mtx_entry *mtx_tab; +kern_entry *kern_tab; +char *enc_names[MAX_CHAR_CODE + 1]; + +cmap_entry *cmap_tab; +TTF_USHORT ncmapsubtabs; +long cmap_offset; + +TTF_USHORT unicode_map[0xFFFF]; + +#include "macnames.c" + +void ttf_fail(char *fmt,...) +{ + va_list args; + va_start(args, fmt); + fprintf(stderr, "\nError: ttf2afm"); + if (cur_file_name) + fprintf(stderr, " (file %s)", cur_file_name); + fprintf(stderr, ": "); + vfprintf(stderr, fmt, args); + fprintf(stderr, "\n"); + va_end(args); + exit(-1); +} + +void ttf_warn(char *fmt,...) +{ + va_list args; + va_start(args, fmt); + fprintf(stderr, "\nWarning: ttf2afm"); + if (cur_file_name) + fprintf(stderr, " (file %s)", cur_file_name); + fprintf(stderr, ": "); + vfprintf(stderr, fmt, args); + fprintf(stderr, "\n"); + va_end(args); +} + +int xgetc(FILE *stream) +{ + int c = getc(stream); + if (c < 0 && c != EOF) + ttf_fail("getc() failed"); + return c; +} + +long ttf_getnum(int s) +{ + long i = 0; + int c; + while (s > 0) { + if ((c = xgetc(fontfile)) < 0) + ttf_fail("unexpected EOF"); + i = (i << 8) + c; + s--; + } + return i; +} + +dirtab_entry *name_lookup(char *s) +{ + dirtab_entry *p; + for (p = dir_tab; p - dir_tab < ntabs; p++) + if (strncmp(p->tag, s, 4) == 0) + break; + if (p - dir_tab == ntabs) + p = NULL; + return p; +} + +void ttf_seek_tab(char *name, TTF_LONG offset) +{ + dirtab_entry *p = name_lookup(name); + if (p == NULL) + ttf_fail("can't find table `%s'", name); + if (fseek(fontfile, p->offset + offset, SEEK_SET) < 0) + ttf_fail("fseek() failed while reading `%s' table", name); +} + +void ttf_seek_off(char *name, TTF_LONG offset) +{ + if (fseek(fontfile, offset, SEEK_SET) < 0) + ttf_fail("fseek() failed while reading `%s' table", name); +} + +void store_kern_value(TTF_USHORT i, TTF_USHORT j, TTF_FWORD v) +{ + kern_entry *pk; + for (pk = kern_tab + i; pk->next != NULL; pk = pk->next); + pk->next = xtalloc(1, kern_entry); + pk = pk->next; + pk->next = NULL; + pk->adjacent = j; + pk->value = v; +} + +TTF_FWORD get_kern_value(TTF_USHORT i, TTF_USHORT j) +{ + kern_entry *pk; + for (pk = kern_tab + i; pk->next != NULL; pk = pk->next) + if (pk->adjacent == j) + return pk->value; + return 0; +} + +void free_tabs() +{ + int i; + kern_entry *p, *q, *r; + unicode_entry *u, *v; + mtx_entry *pm; + xfree(ps_glyphs_buf); + xfree(dir_tab); + xfree(cmap_tab); + for (pm = mtx_tab; pm - mtx_tab < nglyphs; pm++) + if (pm->unicode_list != NULL) { + for (u = pm->unicode_list; u != NULL; u = v) { + v = u->next; + xfree(u); + } + } + xfree(mtx_tab); + for (i = 0; i <= MAX_CHAR_CODE; i++) + if (enc_names[i] != notdef) + free(enc_names[i]); + if (kern_tab == NULL) + return; + for (p = kern_tab; p - kern_tab < nglyphs; p++) + if (p->next != NULL) { + for (q = p->next; q != NULL; q = r) { + r = q->next; + xfree(q); + } + } + xfree(kern_tab); +} + +void enc_getline() +{ + char *p; + int c; +restart: + if (enc_eof()) + ttf_fail("unexpected end of file"); + p = enc_line; + do { + c = enc_getchar(); + append_char_to_buf(c, p, enc_line, ENC_BUF_SIZE); + } while (c != 10); + append_eol(p, enc_line, ENC_BUF_SIZE); + if (p - enc_line <= 2 || *enc_line == '%') + goto restart; +} + +void read_encoding(char *encname) +{ + char buf[ENC_BUF_SIZE], *q, *r; + int i; + cur_file_name = encname; + if ((encfile = kpse_open_file(encname, kpse_enc_format)) == NULL) + ttf_fail("can't open encoding file for reading"); + enc_getline(); + if (*enc_line != '/' || (r = strchr(enc_line, '[')) == 0) + ttf_fail("invalid encoding vector: name or `[' missing:\n%s", enc_line); + for (i = 0; i <= MAX_CHAR_CODE; i++) + enc_names[i] = (char*) notdef; + if (r[1] == 32) + r += 2; + else + r++; + for (;;) { + while (*r == '/') { + for (q = buf, r++; *r != ' ' && *r != 10 && *r != ']' && *r != '/'; *q++ = *r++); + *q = 0; + if (*r == ' ') + r++; + if (strcmp(buf, notdef) != 0) + enc_names[names_count] = xstrdup(buf); + if (names_count++ > MAX_CHAR_CODE) + ttf_fail("encoding vector contains more than %i names", + (int)(MAX_CHAR_CODE + 1)); + } + if (*r != 10 && *r != '%') + if (strncmp(r, "] def", strlen("] def")) == 0) + goto done; + else + ttf_fail("invalid encoding vector: a name or `] def' expected:\n%s", enc_line); + enc_getline(); + r = enc_line; + } +done: + xfclose(encfile, cur_file_name); + if (names_count != MAX_CHAR_CODE + 1) + ttf_warn("encoding vector contains only %i names (expected %i)", + names_count, MAX_CHAR_CODE + 1); +} + +void append_unicode(long glyph_index, TTF_USHORT code) +{ + mtx_entry *m; + unicode_entry *u, *v; + assert(glyph_index >= 0 && glyph_index < nglyphs); + u = xtalloc(1, unicode_entry), *v; + m = mtx_tab + glyph_index; + u->next = NULL; + u->code = code; + if (m->unicode_list == NULL) + m->unicode_list = u; + else { + for (v = m->unicode_list; v->next != NULL; v = v->next); + v->next = u; + } +} + +void read_cmap() +{ + cmap_entry *e; + seg_entry *seg_tab, *s; + TTF_USHORT *glyphId, format, segCount; + long int n, i, j, k, first_code, length, last_sep, index; + int unicode_map_count = 0; + ttf_seek_tab("cmap", TTF_USHORT_SIZE); /* skip the table vesrion number (=0) */ + ncmapsubtabs = get_ushort(); + cmap_offset = xftell(fontfile, cur_file_name) - 2*TTF_USHORT_SIZE; + cmap_tab = xtalloc(ncmapsubtabs, cmap_entry); + for (e = cmap_tab; e - cmap_tab < ncmapsubtabs; e++) { + e->platform_id = get_ushort(); + e->encoding_id = get_ushort(); + e->offset = get_ulong(); + } + for (i = 0; i < 0xFFFF; ++i) + unicode_map[i] = NOGLYPH_ASSIGNED_YET; + for (e = cmap_tab; e - cmap_tab < ncmapsubtabs; e++) { + ttf_seek_off("cmap", cmap_offset + e->offset); + format = get_ushort(); + if (is_unicode_mapping(e) && format == 4) { + ++unicode_map_count; + if (unicode_map_count == select_unicode) + goto read_unicode_mapping; + } + continue; +read_unicode_mapping: + length = get_ushort(); /* length of subtable */ + get_ushort(); /* skip the version number */ + segCount = get_ushort()/2; + get_ushort(); /* skip searchRange */ + get_ushort(); /* skip entrySelector */ + get_ushort(); /* skip rangeShift */ + seg_tab = xtalloc(segCount, seg_entry); + for (s = seg_tab; s - seg_tab < segCount; s++) + s->endCode = get_ushort(); + get_ushort(); /* skip reversedPad */ + for (s = seg_tab; s - seg_tab < segCount; s++) + s->startCode = get_ushort(); + for (s = seg_tab; s - seg_tab < segCount; s++) + s->idDelta = get_ushort(); + for (s = seg_tab; s - seg_tab < segCount; s++) + s->idRangeOffset = get_ushort(); + length -= 8*TTF_USHORT_SIZE + 4*segCount*TTF_USHORT_SIZE; + n = length/TTF_USHORT_SIZE; /* number of glyphID's */ + glyphId = xtalloc(n, TTF_USHORT); + for (i = 0; i < n; i++) + glyphId[i] = get_ushort(); + for (s = seg_tab; s - seg_tab < segCount; s++) { + for (i = s->startCode; i <= s->endCode; i++) { + if (i == 0xFFFF) + break; + if (s->idRangeOffset != 0xFFFF) { + if (s->idRangeOffset == 0) + index = (s->idDelta + i) & 0xFFFF; + else { + k = (i - s->startCode) + s->idRangeOffset/2 + + (s - seg_tab) - segCount ; + assert(k >= 0 && k < n); + index = glyphId[k]; + if (index != 0) + index = (index + s->idDelta) & 0xFFFF; + } + if (index < 0 || index >= nglyphs) + ttf_fail("cmap: glyph index out of range [0..%i)", nglyphs); + if (unicode_map[i] != NOGLYPH_ASSIGNED_YET) + ttf_fail("cmap: unicode %.4X is mapped to multiple glyphs", i); + if (unicode_map[i] == 0) + ttf_warn("unicode %.4X is mapped to glyph 0", i); + unicode_map[i] = index; + append_unicode(index, i); + } + } + } + xfree(seg_tab); + xfree(glyphId); + break; + } + if (e - cmap_tab == ncmapsubtabs) + ttf_fail("Invalid argument `-m %i': out of range [1..%i]", + select_unicode, unicode_map_count); +} + +void read_font() +{ + long i, j, k, l, n, m, platform_id, encoding_id; + TTF_FWORD kern_value; + char buf[1024], *p; + dirtab_entry *pd; + kern_entry *pk; + mtx_entry *pm; + ttf_skip(TTF_FIXED_SIZE); + ntabs = get_ushort(); + ttf_skip(3*TTF_USHORT_SIZE); + dir_tab = xtalloc(ntabs, dirtab_entry); + for (pd = dir_tab; pd - dir_tab < ntabs; pd++) { + pd->tag[0] = get_char(); + pd->tag[1] = get_char(); + pd->tag[2] = get_char(); + pd->tag[3] = get_char(); + ttf_skip(TTF_ULONG_SIZE); + pd->offset = get_ulong(); + pd->length = get_ulong(); + } + ttf_seek_tab("head", 2*TTF_FIXED_SIZE + 2*TTF_ULONG_SIZE + TTF_USHORT_SIZE); + upem = get_ushort(); + ttf_skip(16); + FontBBox1 = get_fword(); + FontBBox2 = get_fword(); + FontBBox3 = get_fword(); + FontBBox4 = get_fword(); + ttf_skip(TTF_USHORT_SIZE); + ttf_skip(TTF_USHORT_SIZE + TTF_SHORT_SIZE); + loca_format = get_short(); + ttf_seek_tab("maxp", TTF_FIXED_SIZE); + nglyphs = get_ushort(); + mtx_tab = xtalloc(nglyphs + 1, mtx_entry); + for (pm = mtx_tab; pm - mtx_tab < nglyphs + 1; pm++) { + pm->name = NULL; /* notdef */ + pm->found = 0; + pm->unicode_list = NULL; + } + ttf_seek_tab("hhea", TTF_FIXED_SIZE); + Ascender = get_fword(); + Descender = get_fword(); + ttf_skip(TTF_FWORD_SIZE + TTF_UFWORD_SIZE + 3*TTF_FWORD_SIZE + 8*TTF_SHORT_SIZE); + nhmtx = get_ushort(); + ttf_seek_tab("hmtx", 0); + for (pm = mtx_tab; pm - mtx_tab < nhmtx; pm++) { + pm->wx = get_ufword(); + ttf_skip(TTF_FWORD_SIZE); + } + i = pm[-1].wx; + for (; pm - mtx_tab < nglyphs; pm++) + pm->wx = i; + ttf_seek_tab("post", 0); + post_format = get_fixed(); + ItalicAngle = get_fixed(); + UnderlinePosition = get_fword(); + UnderlineThickness = get_fword(); + IsFixedPitch = get_ulong(); + ttf_skip(4*TTF_ULONG_SIZE); + switch (post_format) { + case 0x00010000: + for (pm = mtx_tab; pm - mtx_tab < NMACGLYPHS; pm++) + pm->name = mac_glyph_names[pm - mtx_tab]; + break; + case 0x00020000: + l = get_ushort(); /* some fonts have this value different from nglyphs */ + for (pm = mtx_tab; pm - mtx_tab < l; pm++) + pm->index = get_ushort(); + if ((pd = name_lookup("post")) == NULL) + ttf_fail("can't find table `post'"); + n = pd->length - (xftell(fontfile, cur_file_name) - pd->offset); + ps_glyphs_buf = xtalloc(n + 1, char); + for (m = 0, p = ps_glyphs_buf; p - ps_glyphs_buf < n;) { + for (i = get_byte(); i > 0; i--) + *p++ = get_char(); + *p++ = 0; + m++; + } + for (pm = mtx_tab; pm - mtx_tab < l; pm++) { + if (pm->index < NMACGLYPHS) + pm->name = mac_glyph_names[pm->index]; + else { + k = pm->index - NMACGLYPHS; + if (k < m) { + for (p = ps_glyphs_buf; k > 0; k--) + p = (char *)strend(p) + 1; + pm->name = p; + } + else { + pm->name = NULL; /* index out of valid range, fix name to notdef */ + } + } + } + break; + case 0x00030000: + if (print_glyph == AS_NAME) { + ttf_warn("no names available in `post' table, print glyph names as indices"); + print_glyph = AS_INDEX; + } + break; + default: + ttf_fail("unsupported format (%.8X) of `post' table", post_format); + } + ttf_seek_tab("loca", 0); + for (pm = mtx_tab; pm - mtx_tab < nglyphs + 1; pm++) + pm->offset = (loca_format == 1 ? get_ulong() : get_ushort() << 1); + if ((pd = name_lookup("glyf")) == NULL) + ttf_fail("can't find table `glyf'"); + for (n = pd->offset, pm = mtx_tab; pm - mtx_tab < nglyphs; pm++) { + ttf_seek_off("glyf", n + pm->offset); + ttf_skip(TTF_SHORT_SIZE); + pm->bbox[0] = get_fword(); + pm->bbox[1] = get_fword(); + pm->bbox[2] = get_fword(); + pm->bbox[3] = get_fword(); + } + + ttf_seek_tab("name", 0); + i = ftell(fontfile); + get_ushort(); /* skip Format selector (=0) */ + n = get_ushort(); /* number of name records */ + j = get_ushort() + i; /* start of string storage */ + i += 3*TTF_USHORT_SIZE; /* update the current offset */ + while (n-- > 0) { + ttf_seek_off("name", i); + platform_id = get_ushort(); + encoding_id = get_ushort(); + get_ushort(); /* skip language_id */ + k = get_ushort(); /* name_id */ + l = get_ushort(); /* string length */ + if ((platform_id == 1 && encoding_id == 0) && + (k == 0 || k == 1 || k == 4 || k == 5 || + k == 6)) { + ttf_seek_off("name", j + get_ushort()); + for (p = buf; l-- > 0; p++) + *p = get_char(); + *p++ = 0; + p = xstrdup(buf); + switch (k) { + case 0: Notice = p; break; + case 1: FamilyName = p; break; + case 4: FullName = p; break; + case 5: Version = p; break; + case 6: FontName = p; break; + } + if (Notice != NULL && FamilyName != NULL && + FullName != NULL && FontName != NULL && + Version != NULL) + break; + } + i += 6*TTF_USHORT_SIZE; + } + if ((pd = name_lookup("PCLT")) != NULL) { + ttf_seek_off("PCLT", pd->offset + TTF_FIXED_SIZE + TTF_ULONG_SIZE + TTF_USHORT_SIZE); + XHeight = get_ushort(); + if (XHeight > FontBBox4) { + ttf_warn("XHeight is too big (%i)\n" + "This is likely a font bug, so I discarded this parameter.", + (int)get_ttf_funit(XHeight)); + XHeight = 0; + } + ttf_skip(2*TTF_USHORT_SIZE); + CapHeight = get_ushort(); + if (CapHeight > FontBBox4) { + ttf_warn("CapHeight is too big (%i)\n" + "This is likely a font bug, so I discarded this parameter.", + (int)get_ttf_funit(CapHeight)); + CapHeight = 0; + } + } + if ((pd = name_lookup("OS/2")) != NULL) { + ttf_seek_off("OS/2", pd->offset + TTF_USHORT_SIZE + TTF_SHORT_SIZE); + switch (get_ushort()) { + case 100: Weight = xstrdup("Thin"); break; + case 200: Weight = xstrdup("ExtraLight"); break; + case 300: Weight = xstrdup("Light"); break; + case 400: Weight = xstrdup("Normal"); break; + case 500: Weight = xstrdup("Medium"); break; + case 600: Weight = xstrdup("SemiBold"); break; + case 700: Weight = xstrdup("Bold"); break; + case 800: Weight = xstrdup("ExtraBold"); break; + case 900: Weight = xstrdup("Black"); break; + } + } + read_cmap(); + if ((pd = name_lookup("kern")) == NULL) + return; + kern_tab = xtalloc(nglyphs, kern_entry); + for (pk = kern_tab; pk - kern_tab < nglyphs; pk++) { + pk->next = NULL; + pk->value = 0; + } + ttf_seek_off("kern", pd->offset + TTF_USHORT_SIZE); + for (n = get_ushort(); n > 0; n--) { + ttf_skip(2*TTF_USHORT_SIZE); + k = get_ushort(); + if (!(k & 1) || (k & 2) || (k & 4)) + return; + if (k >> 8 != 0) { + ttf_warn("warning: only format 0 supported of `kern' \ + subtables, others are ignored\n"); + continue; + } + k = get_ushort(); + ttf_skip(3*TTF_USHORT_SIZE); + while (k-- > 0) { + i = get_ushort(); + j = get_ushort(); + kern_value = get_fword(); + if (kern_value != 0) { + store_kern_value(i, j, kern_value); + nkernpairs++; + } + } + } +} + +int null_glyph(const char *s) +{ + return (s == NULL || s == notdef); + /* + strcmp(s, ".null") == 0 || + strcmp(s, ".notdef") == 0 || + strcmp(s, "CR") == 0 || + strcmp(s, "nonmarkingreturn") == 0 + */ +} + +void print_glyph_name(FILE *f, long glyph_index, int convention) +{ + unicode_entry *u; + static char buf[1024]; + const char *n; + assert(glyph_index >= 0 && glyph_index < nglyphs); + n = mtx_tab[glyph_index].name; + if (printing_enc && (n == notdef || glyph_index == 0)) { + fputs(notdef, f); + return; + } + switch (convention) { + case AS_NAME: + if (!null_glyph(n)) + fprintf(f, "%s", mtx_tab[glyph_index].name); + else if (n == notdef && glyph_index == 0) + fputs(notdef, f); + else + fprintf(f, "%s%li", GLYPH_PREFIX_INDEX, glyph_index); + break; + case AS_INDEX: + fprintf(f, "%s%li", GLYPH_PREFIX_INDEX, glyph_index); + break; + case AS_UNICODE: + u = mtx_tab[glyph_index].unicode_list; + if (glyph_index == 0 || u == NULL) + fprintf(f, "%s%li", GLYPH_PREFIX_INDEX, glyph_index); + else { + fprintf(f, "%s%.4X", GLYPH_PREFIX_UNICODE, u->code); + if (u->next != NULL) { + *buf = 0; + for (; u != NULL; u = u->next) { + assert(strlen(buf) + strlen(GLYPH_PREFIX_UNICODE) + 4 < sizeof(buf)); + sprintf(strend(buf), "%s%.4X ", GLYPH_PREFIX_UNICODE, u->code); + } + ttf_warn("glyph %li have multiple encodings: %s", + glyph_index, buf); + } + } + break; + } +} + +void print_char_metric(FILE *f, int charcode, long glyph_index) +{ + assert(glyph_index >= 0 && glyph_index < nglyphs); + fprintf(f, "C %i ; WX %i ; N ", (int) charcode, + (int)get_ttf_funit(mtx_tab[glyph_index].wx)); + print_glyph_name(f, glyph_index, print_glyph); + fprintf(f, " ; B %i %i %i %i ;\n", + (int)get_ttf_funit(mtx_tab[glyph_index].bbox[0]), + (int)get_ttf_funit(mtx_tab[glyph_index].bbox[1]), + (int)get_ttf_funit(mtx_tab[glyph_index].bbox[2]), + (int)get_ttf_funit(mtx_tab[glyph_index].bbox[3])); +} + +void print_afm(char *date, char *fontname) +{ + int i, ncharmetrics; + mtx_entry *pm; + short mtx_index[MAX_CHAR_CODE + 1], *idx; + unsigned int index; + char **pe; + kern_entry *pk, *qk; + unicode_entry *u; + char buf[20]; + fputs("StartFontMetrics 2.0\n", outfile); + fprintf(outfile, "Comment Converted at %s by ttf2afm from font file `%s'\n", date, fontname); + print_str(FontName); + print_str(FullName); + print_str(FamilyName); + print_str(Weight); + fprintf(outfile, "ItalicAngle %i", (int)(ItalicAngle/0x10000)); + if (ItalicAngle%0x10000 > 0) + fprintf(outfile, ".%i", (int)((ItalicAngle%0x10000)*1000)/0x10000); + fputs("\n", outfile); + fprintf(outfile, "IsFixedPitch %s\n", IsFixedPitch ? "true" : "false"); + fprintf(outfile, "FontBBox %i %i %i %i\n", + (int)get_ttf_funit(FontBBox1), + (int)get_ttf_funit(FontBBox2), + (int)get_ttf_funit(FontBBox3), + (int)get_ttf_funit(FontBBox4)); + print_dimen(UnderlinePosition); + print_dimen(UnderlineThickness); + print_str(Version); + print_str(Notice); + fputs("EncodingScheme FontSpecific\n", outfile); + print_dimen(CapHeight); + print_dimen(XHeight); + print_dimen(Ascender); + print_dimen(Descender); + ncharmetrics = nglyphs; + if (use_ext_enc == 0) { /* external encoding vector not given */ + fprintf(outfile, "StartCharMetrics %u\n", ncharmetrics); + for (pm = mtx_tab; pm - mtx_tab < nglyphs; pm++) { + pm->found = 1; + print_char_metric(outfile, -1, pm - mtx_tab); + } + } + else { /* external encoding vector given */ + for (idx = mtx_index; idx - mtx_index <= MAX_CHAR_CODE; *idx++ = 0); + for (pe = enc_names; pe - enc_names < names_count; pe++) { + if (*pe == notdef) + continue; + /* scan form `uniABCD' */ + if (sscanf(*pe, GLYPH_PREFIX_UNICODE "%X", &index) == 1) { + if (unicode_map[index] != NOGLYPH_ASSIGNED_YET) { + pm = mtx_tab + unicode_map[index]; + pm->found = 1; + } + else + ttf_warn("`unicode %s%.4X' is not mapped to any glyph", + GLYPH_PREFIX_UNICODE, index); + continue; + } + /* scan form `index123' */ + if (sscanf(*pe, GLYPH_PREFIX_INDEX "%u", &index) == 1) { + if (index >= nglyphs) + ttf_fail("`%s' out of valid range [0..%i)", + *pe, nglyphs); + pm = mtx_tab + index; + pm->found = 1; + continue; + } + for (pm = mtx_tab; pm - mtx_tab < nglyphs; pm++) + if (pm->name != NULL && strcmp(*pe, pm->name) == 0) + break; + if (pm - mtx_tab < nglyphs) { + mtx_index[pe - enc_names] = pm - mtx_tab; + pm->found = 1; + continue; + } + else + ttf_warn("glyph `%s' not found", *pe); + } + fprintf(outfile, "StartCharMetrics %u\n", ncharmetrics); + for (idx = mtx_index; idx - mtx_index <= MAX_CHAR_CODE; idx++) { + if (*idx != 0 && mtx_tab[*idx].found == 1) + print_char_metric(outfile, idx - mtx_index, *idx); + } + for (pm = mtx_tab; pm - mtx_tab < nglyphs; pm++) { + if (pm->found == 0) + print_char_metric(outfile, -1, pm - mtx_tab); + } + } +end_metrics: + fputs("EndCharMetrics\n", outfile); + if (nkernpairs == 0) + goto end_kerns; + fprintf(outfile, "StartKernData\nStartKernPairs %i\n", nkernpairs); + for (pk = kern_tab; pk - kern_tab < nglyphs; pk++) + for (qk = pk; qk != NULL; qk = qk->next) + if (qk->value != 0) { + fputs("KPX ", outfile); + print_glyph_name(outfile, pk - kern_tab, print_glyph); + fputs(" ", outfile); + print_glyph_name(outfile, qk->adjacent, print_glyph); + fprintf(outfile, " %i\n", get_ttf_funit(qk->value)); + } + fputs("EndKernPairs\nEndKernData\n", outfile); +end_kerns: + fputs("EndFontMetrics\n", outfile); +} + +void print_encoding(char *fontname) +{ + long int i, k, first_code, length, last_sep; + FILE *file; + TTF_USHORT format; + char *enc_name, *end_enc_name; + cmap_entry *e; + const char *n; + printing_enc = 1; + enc_name = xtalloc(strlen(bname) + 20, char); + strcpy(enc_name, bname); + end_enc_name = strend(enc_name); + for (e = cmap_tab; e - cmap_tab < ncmapsubtabs; e++) { + ttf_seek_off("cmap", cmap_offset + e->offset); + format = get_ushort(); + if (format != 0 && format != 4 && format != 6) { + ttf_warn("format %i of encoding subtable unsupported", (int)format); + continue; + } + sprintf(end_enc_name, ".e%i%i", + (int)e->platform_id, (int)e->encoding_id); + if ((file = xfopen(enc_name, FOPEN_W_MODE)) == NULL) + ttf_fail("cannot open file for writing (%s)\n", enc_name); + fprintf(file, "%% Encoding table from font file %s\n", fontname); + fprintf(file, "%% Platform ID %i", (int)e->platform_id); + switch (e->platform_id) { + case 0: fprintf(file, " (Apple Unicode)"); break; + case 1: fprintf(file, " (Macintosh)"); break; + case 2: fprintf(file, " (ISO)"); break; + case 3: fprintf(file, " (Microsoft)"); break; + } + fprintf(file, "\n"); + fprintf(file, "%% Encoding ID %i", (int)e->encoding_id); + if (e->platform_id == 1 && e->encoding_id == 0) + fprintf(file, " (Roman)"); + if (e->platform_id == 3) + switch (e->encoding_id) { + case 0: fprintf(file, " (Symbol)"); break; + case 1: fprintf(file, " (Unicode)"); break; + } + fprintf(file, "\n"); + fprintf(file, "%% Format %i", (int)(format)); + switch (format) { + case 0: fprintf(file, " (byte encoding table)"); break; + case 4: fprintf(file, " (segment mapping to delta values)"); break; + case 6: fprintf(file, " (trimmed table mapping)"); break; + } + fprintf(file, "\n"); + fprintf(file, "/Encoding%i [\n", (int)(e - cmap_tab + 1)); + switch (format) { + case 0: + get_ushort(); /* skip length */ + get_ushort(); /* skip version number */ + for (i = 0; i <= MAX_CHAR_CODE; i++) { + fputs("/", file); + print_glyph_name(file, get_byte(), print_glyph); + fputs("\n", file); + } + break; + case 4: + for (i = 0; i < nglyphs; ++i) { + fprintf(file, "%% Glyph %li -> ", i); + print_glyph_name(file, i, AS_UNICODE); + fputs("\n", file); + } + break; + case 6: + get_ushort(); /* skip table length */ + get_ushort(); /* skip version number */ + first_code = get_ushort(); /* first character code */ + for (i = 0; i < first_code; ++i) + fprintf(file, "/%s\n", notdef); + length = get_ushort(); /* number of character codes */ + for (i = first_code; i < first_code + length; i++) { + k = get_ushort(); + if (i > MAX_CHAR_CODE) + fputs("% ", file); + fputs("/", file); + print_glyph_name(file, k, print_glyph); + fputs("\n", file); + } + for (i = first_code + length; i <= MAX_CHAR_CODE; i++) + fprintf(file, "/%s\n", notdef); + break; + default: + ttf_warn("format %i of encoding subtable unsupported", (int)format); + } + fprintf(file, "] def\n"); + } + xfree(enc_name); +} + +void usage() +{ + cur_file_name = NULL; + fprintf(stderr, + "Usage: ttf2afm [-i|-u|-c|-v] [-e enc] [-o filename] [-m NUM] fontfile\n" + " -i: force printing glyph names in form 'index123'\n" + " -u: force printing glyph names in form 'uniABCD'\n" + " -c: print encoding tables to `basename.e<platformID><encodingID>'\n" + " -v: print version\n" + " -e enc: encode the AFM output using encoding vector from `enc'\n" + " -o filename: write output to file `filename' instead of stdout\n" + " -m NUM: select unicode mapping (default = 1, ie the first)\n" + " fontfile: the TrueType fontfile\n" + "\nPlease send bug reports or feature requests to <pdftex@tug.org>\n" + ); + _exit(-1); +} + +int main(int argc, char **argv) +{ + char date[128], *s; + time_t t = time(&t); + int c; + kpse_set_progname(argv[0]); + kpse_init_prog("ttf2afm", 0, 0, 0) ; + while ((c = getopt(argc, argv, "iucve:o:m:")) != -1) + switch (c) { + case 'i': + print_glyph = AS_INDEX; + break; + case 'u': + print_glyph = AS_UNICODE; + break; + case 'c': + print_cmap = 1; + break; + case 'e': + cur_file_name = optarg; + read_encoding(cur_file_name); + use_ext_enc = 1; + break; + case 'o': + cur_file_name = optarg; + outfile = xfopen(cur_file_name, FOPEN_W_MODE); + if (outfile == NULL) + ttf_fail("cannot open file for writing"); + break; + case 'm': + select_unicode = atoi(optarg); + break; + case 'v': + fprintf(stderr, + "ttf2afm version " VERSION "\n" + "Copyright (C) 1997-2005 Han The Thanh.\n" + "There is NO warranty. Redistribution of this software is\n" + "covered by the terms of both the pdfTeX copyright and\n" + "the GNU General Public License.\n" + "For more information about these matters, see the files\n" + "named COPYING and the pdfTeX source.\n" + "Primary author of ttf2afm: Han The Thanh.\n" + ); + _exit(0); + default: + usage(); + } + if (argc - optind != 1) + usage(); + sprintf(date, "%s\n", ctime(&t)); + *(char *)strchr(date, '\n') = 0; + cur_file_name = argv[optind]; + if (print_cmap) { + bname = strdup(xbasename(cur_file_name)); + if ((s = rindex(bname, '.')) != NULL) + *s = 0; + } + if ((fontfile = kpse_open_file(cur_file_name, kpse_truetype_format)) == NULL) + ttf_fail("can't open font file for reading"); + read_font(); + if (outfile == NULL) + outfile = stdout; + print_afm(date, cur_file_name); + if (print_cmap) + print_encoding(cur_file_name); + xfree(FontName); + xfree(FullName); + xfree(FamilyName); + xfree(Notice); + xfree(Version); + xfree(Weight); + free_tabs(); + xfclose(fontfile, cur_file_name); + return 0; +} diff --git a/Build/source/texk/web2c/pdftexdir/ttf2afm.rc b/Build/source/texk/web2c/pdftexdir/ttf2afm.rc new file mode 100644 index 00000000000..a63881df7d1 --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/ttf2afm.rc @@ -0,0 +1,35 @@ +/* ttf2afm.rc: ttf2afm -*- C++ -*- + + Copyright (C) 1996-2003 Fabrice Popineau <fabrice.popineau@supelec.fr> + + This file 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, or (at your + option) any later version. + + This file 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this file; if not, write to the Free Software + Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, + USA. */ + +#include <texlive-version.h> + +#define VER_FILEVERSION TEXLIVE_MAJOR_VERSION,TEXLIVE_MINOR_VERSION,TEXLIVE_BETA_NUMBER,TEXLIVE_ALPHA_NUMBER +#define VER_FILEVERSION_STR TEXLIVE_PRODUCTVERSION_STR " ttf2afm 1.10a" + +#define VER_INTERNALNAME_STR "ttf2afm" +#define VER_ORIGINALFILENAME_STR "ttf2afm.exe" + +#define VER_FILEDESCRIPTION_STR "TTF-to-AFM Converter" + +#define VER_COMPANYNAME_STR "" +#define VER_LEGALCOPYRIGHT_STR "Copyright (c) 1996-2002 Han The Thanh, <thanh@pdftex.org>" + +#include "texlive.version" + +/* ttf2afm.rc ends here */ diff --git a/Build/source/texk/web2c/pdftexdir/utils.c b/Build/source/texk/web2c/pdftexdir/utils.c new file mode 100644 index 00000000000..c1be283ba2e --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/utils.c @@ -0,0 +1,1129 @@ +/* +Copyright (c) 1996-2005 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/utils.c#25 $ +*/ + +#include "sys/types.h" +#include "regex.h" +#include "ptexlib.h" +#include "zlib.h" +#include "md5.h" +#include <kpathsea/c-vararg.h> +#include <kpathsea/c-proto.h> +#include <kpathsea/c-stat.h> +#include <kpathsea/c-fopen.h> +#include <time.h> + +static const char perforce_id[] = + "$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/utils.c#25 $"; + +char *cur_file_name = NULL; +strnumber last_tex_string; +static char print_buf[PRINTF_BUF_SIZE]; +static char *jobname_cstr = NULL; +static char *job_id_string = NULL; +extern string ptexbanner; /* from web2c/lib/texmfmp.c */ +extern string versionstring; /* from web2c/lib/version.c */ +extern KPSEDLL string kpathsea_version_string; /* from kpathsea/version.c */ + +size_t last_ptr_index; /* for use with alloc_array */ + +/* define fb_ptr, fb_array & fb_limit */ +typedef char fb_entry; +define_array(fb); + +/* define char_ptr, char_array & char_limit */ +typedef char char_entry; +define_array(char); + +integer fb_offset(void) +{ + return fb_ptr - fb_array; +} + +void fb_seek(integer offset) +{ + fb_ptr = fb_array + offset; +} + +void fb_putchar(eightbits b) +{ + alloc_array(fb, 1, SMALL_ARRAY_SIZE); + *fb_ptr++ = b; +} + +void fb_flush(void) +{ + fb_entry *p; + integer n; + for (p = fb_array; p < fb_ptr;) { + n = pdfbufsize - pdfptr; + if (fb_ptr - p < n) + n = fb_ptr - p; + memcpy(pdfbuf + pdfptr, p, (unsigned)n); + pdfptr += n; + if (pdfptr == pdfbufsize) + pdfflush(); + p += n; + } + fb_ptr = fb_array; +} + +static void fnstr_append(const char *s) +{ + int l = strlen(s) + 1; + alloc_array(char, l, SMALL_ARRAY_SIZE); + strcat(char_ptr, s); + char_ptr = strend(char_ptr); +} + +void make_subset_tag(fm_entry *fm_cur, char **glyph_names) +{ + char tag[7]; + unsigned long crc; + int i, l = strlen(job_id_string) + 1; + alloc_array(char, l, SMALL_ARRAY_SIZE); + strcpy(char_array, job_id_string); + char_ptr = strend(char_array); + if (fm_cur->tfm_name != NULL) { + fnstr_append(" TFM name: "); + fnstr_append(fm_cur->tfm_name); + } + fnstr_append(" PS name: "); + if (font_keys[FONTNAME_CODE].valid) + fnstr_append(fontname_buf); + else if (fm_cur->ps_name != NULL) + fnstr_append(fm_cur->ps_name); + fnstr_append(" Encoding: "); + if (fm_cur->encoding != NULL && (fm_cur->encoding)->name != NULL) + fnstr_append((fm_cur->encoding)->name); + else + fnstr_append("built-in"); + fnstr_append(" CharSet: "); + assert(glyph_names != NULL); + for (i = 0; i <= MAX_CHAR_CODE; i++) + if (pdfcharmarked(tex_font, i) && glyph_names[i] != notdef) { + fnstr_append(" /"); + fnstr_append(glyph_names[i]); + } + if (fm_cur->charset != NULL) { + fnstr_append(" Extra CharSet: "); + fnstr_append(fm_cur->charset); + } + crc = crc32(0L, Z_NULL, 0); + crc = crc32(crc, (Bytef*)char_array, strlen(char_array)); + /* we need to fit a 32-bit number into a string of 6 uppercase chars long; + * there are 26 uppercase chars ==> each char represents a number in range + * 0..25. The maximal number that can be represented by the tag is + * 26^6 - 1, which is a number between 2^28 and 2^29. Thus the bits 29..31 + * of the CRC must be dropped out. + */ + for (i = 0; i < 6; i++) { + tag[i] = 'A' + crc % 26; + crc /= 26; + } + tag[6] = 0; + fm_cur->subset_tag = xstrdup(tag); +} + +void pdf_puts(const char *s) +{ + pdfroom(strlen(s) + 1); + while (*s) + pdfbuf[pdfptr++] = *s++; +} + +void pdf_printf(const char *fmt,...) +{ + va_list args; + va_start(args, fmt); + vsprintf(print_buf, fmt, args); + pdf_puts(print_buf); + va_end(args); +} + +strnumber maketexstring(const char *s) +{ + int l; + if (s == NULL || *s == 0) + return getnullstr(); + l = strlen(s); + check_buf(poolptr + l, poolsize); + while (l-- > 0) + strpool[poolptr++] = *s++; + last_tex_string = makestring(); + return last_tex_string; +} + +void tex_printf(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vsprintf(print_buf, fmt, args); + print(maketexstring(print_buf)); + flushstr(last_tex_string); + xfflush(stdout); + va_end(args); +} + +/* Helper for pdftex_fail. */ +static void safe_print(const char *str) +{ + const char *c; + for (c = str; *c; ++c) + print(*c); +} + +/* pdftex_fail may be called when a buffer overflow has happened/is + happening, therefore may not call mktexstring. However, with the + current implementation it appears that error messages are misleading, + possibly because pool overflows are detected too late. */ +void pdftex_fail(const char *fmt,...) +{ + va_list args; + va_start(args, fmt); + println(); + safe_print("Error: "); + safe_print(program_invocation_name); + if (cur_file_name) { + safe_print(" (file "); + safe_print(cur_file_name); + safe_print(")"); + } + safe_print(": "); + vsprintf(print_buf, fmt, args); + safe_print(print_buf); + va_end(args); + println(); + safe_print(" ==> Fatal error occurred, the output PDF file is not finished!"); + println(); + exit(-1); +} + +void pdftex_warn(const char *fmt,...) +{ + va_list args; + va_start(args, fmt); + println(); + tex_printf("Warning: %s", program_invocation_name); + if (cur_file_name) + tex_printf(" (file %s)", cur_file_name); + tex_printf(": "); + vsprintf(print_buf, fmt, args); + print(maketexstring(print_buf)); + flushstr(last_tex_string); + va_end(args); + println(); +} + +char *makecstring(integer s) +{ + static char cstrbuf[MAX_CSTRING_LEN]; + char *p = cstrbuf; + int i, l = strstart[s + 1] - strstart[s]; + check_buf(l + 1, MAX_CSTRING_LEN); + for (i = 0; i < l; i++) + *p++ = strpool[i + strstart[s]]; + *p = 0; + return cstrbuf; +} + +/* +boolean str_eq_cstr(strnumber n, char *s) +{ + int l; + if (s == NULL || n == 0) + return false; + l = strstart[n]; + while (*s && l < strstart[n + 1] && *s == strpool[l]) + l++, s++; + return !*s && l == strstart[n + 1]; +} +*/ + +void setjobid(int year, int month, int day, int time, int pdftexversion, int pdftexrevision) +{ + char *name_string, *format_string, *s; + + if (job_id_string != NULL) + return; + + name_string = xstrdup(makecstring(jobname)); + format_string = xstrdup(makecstring(formatident)); + s = xtalloc(SMALL_BUF_SIZE + + strlen(name_string) + + strlen(format_string) + + strlen(ptexbanner) + + strlen(versionstring) + + strlen(kpathsea_version_string), char); + /* The Web2c version string starts with a space. */ + sprintf(s, "%.4d/%.2d/%.2d %.2d:%.2d %s %s %s%s %s", + year, month, day, time/60, time%60, + name_string, format_string, ptexbanner, + versionstring, kpathsea_version_string); + job_id_string = xstrdup(s); + xfree(s); + xfree(name_string); + xfree(format_string); +} + +void makepdftexbanner(void) +{ + static boolean pdftexbanner_init = false; + char *s; + + if (pdftexbanner_init) + return; + + s = xtalloc(SMALL_BUF_SIZE + + strlen(ptexbanner) + + strlen(versionstring) + + strlen(kpathsea_version_string), char); + /* The Web2c version string starts with a space. */ + sprintf(s, "%s%s %s", ptexbanner, versionstring, kpathsea_version_string); + pdftexbanner = maketexstring(s); + xfree(s); + pdftexbanner_init = true; +} + +strnumber getresnameprefix(void) +{ +/* static char name_str[] = */ +/* "!\"$&'*+,-.0123456789:;=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ\\" */ +/* "^_`abcdefghijklmnopqrstuvwxyz|~"; */ + static char name_str[] = +"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + char prefix[7]; /* make a tag of 6 chars long */ + unsigned long crc; + int i, base = strlen(name_str); + crc = crc32(0L, Z_NULL, 0); + crc = crc32(crc, (Bytef*)job_id_string, strlen(job_id_string)); + for (i = 0; i < 6; i++) { + prefix[i] = name_str[crc % base]; + crc /= base; + } + prefix[6] = 0; + return maketexstring(prefix); +} + +size_t xfwrite(void *ptr, size_t size, size_t nmemb, FILE *stream) +{ + if (fwrite(ptr, size, nmemb, stream) != nmemb) + pdftex_fail("fwrite() failed"); + return nmemb; +} + +int xfflush(FILE *stream) +{ + if (fflush(stream) != 0) + pdftex_fail("fflush() failed"); + return 0; +} + +int xgetc(FILE *stream) +{ + int c = getc(stream); + if (c < 0 && c != EOF) + pdftex_fail("getc() failed"); + return c; +} + +int xputc(int c, FILE *stream) +{ + int i = putc(c, stream); + if (i < 0) + pdftex_fail("putc() failed"); + return i; +} + +void writestreamlength(integer length, integer offset) +{ + integer save_offset; + if (jobname_cstr == NULL) + jobname_cstr = xstrdup(makecstring(jobname)); + save_offset = xftell(pdffile, jobname_cstr); + xfseek(pdffile, offset, SEEK_SET, jobname_cstr); + fprintf(pdffile, "%li", (long int)length); + xfseek(pdffile, pdfoffset(), SEEK_SET, jobname_cstr); +} + +scaled extxnoverd(scaled x, scaled n, scaled d) +{ + double r = (((double)x)*((double)n))/((double)d); + if (r > 0) + r += 0.5; + else + r -= 0.5; + if (r >= (double)maxinteger || r <= -(double)maxinteger) + pdftex_warn("arithmetic: number too big"); + return r; +} + +void libpdffinish() +{ + xfree(fb_array); + xfree(char_array); + xfree(job_id_string); + fm_free(); + t1_free(); + enc_free(); + img_free(); + vf_free(); + epdf_free(); +} + +/* 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! + */ +char *convertStringToPDFString (char *in, int len) +{ + static char pstrbuf[MAX_PSTRING_LEN]; + char *out = pstrbuf; + int i, j; + char buf[5]; + j = 0; + for (i = 0; i < len; i++) { + check_buf(j + sizeof(buf), MAX_PSTRING_LEN); + if (((unsigned char)in[i] < '!') || ((unsigned char)in[i] > '~')){ + /* convert control characters into oct */ + sprintf (buf, "\\%03o", (unsigned int)(unsigned char)in[i]); + 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 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! + * + * See escapename for parameter description. + */ +void escapestring(poolpointer in) +{ + poolpointer out = poolptr; + unsigned char ch; + while (in < out) { + if (poolptr + 4 >= poolsize) { + poolptr = poolsize; + /* error by str_toks that calls str_room(1) */ + return; + } + + ch = (unsigned char)strpool[in++]; + + if ((ch < '!') || (ch > '~')) { + /* convert control characters into oct */ + sprintf (&strpool[poolptr], "\\%.3o", (unsigned int)ch); + poolptr += 4; + continue; + } + if ((ch == '(') || (ch == ')') || (ch == '\\')) { + /* escape parenthesis and backslash */ + strpool[poolptr++] = '\\'; + } + /* copy char :-) */ + strpool[poolptr++] = ch; + } +} + + +/* Convert any given string in a PDF name using escaping mechanism + of PDF 1.2. The result does not include the leading slash. + + PDF specification 1.6, section 3.2.6 "Name Objects" explains: + <blockquote> + Beginning with PDF 1.2, any character except null (character code 0) may + be included in a name by writing its 2-digit hexadecimal code, preceded + by the number sign character (#); see implementation notes 3 and 4 in + Appendix H. This syntax is required to represent any of the delimiter or + white-space characters or the number sign character itself; it is + recommended but not required for characters whose codes are outside the + range 33 (!) to 126 (~). + </blockquote> + The following table shows the conversion that are done by this + function: + code result reason + ----------------------------------- + 0 ignored not allowed + 1..32 escaped must for white-space: + 9 (tab), 10 (lf), 12 (ff), 13 (cr), 32 (space) + recommended for the other control characters + 35 escaped escape char "#" + 37 escaped delimiter "%" + 40..41 escaped delimiters "(" and ")" + 47 escaped delimiter "/" + 60 escaped delimiter "<" + 62 escaped delimiter ">" + 91 escaped delimiter "[" + 93 escaped delimiter "]" + 123 escaped delimiter "{" + 125 escaped delimiter "}" + 127..255 escaped recommended + else copy regular characters + + Parameter "in" is a pointer into the string pool where + the input string is located. The output string is written + as temporary string right after the input string. + Thus at the begin of the procedure the global variable + "poolptr" points to the start of the output string and + after the end when the procedure returns. +*/ +void escapename(poolpointer in) +{ + poolpointer out = poolptr; + unsigned char ch; + + while (in < out) { + if (poolptr + 3 >= poolsize) { + poolptr = poolsize; + /* error by str_toks that calls str_room(1) */ + return; + } + + ch = (unsigned char)strpool[in++]; + + if ((ch >= 1 && ch <= 32) || ch >= 127) { + /* escape */ + sprintf(&strpool[poolptr], "#%.2X", (unsigned int)ch); + poolptr += 3; + continue; + } + switch (ch) { + case 0: + /* ignore */ + break; + case 35: + case 37: + case 40: + case 41: + case 47: + case 60: + case 62: + case 91: + case 93: + case 123: + case 125: + /* escape */ + sprintf(&strpool[poolptr], "#%.2X", (unsigned int)ch); + poolptr += 3; + break; + default: + /* copy */ + strpool[poolptr++] = ch; + } + } +} + +/* Convert any given string in a PDF hexadecimal string. The + result does not include the angle brackets. + + This procedure uses uppercase hexadecimal letters. + + See escapename for description of parameters. +*/ +void escapehex(poolpointer in) +{ + poolpointer out = poolptr; + unsigned char ch; + + while (in < out) { + if (poolptr + 2 >= poolsize) { + poolptr = poolsize; + /* error by str_toks that calls str_room(1) */ + return; + } + + ch = (unsigned char)strpool[in++]; + + sprintf(&strpool[poolptr], "%.2X", (unsigned int)ch); + poolptr += 2; + } +} + +/* Unescape any given hexadecimal string. + + Last hex digit can be omitted, it is replaced by zero, see + PDF specification. + + Invalid digits are silently ignored. + + See escapename for description of parameters. +*/ +void unescapehex(poolpointer in) +{ + poolpointer out = poolptr; + unsigned char ch, a; + boolean first = true; + + while (in < out) { + if (poolptr + 1 >= poolsize) { + poolptr = poolsize; + /* error by str_toks that calls str_room(1) */ + return; + } + + ch = (unsigned char)strpool[in++]; + + if ((ch >= '0') && (ch <= '9')) { + ch -= '0'; + } + else if ((ch >= 'A') && (ch <= 'F')) { + ch -= 'A' - 10; + } + else if ((ch >= 'a') && (ch <= 'f')) { + ch -= 'a' - 10; + } + else { + continue; /* ignore wrong character */ + } + + if (first) { + a = ch << 4; + first = false; + continue; + } + + strpool[poolptr++] = a + ch; + first = true; + } + if (!first) { /* last hex digit is omitted */ + strpool[poolptr++] = ch << 4; + } +} + + +/* Converts any string given in in in an allowed PDF string which is + * hexadecimal encoded; + * sizeof(out) should be at least lin*2+1. + */ +void convertStringToHexString (char *in, char *out, int lin) +{ + int i, j; + char buf[3]; + j = 0; + for (i = 0; i < lin; i++) { + sprintf (buf, "%02X", (unsigned int)(unsigned char)in[i]); + out[j++] = buf[0]; + out[j++] = buf[1]; + } + out[j] = '\0'; +} + +/* Compute the ID string as per PDF1.4 9.3: + <blockquote> + 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 ) + </blockquote> + 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. + */ +void printID (strnumber filename) +{ + time_t t; + size_t size; + char time_str[32]; + md5_state_t state; + md5_byte_t digest[16]; + char id[64]; + char *file_name; + 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, size); + /* get the file name */ + if (getcwd(pwd, sizeof(pwd)) == NULL) + pdftex_fail("getcwd() failed (path too long?)"); + file_name = makecstring(filename); + md5_append(&state, (const md5_byte_t *)pwd, strlen(pwd)); + md5_append(&state, (const md5_byte_t *)"/", 1); + md5_append(&state, (const md5_byte_t *)file_name, strlen(file_name)); + /* finish md5 */ + md5_finish(&state, digest); + /* write the IDs */ + convertStringToHexString ((char*)digest, id, 16); + pdf_printf("/ID [<%s> <%s>]", id, id); +} + +/* Print the /CreationDate entry. + + PDF Reference, third edition says about the expected date format: + <blockquote> + 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' + </blockquote> + + 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). +*/ + +time_t start_time = 0; +#define TIME_STR_SIZE 30 +char start_time_str[TIME_STR_SIZE]; +char time_str[TIME_STR_SIZE]; + /* minimum size for time_str is 24: "D:YYYYmmddHHMMSS+HH'MM'" */ + +void makepdftime(time_t t, char *time_str) +{ + + struct tm lt, gmt; + size_t size; + int off, off_hours, off_mins; + + /* get the time */ + lt = *localtime(&t); + size = strftime(time_str, TIME_STR_SIZE, "D:%Y%m%d%H%M%S", <); + /* expected format: "YYYYmmddHHMMSS" */ + if (size == 0) { + /* unexpected, contents of time_str is undefined */ + time_str[0] = '\0'; + return; + } + + /* correction for seconds: %S can be in range 00..61, + the PDF reference expects 00..59, + therefore we map "60" and "61" to "59" */ + if (time_str[14] == '6') { + time_str[14] = '5'; + time_str[15] = '9'; + time_str[16] = '\0'; /* for safety */ + } + + /* get the time zone offset */ + gmt = *gmtime(&t); + + /* this calculation method was found in exim's tod.c */ + off = 60*(lt.tm_hour - gmt.tm_hour) + lt.tm_min - gmt.tm_min; + if (lt.tm_year != gmt.tm_year) { + off += (lt.tm_year > gmt.tm_year) ? 1440 : -1440; + } + else if (lt.tm_yday != gmt.tm_yday) { + off += (lt.tm_yday > gmt.tm_yday) ? 1440 : -1440; + } + + if (off == 0) { + time_str[size++] = 'Z'; + time_str[size] = 0; + } + else { + off_hours = off/60; + off_mins = abs(off - off_hours*60); + sprintf(&time_str[size], "%+03i'%02d'", off_hours, off_mins); + } +} + +void initstarttime() { + if (start_time == 0) { + start_time = time((time_t *) NULL); + makepdftime(start_time, start_time_str); + } +} + +void printcreationdate() { + initstarttime(); + pdf_printf("/CreationDate (%s)\n", start_time_str); +} + +void getcreationdate() +{ + /* put creation date on top of string pool and update poolptr */ + poolpointer out = poolptr; + unsigned char ch; + int len = strlen(start_time_str); + + initstarttime(); + + if (poolptr + len >= poolsize) { + poolptr = poolsize; + /* error by str_toks that calls str_room(1) */ + return; + } + + memcpy(&strpool[poolptr], start_time_str, len); + poolptr += len; +} + +void getfilemoddate(strnumber s) { + struct stat file_data; + + char *file_name = kpse_find_tex(makecfilename(s)); + if (file_name == NULL) { + return; /* empty string */ + } + + /* get file status */ + if (stat(file_name, &file_data) == 0) { + int len; + + makepdftime(file_data.st_mtime, time_str); + len = strlen(time_str); + if (poolptr + len >= poolsize) { + poolptr = poolsize; + /* error by str_toks that calls str_room(1) */ + } + else { + memcpy(&strpool[poolptr], time_str, len); + poolptr += len; + } + } + /* else { errno contains error code } */ + + xfree(file_name); +} + +void getfilesize(strnumber s) { + struct stat file_data; + + char *file_name = kpse_find_tex(makecfilename(s)); + if (file_name == NULL) { + return; /* empty string */ + } + + /* get file status */ + if (stat(file_name, &file_data) == 0) { + int len; + char buf[20]; + + /* st_size has type off_t */ + sprintf(buf, "%lu", (long unsigned int)file_data.st_size); + len = strlen(buf); + if (poolptr + len >= poolsize) { + poolptr = poolsize; + /* error by str_toks that calls str_room(1) */ + } + else { + memcpy(&strpool[poolptr], buf, len); + poolptr += len; + } + } + /* else { errno contains error code } */ + + xfree(file_name); +} + +#define DIGEST_SIZE 16 +#define FILE_BUF_SIZE 1024 + +void getmd5sum(strnumber s, boolean file) { + md5_state_t state; + md5_byte_t digest[DIGEST_SIZE]; + char outbuf[2 * DIGEST_SIZE + 1]; + int len = 2 * DIGEST_SIZE; + + if (file) { + char file_buf[FILE_BUF_SIZE]; + int read = 0; + FILE *f; + + char *file_name = kpse_find_tex(makecfilename(s)); + if (file_name == NULL) { + return; /* empty string */ + } + /* in case of error the empty string is returned, + no need for xfopen that aborts on error. + */ + f = fopen(file_name, FOPEN_RBIN_MODE); + if (f == NULL) { + xfree(file_name); + return; + } + md5_init(&state); + while ((read = fread(&file_buf, sizeof(char), + FILE_BUF_SIZE, f)) > 0) { + md5_append(&state, (const md5_byte_t *)file_buf, read); + } + md5_finish(&state, digest); + fclose(f); + + xfree(file_name); + } + else { + /* s contains the data */ + md5_init(&state); + md5_append(&state, + (const md5_byte_t *)&strpool[strstart[s]], + strstart[s + 1] - strstart[s]); + md5_finish(&state, digest); + } + + if (poolptr + len >= poolsize) { + /* error by str_toks that calls str_room(1) */ + return; + } + convertStringToHexString((char*)digest, outbuf, DIGEST_SIZE); + memcpy(&strpool[poolptr], outbuf, len); + poolptr += len; +} + +void getfiledump(strnumber s, int offset, int length) { + FILE *f; + int read; + poolpointer data_ptr; + poolpointer data_end; + char *file_name; + + if (length == 0) { + /* empty result string */ + return; + } + + if (poolptr + 2 * length + 1 >= poolsize) { + /* no place for result */ + poolptr = poolsize; + /* error by str_toks that calls str_room(1) */ + return; + } + + file_name = kpse_find_tex(makecfilename(s)); + if (file_name == NULL) { + return; /* empty string */ + } + + /* read file data */ + f = fopen(file_name, FOPEN_RBIN_MODE); + if (f == NULL) { + xfree(file_name); + return; + } + if (fseek(f, (long)offset, SEEK_SET) != 0) { + xfree(file_name); + return; + } + /* there is enough space in the string pool, the read + data are put in the upper half of the result, thus + the conversion to hex can be done without overwriting + unconverted bytes. Be aware that sprintf also appends + a nul byte at the end. */ + data_ptr = poolptr + length; + read = fread(&strpool[data_ptr], + sizeof(char), length, f); + fclose(f); + + /* convert to hex */ + data_end = data_ptr + read; + for (; data_ptr < data_end; data_ptr++) { + sprintf(&strpool[poolptr], "%.2X", + (unsigned int)strpool[data_ptr]); + poolptr += 2; + } + xfree(file_name); +} + +#define DEFAULT_SUB_MATCH_COUNT 10 +int sub_match_count = DEFAULT_SUB_MATCH_COUNT; +regmatch_t *pmatch = NULL; +char *match_string = NULL; + +void matchstrings(strnumber s, strnumber t, int subcount, boolean icase) { + regex_t preg; + int cflags = REG_EXTENDED; + int eflags = 0; + int ret; + char *str; + + if (icase) { + cflags |= REG_ICASE; + } + + if (poolptr + 10 >= poolsize) { + poolptr = poolsize; + return; + } + + str = makecstring(s); + ret = regcomp(&preg, str, cflags); + if (ret != 0) { + int size = regerror(ret, &preg, NULL, 0); + str = xtalloc(size, char); + regerror(ret, &preg, str, size); + pdftex_warn("%s%s", "\\pdfmatch: ", str); + xfree(str); + strpool[poolptr++] = '-'; + strpool[poolptr++] = '1'; + } + else { + str = makecstring(t); + sub_match_count = ((subcount < 0) ? + DEFAULT_SUB_MATCH_COUNT : subcount); + xfree(pmatch); + if (sub_match_count > 0) { + pmatch = xtalloc(sub_match_count, regmatch_t); + } + ret = regexec(&preg, str, sub_match_count, pmatch, eflags); + xfree(match_string); + match_string = xstrdup(str); + if (ret == 0) { + strpool[poolptr++] = '1'; + } + else { /* REG_NOMATCH */ + strpool[poolptr++] = '0'; + } + } + + regfree(&preg); +} + +void getmatch(int i) { + int size = 0; + int len = 0; + + boolean found = i < sub_match_count + && match_string != NULL + && pmatch[i].rm_so >= 0 + && i >= 0; + + if (found) { + len = pmatch[i].rm_eo - pmatch[i].rm_so; + size = 20 + len; + /* 20: place for integer number and '->' */ + } + else { + size = 4; + } + + if (poolptr + size >= poolsize) { + poolptr = poolsize; + return; + } + + if (found) { + sprintf(&strpool[poolptr], "%d", pmatch[i].rm_so); + poolptr += strlen(&strpool[poolptr]); + strpool[poolptr++] = '-'; + strpool[poolptr++] = '>'; + memcpy(&strpool[poolptr], &match_string[pmatch[i].rm_so], len); + poolptr += len; + return; + } + + strpool[poolptr++] = '-'; + strpool[poolptr++] = '1'; + strpool[poolptr++] = '-'; + strpool[poolptr++] = '>'; +} + + +/* makecfilename + input/ouput same as makecstring: + input: string number + output: C string with quotes removed. +*/ +char *makecfilename(strnumber s) { + char *name = makecstring(s); + char *p = name; + char *q = name; + + while (*p) { + if (*p != '"') + *q++ = *p; + p++; + } + *q = '\0'; + fprintf(stderr, " %s\n", name); + return name; +} diff --git a/Build/source/texk/web2c/pdftexdir/vadjust.ch b/Build/source/texk/web2c/pdftexdir/vadjust.ch new file mode 100644 index 00000000000..09887ea01a8 --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/vadjust.ch @@ -0,0 +1,273 @@ +% WEB change file containing vadjust extension for pdfTeX +% +% Copyright (c) 1996-2004 Han Th\^e\llap{\raise 0.5ex\hbox{\'{}}} Th\`anh, <thanh@pdftex.org> +% +% This file is part of pdfTeX. +% +% pdfTeX 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. +% +% pdfTeX 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 General Public License for more details. +% +% You should have received a copy of the GNU General Public License +% along with pdfTeX; if not, write to the Free Software +% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +% +% $Id: vadjust.ch,v 1.2 2004/08/01 12:12:23 olaf Exp $ + +@x [142] - pre-vadjust +@d adjust_node=5 {|type| of an adjust node} +@y +@d adjust_node=5 {|type| of an adjust node} +@d adjust_pre == subtype {pre-adjustment?} +@#{|append_list| is used to append a list to |tail|} +@d append_list(#) == begin link(tail) := link(#); append_list_end +@d append_list_end(#) == tail := #; end + +@z + +@x [162] - pre-vadjust +@d backup_head==mem_top-13 {head of token list built by |scan_keyword|} +@d hi_mem_stat_min==mem_top-13 {smallest statically allocated word in + the one-word |mem|} +@d hi_mem_stat_usage=14 {the number of one-word nodes always present} +@y +@d backup_head==mem_top-13 {head of token list built by |scan_keyword|} +@d pre_adjust_head==mem_top-14 {head of pre-adjustment list returned by |hpack|} +@d hi_mem_stat_min==mem_top-14 {smallest statically allocated word in + the one-word |mem|} +@d hi_mem_stat_usage=15 {the number of one-word nodes always present} +@z + +@x [197] - pre-vadjust +begin print_esc("vadjust"); node_list_display(adjust_ptr(p)); {recursive call} +@y +begin print_esc("vadjust"); if adjust_pre(p) <> 0 then print(" pre "); +node_list_display(adjust_ptr(p)); {recursive call} +@z + +@x [649] - pre-vadjust +if adjust_tail<>null then link(adjust_tail):=null; +@y +if adjust_tail<>null then link(adjust_tail):=null; +if pre_adjust_tail<>null then link(pre_adjust_tail):=null; +@z + +@x [655] - pre-vadjust +@<Transfer node |p| to the adjustment list@>= +begin while link(q)<>p do q:=link(q); +if type(p)=adjust_node then + begin link(adjust_tail):=adjust_ptr(p); + while link(adjust_tail)<>null do adjust_tail:=link(adjust_tail); + p:=link(p); free_node(link(q),small_node_size); + end +@y +@<Glob...@>= +@!pre_adjust_tail: pointer; + +@ @<Set init...@>= +pre_adjust_tail := null; + +@ Materials in \.{\\vadjust} used with \.{pre} keyword will be appended to +|pre_adjust_tail| instead of |adjust_tail|. + +@d update_adjust_list(#) == begin + link(#) := adjust_ptr(p); + while link(#) <> null do + # := link(#); +end + +@<Transfer node |p| to the adjustment list@>= +begin while link(q)<>p do q:=link(q); + if type(p) = adjust_node then begin + if adjust_pre(p) <> 0 then + update_adjust_list(pre_adjust_tail) + else + update_adjust_list(adjust_tail); + p := link(p); free_node(link(q), small_node_size); + end +@z + +@x [770] - pre-vadjust +@d align_stack_node_size=5 {number of |mem| words to save alignment states} +@y +@d align_stack_node_size=6 {number of |mem| words to save alignment states} +@z + +@x [770] - pre-vadjust +@!cur_head,@!cur_tail:pointer; {adjustment list pointers} +@y +@!cur_head,@!cur_tail:pointer; {adjustment list pointers} +@!cur_pre_head,@!cur_pre_tail:pointer; {pre-adjustment list pointers} +@z + +@x [771] - pre-vadjust +cur_head:=null; cur_tail:=null; +@y +cur_head:=null; cur_tail:=null; +cur_pre_head:=null; cur_pre_tail:=null; +@z + +@x [772] - pre-vadjust +info(p+4):=cur_head; link(p+4):=cur_tail; +@y +info(p+4):=cur_head; link(p+4):=cur_tail; +info(p+5):=cur_pre_head; link(p+5):=cur_pre_tail; +@z + +@x [771] - pre-vadjust +cur_tail:=link(p+4); cur_head:=info(p+4); +@y +cur_tail:=link(p+4); cur_head:=info(p+4); +cur_pre_tail:=link(p+5); cur_pre_head:=info(p+5); +@z + +@x [786] - pre-vadjust +cur_align:=link(preamble); cur_tail:=cur_head; init_span(cur_align); +@y +cur_align:=link(preamble); cur_tail:=cur_head; cur_pre_tail:=cur_pre_head; +init_span(cur_align); +@z + +@x [791] - pre-vadjust + begin adjust_tail:=cur_tail; u:=hpack(link(head),natural); w:=width(u); + cur_tail:=adjust_tail; adjust_tail:=null; + end +@y + begin adjust_tail:=cur_tail; pre_adjust_tail:=cur_pre_tail; + u:=hpack(link(head),natural); w:=width(u); + cur_tail:=adjust_tail; adjust_tail:=null; + cur_pre_tail:=pre_adjust_tail; pre_adjust_tail:=null; + end +@z + +@x [799] - pre-vadjust + pop_nest; append_to_vlist(p); + if cur_head<>cur_tail then + begin link(tail):=link(cur_head); tail:=cur_tail; + end; +@y + pop_nest; + if cur_pre_head <> cur_pre_tail then + append_list(cur_pre_head)(cur_pre_tail); + append_to_vlist(p); + if cur_head <> cur_tail then + append_list(cur_head)(cur_tail); +@z + +@x [888] - pre-vadjust +append_to_vlist(just_box); +if adjust_head<>adjust_tail then + begin link(tail):=link(adjust_head); tail:=adjust_tail; + end; +adjust_tail:=null +@y +if pre_adjust_head <> pre_adjust_tail then + append_list(pre_adjust_head)(pre_adjust_tail); +pre_adjust_tail := null; +append_to_vlist(just_box); +if adjust_head <> adjust_tail then + append_list(adjust_head)(adjust_tail); +adjust_tail := null +@z + +@x +adjust_tail:=adjust_head; +@y +adjust_tail:=adjust_head; +pre_adjust_tail := pre_adjust_head; +@z + +@x [1076] - pre-vadjust + begin append_to_vlist(cur_box); + if adjust_tail<>null then + begin if adjust_head<>adjust_tail then + begin link(tail):=link(adjust_head); tail:=adjust_tail; + end; + adjust_tail:=null; + end; +@y + begin + if pre_adjust_tail <> null then begin + if pre_adjust_head <> pre_adjust_tail then + append_list(pre_adjust_head)(pre_adjust_tail); + pre_adjust_tail := null; + end; + append_to_vlist(cur_box); + if adjust_tail <> null then begin + if adjust_head <> adjust_tail then + append_list(adjust_head)(adjust_tail); + adjust_tail := null; + end; +@z + +@x [1085] - pre-vadjust +adjusted_hbox_group: begin adjust_tail:=adjust_head; package(0); +@y +adjusted_hbox_group: begin adjust_tail:=adjust_head; + pre_adjust_tail:=pre_adjust_head; package(0); +@z + +@x [1099] - pre-vadjust +saved(0):=cur_val; incr(save_ptr); +new_save_level(insert_group); scan_left_brace; normal_paragraph; +push_nest; mode:=-vmode; prev_depth:=ignore_depth; +end; +@y +saved(0) := cur_val; +if (cur_cmd = vadjust) and scan_keyword("pre") then + saved(1) := 1 +else + saved(1) := 0; +save_ptr := save_ptr + 2; +new_save_level(insert_group); scan_left_brace; normal_paragraph; +push_nest; mode:=-vmode; prev_depth:=ignore_depth; +end; +@z + +@x [1100] - pre-vadjust + d:=split_max_depth; f:=floating_penalty; unsave; decr(save_ptr); +@y + d:=split_max_depth; f:=floating_penalty; unsave; save_ptr := save_ptr - 2; +@z + +@x [1100] - pre-vadjust + subtype(tail):=0; {the |subtype| is not used} +@y + adjust_pre(tail) := saved(1); {the |subtype| is used for |adjust_pre|} +@z + +@x [1198] - pre-vadjust +@!t:pointer; {tail of adjustment list} +@y +@!t:pointer; {tail of adjustment list} +@!pre_t:pointer; {tail of pre-adjustment list} +@z + +@x [1199] - pre-vadjust +adjust_tail:=adjust_head; b:=hpack(p,natural); p:=list_ptr(b); +t:=adjust_tail; adjust_tail:=null;@/ +@y +adjust_tail:=adjust_head; pre_adjust_tail:=pre_adjust_head; +b:=hpack(p,natural); p:=list_ptr(b); +t:=adjust_tail; adjust_tail:=null;@/ +pre_t:=pre_adjust_tail; pre_adjust_tail:=null;@/ +@z + +@x [1205] - pre-vadjust +if t<>adjust_head then {migrating material comes after equation number} + begin link(tail):=link(adjust_head); tail:=t; + end; +@y +if t<>adjust_head then {migrating material comes after equation number} + begin link(tail):=link(adjust_head); tail:=t; + end; +if pre_t<>pre_adjust_head then + begin link(tail):=link(pre_adjust_head); tail:=pre_t; + end; +@z diff --git a/Build/source/texk/web2c/pdftexdir/vfpacket.c b/Build/source/texk/web2c/pdftexdir/vfpacket.c new file mode 100644 index 00000000000..1f8f86b8d82 --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/vfpacket.c @@ -0,0 +1,116 @@ +/* +Copyright (c) 1996-2002 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/vfpacket.c#7 $ +*/ + +#include "ptexlib.h" + +typedef struct { + internalfontnumber font; + char *dataptr; + int len; +} packet_entry; + +/* define packet_ptr, packet_array & packet_limit */ +define_array(packet); + +typedef struct { + char **data; + int *len; + internalfontnumber font; +} vf_entry; + +/* define vf_ptr, vf_array & vf_limit */ +define_array(vf); + +static char *packet_data_ptr; + +integer newvfpacket(internalfontnumber f) +{ + int i, + n = fontec[f] - fontbc[f] + 1; + alloc_array(vf, 1, SMALL_ARRAY_SIZE); + vf_ptr->len = xtalloc(n, int); + vf_ptr->data = xtalloc(n, char *); + for (i = 0; i < n; i++) { + vf_ptr->data[i] = NULL; + vf_ptr->len[i] = 0; + } + vf_ptr->font = f; + return vf_ptr++ - vf_array; +} + +void storepacket(integer f, integer c, integer s) +{ + int l = strstart[s + 1] - strstart[s]; + vf_array[vfpacketbase[f]].len[c - fontbc[f]] = l; + vf_array[vfpacketbase[f]].data[c - fontbc[f]] = xtalloc(l, char); + memcpy((void *)vf_array[vfpacketbase[f]].data[c - fontbc[f]], + (void *)(strpool + strstart[s]), (unsigned)l); +} + +void pushpacketstate() +{ + alloc_array(packet, 1, SMALL_ARRAY_SIZE); + packet_ptr->font = f; + packet_ptr->dataptr = packet_data_ptr; + packet_ptr->len = vfpacketlength; + packet_ptr++; +} + +void poppacketstate() +{ + if (packet_ptr == packet_array) + pdftex_fail("packet stack empty, impossible to pop"); + packet_ptr--; + f = packet_ptr->font; + packet_data_ptr = packet_ptr->dataptr; + vfpacketlength = packet_ptr->len; +} + +void startpacket(internalfontnumber f, integer c) +{ + packet_data_ptr = vf_array[vfpacketbase[f]].data[c - fontbc[f]]; + vfpacketlength = vf_array[vfpacketbase[f]].len[c - fontbc[f]]; +} + +eightbits packetbyte() +{ + vfpacketlength--; + return *packet_data_ptr++; +} + +void vf_free(void) +{ + vf_entry *v; + int n; + char **p; + if (vf_array != NULL) { + for (v = vf_array; v < vf_ptr; v++) { + xfree(v->len); + n = fontec[v->font] - fontec[v->font] + 1; + for (p = v->data; p - v->data < n ; p++) + xfree(*p); + xfree(v->data); + } + xfree(vf_array); + } + xfree(packet_array); +} diff --git a/Build/source/texk/web2c/pdftexdir/win32.mak b/Build/source/texk/web2c/pdftexdir/win32.mak new file mode 100644 index 00000000000..1a0e5ba3a45 --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/win32.mak @@ -0,0 +1,71 @@ +################################################################################ +# +# Makefile : Web2C / pdftexdir +# Author : Fabrice Popineau <Fabrice.Popineau@supelec.fr> +# Platform : Win32, Microsoft VC++ 6.0, depends upon fpTeX 0.5 sources +# Time-stamp: <04/03/13 13:12:08 popineau> +# +################################################################################ +root_srcdir = ..\..\.. +!ifdef DEVELOPMENT +INCLUDE=$(INCLUDE);$(root_srcdir)\texk.development +!else +INCLUDE=$(INCLUDE);$(root_srcdir)\texk +!endif + + +USE_XPDF = 1 +USE_ZLIB = 1 +USE_PNG = 1 +USE_JPEG = 1 +USE_TEX = 1 +USE_MD5 = 1 +USE_GNUW32 = 1 +USE_KPATHSEA = 1 + +!include <msvc/common.mak> + +DEFS = -I.. -I$(top_srcdir) $(DEFS) -DMAKE_TEX_DLL -DHAVE_CONFIG_H -DpdfeTeX + +objects = $(objdir)\avl.obj $(objdir)\avlstuff.obj $(objdir)\epdf.obj \ + $(objdir)\mapfile.obj \ + $(objdir)\utils.obj $(objdir)\vfpacket.obj \ + $(objdir)\pkin.obj $(objdir)\writefont.obj $(objdir)\writet1.obj \ + $(objdir)\writet3.obj $(objdir)\writezip.obj $(objdir)\writeenc.obj \ + $(objdir)\writettf.obj $(objdir)\writejpg.obj $(objdir)\writepng.obj \ + $(objdir)\writeimg.obj \ + $(objdir)\pdftoepdf.obj + +default: all + +all: $(objdir) libpdftoepdf $(objdir)\libpdf.lib + +$(objdir)\libpdf.lib: $(objdir) $(objects) $(md5lib) + $(archive) $(objects) $(md5lib) + +libpdftoepdf: $(objdir) $(objdir)\libpdftoepdf.lib + +$(objdir)\libpdftoepdf.lib: $(objdir)\pdftoepdf.obj $(xpdflib) + $(archive) $(objdir)\pdftoepdf.obj $(xpdflib) + +$(objdir)\pdftoepdf.obj: pdftoepdf.cc # $(xpdf) + +ptexlib.h: ..\pdftexd.h + +..\pdftexd.h: + -@echo $(verbose) & ( \ + pushd .. & $(make) pdftexd.h & popd \ + ) + +!include <msvc/config.mak> +!include <msvc/install.mak> + +!include <msvc/clean.mak> +!include <msvc/rdepend.mak> + +!include "./depend.mak" + +# +# Local Variables: +# mode: makefile +# End: diff --git a/Build/source/texk/web2c/pdftexdir/writeenc.c b/Build/source/texk/web2c/pdftexdir/writeenc.c new file mode 100644 index 00000000000..7963403ec7e --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/writeenc.c @@ -0,0 +1,145 @@ +/* +Copyright (c) 1996-2005 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/writeenc.c#13 $ + +source code indentation by "indent -kr -nut" +*/ + +#include "ptexlib.h" +#include "avlstuff.h" + +static const char perforce_id[] = + "$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/writeenc.c#13 $"; + +void read_enc(enc_entry * e) +{ + assert(e != NULL); + if (e->loaded) + return; + load_enc(e->name, e->glyph_names); + e->loaded = true; +} + +/* write_enc is used to write either external encoding (given in map file) or + * internal encoding (read from the font file); when glyph_names is NULL + * the 2nd argument is a pointer to the encoding entry; otherwise the 3rd is + * the object number of the Encoding object + */ +void write_enc(char **glyph_names, enc_entry * e, integer eobjnum) +{ + boolean is_notdef; + int i; + char **g; + if (glyph_names == NULL) { + assert(e != NULL); + if (e->objnum != 0) /* the encoding has been written already */ + return; + pdfnewdict(0, 0); + e->objnum = objptr; + g = e->glyph_names; + } else { + pdfbegindict(eobjnum); + g = glyph_names; + } + pdf_printf("/Type /Encoding\n/Differences [ 0 /%s", g[0]); + is_notdef = (g[0] == notdef); + for (i = 1; i <= MAX_CHAR_CODE; i++) { + if (g[i] == notdef) { + if (!is_notdef) { + pdf_printf(" %i/%s", i, notdef); + is_notdef = true; + } + } else { + if (is_notdef) { + pdf_printf(" %i", i); + is_notdef = false; + } + pdf_printf("/%s", g[i]); + } + } + pdf_puts("]\n"); + pdfenddict(); +} + +/**********************************************************************/ +/* All encoding entries go into AVL tree for fast search by name. */ + +struct avl_table *enc_tree = NULL; + +/* AVL sort enc_entry into enc_tree by name */ + +static int comp_enc_entry(const void *pa, const void *pb, void *p) +{ + return strcmp(((const enc_entry *) pa)->name, + ((const enc_entry *) pb)->name); +} + +enc_entry *add_enc(char *s) +{ + int i; + enc_entry tmp, *p; + void **aa; + + assert(s != NULL); + if (enc_tree == NULL) { + enc_tree = avl_create(comp_enc_entry, NULL, &avl_xallocator); + assert(enc_tree != NULL); + } + tmp.name = s; + p = (enc_entry *) avl_find(enc_tree, &tmp); + if (p != NULL) /* encoding already registered */ + return p; + p = xtalloc(1, enc_entry); + p->loaded = false; + p->name = xstrdup(s); + p->objnum = 0; + p->glyph_names = xtalloc(MAX_CHAR_CODE + 1, char *); + for (i = 0; i <= MAX_CHAR_CODE; i++) + p->glyph_names[i] = (char *) notdef; + aa = avl_probe(enc_tree, p); + assert(aa != NULL); + return p; +} + +/**********************************************************************/ +/* cleaning up... */ + +static void destroy_enc_entry(void *pa, void *pb) +{ + enc_entry *p; + int i; + + p = (enc_entry *) pa; + xfree(p->name); + if (p->glyph_names != NULL) + for (i = 0; i <= MAX_CHAR_CODE; i++) + if (p->glyph_names[i] != notdef) + xfree(p->glyph_names[i]); + xfree(p->glyph_names); + xfree(p); +} + +void enc_free() +{ + if (enc_tree != NULL) + avl_destroy(enc_tree, destroy_enc_entry); +} + +/**********************************************************************/ diff --git a/Build/source/texk/web2c/pdftexdir/writefont.c b/Build/source/texk/web2c/pdftexdir/writefont.c new file mode 100644 index 00000000000..abb0074bde0 --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/writefont.c @@ -0,0 +1,318 @@ +/* +Copyright (c) 1996-2002 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/writefont.c#15 $ +*/ + +#include "ptexlib.h" + +static const char perforce_id[] = + "$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/writefont.c#15 $"; + +key_entry font_keys[FONT_KEYS_NUM] = { + {"Ascent", "Ascender", 0, false}, + {"CapHeight", "CapHeight", 0, false}, + {"Descent", "Descender", 0, false}, + {"FontName", "FontName", 0, false}, + {"ItalicAngle", "ItalicAngle", 0, false}, + {"StemV", "StdVW", 0, false}, + {"XHeight", "XHeight", 0, false}, + {"FontBBox", "FontBBox", 0, false}, + {"", "", 0, false}, + {"", "", 0, false}, + {"", "", 0, false} +}; + +internalfontnumber tex_font; +boolean fontfile_found; +boolean is_otf_font; +boolean write_ttf_glyph_names; +char fontname_buf[FONTNAME_BUF_SIZE]; + +static int first_char, last_char; +static integer char_widths[MAX_CHAR_CODE + 1]; +static boolean write_fontfile_only; +static int char_widths_objnum, + encoding_objnum; +static char **cur_glyph_names; + +static void print_key(integer code, integer v) +{ + pdf_printf("/%s ", font_keys[code].pdfname); + if (font_keys[code].valid) + pdf_printf("%i", (int)font_keys[code].value); + else + pdf_printf("%i", (int)dividescaled(v, pdffontsize[tex_font], 3)); + pdf_puts("\n"); +} + +static void print_italic_angle() +{ + pdf_printf("/%s ", font_keys[ITALIC_ANGLE_CODE].pdfname); + if (font_keys[ITALIC_ANGLE_CODE].valid) + pdf_printf("%g", font_keys[ITALIC_ANGLE_CODE].value); + else + pdf_printf("%g", -atan(getslant(tex_font)/65536.0)*(180/M_PI)); + pdf_puts("\n"); +} + +static integer getstemv(void) +{ + return getcharwidth(tex_font, '.')/3; +} + +static void getbbox(void) +{ + font_keys[FONTBBOX1_CODE].value = 0; + font_keys[FONTBBOX2_CODE].value = + dividescaled(-getchardepth(tex_font, 'y'), pdffontsize[tex_font], 3); + font_keys[FONTBBOX3_CODE].value = + dividescaled(getquad(tex_font), pdffontsize[tex_font], 3); + font_keys[FONTBBOX4_CODE].value = + dividescaled(getcharheight(tex_font, 'H'), pdffontsize[tex_font], 3); +} + +static void get_char_widths(void) +{ + int i; + for (i = 0; i <= MAX_CHAR_CODE; i++) { + if (i < fontbc[tex_font] || i > fontec[tex_font]) + char_widths[i] = 0; + else + char_widths[i] = getcharwidth(tex_font, i); + } + for (i = fontbc[tex_font]; i <= 32; i++) + char_widths[pdfcharmap[tex_font][i]] = char_widths[i]; + for (i = fontbc[tex_font]; i <= MAX_CHAR_CODE; i++) + if (pdfcharmarked(tex_font, i)) + break; + first_char = i; + for (i = MAX_CHAR_CODE; i > first_char; i--) + if (pdfcharmarked(tex_font, i)) + break; + last_char = i; + if ((first_char > last_char) || + (first_char == last_char && !pdfcharmarked(tex_font, first_char))) { + write_fontfile_only = true; /* the font is used in PDF images only */ + return; + } + for (i = first_char; i <= last_char; i++) + if (pdfcharmarked(tex_font, i)) + char_widths[i] = dividescaled(char_widths[i], + pdffontsize[tex_font], 3); + else + char_widths[i] = 0; +} + +static void write_char_widths(void) +{ + int i; + pdfbeginobj(char_widths_objnum); + pdf_puts("["); + for (i = first_char; i <= last_char; i++) + pdf_printf("%i ", char_widths[i]); + pdf_puts("]\n"); + pdfendobj(); +} + +static void write_fontname(boolean as_reference) +{ + if (as_reference && fm_cur->fn_objnum != 0) { + pdf_printf("%i 0 R\n", (int)fm_cur->fn_objnum); + return; + } + pdf_puts("/"); + if (fm_cur->subset_tag != NULL) + pdf_printf("%s+", fm_cur->subset_tag); + if (font_keys[FONTNAME_CODE].valid) + pdf_printf("%s", fontname_buf); + else if (fm_cur->ps_name != NULL) + pdf_printf("%s", fm_cur->ps_name); + else + pdf_printf("%s", fm_cur->tfm_name); + pdf_puts("\n"); +} + +static void write_fontobj(integer font_objnum) +{ + pdfbegindict(font_objnum); + pdf_puts("/Type /Font\n"); + pdf_printf("/Subtype /%s\n", is_truetype(fm_cur) ? "TrueType" : "Type1"); + if (encoding_objnum != 0) + pdf_printf("/Encoding %i 0 R\n", (int)encoding_objnum); + if (pdffontattr[tex_font] != getnullstr()) { + pdfprint(pdffontattr[tex_font]); + pdf_puts("\n"); + } + if (no_font_desc(fm_cur)) { + pdf_printf("/BaseFont /%s\n", fm_cur->ps_name); + pdfenddict(); + return; + } + char_widths_objnum = pdfnewobjnum(); + pdf_printf("/FirstChar %i\n/LastChar %i\n/Widths %i 0 R\n", + first_char, last_char, char_widths_objnum); + pdf_printf("/BaseFont "); + write_fontname(true); + if (fm_cur->fd_objnum == 0) + fm_cur->fd_objnum = pdfnewobjnum(); + pdf_printf("/FontDescriptor %i 0 R\n", fm_cur->fd_objnum); + pdfenddict(); +} + +static void write_fontfile(void) +{ + int i; + for (i = 0; i < FONT_KEYS_NUM; i++) + font_keys[i].valid = false; + fontfile_found = false; + is_otf_font = false; + if (is_truetype(fm_cur)) + writettf(); + else + writet1(); + if (!fontfile_found || !is_included(fm_cur)) + return; + if (fm_cur->ff_objnum == 0) + pdftex_fail("font file object number for `%s' not initialized", + fm_cur->tfm_name); + pdfbegindict(fm_cur->ff_objnum); /* font file stream */ + if (is_truetype(fm_cur)) + pdf_printf("/Length1 %i\n", (int)ttf_length); + else if (is_otf_font) + pdf_printf("/Subtype /Type1C\n"); + else + pdf_printf("/Length1 %i\n/Length2 %i\n/Length3 %i\n", + (int)t1_length1, (int)t1_length2, (int)t1_length3); + pdfbeginstream(); + fb_flush(); + pdfendstream(); +} + +static void write_fontdescriptor(void) +{ + int i; + pdfbegindict(fm_cur->fd_objnum); /* font descriptor */ + print_key(ASCENT_CODE, getcharheight(tex_font, 'h')); + print_key(CAPHEIGHT_CODE, getcharheight(tex_font, 'H')); + print_key(DESCENT_CODE, -getchardepth(tex_font, 'y')); + pdf_printf("/FontName "); + write_fontname(true); + print_italic_angle(); + print_key(STEMV_CODE, getstemv()); + print_key(XHEIGHT_CODE, getxheight(tex_font)); + if (!font_keys[FONTBBOX1_CODE].valid) { + getbbox(); + } + pdf_printf("/%s [%i %i %i %i]\n", + font_keys[FONTBBOX1_CODE].pdfname, + (int)font_keys[FONTBBOX1_CODE].value, + (int)font_keys[FONTBBOX2_CODE].value, + (int)font_keys[FONTBBOX3_CODE].value, + (int)font_keys[FONTBBOX4_CODE].value); + if (!fontfile_found && fm_cur->flags == 4) + pdf_puts("/Flags 34\n"); /* assumes a roman sans serif font */ + else + pdf_printf("/Flags %i\n", (int)fm_cur->flags); + if (is_included(fm_cur) && fontfile_found) { + if (is_subsetted(fm_cur) && !is_truetype(fm_cur)) { + cur_glyph_names = t1_glyph_names; + pdf_puts("/CharSet ("); + for (i = 0; i <= MAX_CHAR_CODE; i++) + if (pdfcharmarked(tex_font, i) && cur_glyph_names[i] != notdef) + pdf_printf("/%s", cur_glyph_names[i]); + pdf_puts(")\n"); + } + if (is_truetype(fm_cur)) + pdf_printf("/FontFile2 %i 0 R\n", fm_cur->ff_objnum); + else if (is_otf_font) + pdf_printf("/FontFile3 %i 0 R\n", fm_cur->ff_objnum); + else + pdf_printf("/FontFile %i 0 R\n", fm_cur->ff_objnum); + } + pdfenddict(); +} + +void dopdffont(integer font_objnum, internalfontnumber f) +{ + int i; + tex_font = f; + cur_glyph_names = NULL; + encoding_objnum = 0; + write_ttf_glyph_names = false; + write_fontfile_only = false; + if (pdffontmap[tex_font] == NULL) + pdftex_fail("pdffontmap not initialized for font %s", + makecstring(fontname[tex_font])); + if (hasfmentry(tex_font)) + fm_cur = (fm_entry *) pdffontmap[tex_font]; + else + fm_cur = NULL; + if (fm_cur == NULL || (fm_cur->ps_name == NULL && fm_cur->ff_name == NULL)) { + writet3(font_objnum, tex_font); + return; + } + + get_char_widths(); /* update char widths; also check whether this font is + used in embedded PDF only; if so then set + write_fontfile_only to true */ + + if (!write_fontfile_only) { /* encoding vector needed */ + if ((is_reencoded(fm_cur))) { + read_enc(fm_cur->encoding); + if (!is_truetype(fm_cur)) { + write_enc(NULL, fm_cur->encoding, 0); + encoding_objnum = (fm_cur->encoding)->objnum; + } + else + write_ttf_glyph_names = true; + } + else if (is_fontfile(fm_cur) && !is_truetype(fm_cur)) { + encoding_objnum = pdfnewobjnum(); + } + } + if (is_included(fm_cur)) + write_fontfile(); + if (fm_cur->fn_objnum != 0) { + pdfbeginobj(fm_cur->fn_objnum); + write_fontname(false); + pdfendobj(); + } + if (!write_fontfile_only) + write_fontobj(font_objnum); + if (no_font_desc(fm_cur)) + return; + if (!write_fontfile_only) { + write_fontdescriptor(); + write_char_widths(); + } + if (cur_glyph_names == t1_builtin_glyph_names) { + if (!write_fontfile_only) { + for (i = 0; i <= MAX_CHAR_CODE; i++) + if (!pdfcharmarked(tex_font, i) && cur_glyph_names[i] != notdef) { + xfree(cur_glyph_names[i]); + cur_glyph_names[i] = (char*) notdef; + } + write_enc(cur_glyph_names, NULL, encoding_objnum); + } + for (i = 0; i <= MAX_CHAR_CODE; i++) + if (cur_glyph_names[i] != notdef) + xfree(cur_glyph_names[i]); + } +} diff --git a/Build/source/texk/web2c/pdftexdir/writeimg.c b/Build/source/texk/web2c/pdftexdir/writeimg.c new file mode 100644 index 00000000000..397e5fba7e0 --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/writeimg.c @@ -0,0 +1,354 @@ +/* +Copyright (c) 1996-2002, 2005 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/writeimg.c#18 $ +*/ + +#include "ptexlib.h" +#include "image.h" +#include <kpathsea/c-auto.h> +#include <kpathsea/c-memstr.h> + +static const char perforce_id[] = + "$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/writeimg.c#18 $"; + +#define bp2int(p) round(p*(onehundredbp/100.0)) + +/* define image_ptr, image_array & image_limit */ +define_array(image); + +float epdf_width; +float epdf_height; +float epdf_orig_x; +float epdf_orig_y; +integer epdf_selected_page; +integer epdf_num_pages; +integer epdf_page_box; +integer epdf_always_use_pdf_pagebox; +void *epdf_doc; + +static integer new_image_entry(void) +{ + alloc_array(image, 1, SMALL_BUF_SIZE); + image_ptr->image_type = IMAGE_TYPE_NONE; + image_ptr->color_type = 0; + image_ptr->num_pages = 0; + image_ptr->x_res = 0; + image_ptr->y_res = 0; + image_ptr->width = 0; + image_ptr->height = 0; + image_ptr->colorspace_ref = 0; + return image_ptr++ - image_array; +} + +integer imagecolor(integer img) +{ + return img_color(img); +} + +integer imagewidth(integer img) +{ + return img_width(img); +} + +integer imageheight(integer img) +{ + return img_height(img); +} + +integer imagexres(integer img) +{ + return img_xres(img); +} + +integer imageyres(integer img) +{ + return img_yres(img); +} + +boolean ispdfimage(integer img) +{ + return img_type(img) == IMAGE_TYPE_PDF; +} + +boolean checkimageb(integer procset) +{ + return procset & IMAGE_COLOR_B; +} + +boolean checkimagec(integer procset) +{ + return procset & IMAGE_COLOR_C; +} + +boolean checkimagei(integer procset) +{ + return procset & IMAGE_COLOR_I; +} + +void updateimageprocset(integer img) +{ + pdfimageprocset |= img_color(img); +} + +integer epdforigx(integer img) +{ + return pdf_ptr(img)->orig_x; +} + +integer epdforigy(integer img) +{ + return pdf_ptr(img)->orig_y; +} + +integer imagepages(integer img) +{ + return img_pages(img); +} + +integer imagecolordepth(integer img) +{ + switch (img_type(img)) { + case IMAGE_TYPE_PNG: + return png_info(img)->bit_depth; + case IMAGE_TYPE_JPG: + return jpg_ptr(img)->bits_per_component; + case IMAGE_TYPE_PDF: + return 0; + default: + pdftex_fail("unknown type of image"); + } +} + +/* + Patch ImageTypeDetection 2003/02/08 by Heiko Oberdiek. + + Function "readimage" performs some basic initializations. + Then it looks at the file extension to determine the + image type and calls specific code/functions. + The main disadvantage is that standard file extensions + have to be used, otherwise pdfTeX is not able to detect + the correct image type. + + The patch now looks at the file header first regardless of + the file extension. This is implemented in function + "checktypebyheader". If this check fails, the traditional + test of standard file extension is tried, done in function + "checktypebyextension". + + Magic headers: + + * "PNG (Portable Network Graphics) Specification", Version 1.2 + (http://www.libpng.org/pub/png): + + | 3.1. PNG file signature + | + | The first eight bytes of a PNG file always contain the following + | (decimal) values: + | + | 137 80 78 71 13 10 26 10 + + Translation to C: "\x89PNG\r\n\x1A\n" + + * "JPEG File Interchange Format", Version 1.02: + + | o you can identify a JFIF file by looking for the following + | sequence: X'FF', SOI X'FF', APP0, <2 bytes to be skipped>, + | "JFIF", X'00'. + + Function "checktypebyheader" only looks at the first two bytes: + "\xFF\xD8" + + * "PDF Reference", third edition: + * The first line should contain "%PDF-1.0" until "%PDF-1.4" + (section 3.4.1 "File Header"). + * The "implementation notes" say: + + | 3.4.1, File Header + | 12. Acrobat viewers require only that the header appear + | somewhere within the first 1024 bytes of the file. + | 13. Acrobat viewers will also accept a header of the form + | %!PS-Adobe-N.n PDF-M.m + + The check in function "checktypebyheader" only implements + the first issue. The implementation notes are not considered. + Therefore files with garbage at start of file must have the + standard extension. + + Functions "checktypebyheader" and "checktypebyextension": + img_type(img) is set to IMAGE_TYPE_NONE by new_image_entry(). + Both functions tries to detect a type and set img_type(img). + Thus a value other than IMAGE_TYPE_NONE indicates that a + type is found. +*/ + +#define HEADER_JPG "\xFF\xD8" +#define HEADER_PNG "\x89PNG\r\n\x1A\n" +#define HEADER_PDF "%PDF-1." +#define MAX_HEADER (sizeof(HEADER_PNG)-1) +static void checktypebyheader(integer img) +{ + int i; + FILE *file = NULL; + char header[MAX_HEADER]; + + if (img_type(img) != IMAGE_TYPE_NONE) /* nothing to do */ + return; + + /* read the header */ + file = xfopen(img_name(img), FOPEN_RBIN_MODE); + for (i=0; i<MAX_HEADER; i++) { + header[i] = xgetc(file); + if (feof(file)) + pdftex_fail("reading image file failed"); + } + xfclose(file, img_name(img)); + + /* tests */ + if (strncmp(header, HEADER_JPG, sizeof(HEADER_JPG)-1) == 0) + img_type(img) = IMAGE_TYPE_JPG; + else if (strncmp(header, HEADER_PNG, sizeof(HEADER_PNG)-1) == 0) + img_type(img) = IMAGE_TYPE_PNG; + else if (strncmp(header, HEADER_PDF, sizeof(HEADER_PDF)-1) == 0) + img_type(img) = IMAGE_TYPE_PDF; +} + +static void checktypebyextension(integer img) +{ + char *image_suffix; + + if (img_type(img) != IMAGE_TYPE_NONE) /* nothing to do */ + return; + /* tests */ + if ((image_suffix = strrchr(cur_file_name, '.')) == 0) + img_type(img) = IMAGE_TYPE_NONE; + else if (strcasecmp(image_suffix, ".pdf") == 0) + img_type(img) = IMAGE_TYPE_PDF; + else if (strcasecmp(image_suffix, ".png") == 0) + img_type(img) = IMAGE_TYPE_PNG; + else if (strcasecmp(image_suffix, ".jpg") == 0 || + strcasecmp(image_suffix, ".jpeg") == 0) + img_type(img) = IMAGE_TYPE_JPG; +} + +integer readimage(strnumber s, integer page_num, strnumber page_name, integer colorspace, + integer pdfversion, integer pdfforcepagebox, + integer pdfinclusionerrorlevel) +{ + char *dest = NULL; + integer img = new_image_entry(); + img_colorspace_ref(img) = colorspace; + + /* need to allocate new string as makecstring's buffer is + already used by cur_file_name */ + if (page_name != 0) + dest = xstrdup(makecstring(page_name)); + cur_file_name = makecfilename(s); + img_name(img) = kpse_find_file(cur_file_name, kpse_tex_format, true); + if (img_name(img) == NULL) + pdftex_fail("cannot find image file"); + /* kpse_find_file perhaps changed the file name */ + cur_file_name = img_name(img); + /* type checks */ + checktypebyheader(img); + checktypebyextension(img); + /* read image */ + switch (img_type(img)) { + case IMAGE_TYPE_PDF: + pdf_ptr(img) = xtalloc(1, pdf_image_struct); + pdf_ptr(img)->page_box = pdflastpdfboxspec; + pdf_ptr(img)->always_use_pdfpagebox = pdfforcepagebox; + page_num = read_pdf_info(img_name(img), dest, page_num, + pdfversion, pdfforcepagebox, + pdfinclusionerrorlevel); + img_width(img) = bp2int(epdf_width); + img_height(img) = bp2int(epdf_height); + img_pages(img) = epdf_num_pages; + pdf_ptr(img)->orig_x = bp2int(epdf_orig_x); + pdf_ptr(img)->orig_y = bp2int(epdf_orig_y); + pdf_ptr(img)->selected_page = page_num; + pdf_ptr(img)->doc = epdf_doc; + break; + case IMAGE_TYPE_PNG: + img_pages(img) = 1; + read_png_info(img); + break; + case IMAGE_TYPE_JPG: + jpg_ptr(img) = xtalloc(1, JPG_IMAGE_INFO); + img_pages(img) = 1; + read_jpg_info(img); + break; + default: + pdftex_fail("unknown type of image"); + } + xfree(dest); + cur_file_name = NULL; + return img; +} + +void writeimage(integer img) +{ + cur_file_name = img_name(img); + tex_printf(" <%s", img_name(img)); + switch (img_type(img)) { + case IMAGE_TYPE_PNG: + write_png(img); + break; + case IMAGE_TYPE_JPG: + write_jpg(img); + break; + case IMAGE_TYPE_PDF: + epdf_doc = pdf_ptr(img)->doc; + epdf_selected_page = pdf_ptr(img)->selected_page; + epdf_page_box = pdf_ptr(img)->page_box; + epdf_always_use_pdf_pagebox = pdf_ptr(img)->always_use_pdfpagebox; + write_epdf(); + break; + default: + pdftex_fail("unknown type of image"); + } + tex_printf(">"); + cur_file_name = NULL; +} + +void deleteimage(integer img) +{ + switch (img_type(img)) { + case IMAGE_TYPE_PDF: + epdf_doc = pdf_ptr(img)->doc; + epdf_delete(); + break; + case IMAGE_TYPE_PNG: + xfclose(png_ptr(img)->io_ptr, cur_file_name); + png_destroy_read_struct(&(png_ptr(img)), &(png_info(img)), NULL); + break; + case IMAGE_TYPE_JPG: + xfclose(jpg_ptr(img)->file, cur_file_name); + break; + default: + pdftex_fail("unknown type of image"); + } + xfree(img_name(img)); + return; +} + +void img_free() +{ + xfree(image_array); +} diff --git a/Build/source/texk/web2c/pdftexdir/writejpg.c b/Build/source/texk/web2c/pdftexdir/writejpg.c new file mode 100644 index 00000000000..1b01737e4e5 --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/writejpg.c @@ -0,0 +1,227 @@ +/* +Copyright (c) 1996-2002 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/writejpg.c#10 $ +*/ + +#include "ptexlib.h" +#include "image.h" + +#define JPG_GRAY 1 /* Gray color space, use /DeviceGray */ +#define JPG_RGB 3 /* RGB color space, use /DeviceRGB */ +#define JPG_CMYK 4 /* CMYK color space, use /DeviceCMYK */ + +typedef enum { /* JPEG marker codes */ + M_SOF0 = 0xc0, /* baseline DCT */ + M_SOF1 = 0xc1, /* extended sequential DCT */ + M_SOF2 = 0xc2, /* progressive DCT */ + M_SOF3 = 0xc3, /* lossless (sequential) */ + + M_SOF5 = 0xc5, /* differential sequential DCT */ + M_SOF6 = 0xc6, /* differential progressive DCT */ + M_SOF7 = 0xc7, /* differential lossless */ + + M_JPG = 0xc8, /* JPEG extensions */ + M_SOF9 = 0xc9, /* extended sequential DCT */ + M_SOF10 = 0xca, /* progressive DCT */ + M_SOF11 = 0xcb, /* lossless (sequential) */ + + M_SOF13 = 0xcd, /* differential sequential DCT */ + M_SOF14 = 0xce, /* differential progressive DCT */ + M_SOF15 = 0xcf, /* differential lossless */ + + M_DHT = 0xc4, /* define Huffman tables */ + + M_DAC = 0xcc, /* define arithmetic conditioning table */ + + M_RST0 = 0xd0, /* restart */ + M_RST1 = 0xd1, /* restart */ + M_RST2 = 0xd2, /* restart */ + M_RST3 = 0xd3, /* restart */ + M_RST4 = 0xd4, /* restart */ + M_RST5 = 0xd5, /* restart */ + M_RST6 = 0xd6, /* restart */ + M_RST7 = 0xd7, /* restart */ + + M_SOI = 0xd8, /* start of image */ + M_EOI = 0xd9, /* end of image */ + M_SOS = 0xda, /* start of scan */ + M_DQT = 0xdb, /* define quantization tables */ + M_DNL = 0xdc, /* define number of lines */ + M_DRI = 0xdd, /* define restart interval */ + M_DHP = 0xde, /* define hierarchical progression */ + M_EXP = 0xdf, /* expand reference image(s) */ + + M_APP0 = 0xe0, /* application marker, used for JFIF */ + M_APP1 = 0xe1, /* application marker */ + M_APP2 = 0xe2, /* application marker */ + M_APP3 = 0xe3, /* application marker */ + M_APP4 = 0xe4, /* application marker */ + M_APP5 = 0xe5, /* application marker */ + M_APP6 = 0xe6, /* application marker */ + M_APP7 = 0xe7, /* application marker */ + M_APP8 = 0xe8, /* application marker */ + M_APP9 = 0xe9, /* application marker */ + M_APP10 = 0xea, /* application marker */ + M_APP11 = 0xeb, /* application marker */ + M_APP12 = 0xec, /* application marker */ + M_APP13 = 0xed, /* application marker */ + M_APP14 = 0xee, /* application marker, used by Adobe */ + M_APP15 = 0xef, /* application marker */ + + M_JPG0 = 0xf0, /* reserved for JPEG extensions */ + M_JPG13 = 0xfd, /* reserved for JPEG extensions */ + M_COM = 0xfe, /* comment */ + + M_TEM = 0x01, /* temporary use */ + + M_ERROR = 0x100 /* dummy marker, internal use only */ +} JPEG_MARKER; + +static JPG_UINT16 read2bytes(FILE *f) +{ + int c = xgetc(f); + return (c << 8) + xgetc(f); +} + +void read_jpg_info(integer img) +{ + int i; + char jpg_id[]="JFIF"; + int units=0; + img_xres(img)=img_yres(img)=0; + jpg_ptr(img)->file = xfopen(img_name(img), FOPEN_RBIN_MODE); + xfseek(jpg_ptr(img)->file,0,SEEK_END,cur_file_name); + jpg_ptr(img)->length=xftell(jpg_ptr(img)->file,cur_file_name); + xfseek(jpg_ptr(img)->file,0,SEEK_SET,cur_file_name); + if(read2bytes(jpg_ptr(img)->file)!=0xFFD8) + pdftex_fail("reading JPEG image failed"); + + if(read2bytes(jpg_ptr(img)->file)==0xFFE0) { /* JFIF APP0 */ + (void)read2bytes(jpg_ptr(img)->file); + for(i=0;i<5;i++) if(xgetc(jpg_ptr(img)->file)!=jpg_id[i]) + pdftex_fail("reading JPEG image failed"); + (void)read2bytes(jpg_ptr(img)->file); + units=xgetc(jpg_ptr(img)->file); + img_xres(img)=read2bytes(jpg_ptr(img)->file); + img_yres(img)=read2bytes(jpg_ptr(img)->file); + switch(units) { + case 1: break; /* pixels per inch */ + case 2: img_xres(img)*=2.54; img_yres(img)*=2.54; + break; /* pixels per cm */ + default:img_xres(img)=img_yres(img)=0; break; + } + } + + xfseek(jpg_ptr(img)->file,0,SEEK_SET,cur_file_name); + while(1) { + if(feof(jpg_ptr(img)->file) || fgetc(jpg_ptr(img)->file)!=0xFF) + pdftex_fail("reading JPEG image failed"); + switch(xgetc(jpg_ptr(img)->file)) { + case M_SOF5: + case M_SOF6: + case M_SOF7: + case M_SOF9: + case M_SOF10: + case M_SOF11: + case M_SOF13: + case M_SOF14: + case M_SOF15: + pdftex_fail("unsupported type of compression"); + case M_SOF2: + if (fixedpdfminorversion <= 2) + pdftex_fail("cannot use progressive DCT with PDF-1.2"); + case M_SOF0: + case M_SOF1: + case M_SOF3: + (void)read2bytes(jpg_ptr(img)->file); /* read segment length */ + jpg_ptr(img)->bits_per_component = xgetc(jpg_ptr(img)->file); + img_height(img) = read2bytes(jpg_ptr(img)->file); + img_width(img) = read2bytes(jpg_ptr(img)->file); + jpg_ptr(img)->color_space = xgetc(jpg_ptr(img)->file); + xfseek(jpg_ptr(img)->file,0,SEEK_SET,cur_file_name); + switch (jpg_ptr(img)->color_space) { + case JPG_GRAY: + img_color(img) = IMAGE_COLOR_B; + break; + case JPG_RGB: + img_color(img) = IMAGE_COLOR_C; + break; + case JPG_CMYK: + img_color(img) = IMAGE_COLOR_C; + break; + default: + pdftex_fail("Unsupported color space %i", + (int)jpg_ptr(img)->color_space); + } + return; + case M_SOI: /* ignore markers without parameters */ + case M_EOI: + case M_TEM: + case M_RST0: + case M_RST1: + case M_RST2: + case M_RST3: + case M_RST4: + case M_RST5: + case M_RST6: + case M_RST7: + break; + default: /* skip variable length markers */ + xfseek(jpg_ptr(img)->file,read2bytes(jpg_ptr(img)->file)-2,SEEK_CUR,cur_file_name); + break; + } + } +} + +void write_jpg(integer img) +{ + long unsigned l; + FILE *f; + pdf_puts("/Type /XObject\n/Subtype /Image\n"); + pdf_printf("/Width %i\n/Height %i\n/BitsPerComponent %i\n/Length %i\n", + img_width(img), + img_height(img), + (int)jpg_ptr(img)->bits_per_component, + (int)jpg_ptr(img)->length); + pdf_puts("/ColorSpace "); + if (img_colorspace_ref(img) != 0) { + pdf_printf("%i 0 R\n", (int)img_colorspace_ref(img)); + } + else { + switch (jpg_ptr(img)->color_space) { + case JPG_GRAY: + pdf_puts("/DeviceGray\n"); + break; + case JPG_RGB: + pdf_puts("/DeviceRGB\n"); + break; + case JPG_CMYK: + pdf_puts("/DeviceCMYK\n/Decode [1 0 1 0 1 0 1 0]\n"); + break; + default: + pdftex_fail("Unsupported color space %i", + (int)jpg_ptr(img)->color_space); + } + } + pdf_puts("/Filter /DCTDecode\n>>\nstream\n"); + for (l = jpg_ptr(img)->length, f = jpg_ptr(img)->file; l > 0; l--) + pdfout(xgetc(f)); + pdf_puts("endstream\nendobj\n"); +} diff --git a/Build/source/texk/web2c/pdftexdir/writepng.c b/Build/source/texk/web2c/pdftexdir/writepng.c new file mode 100644 index 00000000000..30340c9e08e --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/writepng.c @@ -0,0 +1,593 @@ +/* +Copyright (c) 1996-2004 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/writepng.c#8 $ +*/ + +#include "ptexlib.h" +#include "image.h" + + + +static const char perforce_id[] = + "$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/writepng.c#8 $"; + + +void read_png_info(integer img) +{ + double gamma; + FILE *png_file = xfopen(img_name(img), FOPEN_RBIN_MODE); + + if ((png_ptr(img) = png_create_read_struct(PNG_LIBPNG_VER_STRING, + NULL, NULL, NULL)) == NULL) + pdftex_fail("libpng: png_create_read_struct() failed"); + if ((png_info(img) = png_create_info_struct(png_ptr(img))) == NULL) + pdftex_fail("libpng: png_create_info_struct() failed"); + if (setjmp(png_ptr(img)->jmpbuf)) + pdftex_fail("libpng: internal error"); + png_init_io(png_ptr(img), png_file); + png_read_info(png_ptr(img), png_info(img)); + /* simple transparency support */ + if (png_get_valid(png_ptr(img), png_info(img), PNG_INFO_tRNS)) { + png_set_tRNS_to_alpha(png_ptr(img)); + } + /* alpha channel support */ + if (fixedpdfminorversion < 4 && png_ptr(img)->color_type | PNG_COLOR_MASK_ALPHA) + png_set_strip_alpha(png_ptr(img)); + /* 16bit depth support */ + if (fixedpdfminorversion < 5) + fixedimagehicolor = 0; + if (png_info(img)->bit_depth == 16 && !fixedimagehicolor) + png_set_strip_16(png_ptr(img)); + /* gamma support */ + if (fixedimageapplygamma) { + if(png_get_gAMA(png_ptr(img), png_info(img), &gamma)) + png_set_gamma(png_ptr(img), (fixedgamma / 1000.0), gamma); + else + png_set_gamma(png_ptr(img), (fixedgamma / 1000.0), (1000.0/ fixedimagegamma )); + } + /* reset structure */ + png_read_update_info(png_ptr(img), png_info(img)); + /* resolution support */ + img_width(img) = png_info(img)->width; + img_height(img) = png_info(img)->height; + if (png_info(img)->valid & PNG_INFO_pHYs) { + img_xres(img) = + round(0.0254*png_get_x_pixels_per_meter(png_ptr(img), png_info(img))); + img_yres(img) = + round(0.0254*png_get_y_pixels_per_meter(png_ptr(img), png_info(img))); + } + switch (png_info(img)->color_type) { + case PNG_COLOR_TYPE_PALETTE: + img_color(img) = IMAGE_COLOR_C | IMAGE_COLOR_I; + break; + case PNG_COLOR_TYPE_GRAY: + case PNG_COLOR_TYPE_GRAY_ALPHA: + img_color(img) = IMAGE_COLOR_B; + break; + case PNG_COLOR_TYPE_RGB: + case PNG_COLOR_TYPE_RGB_ALPHA: + img_color(img) = IMAGE_COLOR_C; + break; + default: + pdftex_fail("unsupported type of color_type <%i>", png_info(img)->color_type); + } +} + + +#define write_gray_pixel_16(r) \ + if (j % 4 == 0||j % 4 == 1) pdfbuf[pdfptr++] = *r++; \ + else smask[smask_ptr++] = *r++ + +#define write_gray_pixel_8(r) \ + if (j % 2 == 0) pdfbuf[pdfptr++] = *r++; \ + else smask[smask_ptr++] = *r++ + + +#define write_rgb_pixel_16(r) \ + if (!(j % 8 == 6||j % 8 == 7)) pdfbuf[pdfptr++] = *r++; \ + else smask[smask_ptr++] = *r++ + +#define write_rgb_pixel_8(r) \ + if (j % 4 != 3) pdfbuf[pdfptr++] = *r++; \ + else smask[smask_ptr++] = *r++ + +#define write_simple_pixel(r) pdfbuf[pdfptr++] = *r++ + + +#define write_noninterlaced(outmac) \ + for (i = 0; i < (int)png_info(img)->height; i++) { \ + png_read_row(png_ptr(img), row, NULL); \ + r = row; \ + k = png_info(img)->rowbytes; \ + while(k > 0) { \ + l = (k > pdfbufsize)? pdfbufsize : k; \ + pdfroom(l); \ + for (j = 0; j < l; j++) { \ + outmac; \ + } \ + k -= l; \ + } \ + } + +#define write_interlaced(outmac) \ + for (i = 0; i < (int)png_info(img)->height; i++) { \ + row = rows[i]; \ + k = png_info(img)->rowbytes; \ + while(k > 0) { \ + l = (k > pdfbufsize)? pdfbufsize : k; \ + pdfroom(l); \ + for (j = 0; j < l; j++) { \ + outmac; \ + } \ + k -= l; \ + } \ + xfree(rows[i]); \ + } + + +void write_png_palette (integer img) +{ + int i, j, k, l; + png_bytep row, r, *rows; + integer palette_objnum = 0; + pdfcreateobj(0, 0); + palette_objnum = objptr; + if (img_colorspace_ref(img) != 0) { + pdf_printf("%i 0 R\n", (int)img_colorspace_ref(img)); + } + else { + pdf_printf("[/Indexed /DeviceRGB %i %i 0 R]\n", + (int)(png_info(img)->num_palette - 1), + (int)palette_objnum); + } + pdfbeginstream(); + if (png_info(img)->interlace_type == PNG_INTERLACE_NONE) { + row = xtalloc(png_info(img)->rowbytes, png_byte); + write_noninterlaced(write_simple_pixel(r)); + xfree(row); + } else { + if (png_info(img)->height*png_info(img)->rowbytes >= 10240000L) + pdftex_warn("large interlaced PNG might cause out of memory (use non-interlaced PNG to fix this)"); + rows = xtalloc(png_info(img)->height, png_bytep); + for (i = 0; i < png_info(img)->height; i++) + rows[i] = xtalloc(png_info(img)->rowbytes, png_byte); + png_read_image(png_ptr(img), rows); + write_interlaced(write_simple_pixel(row)); + xfree(rows); + } + pdfendstream(); + if (palette_objnum > 0) { + pdfbegindict(palette_objnum); + pdfbeginstream(); + for (i = 0; i < png_info(img)->num_palette; i++) { + pdfroom(3); + pdfbuf[pdfptr++] = png_info(img)->palette[i].red; + pdfbuf[pdfptr++] = png_info(img)->palette[i].green; + pdfbuf[pdfptr++] = png_info(img)->palette[i].blue; + } + pdfendstream(); + } +} + +void write_png_gray (integer img) +{ + int i, j, k, l; + png_bytep row, r, *rows; + if (img_colorspace_ref(img) != 0) { + pdf_printf("%i 0 R\n", (int)img_colorspace_ref(img)); + } + else { + pdf_puts("/DeviceGray\n"); + } + pdfbeginstream(); + if (png_info(img)->interlace_type == PNG_INTERLACE_NONE) { + row = xtalloc(png_info(img)->rowbytes, png_byte); + write_noninterlaced(write_simple_pixel(r)); + xfree(row); + } else { + if (png_info(img)->height*png_info(img)->rowbytes >= 10240000L) + pdftex_warn("large interlaced PNG might cause out of memory (use non-interlaced PNG to fix this)"); + rows = xtalloc(png_info(img)->height, png_bytep); + for (i = 0; i < png_info(img)->height; i++) + rows[i] = xtalloc(png_info(img)->rowbytes, png_byte); + png_read_image(png_ptr(img), rows); + write_interlaced(write_simple_pixel(row)); + xfree(rows); + } + pdfendstream(); +} + + + +void write_png_gray_alpha (integer img) +{ + int i, j, k, l; + png_bytep row, r, *rows; + integer smask_objnum = 0; + png_bytep smask; + integer smask_ptr = 0; + integer smask_size = 0; + int bitdepth; + if (img_colorspace_ref(img) != 0) { + pdf_printf("%i 0 R\n", (int)img_colorspace_ref(img)); + } + else { + pdf_puts("/DeviceGray\n"); + } + pdfcreateobj(0, 0); + smask_objnum = objptr; + pdf_printf("/SMask %i 0 R\n", + (int)smask_objnum); + smask_size = (png_info(img)->rowbytes/2)*png_info(img)->height; + smask = xtalloc(smask_size, png_byte); + pdfbeginstream(); + if (png_info(img)->interlace_type == PNG_INTERLACE_NONE) { + row = xtalloc(png_info(img)->rowbytes, png_byte); + if ((png_info(img)->bit_depth == 16) && fixedimagehicolor) { + write_noninterlaced(write_gray_pixel_16(r)); + } else { + write_noninterlaced(write_gray_pixel_8(r)); + } + xfree(row); + } else { + if (png_info(img)->height*png_info(img)->rowbytes >= 10240000L) + pdftex_warn("large interlaced PNG might cause out of memory (use non-interlaced PNG to fix this)"); + rows = xtalloc(png_info(img)->height, png_bytep); + for (i = 0; i < png_info(img)->height; i++) + rows[i] = xtalloc(png_info(img)->rowbytes, png_byte); + png_read_image(png_ptr(img), rows); + if ((png_info(img)->bit_depth == 16) && fixedimagehicolor) { + write_interlaced(write_gray_pixel_16(row)); + } else { + write_interlaced(write_gray_pixel_8(row)); + } + xfree(rows); + } + pdfendstream(); + pdfflush(); + /* now write the Smask object */ + if (smask_objnum > 0) { + bitdepth = (int)png_info(img)->bit_depth; + pdfbegindict(smask_objnum); + pdf_puts("/Type /XObject\n/Subtype /Image\n"); + pdf_printf("/Width %i\n/Height %i\n/BitsPerComponent %i\n", + (int)png_info(img)->width, + (int)png_info(img)->height, + (bitdepth == 16 ? 8 : bitdepth)); + pdf_puts("/ColorSpace /DeviceGray\n"); + pdfbeginstream(); + for (i = 0; i <smask_size; i++) { + if (i % 8 == 0) + pdfroom(8); + pdfbuf[pdfptr++] = smask[i]; + if (bitdepth == 16) + i++; + } + xfree(smask); + pdfendstream(); + } +} + +void write_png_rgb (integer img) +{ + int i, j, k, l; + png_bytep row, r, *rows; + if (img_colorspace_ref(img) != 0) { + pdf_printf("%i 0 R\n", (int)img_colorspace_ref(img)); + } + else { + pdf_puts("/DeviceRGB\n"); + } + pdfbeginstream(); + if (png_info(img)->interlace_type == PNG_INTERLACE_NONE) { + row = xtalloc(png_info(img)->rowbytes, png_byte); + write_noninterlaced(write_simple_pixel(r)); + xfree(row); + } else { + if (png_info(img)->height*png_info(img)->rowbytes >= 10240000L) + pdftex_warn("large interlaced PNG might cause out of memory (use non-interlaced PNG to fix this)"); + rows = xtalloc(png_info(img)->height, png_bytep); + for (i = 0; i < png_info(img)->height; i++) + rows[i] = xtalloc(png_info(img)->rowbytes, png_byte); + png_read_image(png_ptr(img), rows); + write_interlaced(write_simple_pixel(row)); + xfree(rows); + } + pdfendstream(); +} + +void write_png_rgb_alpha (integer img) +{ + int i, j, k, l; + png_bytep row, r, *rows; + integer smask_objnum = 0; + png_bytep smask; + integer smask_ptr = 0; + integer smask_size = 0; + int bitdepth; + if (img_colorspace_ref(img) != 0) { + pdf_printf("%i 0 R\n", (int)img_colorspace_ref(img)); + } + else { + pdf_puts("/DeviceRGB\n"); + } + pdfcreateobj(0, 0); + smask_objnum = objptr; + pdf_printf("/SMask %i 0 R\n", + (int)smask_objnum); + smask_size = (png_info(img)->rowbytes/2)*png_info(img)->height; + smask = xtalloc(smask_size, png_byte); + pdfbeginstream(); + if (png_info(img)->interlace_type == PNG_INTERLACE_NONE) { + row = xtalloc(png_info(img)->rowbytes, png_byte); + if ((png_info(img)->bit_depth == 16) && fixedimagehicolor) { + write_noninterlaced(write_rgb_pixel_16(r)); + } else { + write_noninterlaced(write_rgb_pixel_8(r)); + } + xfree(row); + } else { + if (png_info(img)->height*png_info(img)->rowbytes >= 10240000L) + pdftex_warn("large interlaced PNG might cause out of memory (use non-interlaced PNG to fix this)"); + rows = xtalloc(png_info(img)->height, png_bytep); + for (i = 0; i < png_info(img)->height; i++) + rows[i] = xtalloc(png_info(img)->rowbytes, png_byte); + png_read_image(png_ptr(img), rows); + if ((png_info(img)->bit_depth == 16) && fixedimagehicolor) { + write_interlaced(write_rgb_pixel_16(row)); + } else { + write_interlaced(write_rgb_pixel_8(row)); + } + xfree(rows); + } + pdfendstream(); + pdfflush(); + /* now write the Smask object */ + if (smask_objnum > 0) { + bitdepth = (int)png_info(img)->bit_depth; + pdfbegindict(smask_objnum); + pdf_puts("/Type /XObject\n/Subtype /Image\n"); + pdf_printf("/Width %i\n/Height %i\n/BitsPerComponent %i\n", + (int)png_info(img)->width, + (int)png_info(img)->height, + (bitdepth == 16 ? 8 : bitdepth)); + pdf_puts("/ColorSpace /DeviceGray\n"); + pdfbeginstream(); + for (i = 0; i <smask_size; i++) { + if (i % 8 == 0) + pdfroom(8); + pdfbuf[pdfptr++] = smask[i]; + if (bitdepth == 16) + i++; + } + xfree(smask); + pdfendstream(); + } +} + + +/**********************************************************************/ +/* + * + * The |copy_png| function is from Hartmut Henkel. The goal is to use + * pdf's native FlateDecode support if that is possible. + * + * Only a subset of the png files allows this, but when possible it + * greatly improves inclusion speed. + * + */ + +/* Code cheerfully gleaned from Thomas Merz' PDFlib, file p_png.c "SPNG - Simple PNG" */ + +static int spng_getint(FILE * fp) +{ + unsigned char buf[4]; + if (fread(buf, 1, 4, fp) != 4) + pdftex_fail("writepng: reading chunk type failed"); + return (((((int) buf[0] << 8) + buf[1]) << 8) + buf[2] << 8) + buf[3]; +} + +#define SPNG_CHUNK_IDAT 0x49444154 +#define SPNG_CHUNK_IEND 0x49454E44 + +void copy_png(integer img) +{ + FILE *fp = png_ptr(img)->io_ptr; + int i, len, type, streamlength = 0; + boolean endflag = false; + int idat = 0; /* flag to check continuous IDAT chunks sequence */ + /* 1st pass to find overall stream /Length */ + if (fseek(fp, 8, SEEK_SET) != 0) + pdftex_fail("writepng: fseek in PNG file failed"); + do { + len = spng_getint(fp); + type = spng_getint(fp); + switch (type) { + case SPNG_CHUNK_IEND: + endflag = true; + break; + case SPNG_CHUNK_IDAT: + streamlength += len; + default: + if (fseek(fp, len + 4, SEEK_CUR) != 0) + pdftex_fail("writepng: fseek in PNG file failed"); + } + } while (endflag == false); + pdf_printf("/Length %d\n", streamlength); + pdf_printf("/Filter /FlateDecode\n"); + pdf_printf("/DecodeParms << "); + pdf_printf("/Colors %d ", png_info(img)->color_type == 2 ? 3 : 1); + pdf_printf("/Columns %d ", (int) png_info(img)->width); + pdf_printf("/BitsPerComponent %i ", (int) png_info(img)->bit_depth); + pdf_printf("/Predictor %d ", 10); /* actual predictor defined on line basis */ + pdf_printf(">>\n>>\nstream\n"); + /* 2nd pass to copy data */ + endflag = false; + if (fseek(fp, 8, SEEK_SET) != 0) + pdftex_fail("writepng: fseek in PNG file failed"); + do { + len = spng_getint(fp); + type = spng_getint(fp); + switch (type) { + case SPNG_CHUNK_IDAT: /* do copy */ + if (idat == 2) + pdftex_fail("writepng: IDAT chunk sequence broken"); + idat = 1; + while (len > 0) { + i = (len > pdfbufsize) ? pdfbufsize : len; + pdfroom(i); + fread(&pdfbuf[pdfptr], 1, i, fp); + pdfptr += i; + len -= i; + } + if (fseek(fp, 4, SEEK_CUR) != 0) + pdftex_fail("writepng: fseek in PNG file failed"); + break; + case SPNG_CHUNK_IEND: /* done */ + pdf_puts("\nendstream\nendobj\n"); + endflag = true; + break; + default: + if (idat == 1) + idat = 2; + if (fseek(fp, len + 4, SEEK_CUR) != 0) + pdftex_fail("writepng: fseek in PNG file failed"); + } + } while (endflag == false); +} + +void write_png (integer img) +{ + + double gamma, checked_gamma; + int i; + integer palette_objnum = 0; + if (fixedpdfminorversion < 5) + fixedimagehicolor = 0; + + pdf_puts("/Type /XObject\n/Subtype /Image\n"); + pdf_printf("/Width %i\n/Height %i\n/BitsPerComponent %i\n", + (int)png_info(img)->width, + (int)png_info(img)->height, + (int)png_info(img)->bit_depth); + pdf_puts("/ColorSpace "); + checked_gamma = 1.0; + if (fixedimageapplygamma) { + if(png_get_gAMA(png_ptr(img), png_info(img), &gamma)) { + checked_gamma = (fixedgamma / 1000.0) * gamma; + } else { + checked_gamma = (fixedgamma / 1000.0) * (1000.0/ fixedimagegamma ); + } + } + /* the switching between |png_info| and |png_ptr| queries has been trial and error. + */ + if (fixedpdfminorversion > 1 + && png_info(img)->interlace_type == PNG_INTERLACE_NONE + && (png_ptr(img)->transformations == 0 || + png_ptr(img)->transformations == 0x2000 ) /* gamma */ + && !(png_ptr(img)->color_type == PNG_COLOR_TYPE_GRAY_ALPHA || + png_ptr(img)->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + && (fixedimagehicolor || (png_ptr(img)->bit_depth <= 8)) + && (checked_gamma <= 1.01 && checked_gamma > 0.99) + ) + { + if (img_colorspace_ref(img) != 0) { + pdf_printf("%i 0 R\n", (int)img_colorspace_ref(img)); + } + else { + switch (png_info(img)->color_type) { + case PNG_COLOR_TYPE_PALETTE: + pdfcreateobj(0, 0); + palette_objnum = objptr; + pdf_printf("[/Indexed /DeviceRGB %i %i 0 R]\n", + (int) (png_info(img)->num_palette - 1), + (int) palette_objnum); + break; + case PNG_COLOR_TYPE_GRAY: + pdf_puts("/DeviceGray\n"); + break; + default: /* RGB */ + pdf_puts("/DeviceRGB\n"); + }; + } + tex_printf(" (PNG copy)"); + copy_png(img); + if (palette_objnum > 0) { + pdfbegindict(palette_objnum); + pdfbeginstream(); + for (i = 0; i < png_info(img)->num_palette; i++) { + pdfroom(3); + pdfbuf[pdfptr++] = png_info(img)->palette[i].red; + pdfbuf[pdfptr++] = png_info(img)->palette[i].green; + pdfbuf[pdfptr++] = png_info(img)->palette[i].blue; + } + pdfendstream(); + } + } else { + if (0) { + tex_printf(" PNG copy skipped because: "); + if(fixedimageapplygamma && + (checked_gamma > 1.01 || checked_gamma < 0.99)) + tex_printf("gamma delta=%lf ", checked_gamma); + if (png_ptr(img)->transformations != PNG_TRANSFORM_IDENTITY) + tex_printf("transform=%d",png_ptr(img)->transformations); + if ((png_info(img)->color_type != PNG_COLOR_TYPE_GRAY) && + (png_info(img)->color_type != PNG_COLOR_TYPE_RGB) && + (png_info(img)->color_type != PNG_COLOR_TYPE_PALETTE)) + tex_printf("colortype "); + if (fixedpdfminorversion <= 1) + tex_printf("version=%d ",fixedpdfminorversion); + if (png_info(img)->interlace_type != PNG_INTERLACE_NONE) + tex_printf("interlaced "); + if (png_info(img)->bit_depth > 8) + tex_printf("bitdepth=%d ",png_info(img)->bit_depth); + if (png_get_valid(png_ptr(img), png_info(img), PNG_INFO_tRNS)) + tex_printf("simple transparancy "); + } + switch (png_info(img)->color_type) { + case PNG_COLOR_TYPE_PALETTE: + write_png_palette(img); + break; + case PNG_COLOR_TYPE_GRAY: + write_png_gray(img); + break; + case PNG_COLOR_TYPE_GRAY_ALPHA: + if (fixedpdfminorversion >=4) + write_png_gray_alpha(img); + else + write_png_gray(img); + break; + case PNG_COLOR_TYPE_RGB: + write_png_rgb(img); + break; + case PNG_COLOR_TYPE_RGB_ALPHA: + if (fixedpdfminorversion >=4) + write_png_rgb_alpha(img); + else + write_png_rgb(img); + break; + default: + pdftex_fail("unsupported type of color_type <%i>", png_info(img)->color_type); + } + } + pdfflush(); +} + + diff --git a/Build/source/texk/web2c/pdftexdir/writet1.c b/Build/source/texk/web2c/pdftexdir/writet1.c new file mode 100644 index 00000000000..08704286524 --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/writet1.c @@ -0,0 +1,1780 @@ +/* +Copyright (c) 1996-2005 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/writet1.c#25 $ +*/ + +static const char perforce_id[] = + "$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/writet1.c#25 $"; + +#ifdef pdfTeX /* writet1 used with pdfTeX */ +#include "ptexlib.h" +#define t1_log(s) tex_printf(s) +#define t1_open() \ + open_input(&t1_file, kpse_type1_format, FOPEN_RBIN_MODE) +#define enc_open() \ + open_input(&enc_file, kpse_enc_format, FOPEN_RBIN_MODE) +#define external_enc() (fm_cur->encoding)->glyph_names +#define full_file_name() (char*)nameoffile + 1 +#define get_length1() t1_length1 = t1_offset() - t1_save_offset +#define get_length2() t1_length2 = t1_offset() - t1_save_offset +#define get_length3() t1_length3 = t1_offset() - t1_save_offset +#define is_used_char(c) pdfcharmarked(tex_font, c) +#define t1_putchar fb_putchar +#define t1_offset fb_offset +#define out_eexec_char t1_putchar +#define save_offset() t1_save_offset = t1_offset() +#define end_last_eexec_line() \ + t1_eexec_encrypt = false +#define t1_char(c) c +#define embed_all_glyphs(tex_font) fm_cur->all_glyphs +#define extra_charset() fm_cur->charset +#define update_subset_tag() \ + strncpy(fb_array + t1_fontname_offset, fm_cur->subset_tag, 6) + +integer t1_length1, t1_length2, t1_length3; +static integer t1_save_offset; +static integer t1_fontname_offset; +extern char *fb_array; + +#else /* writet1 used with dvips */ +#include "dvips.h" +#include "ptexmac.h" +#undef fm_extend +#define fm_extend(f) 0 +#undef fm_slant +#define fm_slant(f) 0 +#undef is_reencoded +#define is_reencoded(f) (cur_enc_name != NULL) +#undef is_subsetted +#define is_subsetted(f) true +#undef is_included +#define is_included(f) true +#undef set_cur_file_name +#define set_cur_file_name(s) cur_file_name = s +#define t1_open() \ + ((t1_file = search(headerpath, cur_file_name, FOPEN_RBIN_MODE)) != NULL) +#define enc_open() \ + ((enc_file = search(encpath, cur_file_name, FOPEN_RBIN_MODE)) != NULL) +#define external_enc() ext_glyph_names +#define full_file_name() cur_file_name +#define get_length1() +#define get_length2() +#define get_length3() +#define is_used_char(c) (grid[c] == 1) +#define out_eexec_char t1_outhex +#define save_offset() +#define end_last_eexec_line() \ + hexline_length = HEXLINE_WIDTH; \ + end_hexline(); \ + t1_eexec_encrypt = false +#define t1_log(s) +#define t1_scan_only() +#define t1_include() +#define t1_putchar(c) fputc(c, bitfile) +#define t1_scan_keys() +#define embed_all_glyphs(tex_font) false +#undef pdfmovechars +#ifdef SHIFTLOWCHARS +extern char errbuf[]; +extern Boolean shiftlowchars; +#define pdfmovechars shiftlowchars +#define t1_char(c) T1Char(c) +#else /* SHIFTLOWCHARS */ +#define t1_char(c) c +#define pdfmovechars 0 +#endif /* SHIFTLOWCHARS */ +#define extra_charset() dvips_extra_charset +#define make_subset_tag(a, b) +#define update_subset_tag() + +static char *dvips_extra_charset ; +extern FILE *bitfile ; +extern FILE *search(); +static char *cur_file_name; +static char *cur_enc_name; +static unsigned char *grid; +static char *ext_glyph_names[MAX_CHAR_CODE + 1]; +static char print_buf[PRINTF_BUF_SIZE]; +static int hexline_length; +static char notdef[] = ".notdef"; +static size_t last_ptr_index; +#endif /* pdfTeX */ + +#include <kpathsea/c-vararg.h> +#include <kpathsea/c-proto.h> + +#define t1_getchar() getc(t1_file) +#define t1_ungetchar(c) ungetc(c, t1_file) +#define t1_eof() feof(t1_file) +#define t1_close() xfclose(t1_file, cur_file_name) + +#define enc_getchar() getc(enc_file) +#define enc_eof() feof(enc_file) +#define enc_close() xfclose(enc_file, cur_file_name) + +#define valid_code(c) (c >= 0 && c <= MAX_CHAR_CODE) + +static const char *standard_glyph_names[MAX_CHAR_CODE + 1] = { +notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, +notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, +notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, +notdef, notdef, notdef, notdef, notdef, "space", "exclam", "quotedbl", +"numbersign", "dollar", "percent", "ampersand", "quoteright", "parenleft", +"parenright", "asterisk", "plus", "comma", "hyphen", "period", "slash", +"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", +"nine", "colon", "semicolon", "less", "equal", "greater", "question", "at", +"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", +"P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", +"backslash", "bracketright", "asciicircum", "underscore", "quoteleft", "a", +"b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", +"q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar", +"braceright", "asciitilde", notdef, notdef, notdef, notdef, notdef, notdef, +notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, +notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, +notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, +notdef, "exclamdown", "cent", "sterling", "fraction", "yen", "florin", +"section", "currency", "quotesingle", "quotedblleft", "guillemotleft", +"guilsinglleft", "guilsinglright", "fi", "fl", notdef, "endash", "dagger", +"daggerdbl", "periodcentered", notdef, "paragraph", "bullet", +"quotesinglbase", "quotedblbase", "quotedblright", "guillemotright", +"ellipsis", "perthousand", notdef, "questiondown", notdef, "grave", "acute", +"circumflex", "tilde", "macron", "breve", "dotaccent", "dieresis", notdef, +"ring", "cedilla", notdef, "hungarumlaut", "ogonek", "caron", "emdash", +notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, +notdef, notdef, notdef, notdef, notdef, notdef, notdef, "AE", notdef, +"ordfeminine", notdef, notdef, notdef, notdef, "Lslash", "Oslash", "OE", +"ordmasculine", notdef, notdef, notdef, notdef, notdef, "ae", notdef, notdef, +notdef, "dotlessi", notdef, notdef, "lslash", "oslash", "oe", "germandbls", +notdef, notdef, notdef, notdef +}; + +static char charstringname[] = "/CharStrings"; + +char **t1_glyph_names; +char *t1_builtin_glyph_names[MAX_CHAR_CODE + 1]; +static boolean read_encoding_only; +static int t1_encoding; + +#define T1_BUF_SIZE 0x10 +#define ENC_BUF_SIZE 0x1000 + +#define ENC_STANDARD 0 +#define ENC_BUILTIN 1 + +#define CS_HSTEM 1 +#define CS_VSTEM 3 +#define CS_VMOVETO 4 +#define CS_RLINETO 5 +#define CS_HLINETO 6 +#define CS_VLINETO 7 +#define CS_RRCURVETO 8 +#define CS_CLOSEPATH 9 +#define CS_CALLSUBR 10 +#define CS_RETURN 11 +#define CS_ESCAPE 12 +#define CS_HSBW 13 +#define CS_ENDCHAR 14 +#define CS_RMOVETO 21 +#define CS_HMOVETO 22 +#define CS_VHCURVETO 30 +#define CS_HVCURVETO 31 +#define CS_1BYTE_MAX (CS_HVCURVETO + 1) + +#define CS_DOTSECTION CS_1BYTE_MAX + 0 +#define CS_VSTEM3 CS_1BYTE_MAX + 1 +#define CS_HSTEM3 CS_1BYTE_MAX + 2 +#define CS_SEAC CS_1BYTE_MAX + 6 +#define CS_SBW CS_1BYTE_MAX + 7 +#define CS_DIV CS_1BYTE_MAX + 12 +#define CS_CALLOTHERSUBR CS_1BYTE_MAX + 16 +#define CS_POP CS_1BYTE_MAX + 17 +#define CS_SETCURRENTPOINT CS_1BYTE_MAX + 33 +#define CS_2BYTE_MAX (CS_SETCURRENTPOINT + 1) +#define CS_MAX CS_2BYTE_MAX + +typedef unsigned char byte; + +typedef struct { + byte nargs; /* number of arguments */ + boolean bottom; /* take arguments from bottom of stack? */ + boolean clear; /* clear stack? */ + boolean valid; +} cc_entry; /* CharString Command */ + +typedef struct { + char *name; /* glyph name (or notdef for Subrs entry) */ + byte *data; + unsigned short len; /* length of the whole string */ + unsigned short cslen; /* length of the encoded part of the string */ + boolean used; + boolean valid; +} cs_entry; + +static unsigned short t1_dr, t1_er; +static const unsigned short t1_c1 = 52845, t1_c2 = 22719; +static unsigned short t1_cslen; +static short t1_lenIV; +static char enc_line[ENC_BUF_SIZE]; + +/* define t1_line_ptr, t1_line_array & t1_line_limit */ +typedef char t1_line_entry; +define_array(t1_line); + +/* define t1_buf_ptr, t1_buf_array & t1_buf_limit */ +typedef char t1_buf_entry; +define_array(t1_buf); + +static int cs_start; + +static cs_entry *cs_tab, *cs_ptr, *cs_notdef; +static char *cs_dict_start, *cs_dict_end; +static int cs_count, cs_size, cs_size_pos; + +static cs_entry *subr_tab; +static char *subr_array_start, *subr_array_end; +static int subr_max, subr_size, subr_size_pos; + +/* This list contains the begin/end tokens commonly used in the */ +/* /Subrs array of a Type 1 font. */ +static const char *cs_token_pairs_list[][2] = { + {" RD", "NP"}, + {" -|", "|"}, + {" RD", "noaccess put"}, + {" -|", "noaccess put"}, + {NULL, NULL} +}; +static const char **cs_token_pair; + +static boolean t1_pfa, t1_cs, t1_scan, t1_eexec_encrypt, t1_synthetic; +static int t1_in_eexec; /* 0 before eexec-encrypted, 1 during, 2 after */ +static long t1_block_length; +static int last_hexbyte; +static FILE *t1_file; +static FILE *enc_file; + +#define str_prefix(s1, s2) (strncmp(s1, s2, strlen(s2)) == 0) +#define t1_prefix(s) str_prefix(t1_line_array, s) +#define t1_buf_prefix(s) str_prefix(t1_buf_array, s) +#define t1_suffix(s) str_suffix(t1_line_array, t1_line_ptr, s) +#define t1_buf_suffix(s) str_suffix(t1_buf_array, t1_buf_ptr, s) +#define t1_charstrings() strstr(t1_line_array, charstringname) +#define t1_subrs() t1_prefix("/Subrs") +#define t1_end_eexec() t1_suffix("mark currentfile closefile") +#define t1_cleartomark() t1_prefix("cleartomark") + +#ifndef pdfTeX +static void pdftex_fail(char *fmt,...) +{ + va_list args; + va_start(args, fmt); + fputs("\nError: module writet1", stderr); + if (cur_file_name) + fprintf(stderr, " (file %s)", cur_file_name); + fputs(": ", stderr); + vsprintf(print_buf, fmt, args); + fputs(print_buf, stderr); + fputs("\n ==> Fatal error occurred, the output PS file is not finished!\n", stderr); + va_end(args); + exit(-1); +} + +static void pdftex_warn(char *fmt,...) +{ + va_list args; + va_start(args, fmt); + fputs("\nWarning: module writet1 of dvips", stderr); + if (cur_file_name) + fprintf(stderr, " (file %s)", cur_file_name); + fputs(": ", stderr); + vsprintf(print_buf, fmt, args); + fputs(print_buf, stderr); + fputs("\n", stderr); + va_end(args); +} + +#define HEXLINE_WIDTH 64 + +static void end_hexline() +{ + if (hexline_length == HEXLINE_WIDTH) { + fputs("\n", bitfile); + hexline_length = 0; + } +} + +static void t1_outhex(byte b) +{ + static char *hexdigits = "0123456789ABCDEF"; + t1_putchar(hexdigits[b/16]); + t1_putchar(hexdigits[b%16]); + hexline_length += 2; + end_hexline(); +} +#endif /* pdfTeX */ + + +static void enc_getline(void) +{ + char *p; + int c; +restart: + if (enc_eof()) + pdftex_fail("unexpected end of file"); + p = enc_line; + do { + c = enc_getchar(); + append_char_to_buf(c, p, enc_line, ENC_BUF_SIZE); + } while (c != 10); + append_eol(p, enc_line, ENC_BUF_SIZE); + if (p - enc_line < 2 || *enc_line == '%') + goto restart; +} + +void load_enc(char *enc_name, char **glyph_names) +{ + char buf[ENC_BUF_SIZE], *p, *r; + int names_count; + set_cur_file_name(enc_name); + if (!enc_open()) { + pdftex_warn("cannot open encoding file for reading"); + cur_file_name = NULL; + return; + } + t1_log("{"); + t1_log(cur_file_name = full_file_name()); + enc_getline(); + if (*enc_line != '/' || (r = strchr(enc_line, '[')) == NULL) { + remove_eol(r, enc_line); + pdftex_fail("invalid encoding vector (a name or `[' missing): `%s'", enc_line); + } + names_count = 0; + r++; /* skip '[' */ + skip(r, ' '); + for (;;) { + while (*r == '/') { + for (p = buf, r++; *r != ' ' && *r != 10 && *r != ']' && *r != '/'; *p++ = *r++); + *p = 0; + skip(r, ' '); + if (names_count > MAX_CHAR_CODE) + pdftex_fail("encoding vector contains more than %i names", + (int)(MAX_CHAR_CODE + 1)); + if (strcmp(buf, notdef) != 0) + glyph_names[names_count] = xstrdup(buf); + names_count++; + } + if (*r != 10 && *r != '%') { + if (strncmp(r, "] def", strlen("] def")) == 0) + goto done; + else { + remove_eol(r, enc_line); + pdftex_fail("invalid encoding vector: a name or `] def' expected: `%s'", enc_line); + } + } + enc_getline(); + r = enc_line; + } +done: + enc_close(); + t1_log("}"); + cur_file_name = NULL; +} + +static void t1_check_pfa(void) +{ + int c = t1_getchar(); + if (c != 128) + t1_pfa = true; + else + t1_pfa = false; + t1_ungetchar(c); +} + +static int t1_getbyte(void) +{ + int c = t1_getchar(); + if (t1_pfa) + return c; + if (t1_block_length == 0) { + if (c != 128) + pdftex_fail("invalid marker"); + c = t1_getchar(); + if (c == 3) { + while (!t1_eof()) + t1_getchar(); + return EOF; + } + t1_block_length = t1_getchar() & 0xff; + t1_block_length |= (t1_getchar() & 0xff) << 8; + t1_block_length |= (t1_getchar() & 0xff) << 16; + t1_block_length |= (t1_getchar() & 0xff) << 24; + c = t1_getchar(); + } + t1_block_length--; + return c; +} + +static int hexval(int c) +{ + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + else if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + else if (c >= '0' && c <= '9') + return c - '0'; + else + return -1; +} + +static byte edecrypt(byte cipher) +{ + byte plain; + if (t1_pfa) { + while (cipher == 10 || cipher == 13) + cipher = t1_getbyte(); + last_hexbyte = cipher = (hexval(cipher) << 4) + hexval(t1_getbyte()); + } + plain = (cipher^(t1_dr >> 8)); + t1_dr = (cipher + t1_dr)*t1_c1 + t1_c2; + return plain; +} + +static byte cdecrypt(byte cipher, unsigned short *cr) +{ + byte plain = (cipher^(*cr >> 8)); + *cr = (cipher + *cr)*t1_c1 + t1_c2; + return plain; +} + +static byte eencrypt(byte plain) +{ + byte cipher = (plain^(t1_er >> 8)); + t1_er = (cipher + t1_er)*t1_c1 + t1_c2; + return cipher; +} + +static byte cencrypt(byte plain, unsigned short *cr) +{ + byte cipher = (plain^(*cr >> 8)); + *cr = (cipher + *cr)*t1_c1 + t1_c2; + return cipher; +} + +static char *eol(char *s) +{ + char *p = strend(s); + if (p - s > 1 && p[-1] != 10) { + *p++ = 10; + *p = 0; + } + return p; +} + +static float t1_scan_num(char *p, char **r) +{ + float f; + skip(p, ' '); + if (sscanf(p, "%g", &f) != 1) { + remove_eol(p, t1_line_array); + pdftex_fail("a number expected: `%s'", t1_line_array); + } + if (r != NULL) { + for (; isdigit(*p) || *p == '.' || + *p == 'e' || *p == 'E' || *p == '+' || *p == '-'; p++); + *r = p; + } + return f; +} + +static boolean str_suffix(const char *begin_buf, const char *end_buf, + const char *s) +{ + const char *s1 = end_buf - 1, + *s2 = strend(s) - 1; + if (*s1 == 10) + s1--; + while (s1 >= begin_buf && s2 >= s) { + if (*s1-- != *s2--) + return false; + } + return s2 < s; +} + +static void t1_getline(void) +{ + int c, l, eexec_scan; + char *p; + static const char eexec_str[] = "currentfile eexec"; + static int eexec_len = 17; /* strlen(eexec_str) */ +restart: + if (t1_eof()) + pdftex_fail("unexpected end of file"); + t1_line_ptr = t1_line_array; + alloc_array(t1_line, 1, T1_BUF_SIZE); + t1_cslen = 0; + eexec_scan = 0; + c = t1_getbyte(); + if (c == EOF) + goto exit; + while (!t1_eof()) { + if (t1_in_eexec == 1) + c = edecrypt(c); + alloc_array(t1_line, 1, T1_BUF_SIZE); + append_char_to_buf(c, t1_line_ptr, t1_line_array, t1_line_limit); + if (t1_in_eexec == 0 && eexec_scan >= 0 && eexec_scan < eexec_len) { + if (t1_line_array[eexec_scan] == eexec_str[eexec_scan]) + eexec_scan++; + else + eexec_scan = -1; + } + if (c == 10 || (t1_pfa && eexec_scan == eexec_len && c == 32)) + break; + if (t1_cs && t1_cslen == 0 && (t1_line_ptr - t1_line_array > 4) && + (t1_suffix(" RD ") || t1_suffix(" -| "))) { + p = t1_line_ptr - 5; + while (*p != ' ') + p--; + t1_cslen = l = t1_scan_num(p + 1, 0); + cs_start = t1_line_ptr - t1_line_array; /* cs_start is an index now */ + alloc_array(t1_line, l, T1_BUF_SIZE); + while (l-- > 0) + *t1_line_ptr++ = edecrypt(t1_getbyte()); + } + c = t1_getbyte(); + } + alloc_array(t1_line, 2, T1_BUF_SIZE); /* append_eol can append 2 chars */ + append_eol(t1_line_ptr, t1_line_array, t1_line_limit); + if (t1_line_ptr - t1_line_array < 2) + goto restart; + if (eexec_scan == eexec_len) + t1_in_eexec = 1; +exit: + /* ensure that t1_buf_array has as much room as t1_line_array */ + t1_buf_ptr = t1_buf_array; + alloc_array(t1_buf, t1_line_limit, t1_line_limit); +} + +static void t1_putline(void) +{ + char *p = t1_line_array; + if (t1_line_ptr - t1_line_array <= 1) + return; + if (t1_eexec_encrypt) { + while (p < t1_line_ptr) + out_eexec_char(eencrypt(*p++)); + } + else + while (p < t1_line_ptr) + t1_putchar(*p++); +} + +static void t1_puts(const char *s) +{ + if (s != t1_line_array) + strcpy(t1_line_array, s); + t1_line_ptr = strend(t1_line_array); + t1_putline(); +} + +static void t1_printf(const char *fmt,...) +{ + va_list args; + va_start(args, fmt); + vsprintf(t1_line_array, fmt, args); + t1_puts(t1_line_array); + va_end(args); +} + +static void t1_init_params(const char *open_name_prefix) +{ + t1_log(open_name_prefix); + t1_log(cur_file_name); + t1_lenIV = 4; + t1_dr = 55665; + t1_er = 55665; + t1_in_eexec = 0; + t1_cs = false; + t1_scan = true; + t1_synthetic = false; + t1_eexec_encrypt = false; + t1_block_length = 0; + t1_check_pfa(); +} + +static void t1_close_font_file(const char *close_name_suffix) +{ + t1_log(close_name_suffix); + t1_close(); + cur_file_name = NULL; +} + +static void t1_check_block_len(boolean decrypt) +{ + int l, c; + if (t1_block_length == 0) + return; + c = t1_getbyte(); + if (decrypt) + c = edecrypt(c); + l = t1_block_length; + if (!(l == 0 && (c == 10 || c == 13))) { + pdftex_warn("%i bytes more than expected were ignored", l + 1); + while (l-- > 0) + t1_getbyte(); + } +} + +static void t1_start_eexec(void) +{ + int i; + if (is_included(fm_cur)) { + get_length1(); + save_offset(); + } + if (!t1_pfa) + t1_check_block_len(false); + for (t1_line_ptr = t1_line_array, i = 0; i < 4; i++) { + edecrypt(t1_getbyte()); + *t1_line_ptr++ = 0; + } + t1_eexec_encrypt = true; + if (is_included(fm_cur)) + t1_putline(); /* to put the first four bytes */ +} + +static void t1_stop_eexec(void) +{ + int c; + if (is_included(fm_cur)) { + get_length2(); + save_offset(); + } + end_last_eexec_line(); + if (!t1_pfa) + t1_check_block_len(true); + else { + c = edecrypt(t1_getbyte()); + if (!(c == 10 || c == 13)) { + if (last_hexbyte == 0) + t1_puts("00"); + else + pdftex_warn("unexpected data after eexec"); + } + } + t1_cs = false; + t1_in_eexec = 2; +} + +#ifdef pdfTeX +static void t1_modify_fm(void) +{ + /* + * font matrix is given as six numbers a0..a5, which stands for the matrix + * + * a0 a1 0 + * M = a2 a3 0 + * a4 a5 1 + * + * ExtendFont is given as + * + * e 0 0 + * E = 0 1 0 + * 0 0 1 + * + * SlantFont is given as + * + * 1 0 0 + * S = s 1 0 + * 0 0 1 + * + * and the final transformation is + * + * e*a0 e*a1 0 + * F = E.S.M = s*e*a0+a2 s*e*a1+a3 0 + * a4 a5 1 + */ + float e, s, a[6], b[6]; + int i, c; + char *p, *q, *r; + if ((p = strchr(t1_line_array, '[')) == 0) + if ((p = strchr(t1_line_array, '{')) == 0) { + remove_eol(p, t1_line_array); + pdftex_fail("FontMatrix: an array expected: `%s'", t1_line_array); + } + c = *p++; /* save the character '[' resp. '{' */ + strncpy(t1_buf_array, t1_line_array, (unsigned)(p - t1_line_array)); + r = t1_buf_array + (p - t1_line_array); + for (i = 0; i < 6; i++) { + a[i] = t1_scan_num(p, &q); + p = q; + } + if (fm_extend(fm_cur) != 0) + e = fm_extend(fm_cur)*1E-3; + else + e = 1; + s = fm_slant(fm_cur)*1E-3; + b[0] = e*a[0]; + b[1] = e*a[1]; + b[2] = s*e*a[0] + a[2]; + b[3] = s*e*a[1] + a[3]; + b[4] = a[4]; + b[5] = a[5]; + for (i = 0; i < 6; i++) { + sprintf(r, "%g ", b[i]); + r = strend(r); + } + if (c == '[') { + while (*p != ']' && *p != 0) + p++; + } + else { + while (*p != '}' && *p != 0) + p++; + } + if (*p == 0) { + remove_eol(p, t1_line_array); + pdftex_fail("FontMatrix: cannot find the corresponding character to '%c': `%s'", c, t1_line_array); + } + strcpy(r, p); + strcpy(t1_line_array, t1_buf_array); + t1_line_ptr = eol(t1_line_array); +} + +static void t1_modify_italic(void) +{ + float a; + char *p, *r; + if (fm_slant(fm_cur) == 0) + return; + p = strchr(t1_line_array, ' '); + strncpy(t1_buf_array, t1_line_array, (unsigned)(p - t1_line_array + 1)); + a = t1_scan_num(p + 1, &r); + a -= atan(fm_slant(fm_cur)*1E-3)*(180/M_PI); + sprintf(t1_buf_array + (p - t1_line_array + 1), "%g", a); + strcpy(strend(t1_buf_array), r); + strcpy(t1_line_array, t1_buf_array); + t1_line_ptr = eol(t1_line_array); + font_keys[ITALIC_ANGLE_CODE].value = round(a); + font_keys[ITALIC_ANGLE_CODE].valid = true; +} + +static void t1_scan_keys(void) +{ + int i, k; + char *p, *q, *r; + key_entry *key; + if (fm_extend(fm_cur) != 0 || fm_slant(fm_cur) != 0) { + if (t1_prefix("/FontMatrix")) { + t1_modify_fm(); + return; + } + if (t1_prefix("/ItalicAngle")) { + t1_modify_italic(); + return; + } + } + if (t1_prefix("/FontType")) { + p = t1_line_array + strlen("FontType") + 1; + if ((i = t1_scan_num(p, 0)) != 1) + pdftex_fail("Type%d fonts unsupported by pdfTeX", i); + return; + } + for (key = font_keys; key - font_keys < MAX_KEY_CODE; key++) + if (strncmp(t1_line_array + 1, key->t1name, strlen(key->t1name)) == 0) + break; + if (key - font_keys == MAX_KEY_CODE) + return; + key->valid = true; + p = t1_line_array + strlen(key->t1name) + 1; + skip(p, ' '); + if ((k = key - font_keys) == FONTNAME_CODE) { + if (*p != '/') { + remove_eol(p, t1_line_array); + pdftex_fail("a name expected: `%s'", t1_line_array); + } + r = ++p; /* skip the slash */ + for (q = t1_buf_array; *p != ' ' && *p != 10; *q++ = *p++); + *q = 0; + if (fm_slant(fm_cur) != 0) { + sprintf(q, "-Slant_%i", (int)fm_slant(fm_cur)); + q = strend(q); + } + if (fm_extend(fm_cur) != 0) { + sprintf(q, "-Extend_%i", (int)fm_extend(fm_cur)); + } + strncpy(fontname_buf, t1_buf_array, FONTNAME_BUF_SIZE); + /* at this moment we cannot call make_subset_tag() yet, as the encoding + * is not read; thus we mark the offset of the subset tag and write it + * later */ + if (is_included(fm_cur) && is_subsetted(fm_cur)) { + t1_fontname_offset = t1_offset() + (r - t1_line_array); + strcpy(t1_buf_array, p); + sprintf(r, "ABCDEF+%s%s", fontname_buf, t1_buf_array); + t1_line_ptr = eol(r); + } + return; + } + if ((k == STEMV_CODE || k == FONTBBOX1_CODE) && + (*p == '[' || *p == '{')) + p++; + if (k == FONTBBOX1_CODE) { + for (i = 0; i < 4; i++) { + key[i].value = t1_scan_num(p, &r); + p = r; + } + return; + } + key->value = t1_scan_num(p, 0); +} + +#endif /* pdfTeX */ + +static void t1_scan_param(void) +{ + static const char *lenIV = "/lenIV"; + if (!t1_scan || *t1_line_array != '/') + return; + if (t1_prefix(lenIV)) { + t1_lenIV = t1_scan_num(t1_line_array + strlen(lenIV), 0); + return; + } + t1_scan_keys(); +} + +static void copy_glyph_names(char **glyph_names, int a, int b) +{ + if (glyph_names[b] != notdef) { + free(glyph_names[b]); + glyph_names[b] = (char*) notdef; + } + if (glyph_names[a] != notdef) { + glyph_names[b] = xstrdup(glyph_names[a]); + } +} + +static void t1_builtin_enc(void) +{ + int i, a, b, c, counter = 0; + char *r, *p; + /* + * At this moment "/Encoding" is the prefix of t1_line_array + */ + if (t1_suffix("def")) { /* predefined encoding */ + sscanf(t1_line_array + strlen("/Encoding"), "%256s", t1_buf_array); + if (strcmp(t1_buf_array, "StandardEncoding") == 0) { + for (i = 0; i <= MAX_CHAR_CODE; i++) + if (standard_glyph_names[i] == notdef) + t1_builtin_glyph_names[i] = (char*) notdef; + else + t1_builtin_glyph_names[i] = xstrdup(standard_glyph_names[i]); + t1_encoding = ENC_STANDARD; + } + else + pdftex_fail("cannot subset font (unknown predefined encoding `%s')", + t1_buf_array); + return; + } else + t1_encoding = ENC_BUILTIN; + /* + * At this moment "/Encoding" is the prefix of t1_line_array, and the encoding is + * not a predefined encoding + * + * We have two possible forms of Encoding vector. The first case is + * + * /Encoding [/a /b /c...] readonly def + * + * and the second case can look like + * + * /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for + * dup 0 /x put + * dup 1 /y put + * ... + * readonly def + */ + for (i = 0; i <= MAX_CHAR_CODE; i++) + t1_builtin_glyph_names[i] = (char*) notdef; + if (t1_prefix("/Encoding [") || t1_prefix("/Encoding[")) { /* the first case */ + r = strchr(t1_line_array, '[') + 1; + skip(r, ' '); + for(;;) { + while (*r == '/') { + for (p = t1_buf_array, r++; + *r != 32 && *r != 10 && *r != ']' && *r != '/'; + *p++ = *r++); + *p = 0; + skip(r, ' '); + if (counter > MAX_CHAR_CODE) + pdftex_fail("encoding vector contains more than %i names", + (int)(MAX_CHAR_CODE + 1)); + if (strcmp(t1_buf_array, notdef) != 0) + t1_builtin_glyph_names[counter] = xstrdup(t1_buf_array); + counter++; + } + if (*r != 10 && *r != '%') { + if (str_prefix(r, "] def") || str_prefix(r, "] readonly def")) + break; + else { + remove_eol(r, t1_line_array); + pdftex_fail("a name or `] def' or `] readonly def' expected: `%s'", + t1_line_array); + } + } + t1_getline(); + r = t1_line_array; + } + } + else { /* the second case */ + p = strchr(t1_line_array, 10); + for (;;) { + if (*p == 10) { + t1_getline(); + p = t1_line_array; + } + /* + check for `dup <index> <glyph> put' + */ + if (sscanf(p, "dup %i%256s put", &i, t1_buf_array) == 2 && + *t1_buf_array == '/' && valid_code(i)) { + if (strcmp(t1_buf_array + 1, notdef) != 0) + t1_builtin_glyph_names[i] = xstrdup(t1_buf_array + 1); + p = strstr(p, " put") + strlen(" put"); + skip(p, ' '); + } + /* + check for `dup dup <to> exch <from> get put' + */ + else if (sscanf(p, "dup dup %i exch %i get put", &b, &a) == 2 && + valid_code(a) && valid_code(b)) { + copy_glyph_names(t1_builtin_glyph_names, a, b); + p = strstr(p, " get put") + strlen(" get put"); + skip(p, ' '); + } + /* + check for `dup dup <from> <size> getinterval <to> exch putinterval' + */ + else if (sscanf(p, "dup dup %i %i getinterval %i exch putinterval", + &a, &c, &b) == 3 && + valid_code(a) && valid_code(b) && valid_code(c)) { + for (i = 0; i < c; i++) + copy_glyph_names(t1_builtin_glyph_names, a + i, b + i); + p = strstr(p, " putinterval") + strlen(" putinterval"); + skip(p, ' '); + } + /* + check for `def' or `readonly def' + */ + else if ((p == t1_line_array || (p > t1_line_array && p[-1] == ' ')) && + strcmp(p, "def\n") == 0) + return; + /* + skip an unrecognizable word + */ + else { + while (*p != ' ' && *p != 10) + p++; + skip(p, ' '); + } + } + } +} + +static void t1_check_end(void) +{ + if (t1_eof()) + return; + t1_getline(); + if (t1_prefix("{restore}")) + t1_putline(); +} + +#ifdef pdfTeX +static boolean t1_open_fontfile(const char *open_name_prefix) +{ + char *ex_ffname = NULL; + ff_entry *ff; + ff = check_ff_exist(fm_cur); + if (ff->ff_path != NULL) + t1_file = xfopen(cur_file_name = ff->ff_path, FOPEN_RBIN_MODE); + else { + set_cur_file_name(fm_cur->ff_name); + pdftex_warn("cannot open Type 1 font file for reading"); + return false; + } + t1_init_params(open_name_prefix); + fontfile_found = true; + return true; +} + +static void t1_scan_only(void) +{ + do { + t1_getline(); + t1_scan_param(); + } while (t1_in_eexec == 0); + t1_start_eexec(); + do { + t1_getline(); + t1_scan_param(); + } while (!(t1_charstrings() || t1_subrs())); +} + +static void t1_include(void) +{ + do { + t1_getline(); + t1_scan_param(); + t1_putline(); + } while (t1_in_eexec == 0); + t1_start_eexec(); + do { + t1_getline(); + t1_scan_param(); + t1_putline(); + } while (!(t1_charstrings() || t1_subrs())); + t1_cs = true; + do { + t1_getline(); + t1_putline(); + } while (!t1_end_eexec()); + t1_stop_eexec(); + do { + t1_getline(); + t1_putline(); + } while (!t1_cleartomark()); + t1_check_end(); /* write "{restore}if" if found */ + get_length3(); +} + +#else /* not pdfTeX */ +static boolean t1_open_fontfile(char *open_name_prefix) +{ + if (!t1_open()) { + (void)sprintf(errbuf, "! Couldn't find font file %s", cur_file_name); + error(errbuf); + } + t1_init_params(open_name_prefix); + return true; +} +#endif /* pdfTeX */ + +#define check_subr(subr) \ + if (subr >= subr_size || subr < 0) \ + pdftex_fail("Subrs array: entry index out of range (%i)", subr); + +static const char **check_cs_token_pair() +{ + const char **p = (const char**) cs_token_pairs_list; + for (; p[0] != NULL; ++p) + if (t1_buf_prefix(p[0]) && t1_buf_suffix(p[1])) + return p; + return NULL; +} + +static void cs_store(boolean is_subr) +{ + char *p; + cs_entry *ptr; + int subr; + for (p = t1_line_array, t1_buf_ptr = t1_buf_array; *p != ' '; *t1_buf_ptr++ = *p++); + *t1_buf_ptr = 0; + if (is_subr) { + subr = t1_scan_num(p + 1, 0); + check_subr(subr); + ptr = subr_tab + subr; + } + else { + ptr = cs_ptr++; + if (cs_ptr - cs_tab > cs_size) + pdftex_fail("CharStrings dict: more entries than dict size (%i)", cs_size); + if (strcmp(t1_buf_array + 1, notdef) == 0) /* skip the slash */ + ptr->name = (char*) notdef; + else + ptr->name = xstrdup(t1_buf_array + 1); + } + /* copy " RD " + cs data to t1_buf_array */ + memcpy(t1_buf_array, t1_line_array + cs_start - 4, (unsigned)(t1_cslen + 4)); + /* copy the end of cs data to t1_buf_array */ + for (p = t1_line_array + cs_start + t1_cslen, t1_buf_ptr = t1_buf_array + t1_cslen + 4; + *p != 10; *t1_buf_ptr++ = *p++); + *t1_buf_ptr++ = 10; + if (is_subr && cs_token_pair == NULL) + cs_token_pair = check_cs_token_pair(); + ptr->len = t1_buf_ptr - t1_buf_array; + ptr->cslen = t1_cslen; + ptr->data = xtalloc(ptr->len, byte); + memcpy(ptr->data, t1_buf_array, ptr->len); + ptr->valid = true; +} + +#define store_subr() cs_store(true) +#define store_cs() cs_store(false) + +#define CC_STACK_SIZE 24 + +static integer cc_stack[CC_STACK_SIZE], *stack_ptr = cc_stack; +static cc_entry cc_tab[CS_MAX]; +static boolean is_cc_init = false; + + +#define cc_pop(N) \ + if (stack_ptr - cc_stack < (N)) \ + stack_error(N); \ + stack_ptr -= N + +#define stack_error(N) { \ + pdftex_warn("CharString: invalid access (%i) to stack (%i entries)", \ + N, stack_ptr - cc_stack); \ + goto cs_error; \ +} + +/* +static integer cc_get(integer index) +{ + if (index < 0) { + if (stack_ptr + index < cc_stack ) + stack_error(stack_ptr - cc_stack + index); + return *(stack_ptr + index); + } + else { + if (cc_stack + index >= stack_ptr) + stack_error(index); + return cc_stack[index]; + } +} +*/ + +#define cc_get(N) ((N) < 0 ? *(stack_ptr + (N)) : *(cc_stack + (N))) + +#define cc_push(V) *stack_ptr++ = V +#define cc_clear() stack_ptr = cc_stack + +#define set_cc(N, B, A, C) \ + cc_tab[N].nargs = A; \ + cc_tab[N].bottom = B; \ + cc_tab[N].clear = C; \ + cc_tab[N].valid = true + +static void cc_init(void) +{ + int i; + if (is_cc_init) + return; + for (i = 0; i < CS_MAX; i++) + cc_tab[i].valid = false; + set_cc(CS_HSTEM, true, 2, true); + set_cc(CS_VSTEM, true, 2, true); + set_cc(CS_VMOVETO, true, 1, true); + set_cc(CS_RLINETO, true, 2, true); + set_cc(CS_HLINETO, true, 1, true); + set_cc(CS_VLINETO, true, 1, true); + set_cc(CS_RRCURVETO, true, 6, true); + set_cc(CS_CLOSEPATH, false, 0, true); + set_cc(CS_CALLSUBR, false, 1, false); + set_cc(CS_RETURN, false, 0, false); + /* + set_cc(CS_ESCAPE, false, 0, false); + */ + set_cc(CS_HSBW, true, 2, true); + set_cc(CS_ENDCHAR, false, 0, true); + set_cc(CS_RMOVETO, true, 2, true); + set_cc(CS_HMOVETO, true, 1, true); + set_cc(CS_VHCURVETO, true, 4, true); + set_cc(CS_HVCURVETO, true, 4, true); + set_cc(CS_DOTSECTION, false, 0, true); + set_cc(CS_VSTEM3, true, 6, true); + set_cc(CS_HSTEM3, true, 6, true); + set_cc(CS_SEAC, true, 5, true); + set_cc(CS_SBW, true, 4, true); + set_cc(CS_DIV, false, 2, false); + set_cc(CS_CALLOTHERSUBR, false, 0, false); + set_cc(CS_POP, false, 0, false); + set_cc(CS_SETCURRENTPOINT, true, 2, true); + is_cc_init = true; +} + +#define cs_getchar() cdecrypt(*data++, &cr) + +#define mark_subr(n) cs_mark(0, n) +#define mark_cs(s) cs_mark(s, 0) + +static void cs_warn(const char *cs_name, int subr, const char *fmt,...) +{ + char buf[SMALL_BUF_SIZE]; + va_list args; + va_start(args, fmt); + vsprintf(buf, fmt, args); + va_end(args); + if (cs_name == NULL) + pdftex_warn("Subr (%i): %s", (int)subr, buf); + else + pdftex_warn("CharString (/%s): %s", cs_name, buf); +} + +static void cs_mark(const char *cs_name, int subr) +{ + byte *data; + int i, b, cs_len; + integer a, a1, a2; + unsigned short cr; + static integer lastargOtherSubr3 = 3; /* the argument of last call to + OtherSubrs[3] */ + cs_entry *ptr; + cc_entry *cc; + if (cs_name == NULL) { + check_subr(subr); + ptr = subr_tab + subr; + if (!ptr->valid) + return; + } + else { + if (cs_notdef != NULL && + (cs_name == notdef || strcmp(cs_name, notdef) == 0)) + ptr = cs_notdef; + else { + for (ptr = cs_tab; ptr < cs_ptr; ptr++) + if (strcmp(ptr->name, cs_name) == 0) + break; + if (ptr == cs_ptr) { + pdftex_warn("glyph `%s' undefined", cs_name); + return; + } + if (ptr->name == notdef) + cs_notdef = ptr; + } + } + /* only marked CharString entries and invalid entries can be skipped; + valid marked subrs must be parsed to keep the stack in sync */ + if (!ptr->valid || (ptr->used && cs_name != NULL)) + return; + ptr->used = true; + cr = 4330; + cs_len = ptr->cslen; + data = ptr->data + 4; + for (i = 0; i < t1_lenIV; i++, cs_len--) + cs_getchar(); + while (cs_len > 0) { + --cs_len; + b = cs_getchar(); + if (b >= 32) { + if (b <= 246) + a = b - 139; + else if (b <= 250) { + --cs_len; + a = ((b - 247) << 8) + 108 + cs_getchar(); + } + else if (b <= 254) { + --cs_len; + a = -((b - 251) << 8) - 108 - cs_getchar(); + } + else { + cs_len -= 4; + a = (cs_getchar() & 0xff) << 24; + a |= (cs_getchar() & 0xff) << 16; + a |= (cs_getchar() & 0xff) << 8; + a |= (cs_getchar() & 0xff) << 0; + if (sizeof(integer) > 4 && (a & 0x80000000)) + a |= ~0x7FFFFFFF; + } + cc_push(a); + } + else { + if (b == CS_ESCAPE) { + b = cs_getchar() + CS_1BYTE_MAX; + cs_len--; + } + if (b >= CS_MAX) { + cs_warn(cs_name, subr, "command value out of range: %i", (int)b); + goto cs_error; + } + cc = cc_tab + b; + if (!cc->valid) { + cs_warn(cs_name, subr, "command not valid: %i", (int)b); + goto cs_error; + } + if (cc->bottom) { + if (stack_ptr - cc_stack < cc->nargs) + cs_warn(cs_name, subr, + "less arguments on stack (%i) than required (%i)", + (int)(stack_ptr - cc_stack), (int)cc->nargs); + else if (stack_ptr - cc_stack > cc->nargs) + cs_warn(cs_name, subr, + "more arguments on stack (%i) than required (%i)", + (int)(stack_ptr - cc_stack), (int)cc->nargs); + } + switch (cc - cc_tab) { + case CS_CALLSUBR: + a1 = cc_get(-1); + cc_pop(1); + mark_subr(a1); + if (!subr_tab[a1].valid) { + cs_warn(cs_name, subr, + "cannot call subr (%i)", (int)a1); + goto cs_error; + } + break; + case CS_DIV: + cc_pop(2); + cc_push(0); + break; + case CS_CALLOTHERSUBR: + if (cc_get(-1) == 3) + lastargOtherSubr3 = cc_get(-3); + a1 = cc_get(-2) + 2; + cc_pop(a1); + break; + case CS_POP: + cc_push(lastargOtherSubr3); + /* the only case when we care about the value being pushed onto + stack is when POP follows CALLOTHERSUBR (changing hints by + OtherSubrs[3]) + */ + break; + case CS_SEAC: + a1 = cc_get(3); + a2 = cc_get(4); + cc_clear(); + mark_cs(standard_glyph_names[a1]); + mark_cs(standard_glyph_names[a2]); + break; + default: + if (cc->clear) + cc_clear(); + } + } + } + return; +cs_error: /* an error occured during parsing */ + cc_clear(); + ptr->valid = false; + ptr->used = false; +} + +static void t1_subset_ascii_part(void) +{ + int i, j; + t1_getline(); + while (!t1_prefix("/Encoding")) { + t1_scan_param(); + t1_putline(); + t1_getline(); + } + t1_builtin_enc(); + if (is_reencoded(fm_cur)) + t1_glyph_names = external_enc(); + else + t1_glyph_names = t1_builtin_glyph_names; + if (is_included(fm_cur) && is_subsetted(fm_cur)) { + make_subset_tag(fm_cur, t1_glyph_names); + update_subset_tag(); + } + if (t1_encoding == ENC_STANDARD) + t1_puts("/Encoding StandardEncoding def\n"); + else { + t1_puts("/Encoding 256 array\n0 1 255 {1 index exch /.notdef put} for\n"); + for (i = 0, j = 0; i <= MAX_CHAR_CODE; i++) { + if (is_used_char(i) && t1_glyph_names[i] != notdef) { + j++; + t1_printf("dup %i /%s put\n", (int)t1_char(i), t1_glyph_names[i]); + } + } + /* We didn't mark anything for the Encoding array. */ + /* We add "dup 0 /.notdef put" for compatibility */ + /* with Acrobat 5.0. */ + if (j == 0) + t1_puts("dup 0 /.notdef put\n"); + t1_puts("readonly def\n"); + } + do { + t1_getline(); + t1_scan_param(); + if (!t1_prefix("/UniqueID")) /* ignore UniqueID for subsetted fonts */ + t1_putline(); + } while (t1_in_eexec == 0); +} + +#define t1_subr_flush() t1_flush_cs(true) +#define t1_cs_flush() t1_flush_cs(false) + +static void t1_flush_cs(boolean); + +static void cs_init(void) +{ + cs_ptr = cs_tab = NULL; + cs_dict_start = cs_dict_end = NULL; + cs_count = cs_size = cs_size_pos = 0; + cs_token_pair = NULL; + subr_tab = NULL; + subr_array_start = subr_array_end = NULL; + subr_max = subr_size = subr_size_pos = 0; +} + +static void init_cs_entry(cs_entry *cs) +{ + cs->data = NULL; + cs->name = NULL; + cs->len = 0; + cs->cslen = 0; + cs->used = false; + cs->valid = false; +} + +static void t1_mark_glyphs(void); + +static void t1_read_subrs(void) +{ + int i, s; + cs_entry *ptr; + t1_getline(); + while (!(t1_charstrings() || t1_subrs())) { + t1_scan_param(); + t1_putline(); + t1_getline(); + } +found: + t1_cs = true; + t1_scan = false; + if (!t1_subrs()) + return; + subr_size_pos = strlen("/Subrs") + 1; + /* subr_size_pos points to the number indicating dict size after "/Subrs" */ + subr_size = t1_scan_num(t1_line_array + subr_size_pos, 0); + if (subr_size == 0) { + while (!t1_charstrings()) + t1_getline(); + return; + } + subr_tab = xtalloc(subr_size, cs_entry); + for (ptr = subr_tab; ptr - subr_tab < subr_size; ptr++) + init_cs_entry(ptr); + subr_array_start = xstrdup(t1_line_array); + t1_getline(); + while (t1_cslen) { + store_subr(); + t1_getline(); + } + /* mark the first four entries without parsing */ + for (i = 0; i < subr_size && i < 4; i++) + subr_tab[i].used = true; + /* the end of the Subrs array might have more than one line so we need to + concatnate them to subr_array_end. Unfortunately some fonts don't have + the Subrs array followed by the CharStrings dict immediately (synthetic + fonts). If we cannot find CharStrings in next POST_SUBRS_SCAN lines then + we will treat the font as synthetic and ignore everything until next + Subrs is found + */ +#define POST_SUBRS_SCAN 5 + s = 0; + *t1_buf_array = 0; + for (i = 0; i < POST_SUBRS_SCAN; i++) { + if (t1_charstrings()) + break; + s += t1_line_ptr - t1_line_array; + alloc_array(t1_buf, s, T1_BUF_SIZE); + strcat(t1_buf_array, t1_line_array); + t1_getline(); + } + subr_array_end = xstrdup(t1_buf_array); + if (i == POST_SUBRS_SCAN) { /* CharStrings not found; + suppose synthetic font */ + for (ptr = subr_tab; ptr - subr_tab < subr_size; ptr++) + if (ptr->valid) + xfree(ptr->data); + xfree(subr_tab); + xfree(subr_array_start); + xfree(subr_array_end); + cs_init(); + t1_cs = false; + t1_synthetic = true; + while (!(t1_charstrings() || t1_subrs())) + t1_getline(); + goto found; + } +} + +static void t1_flush_cs(boolean is_subr) +{ + char *p; + byte *r, *return_cs = NULL; + cs_entry *tab, *end_tab, *ptr; + char *start_line, *line_end; + int count, size_pos; + unsigned short cr, cs_len; + if (is_subr) { + start_line = subr_array_start; + line_end = subr_array_end; + size_pos = subr_size_pos; + tab = subr_tab; + count = subr_max + 1; + end_tab = subr_tab + count; + } + else { + start_line = cs_dict_start; + line_end = cs_dict_end; + size_pos = cs_size_pos; + tab = cs_tab; + end_tab = cs_ptr; + count = cs_count; + } + t1_line_ptr = t1_line_array; + for (p = start_line; p - start_line < size_pos;) + *t1_line_ptr++ = *p++; + while (isdigit(*p)) + p++; + sprintf(t1_line_ptr, "%u", count); + strcat(t1_line_ptr, p); + t1_line_ptr = eol(t1_line_array); + t1_putline(); + + /* create return_cs to replace unsused subr's */ + if (is_subr) { + cr = 4330; + cs_len = 0; + return_cs = xtalloc(t1_lenIV + 1, byte); + if (t1_lenIV > 0) { + for (cs_len = 0, r = return_cs; cs_len < t1_lenIV; cs_len++, r++) + *r = cencrypt(0x00, &cr); + *r = cencrypt(CS_RETURN, &cr); + } + else { + *return_cs = CS_RETURN; + } + cs_len++; + } + + for (ptr = tab; ptr < end_tab; ptr++) { + if (ptr->used) { + if (is_subr) + sprintf(t1_line_array, "dup %u %u", ptr - tab, ptr->cslen); + else + sprintf(t1_line_array, "/%s %u", ptr->name, ptr->cslen); + p = strend(t1_line_array); + memcpy(p, ptr->data, ptr->len); + t1_line_ptr = p + ptr->len; + t1_putline(); + } + else { + /* replace unsused subr's by return_cs */ + if (is_subr) { + sprintf(t1_line_array, "dup %u %u%s ", ptr - tab, cs_len, + cs_token_pair[0]); + p = strend(t1_line_array); + memcpy(p, return_cs, cs_len); + t1_line_ptr = p + cs_len; + t1_putline(); + sprintf(t1_line_array, " %s", cs_token_pair[1]); + t1_line_ptr = eol(t1_line_array); + t1_putline(); + } + } + xfree(ptr->data); + if (ptr->name != notdef) + xfree(ptr->name); + } + sprintf(t1_line_array, "%s", line_end); + t1_line_ptr = eol(t1_line_array); + t1_putline(); + if (is_subr) + xfree(return_cs); + xfree(tab); + xfree(start_line); + xfree(line_end); +} + +static void t1_mark_glyphs(void) +{ + int i; + char *charset = extra_charset(); + char *g, *s, *r; + cs_entry *ptr; + if (t1_synthetic || embed_all_glyphs(tex_font)) { /* mark everything */ + if (cs_tab != NULL) + for (ptr = cs_tab; ptr < cs_ptr; ptr++) + if (ptr->valid) + ptr->used = true; + if (subr_tab != NULL) { + for (ptr = subr_tab; ptr - subr_tab < subr_size; ptr++) + if (ptr->valid) + ptr->used = true; + subr_max = subr_size - 1; + } + return; + } + mark_cs(notdef); + for (i = 0; i <= MAX_CHAR_CODE; i++) + if (is_used_char(i)) { + if (t1_glyph_names[i] == notdef) + pdftex_warn("character %i is mapped to %s", i, notdef); + else + mark_cs(t1_glyph_names[i]); + } + if (charset == NULL) + goto set_subr_max; + g = s = charset + 1; /* skip the first '/' */ + r = strend(g); + while (g < r) { + while (*s != '/' && s < r) + s++; + *s = 0; /* terminate g by rewriting '/' to 0 */ + mark_cs(g); + g = s + 1; + } +set_subr_max: + if (subr_tab != NULL) + for (subr_max = -1, ptr = subr_tab; ptr - subr_tab < subr_size; ptr++) + if (ptr->used && ptr - subr_tab > subr_max) + subr_max = ptr - subr_tab; +} + +static void t1_subset_charstrings(void) +{ + cs_entry *ptr; + cs_size_pos = strstr(t1_line_array, charstringname) + strlen(charstringname) + - t1_line_array + 1; + /* cs_size_pos points to the number indicating + dict size after "/CharStrings" */ + cs_size = t1_scan_num(t1_line_array + cs_size_pos, 0); + cs_ptr = cs_tab = xtalloc(cs_size, cs_entry); + for (ptr = cs_tab; ptr - cs_tab < cs_size; ptr++) + init_cs_entry(ptr); + cs_notdef = NULL; + cs_dict_start = xstrdup(t1_line_array); + t1_getline(); + while (t1_cslen) { + store_cs(); + t1_getline(); + } + cs_dict_end = xstrdup(t1_line_array); + t1_mark_glyphs(); + if (subr_tab != NULL) { + if (cs_token_pair == NULL) + pdftex_fail("This Type 1 font uses mismatched subroutine begin/end token pairs."); + t1_subr_flush(); + } + for (cs_count = 0, ptr = cs_tab; ptr < cs_ptr; ptr++) + if (ptr->used) + cs_count++; + t1_cs_flush(); +} + +static void t1_subset_end(void) +{ + if (t1_synthetic) { /* copy to "dup /FontName get exch definefont pop" */ + while (!strstr(t1_line_array, "definefont")) { + t1_getline(); + t1_putline(); + } + while (!t1_end_eexec()) + t1_getline(); /* ignore the rest */ + t1_putline(); /* write "mark currentfile closefile" */ + } + else while (!t1_end_eexec()) { /* copy to "mark currentfile closefile" */ + t1_getline(); + t1_putline(); + } + t1_stop_eexec(); + while (!t1_cleartomark()) { + t1_getline(); + t1_putline(); + } + if (!t1_synthetic) /* don't check "{restore}if" for synthetic fonts */ + t1_check_end(); /* write "{restore}if" if found */ + get_length3(); +} + +void writet1(void) +{ + read_encoding_only = false; +#ifdef pdfTeX + t1_save_offset = 0; + if (strcasecmp(strend(fm_fontfile(fm_cur)) - 4, ".otf") == 0) { + if (!is_included(fm_cur) || is_subsetted(fm_cur)) + pdftex_fail("OTF fonts must be included entirely"); + writeotf(); + is_otf_font = true; + return; + } +#endif + if (!is_included(fm_cur)) { /* scan parameters from font file */ + if (!t1_open_fontfile("{")) + return; + t1_scan_only(); + t1_close_font_file("}"); + return; + } + if (!is_subsetted(fm_cur)) { /* include entire font */ + if (!t1_open_fontfile("<<")) + return; + t1_include(); + t1_close_font_file(">>"); + return; + } + /* partial downloading */ + if (!t1_open_fontfile("<")) + return; + t1_subset_ascii_part(); + t1_start_eexec(); + cc_init(); + cs_init(); + t1_read_subrs(); + t1_subset_charstrings(); + t1_subset_end(); + t1_close_font_file(">"); +} + +void t1_free() +{ + xfree(t1_line_array); + xfree(t1_buf_array); +} + +#ifndef pdfTeX +boolean t1_subset(char *fontfile, char *encfile, unsigned char *g) +{ + int i; + cur_enc_name = encfile; + for (i = 0; i <= MAX_CHAR_CODE; i++) + ext_glyph_names[i] = (char*) notdef; + if (cur_enc_name != NULL) + load_enc(cur_enc_name, ext_glyph_names); + grid = g; + cur_file_name = fontfile; + hexline_length = 0; + writet1(); + for (i = 0; i <= MAX_CHAR_CODE; i++) + if (ext_glyph_names[i] != notdef) + free(ext_glyph_names[i]); + return 1 ; /* note: there *is* no unsuccessful return */ +} + +boolean t1_subset_2(char *fontfile, unsigned char *g, char *extraGlyphs) +{ + int i; + for (i = 0; i <= MAX_CHAR_CODE; i++) + ext_glyph_names[i] = (char*) notdef; + grid = g; + cur_file_name = fontfile; + hexline_length = 0; + dvips_extra_charset = extraGlyphs ; + writet1(); + for (i = 0; i <= MAX_CHAR_CODE; i++) + if (ext_glyph_names[i] != notdef) + free(ext_glyph_names[i]); + return 1 ; /* note: there *is* no unsuccessful return */ +} +#endif /* not pdfTeX */ diff --git a/Build/source/texk/web2c/pdftexdir/writet3.c b/Build/source/texk/web2c/pdftexdir/writet3.c new file mode 100644 index 00000000000..fa9c09bc3d1 --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/writet3.c @@ -0,0 +1,389 @@ +/* +Copyright (c) 1996-2002 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/writet3.c#9 $ +*/ + +#include "ptexlib.h" +#include <kpathsea/tex-glyph.h> +#include <kpathsea/magstep.h> + +#define T3_BUF_SIZE 1024 + +static const char perforce_id[] = + "$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/writet3.c#9 $"; + +/* define t3_line_ptr, t3_line_array & t3_line_limit */ +typedef char t3_line_entry; +define_array(t3_line); + +FILE *t3_file; +static boolean t3_image_used; + +static integer t3_char_procs[MAX_CHAR_CODE + 1]; +static float t3_char_widths[MAX_CHAR_CODE + 1]; +static int t3_glyph_num; +static float t3_font_scale; +static integer t3_b0, t3_b1, t3_b2, t3_b3; +static boolean is_pk_font; + +#define t3_open() \ + open_input(&t3_file, kpse_miscfonts_format, FOPEN_RBIN_MODE) +#define t3_close() xfclose(t3_file, cur_file_name) +#define t3_getchar() xgetc(t3_file) +#define t3_eof() feof(t3_file) +#define t3_prefix(s) (!strncmp(t3_line_array, s, strlen(s))) +#define t3_putchar(c) pdfout(c) + +#define t3_check_eof() \ + if (t3_eof()) \ + pdftex_fail("unexpected end of file"); + +static void t3_getline(void) +{ + int c; +restart: + t3_line_ptr = t3_line_array; + c = t3_getchar(); + while (!t3_eof()) { + alloc_array(t3_line, 1, T3_BUF_SIZE); + append_char_to_buf(c, t3_line_ptr, t3_line_array, t3_line_limit); + if (c == 10) + break; + c = t3_getchar(); + } + alloc_array(t3_line, 2, T3_BUF_SIZE); + append_eol(t3_line_ptr, t3_line_array, T3_BUF_SIZE); + if (t3_line_ptr - t3_line_array < 2 || *t3_line_array == '%') { + if (!t3_eof()) + goto restart; + } +} + +static void t3_putline(void) +{ + char *p = t3_line_array; + while (p < t3_line_ptr) + t3_putchar(*p++); +} + +static void update_bbox(integer llx, integer lly, integer urx, integer ury, boolean is_first_glyph) +{ + if (is_first_glyph) { + t3_b0 = llx; + t3_b1 = lly; + t3_b2 = urx; + t3_b3 = ury; + } + else { + if (llx < t3_b0) + t3_b0 = llx; + if (lly < t3_b1) + t3_b1 = lly; + if (urx > t3_b2) + t3_b2 = urx; + if (ury > t3_b3) + t3_b3 = ury; + } +} + +static void t3_write_glyph(internalfontnumber f) +{ + static char t3_begin_glyph_str[] = "\\pdfglyph"; + static char t3_end_glyph_str[] = "\\endglyph"; + int glyph_index; + int width, height, depth, llx, lly, urx, ury; + char *p; + t3_getline(); + if (t3_prefix(t3_begin_glyph_str)) { + if (sscanf(t3_line_array + strlen(t3_begin_glyph_str) + 1, + "%i %i %i %i %i %i %i %i =", &glyph_index, + &width, &height, &depth, &llx, &lly, &urx, &ury) != 8) { + remove_eol(p, t3_line_array); + pdftex_warn("invalid glyph preamble: `%s'", t3_line_array); + return; + } + if (glyph_index < fontbc[f] || glyph_index > fontec[f]) + return; + } + else + return; + if (!pdfcharmarked(f, glyph_index)) { + while (!t3_prefix(t3_end_glyph_str)) { + t3_check_eof(); + t3_getline(); + } + return; + } + update_bbox(llx, lly, urx, ury, t3_glyph_num == 0); + t3_glyph_num++; + pdfnewdict(0, 0); + t3_char_procs[glyph_index] = objptr; + if (width == 0) + t3_char_widths[glyph_index] = + (getcharwidth(f, glyph_index)/t3_font_scale) / pdffontsize[f]; + else + t3_char_widths[glyph_index] = width; + pdfbeginstream(); + t3_getline(); + pdf_printf("%i 0 %i %i %i %i d1\nq\n", + (int)t3_char_widths[glyph_index], (int)llx, + (int)lly, (int)urx, (int)ury); + while (!t3_prefix(t3_end_glyph_str)) { + t3_check_eof(); + if (t3_prefix("BI")) + t3_image_used = true; + t3_putline(); + t3_getline(); + } + pdf_puts("Q\n"); + pdfendstream(); +} + +static integer get_pk_font_scale(internalfontnumber f) +{ + return + dividescaled(pkscalefactor, + dividescaled(pdffontsize[f], onehundredbp, fixeddecimaldigits + 2), + 0); +} + +static integer pk_char_width(internalfontnumber f, scaled w) +{ + return + dividescaled(dividescaled(w, pdffontsize[f], 7), + get_pk_font_scale(f), 0); +} + +scaled getpkcharwidth(internalfontnumber f, scaled w) +{ + return (get_pk_font_scale(f)/100000.0)* + (pk_char_width(f, w)/100.0)* + pdffontsize[f]; +} + +static boolean writepk(internalfontnumber f) +{ + kpse_glyph_file_type font_ret; + integer llx, lly, urx, ury; + integer cw, rw, i, j; + halfword *row; + char *name; + chardesc cd; + boolean is_null_glyph, check_preamble; + integer dpi; + int e; + dpi = kpse_magstep_fix( + round(fixedpkresolution*(((float)pdffontsize[f])/fontdsize[f])), + fixedpkresolution, NULL); + cur_file_name = makecstring(fontname[f]); + name = kpse_find_pk(cur_file_name, (unsigned)dpi, &font_ret); + if (name == NULL || + !FILESTRCASEEQ(cur_file_name, font_ret.name) || + !kpse_bitmap_tolerance((float)font_ret.dpi, (float)dpi)) { + pdftex_warn("Font %s at %i not found", cur_file_name, (int)dpi); + cur_file_name = NULL; + return false; + } + t3_file = xfopen(name, FOPEN_RBIN_MODE); + t3_image_used = true; + is_pk_font = true; + tex_printf(" <%s", (char *)name); + cd.rastersize = 256; + cd.raster = xtalloc(cd.rastersize, halfword); + check_preamble = true; + while (readchar(check_preamble, &cd) != 0) { + check_preamble = false; + if (!pdfcharmarked(f, cd.charcode)) + continue; + t3_char_widths[cd.charcode] = + pk_char_width(f, getcharwidth(f, cd.charcode)); + if (cd.cwidth < 1 || cd.cheight < 1) { + cd.xescape = cd.cwidth = round(t3_char_widths[cd.charcode]/100.0); + cd.cheight = 1; + cd.xoff = 0; + cd.yoff = 0; + is_null_glyph = true; + } + else + is_null_glyph = false; + llx = -cd.xoff; + lly = cd.yoff - cd.cheight + 1; + urx = cd.cwidth + llx + 1; + ury = cd.cheight + lly; + update_bbox(llx, lly, urx, ury, t3_glyph_num == 0); + t3_glyph_num++; + pdfnewdict(0, 0); + t3_char_procs[cd.charcode] = objptr; + pdfbeginstream(); + pdfprintreal(t3_char_widths[cd.charcode], 2); + pdf_printf(" 0 %i %i %i %i d1\n", + (int)llx, (int)lly, (int)urx, (int)ury); + if (is_null_glyph) + goto end_stream; + pdf_printf("q\n%i 0 0 %i %i %i cm\nBI\n", (int)cd.cwidth, + (int)cd.cheight, (int)llx, (int)lly); + pdf_printf("/W %i\n/H %i\n", + (int)cd.cwidth, (int)cd.cheight); + pdf_puts("/IM true\n/BPC 1\n/D [1 0]\nID "); + cw = (cd.cwidth + 7)/8; + rw = (cd.cwidth + 15)/16; + row = cd.raster; + for (i = 0; i < cd.cheight; i++) { + for (j = 0; j < rw - 1; j++) { + pdfout(*row/256); + pdfout(*row%256); + row++; + } + pdfout(*row/256); + if (2*rw == cw) + pdfout(*row%256); + row++; + } + pdf_puts("\nEI\nQ\n"); +end_stream: + pdfendstream(); + } + xfree(cd.raster); + cur_file_name = NULL; + return true; +} + +void writet3(int objnum, internalfontnumber f) +{ + static char t3_font_scale_str[] = "\\pdffontscale"; + int i, e; + int first_char, last_char; + integer pk_font_scale; + boolean is_notdef; + t3_glyph_num = 0; + t3_image_used = false; + for (i = 0; i <= MAX_CHAR_CODE; i++) { + t3_char_procs[i] = 0; + t3_char_widths[i] = 0; + } + packfilename(fontname[f], getnullstr(), maketexstring(".pgc")); + cur_file_name = makecstring(makenamestring()); + is_pk_font = false; + if (!t3_open()) { + if (writepk(f)) + goto write_font_dict; + else { + cur_file_name = NULL; + return; + } + } + tex_printf("<%s", nameoffile + 1); + t3_getline(); + if (!t3_prefix(t3_font_scale_str) || + sscanf(t3_line_array + strlen(t3_font_scale_str) + 1, "%g", &t3_font_scale) < 1 || + t3_font_scale <= 0 || t3_font_scale > 1000 ) { + pdftex_warn("missing or invalid font scale"); + t3_close(); + cur_file_name = NULL; + return; + } + while (!t3_eof()) + t3_write_glyph(f); +write_font_dict: + for (i = fontbc[f]; i <= fontec[f]; i++) + if (pdfcharmarked(f, i)) + break; + first_char = i; + for (i = fontec[f]; i > first_char; i--) + if (pdfcharmarked(f, i)) + break; + last_char = i; + pdfbegindict(objnum); /* Type 3 font dictionary */ + pdf_puts("/Type /Font\n/Subtype /Type3\n"); + pdf_printf("/Name /F%i\n", (int)f); + if (pdffontattr[f] != getnullstr()) { + pdfprint(pdffontattr[f]); + pdf_puts("\n"); + } + if (is_pk_font) { + pk_font_scale = get_pk_font_scale(f); + pdf_puts("/FontMatrix ["); + pdfprintreal(pk_font_scale, 5); + pdf_puts(" 0 0 "); + pdfprintreal(pk_font_scale, 5); + pdf_puts(" 0 0]\n") ; + } + else + pdf_printf("/FontMatrix [%g 0 0 %g 0 0]\n", + (double)t3_font_scale, (double)t3_font_scale); + pdf_printf("/%s [ %i %i %i %i ]\n", + font_keys[FONTBBOX1_CODE].pdfname, + (int)t3_b0, (int)t3_b1, + (int)t3_b2, (int)t3_b3); + pdf_printf("/Resources << /ProcSet [ /PDF %s] >>\n", + t3_image_used ? "/ImageB " : ""); + pdf_printf("/FirstChar %i\n/LastChar %i\n", first_char, last_char); + pdf_printf("/Widths %i 0 R\n/Encoding %i 0 R\n/CharProcs %i 0 R\n", + (int)(objptr + 1), (int)(objptr + 2), + (int)(objptr + 3)); + pdfenddict(); + pdfnewobj(0, 0); /* chars width array */ + pdf_puts("["); + if (is_pk_font) + for (i = first_char; i <= last_char; i++) { + pdfprintreal(t3_char_widths[i], 2); + pdf_puts(" "); + } + else + for (i = first_char; i <= last_char; i++) + pdf_printf("%i ", (int)t3_char_widths[i]); + pdf_puts("]\n"); + pdfendobj(); + pdfnewdict(0, 0); /* encoding dictionary */ + pdf_printf("/Type /Encoding\n/Differences [%i", first_char); + if (t3_char_procs[first_char] == 0) { + pdf_printf("/%s", notdef); + is_notdef = true; + } + else { + pdf_printf("/a%i", first_char); + is_notdef = false; + } + for (i = first_char + 1; i <= last_char; i++) { + if (t3_char_procs[i] == 0) { + if (!is_notdef) { + pdf_printf(" %i/%s", i, notdef); + is_notdef = true; + } + } + else { + if (is_notdef) { + pdf_printf(" %i", i); + is_notdef = false; + } + pdf_printf("/a%i", i); + } + } + pdf_puts("]\n"); + pdfenddict(); + pdfnewdict(0, 0); /* CharProcs dictionary */ + for (i = first_char; i <= last_char; i++) + if (t3_char_procs[i] != 0) + pdf_printf("/a%i %i 0 R\n", (int)i, (int)t3_char_procs[i]); + pdfenddict(); + t3_close(); + tex_printf(">"); + cur_file_name = NULL; +} diff --git a/Build/source/texk/web2c/pdftexdir/writettf.c b/Build/source/texk/web2c/pdftexdir/writettf.c new file mode 100644 index 00000000000..e2d0d1641d6 --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/writettf.c @@ -0,0 +1,1257 @@ +/* +Copyright (c) 1996-2002 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/writettf.c#16 $ +*/ + +#include "ptexlib.h" +#include "writettf.h" + +static const char perforce_id[] = + "$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/writettf.c#16 $"; + +#define DEFAULT_NTABS 14 +#define NEW_CMAP_SIZE 2 + +#define ttf_putchar fb_putchar +#define ttf_offset fb_offset +#define ttf_seek_outbuf fb_seek + +#define INFILE ttf_file + +#define ttf_open() \ + open_input(&ttf_file, kpse_truetype_format, FOPEN_RBIN_MODE) +#define ttf_close() xfclose(ttf_file, cur_file_name) +#define ttf_getchar() xgetc(ttf_file) +#define ttf_eof() feof(ttf_file) + +typedef struct { + TTF_LONG offset; + TTF_LONG newoffset; + TTF_UFWORD advWidth; + TTF_FWORD lsb; + char *name; /* name of glyph */ + TTF_SHORT newindex; /* new index of glyph in output file */ + TTF_USHORT name_index; /* index of name as read from font file */ +} glyph_entry; + +typedef struct { + char *name; /* name of glyph */ + short newindex; /* new index of glyph in output file */ +} ttfenc_entry; + +typedef struct { + TTF_USHORT platform_id; + TTF_USHORT encoding_id; + TTF_USHORT language_id; + TTF_USHORT name_id; + TTF_USHORT length; + TTF_USHORT offset; + TTF_USHORT new_offset; + TTF_USHORT new_length; +} name_record; + +static TTF_USHORT ntabs; +static TTF_USHORT upem; +static TTF_FIXED post_format; +static TTF_SHORT loca_format; +static TTF_ULONG last_glyf_offset; +static TTF_USHORT glyphs_count; +static TTF_USHORT new_glyphs_count; +static TTF_USHORT nhmtxs; +static TTF_USHORT new_ntabs; + +static glyph_entry *glyph_tab; +static short *glyph_index; +static cmap_entry *cmap_tab, new_cmap_tab[NEW_CMAP_SIZE]; +static name_record *name_tab; +static int name_record_num; +static char *name_buf; +static int name_buf_size; +static dirtab_entry *dir_tab; +static char *glyph_name_buf; +static TTF_ULONG checksum; +static TTF_ULONG tab_length; +static TTF_ULONG tmp_ulong; +static TTF_ULONG checkSumAdjustment_offset; +static FILE *ttf_file; +static ttfenc_entry ttfenc_tab[MAX_CHAR_CODE + 1]; + +static TTF_USHORT unicode_map[0xFFFF]; + + +integer ttf_length; + +#include "macnames.c" + +extern char *fb_array; + +static const char *newtabnames[] = { + "OS/2", + "PCLT", + "cmap", + "cvt ", + "fpgm", + "glyf", + "head", + "hhea", + "hmtx", + "loca", + "maxp", + "name", + "post", + "prep" +}; + +static unsigned char ttf_addchksm(unsigned char b) +{ + tmp_ulong = (tmp_ulong << 8) + b; + tab_length++; + if (tab_length % 4 == 0) { + checksum += tmp_ulong; + tmp_ulong = 0; + } + return b; +} + +static TTF_ULONG ttf_getchksm(void) +{ + while (tab_length % 4 != 0) + ttf_putchar(ttf_addchksm(0)); /* ttf_addchksm updates tab_length */ + return checksum; +} + +static long ttf_putnum(int s, long n) +{ + long i = n; + char buf[TTF_LONG_SIZE + 1], *p = buf; + while (s-- > 0) { + *p++ = i & 0xFF; + i >>= 8; + } + p--; + while (p >= buf) + ttf_putchar(ttf_addchksm(*p--)); + return n; +} + +static long ttf_getnum(int s) +{ + long i = 0; + int c; + while (s > 0) { + if ((c = ttf_getchar()) < 0) + pdftex_fail("unexpected EOF"); + i = (i << 8) + c; + s--; + } + return i; +} + +static long ttf_funit(long n) +{ + if (n < 0) + return -((-n/upem)*1000 + ((-n%upem)*1000)/upem); + else + return (n/upem)*1000 + ((n%upem)*1000)/upem; +} + +static void ttf_ncopy(int n) +{ + while (n-- > 0) + copy_byte(); +} + +static dirtab_entry *ttf_name_lookup(const char *s, boolean required) +{ + dirtab_entry *tab; + for (tab = dir_tab; tab - dir_tab < ntabs; tab++) + if (strncmp(tab->tag, s, 4) == 0) + break; + if (tab - dir_tab == ntabs) { + if (required) + pdftex_fail("can't find table `%s'", s); + else + tab = NULL; + } + return tab; +} + +static dirtab_entry *ttf_seek_tab(const char *name, TTF_LONG offset) +{ + dirtab_entry *tab = ttf_name_lookup(name, true); + xfseek(INFILE, tab->offset + offset, SEEK_SET, cur_file_name); + return tab; +} + +static void ttf_seek_off(TTF_LONG offset) +{ + xfseek(INFILE, offset, SEEK_SET, cur_file_name); +} + +static void ttf_copy_encoding(void) +{ + int i; + char **glyph_names = (fm_cur->encoding)->glyph_names; + ttfenc_entry *e = ttfenc_tab; + pdfmarkchar(tex_font, 'a'); /* workaround for a bug of AcroReader 4.0 */ + for (i = 0; i <= MAX_CHAR_CODE; i++, e++) { + if (pdfcharmarked(tex_font, i)) + e->name = glyph_names[i]; + else + e->name = (char*) notdef; + } +} + +#define ttf_append_byte(B)\ +do {\ + if (name_tab[i].platform_id == 3)\ + *q++ = 0;\ + *q++ = B;\ +} while (0) + +static void ttf_read_name(void) +{ + int i, j; + dirtab_entry *tab = ttf_seek_tab("name", TTF_USHORT_SIZE); + char *p; + name_record_num = get_ushort(); + name_tab = xtalloc(name_record_num, name_record); + name_buf_size = tab->length - + (3*TTF_USHORT_SIZE + name_record_num*6*TTF_USHORT_SIZE); + name_buf = xtalloc(name_buf_size, char); + ttf_skip(TTF_USHORT_SIZE); + for (i = 0; i < name_record_num; i++) { + name_tab[i].platform_id = get_ushort(); + name_tab[i].encoding_id = get_ushort(); + name_tab[i].language_id = get_ushort(); + name_tab[i].name_id = get_ushort(); + name_tab[i].length = get_ushort(); + name_tab[i].offset = get_ushort(); + } + for (p = name_buf; p - name_buf < name_buf_size; p++) + *p = get_char(); + /* look for PS font name */ + for (i = 0; i < name_record_num; i++) { + if (name_tab[i].platform_id == 1 && + name_tab[i].encoding_id == 0 && + name_tab[i].name_id == 6) { + strncpy(fontname_buf, name_buf + name_tab[i].offset, name_tab[i].length); + fontname_buf[name_tab[i].length] = 0; + font_keys[FONTNAME_CODE].valid = true; + break; + } + } + if (!font_keys[FONTNAME_CODE].valid) { + for (i = 0; i < name_record_num; i++) { + if (name_tab[i].platform_id == 3 && + (name_tab[i].encoding_id == 0 || + name_tab[i].encoding_id == 1) && + name_tab[i].name_id == 6) { + for (j = 0, p = fontname_buf; j < name_tab[i].length; j += 2) + *p++ = name_buf[name_tab[i].offset + j + 1]; + *p = 0; + font_keys[FONTNAME_CODE].valid = true; + break; + } + } + } +} + +static void ttf_read_mapx(void) +{ + int i; + glyph_entry *glyph; + ttf_seek_tab("maxp", TTF_FIXED_SIZE); + glyph_tab = xtalloc(1 + (glyphs_count = get_ushort()), glyph_entry); + for (glyph = glyph_tab; glyph - glyph_tab < glyphs_count; glyph++) { + glyph->newindex = -1; + glyph->newoffset = 0; + glyph->name_index = 0; + glyph->name = (char*) notdef; + } + glyph_index = xtalloc(glyphs_count, short); + glyph_index[0] = 0; /* index of ".notdef" glyph */ + glyph_index[1] = 1; /* index of ".null" glyph */ +} + +static void ttf_read_head(void) +{ + ttf_seek_tab("head", 2*TTF_FIXED_SIZE + 2*TTF_ULONG_SIZE + TTF_USHORT_SIZE); + upem = get_ushort(); + ttf_skip(16); + font_keys[FONTBBOX1_CODE].value = ttf_funit(get_fword()); + font_keys[FONTBBOX2_CODE].value = ttf_funit(get_fword()); + font_keys[FONTBBOX3_CODE].value = ttf_funit(get_fword()); + font_keys[FONTBBOX4_CODE].value = ttf_funit(get_fword()); + font_keys[FONTBBOX1_CODE].valid = true; + font_keys[FONTBBOX2_CODE].valid = true; + font_keys[FONTBBOX3_CODE].valid = true; + font_keys[FONTBBOX4_CODE].valid = true; + ttf_skip(2*TTF_USHORT_SIZE + TTF_SHORT_SIZE); + loca_format = get_short(); +} + +static void ttf_read_hhea(void) +{ + ttf_seek_tab("hhea", TTF_FIXED_SIZE); + font_keys[ASCENT_CODE].value = ttf_funit(get_fword()); + font_keys[DESCENT_CODE].value = ttf_funit(get_fword()); + font_keys[ASCENT_CODE].valid = true; + font_keys[DESCENT_CODE].valid = true; + ttf_skip(TTF_FWORD_SIZE + TTF_UFWORD_SIZE + 3*TTF_FWORD_SIZE + 8*TTF_SHORT_SIZE); + nhmtxs = get_ushort(); +} + +static void ttf_read_pclt(void) +{ + if (ttf_name_lookup("PCLT", false) == NULL) + return; + ttf_seek_tab("PCLT", TTF_FIXED_SIZE + TTF_ULONG_SIZE + TTF_USHORT_SIZE); + font_keys[XHEIGHT_CODE].value = ttf_funit(get_ushort()); + ttf_skip(2*TTF_USHORT_SIZE); + font_keys[CAPHEIGHT_CODE].value = ttf_funit(get_ushort()); + font_keys[XHEIGHT_CODE].valid = true; + font_keys[CAPHEIGHT_CODE].valid = true; +} + +static void ttf_read_hmtx(void) +{ + glyph_entry *glyph; + TTF_UFWORD last_advWidth; + ttf_seek_tab("hmtx", 0); + for (glyph = glyph_tab; glyph - glyph_tab < nhmtxs; glyph++) { + glyph->advWidth = get_ufword(); + glyph->lsb = get_ufword(); + } + if (nhmtxs < glyphs_count) { + last_advWidth = glyph[-1].advWidth; + for (;glyph - glyph_tab < glyphs_count; glyph++) { + glyph->advWidth = last_advWidth; + glyph->lsb = get_ufword(); + } + } +} + +static void ttf_read_post(void) +{ + int k, nnames; + long length; + long int_part, frac_part; + int sign = 1; + TTF_FIXED italic_angle; + char *p; + glyph_entry *glyph; + dirtab_entry *tab = ttf_seek_tab("post", 0); + post_format = get_fixed(); + italic_angle = get_fixed(); + int_part = italic_angle >> 16; + if (int_part > 0x7FFF) { /* a negative number */ + int_part = 0x10000 - int_part; + sign = -1; + } + frac_part = italic_angle % 0x10000; + font_keys[ITALIC_ANGLE_CODE].value = sign*(int_part + frac_part*1.0/0x10000); + font_keys[ITALIC_ANGLE_CODE].valid = true; + if (glyph_tab == NULL) + return; /* being called from writeotf() */ + ttf_skip(2*TTF_FWORD_SIZE + 5*TTF_ULONG_SIZE); + switch (post_format) { + case 0x10000: + for (glyph = glyph_tab; glyph - glyph_tab < NMACGLYPHS; glyph++) { + glyph->name = (char*)mac_glyph_names[glyph - glyph_tab]; + glyph->name_index = glyph - glyph_tab; + } + break; + case 0x20000: + nnames = get_ushort(); /* some fonts have this value different from nglyphs */ + for (glyph = glyph_tab; glyph - glyph_tab < nnames; glyph++) + glyph->name_index = get_ushort(); + length = tab->length - (xftell(INFILE, cur_file_name) - tab->offset); + glyph_name_buf = xtalloc(length, char); + for (p = glyph_name_buf; p - glyph_name_buf < length;) { + for (k = get_byte(); k > 0; k--) + *p++ = get_char(); + *p++ = 0; + } + for (glyph = glyph_tab; glyph - glyph_tab < nnames; glyph++) { + if (glyph->name_index < NMACGLYPHS) + glyph->name = (char*)mac_glyph_names[glyph->name_index]; + else { + p = glyph_name_buf; + k = glyph->name_index - NMACGLYPHS; + for (; k > 0; k--) + p = strend(p) + 1; + glyph->name = p; + } + } + break; + case 0x00030000: + for (glyph = glyph_tab; glyph - glyph_tab < NMACGLYPHS; glyph++) { + glyph->name_index = glyph - glyph_tab; + } + break; + default: + pdftex_fail("unsupported format (%.8X) of `post' table", (unsigned int) post_format); + } +} + +static void ttf_read_loca(void) +{ + glyph_entry *glyph; + ttf_seek_tab("loca", 0); + if (loca_format != 0) + for (glyph = glyph_tab; glyph - glyph_tab < glyphs_count + 1; glyph++) + glyph->offset = get_ulong(); + else + for (glyph = glyph_tab; glyph - glyph_tab < glyphs_count + 1; glyph++) + glyph->offset = get_ushort() << 1; +} + +static void ttf_read_tabdir() +{ + int i; + dirtab_entry *tab; +/* if ((version= get_fixed()) != 0x00010000) */ +/* pdftex_fail("unsupport version 0x%.8X; can handle only version 1.0", (int)version); */ + ttf_skip(TTF_FIXED_SIZE); /* ignore the sfnt number */ + dir_tab = xtalloc(ntabs = get_ushort(), dirtab_entry); + ttf_skip(3*TTF_USHORT_SIZE); + for (tab = dir_tab; tab - dir_tab < ntabs; tab++) { + for (i = 0; i < 4; i++) + tab->tag[i] = get_char(); + tab->checksum = get_ulong(); + tab->offset = get_ulong(); + tab->length = get_ulong(); + } +} + +static void ttf_read_cmap(void) +{ + cmap_entry *e; + seg_entry *seg_tab, *s; + TTF_USHORT *glyphId, format, segCount; + TTF_USHORT ncmapsubtabs; + long cmap_offset; + long int n, i, j, k, first_code, length, last_sep, index; + int unicode_map_count = 0; + int select_unicode = 1; /* may be changed later if needed */ + ttf_seek_tab("cmap", TTF_USHORT_SIZE); /* skip the table vesrion number (=0) */ + ncmapsubtabs = get_ushort(); + cmap_offset = xftell(INFILE, cur_file_name) - 2*TTF_USHORT_SIZE; + cmap_tab = xtalloc(ncmapsubtabs, cmap_entry); + for (e = cmap_tab; e - cmap_tab < ncmapsubtabs; e++) { + e->platform_id = get_ushort(); + e->encoding_id = get_ushort(); + e->offset = get_ulong(); + } + for (i = 0; i < 0xFFFF; ++i) + unicode_map[i] = NOGLYPH_ASSIGNED_YET; + for (e = cmap_tab; e - cmap_tab < ncmapsubtabs; e++) { + ttf_seek_off(cmap_offset + e->offset); + format = get_ushort(); + if (is_unicode_mapping(e) && format == 4) { + ++unicode_map_count; + if (unicode_map_count == select_unicode) + goto read_unicode_mapping; + } + continue; +read_unicode_mapping: + length = get_ushort(); /* length of subtable */ + get_ushort(); /* skip the version number */ + segCount = get_ushort()/2; + get_ushort(); /* skip searchRange */ + get_ushort(); /* skip entrySelector */ + get_ushort(); /* skip rangeShift */ + seg_tab = xtalloc(segCount, seg_entry); + for (s = seg_tab; s - seg_tab < segCount; s++) + s->endCode = get_ushort(); + get_ushort(); /* skip reversedPad */ + for (s = seg_tab; s - seg_tab < segCount; s++) + s->startCode = get_ushort(); + for (s = seg_tab; s - seg_tab < segCount; s++) + s->idDelta = get_ushort(); + for (s = seg_tab; s - seg_tab < segCount; s++) + s->idRangeOffset = get_ushort(); + length -= 8*TTF_USHORT_SIZE + 4*segCount*TTF_USHORT_SIZE; + n = length/TTF_USHORT_SIZE; /* number of glyphID's */ + glyphId = xtalloc(n, TTF_USHORT); + for (i = 0; i < n; i++) + glyphId[i] = get_ushort(); + for (s = seg_tab; s - seg_tab < segCount; s++) { + for (i = s->startCode; i <= s->endCode; i++) { + if (i == 0xFFFF) + break; + if (s->idRangeOffset != 0xFFFF) { + if (s->idRangeOffset == 0) + index = (s->idDelta + i) & 0xFFFF; + else { + k = (i - s->startCode) + s->idRangeOffset/2 + + (s - seg_tab) - segCount ; + assert(k >= 0 && k < n); + index = glyphId[k]; + if (index != 0) + index = (index + s->idDelta) & 0xFFFF; + } + if (index >= glyphs_count) + pdftex_fail("cmap: glyph index %i out of range [0..%i)", + index, glyphs_count); + if (unicode_map[i] != NOGLYPH_ASSIGNED_YET) + pdftex_warn("cmap: multiple glyphs are mapped to unicode %.4X, " + "only %i will be used (glyph %i being ignored)", + i, unicode_map[i], index); + else + unicode_map[i] = index; + } + } + } + xfree(seg_tab); + xfree(glyphId); + break; + } + if (e - cmap_tab == ncmapsubtabs) + pdftex_fail("Invalid argument `-m %i': out of range [1..%i]", + select_unicode, unicode_map_count); + xfree(cmap_tab); +} + +static void ttf_read_font(void) +{ + ttf_read_tabdir(); + if (ttf_name_lookup("PCLT", false) == NULL) + new_ntabs--; + if (ttf_name_lookup("fpgm", false) == NULL) + new_ntabs--; + if (ttf_name_lookup("cvt ", false) == NULL) + new_ntabs--; + if (ttf_name_lookup("prep", false) == NULL) + new_ntabs--; + ttf_read_mapx(); + ttf_read_head(); + ttf_read_hhea(); + ttf_read_pclt(); + ttf_read_hmtx(); + ttf_read_post(); + ttf_read_loca(); + ttf_read_name(); + ttf_read_cmap(); +} + +static void ttf_reset_chksm(dirtab_entry *tab) +{ + checksum = 0; + tab_length = 0; + tmp_ulong = 0; + tab->offset = ttf_offset(); + if (tab->offset % 4 != 0) + pdftex_warn("offset of `%4.4s' is not a multiple of 4", tab->tag); +} + + +static void ttf_set_chksm(dirtab_entry *tab) +{ + tab->length = ttf_offset() - tab->offset; + tab->checksum = ttf_getchksm(); +} + +static void ttf_copytab(const char *name) +{ + long i; + dirtab_entry *tab = ttf_seek_tab(name, 0); + ttf_reset_chksm(tab); + for (i = tab->length; i > 0; i--) + copy_char(); + ttf_set_chksm(tab); +} + +#define BYTE_ENCODING_LENGTH \ + ((MAX_CHAR_CODE + 1)*TTF_BYTE_SIZE + 3*TTF_USHORT_SIZE) + +static void ttf_byte_encoding(void) +{ + ttfenc_entry *e; + put_ushort(0); /* format number (0: byte encoding table) */ + put_ushort(BYTE_ENCODING_LENGTH); /* length of table */ + put_ushort(0); /* version number */ + for (e = ttfenc_tab; e - ttfenc_tab <= MAX_CHAR_CODE; e++) + if (e->newindex < 256) { + put_byte(e->newindex); + } + else { + if (e->name != notdef) + pdftex_warn("glyph `%s' has been mapped to `%s' in `ttf_byte_encoding' cmap table", + e->name, notdef); + put_byte(0); /* notdef */ + } +} + +#define TRIMMED_TABLE_MAP_LENGTH (TTF_USHORT_SIZE*(5 + (MAX_CHAR_CODE + 1))) + +static void ttf_trimmed_table_map(void) +{ + ttfenc_entry *e; + put_ushort(6); /* format number (6): trimmed table mapping */ + put_ushort(TRIMMED_TABLE_MAP_LENGTH); + put_ushort(0); /* version number (0) */ + put_ushort(0); /* first character code */ + put_ushort(MAX_CHAR_CODE + 1); /* number of character code in table */ + for (e = ttfenc_tab; e - ttfenc_tab <= MAX_CHAR_CODE; e++) + put_ushort(e->newindex); +} + +#define SEG_MAP_DELTA_LENGTH ((16 + (MAX_CHAR_CODE + 1))*TTF_USHORT_SIZE) + +static void ttf_seg_map_delta(void) +{ + ttfenc_entry *e; + put_ushort(4); /* format number (4: segment mapping to delta values) */ + put_ushort(SEG_MAP_DELTA_LENGTH); + put_ushort(0); /* version number */ + put_ushort(4); /* 2*segCount */ + put_ushort(4); /* searchRange */ + put_ushort(1); /* entrySelector */ + put_ushort(0); /* rangeShift */ + put_ushort(0xF0FF); /* endCount[0] */ + put_ushort(0xFFFF); /* endCount[1] */ + put_ushort(0); /* reversedPad */ + put_ushort(0xF000); /* startCount[0] */ + put_ushort(0xFFFF); /* startCount[1] */ + put_ushort(0); /* idDelta[0] */ + put_ushort(1); /* idDelta[1] */ + put_ushort(2*TTF_USHORT_SIZE); /* idRangeOffset[0] */ + put_ushort(0); /* idRangeOffset[1] */ + for (e = ttfenc_tab; e - ttfenc_tab <= MAX_CHAR_CODE; e++) + put_ushort(e->newindex); +} + +#define CMAP_ENTRY_LENGTH (2*TTF_USHORT_SIZE + TTF_ULONG_SIZE) + +static void ttf_select_cmap(void) +{ + assert(sizeof(new_cmap_tab) <= NEW_CMAP_SIZE*sizeof(cmap_entry)); + new_cmap_tab[0].platform_id = 1; /* Macintosh */ + new_cmap_tab[0].encoding_id = 0; /* Symbol; ignore code page */ + new_cmap_tab[0].format = new_glyphs_count < 256 ? 0 /* byte encoding */ + : 6; /* trimmed table mapping */ + new_cmap_tab[1].platform_id = 3; /* Microsoft */ + new_cmap_tab[1].encoding_id = 0; /* Symbol; ignore code page */ + new_cmap_tab[1].format = 4; /* segment mapping to delta */ +} + +static void ttf_write_cmap(void) +{ + cmap_entry *ce; + long offset; + dirtab_entry *tab = ttf_name_lookup("cmap", true); + ttf_select_cmap(); + ttf_reset_chksm(tab); + put_ushort(0); /* table version number (0) */ + put_ushort(NEW_CMAP_SIZE); /* number of encoding tables */ + offset = 2*TTF_USHORT_SIZE + NEW_CMAP_SIZE*CMAP_ENTRY_LENGTH; + for (ce = new_cmap_tab; ce - new_cmap_tab < NEW_CMAP_SIZE; ce++) { + ce->offset = offset; + switch (ce->format) { + case 0: + offset += BYTE_ENCODING_LENGTH; + break; + case 4: + offset += SEG_MAP_DELTA_LENGTH; + break; + case 6: + offset += TRIMMED_TABLE_MAP_LENGTH; + break; + default: + pdftex_fail("invalid format (it should not have happened)"); + } + put_ushort(ce->platform_id); + put_ushort(ce->encoding_id); + put_ulong(ce->offset); + } + for (ce = new_cmap_tab; ce - new_cmap_tab < NEW_CMAP_SIZE; ce++) { + switch (ce->format) { + case 0: + ttf_byte_encoding(); + break; + case 4: + ttf_seg_map_delta(); + break; + case 6: + ttf_trimmed_table_map(); + break; + } + } + ttf_set_chksm(tab); +} + +static int prepend_subset_tags(int index, char *p) +{ + boolean is_unicode = (name_tab[index].platform_id == 3); + int i; + assert(index > 0 && index < name_record_num && fm_cur->subset_tag != NULL); + if (is_unicode) { + for (i = 0; i < 6; ++i) { + *p++ = 0; + *p++ = fm_cur->subset_tag[i]; + } + *p++ = 0; + *p++ = '+'; + return 14; + } else { + strncpy(p, fm_cur->subset_tag, 6); + p += 6; + *p++ = '+'; + return 7; + } +} + + +static void ttf_write_name(void) +{ + int i, l; + char *p; + int new_name_buf_size; + char *new_name_buf; + name_record *n; + dirtab_entry *tab = ttf_name_lookup("name", true); + if (is_subsetted(fm_cur)) { + l = 0; + for (i = 0; i < name_record_num; i++) + l += name_tab[i].length + 14; /* maximum lengh of new stogare area */ + new_name_buf = xtalloc(l, char); + /* additional space for subset tags */ + p = new_name_buf; + for (i = 0; i < name_record_num; i++) { + n = name_tab + i; + n->new_offset = p - new_name_buf; + if ((n->name_id == 1 || n->name_id == 3 || + n->name_id == 4 || n->name_id == 6) && + ((n->platform_id == 1 && n->encoding_id == 0) || + (n->platform_id == 3 && n->encoding_id == 0) || + (n->platform_id == 3 && n->encoding_id == 1))) + { + l = prepend_subset_tags(i, p); + p += l; + } + else + l = 0; + memcpy(p, name_buf + n->offset, n->length); + p += n->length; + n->new_length = n->length + l; + } + new_name_buf_size = p - new_name_buf; + } + else { + new_name_buf = name_buf; + new_name_buf_size = name_buf_size; + } + ttf_reset_chksm(tab); + put_ushort(0); /* Format selector */ + put_ushort(name_record_num); + put_ushort(3*TTF_USHORT_SIZE + name_record_num*6*TTF_USHORT_SIZE); + for (i = 0; i < name_record_num; i++) { + put_ushort(name_tab[i].platform_id); + put_ushort(name_tab[i].encoding_id); + put_ushort(name_tab[i].language_id); + put_ushort(name_tab[i].name_id); + put_ushort(name_tab[i].new_length); + put_ushort(name_tab[i].new_offset); + } + for (p = new_name_buf; p - new_name_buf < new_name_buf_size; p++) + put_char(*p); + ttf_set_chksm(tab); + if (new_name_buf != name_buf) + xfree(new_name_buf); +} + +static void ttf_write_dirtab(void) +{ + dirtab_entry *tab; + TTF_ULONG i, k; + char *p; + integer save_offset = ttf_offset(); + ttf_seek_outbuf(TABDIR_OFF); + if (is_subsetted(fm_cur)) { + for (i = 0; i < DEFAULT_NTABS; i++) { + tab = ttf_name_lookup(newtabnames[i], false); + if (tab == NULL) + continue; + for (k = 0; k < 4; k++) + put_char(tab->tag[k]); + put_ulong(tab->checksum); + put_ulong(tab->offset); + put_ulong(tab->length); + } + } + else { + for (tab = dir_tab; tab - dir_tab < ntabs; tab++) { + for (k = 0; k < 4; k++) + put_char(tab->tag[k]); + put_ulong(tab->checksum); + put_ulong(tab->offset); + put_ulong(tab->length); + } + } + /* adjust checkSumAdjustment */ + tmp_ulong = 0; + checksum = 0; + for (p = fb_array, i = 0; i < save_offset;) { + tmp_ulong = (tmp_ulong << 8) + *p++; + i++; + if (i % 4 == 0) { + checksum += tmp_ulong; + tmp_ulong = 0; + } + } + if (i % 4 != 0) { + pdftex_warn("font length is not a multiple of 4 (%li)", i); + checksum <<= 8*(4 - i % 4); + } + k = 0xB1B0AFBA - checksum; + ttf_seek_outbuf(checkSumAdjustment_offset); + put_ulong(k); + ttf_seek_outbuf(save_offset); +} + +static void ttf_write_glyf(void) +{ + short *id, k; + TTF_USHORT idx; + TTF_USHORT flags; + dirtab_entry *tab = ttf_name_lookup("glyf", true); + long glyf_offset = tab->offset; + long new_glyf_offset = ttf_offset(); + ttf_reset_chksm(tab); + for (id = glyph_index; id - glyph_index < new_glyphs_count; id++) { + glyph_tab[*id].newoffset = ttf_offset() - new_glyf_offset; + if (glyph_tab[*id].offset != glyph_tab[*id + 1].offset) { + ttf_seek_off(glyf_offset + glyph_tab[*id].offset); + k = copy_short(); + ttf_ncopy(4*TTF_FWORD_SIZE); + if (k < 0) { + do { + flags = copy_ushort(); + idx = get_ushort(); + if (glyph_tab[idx].newindex < 0) { + glyph_tab[idx].newindex = new_glyphs_count; + glyph_index[new_glyphs_count++] = idx; + /* + N.B.: Here we change `new_glyphs_count', + which appears in the condition of the `for' loop + */ + } + put_ushort(glyph_tab[idx].newindex); + if (flags & ARG_1_AND_2_ARE_WORDS) + ttf_ncopy(2*TTF_SHORT_SIZE); + else + ttf_ncopy(TTF_USHORT_SIZE); + if (flags & WE_HAVE_A_SCALE) + ttf_ncopy(TTF_F2DOT14_SIZE); + else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) + ttf_ncopy(2*TTF_F2DOT14_SIZE); + else if (flags & WE_HAVE_A_TWO_BY_TWO) + ttf_ncopy(4*TTF_F2DOT14_SIZE); + } while (flags & MORE_COMPONENTS); + if (flags & WE_HAVE_INSTRUCTIONS) + ttf_ncopy(copy_ushort()); + } + else + ttf_ncopy(glyph_tab[*id + 1].offset - glyph_tab[*id].offset - + TTF_USHORT_SIZE - 4*TTF_FWORD_SIZE); + } + } + last_glyf_offset = ttf_offset() - new_glyf_offset; + ttf_set_chksm(tab); +} + +static void ttf_reindex_glyphs(void) +{ + ttfenc_entry *e; + glyph_entry *glyph; + unsigned int index; + /* + * reindexing glyphs: we append index of used glyphs to `glyph_index' + * while going through `ttfenc_tab'. After appending a new entry to + * `glyph_index' we set field `newindex' of corresponding entries in both + * `glyph_tab' and `ttfenc_tab' to the newly created index + * + */ + for (e = ttfenc_tab; e - ttfenc_tab <= MAX_CHAR_CODE; e++) { + e->newindex = 0; /* index of ".notdef" glyph */ + if (e->name == notdef) + continue; + /* scan form `index123' */ + if (sscanf(e->name, GLYPH_PREFIX_INDEX "%i", &index) == 1) { + if (index >= glyphs_count) { + pdftex_warn("`%s' out of valid range [0..%i)", + e->name, glyphs_count); + continue; + } + glyph = glyph_tab + index; + goto append_new_glyph; + } + /* scan form `uniABCD' */ + if (sscanf(e->name, GLYPH_PREFIX_UNICODE "%X", &index) == 1) { + assert(index <= 0xFFFF); + if (unicode_map[index] != NOGLYPH_ASSIGNED_YET) { + if (unicode_map[index] >= glyphs_count) { + pdftex_warn("`%s' is mapped to index %i which is out of valid range [0..%i)", + e->name, unicode_map[index], glyphs_count); + continue; + } + glyph = glyph_tab + unicode_map[index]; + goto append_new_glyph; + } + else { + pdftex_warn("`unicode %s%.4X' is not mapped to any glyph", + GLYPH_PREFIX_UNICODE, index); + continue; + } + } + /* look up by name */ + for (glyph = glyph_tab; glyph - glyph_tab < glyphs_count; glyph++) + if (glyph->name != notdef && strcmp(glyph->name, e->name) == 0) + break; + if (!(glyph - glyph_tab < glyphs_count)) { + pdftex_warn("glyph `%s' not found", e->name); + continue; + } +append_new_glyph: + assert(glyph - glyph_tab < glyphs_count); + if (glyph->newindex < 0) { + glyph_index[new_glyphs_count] = glyph - glyph_tab; + glyph->newindex = new_glyphs_count; + new_glyphs_count++; + } + e->newindex = glyph->newindex; + } +} + +static void ttf_write_head() +{ + dirtab_entry *tab; + tab = ttf_seek_tab("head", 0); + ttf_reset_chksm(tab); + ttf_ncopy(2*TTF_FIXED_SIZE); + checkSumAdjustment_offset = ttf_offset(); + put_ulong(0); + ttf_skip(TTF_ULONG_SIZE); /* skip checkSumAdjustment */ + ttf_ncopy(TTF_ULONG_SIZE + 2*TTF_USHORT_SIZE + 16 + + 4*TTF_FWORD_SIZE + 2*TTF_USHORT_SIZE + TTF_SHORT_SIZE); + if (is_subsetted(fm_cur)) { + put_short(loca_format); + put_short(0); + } + else + ttf_ncopy(2*TTF_SHORT_SIZE); + ttf_set_chksm(tab); +} + +static void ttf_write_hhea(void) +{ + dirtab_entry *tab; + tab = ttf_seek_tab("hhea", 0); + ttf_reset_chksm(tab); + ttf_ncopy(TTF_FIXED_SIZE + 3*TTF_FWORD_SIZE + TTF_UFWORD_SIZE + 3*TTF_FWORD_SIZE + 8*TTF_SHORT_SIZE); + put_ushort(new_glyphs_count); + ttf_set_chksm(tab); +} + +static void ttf_write_htmx(void) +{ + short *id; + dirtab_entry *tab = ttf_seek_tab("hmtx", 0); + ttf_reset_chksm(tab); + for (id = glyph_index; id - glyph_index < new_glyphs_count; id++) { + put_ufword(glyph_tab[*id].advWidth); + put_ufword(glyph_tab[*id].lsb); + } + ttf_set_chksm(tab); +} + +static void ttf_write_loca(void) +{ + short *id; + dirtab_entry *tab = ttf_seek_tab("loca", 0); + ttf_reset_chksm(tab); + loca_format = 0; + if (last_glyf_offset >= 0x00020000 || (last_glyf_offset & 1)) + loca_format = 1; + else + for (id = glyph_index; id - glyph_index < new_glyphs_count; id++) + if (glyph_tab[*id].newoffset & 1) { + loca_format = 1; + break; + } + if (loca_format != 0) { + for (id = glyph_index; id - glyph_index < new_glyphs_count; id++) + put_ulong(glyph_tab[*id].newoffset); + put_ulong(last_glyf_offset); + } + else { + for (id = glyph_index; id - glyph_index < new_glyphs_count; id++) + put_ushort(glyph_tab[*id].newoffset/2); + put_ushort(last_glyf_offset/2); + } + ttf_set_chksm(tab); +} + +static void ttf_write_mapx(void) +{ + dirtab_entry *tab = ttf_seek_tab("maxp", TTF_FIXED_SIZE + TTF_USHORT_SIZE); + ttf_reset_chksm(tab); + put_fixed(0x00010000); + put_ushort(new_glyphs_count); + ttf_ncopy(13*TTF_USHORT_SIZE); + ttf_set_chksm(tab); +} + +static void ttf_write_OS2(void) +{ + dirtab_entry *tab = ttf_seek_tab("OS/2", 0); + TTF_USHORT version; + ttf_reset_chksm(tab); + version = get_ushort(); + if (version != 0x0000 && version != 0x0001 && version != 0x0002) + pdftex_fail("unknown verssion of OS/2 table (%.4X)", version); + put_ushort(0x0001); /* fix version to 1*/ + ttf_ncopy(2*TTF_USHORT_SIZE + 13*TTF_SHORT_SIZE + 10*TTF_BYTE_SIZE); + ttf_skip(4*TTF_ULONG_SIZE); /* ulUnicodeRange 1--4 */ + put_ulong(0x00000003); /* Basic Latin + Latin-1 Supplement (0x0000--0x00FF) */ + put_ulong(0x10000000); /* Private Use (0xE000--0xF8FF) */ + put_ulong(0x00000000); + put_ulong(0x00000000); + ttf_ncopy(4*TTF_CHAR_SIZE + TTF_USHORT_SIZE); /* achVendID + fsSelection */ + ttf_skip(2*TTF_USHORT_SIZE); + put_ushort(0x0000); /* usFirstCharIndex */ + put_ushort(0xF0FF); /* usLastCharIndex */ + ttf_ncopy(5*TTF_USHORT_SIZE); + /* for version 0 the OS/2 table ends here, the rest is for version 1 */ + put_ulong(0x80000000); /* Symbol Character Set---don't use any code page */ + put_ulong(0x00000000); + ttf_set_chksm(tab); +} + +static boolean unsafe_name(char *s) +{ + const char **p; + for (p = ambiguous_names; *p != NULL; p++) + if (strcmp(s, *p) == 0) + return true; + return false; +} + +static void ttf_write_post(void) +{ + dirtab_entry *tab = ttf_seek_tab("post", TTF_FIXED_SIZE); + glyph_entry *glyph; + char *s; + short *id; + int l; + ttf_reset_chksm(tab); + if (!write_ttf_glyph_names || post_format == 0x00030000) { + put_fixed(0x00030000); + ttf_ncopy(TTF_FIXED_SIZE + 2*TTF_FWORD_SIZE + 5*TTF_ULONG_SIZE); + } + else { + put_fixed(0x00020000); + ttf_ncopy(TTF_FIXED_SIZE + 2*TTF_FWORD_SIZE + 5*TTF_ULONG_SIZE); + put_ushort(new_glyphs_count); + k = 0; + for (id = glyph_index; id - glyph_index < new_glyphs_count; id++) { + glyph = glyph_tab + *id; + if (glyph->name_index >= NMACGLYPHS || unsafe_name(glyph->name)) + glyph->name_index = NMACGLYPHS + k++; + put_ushort(glyph->name_index); + } + for (id = glyph_index; id - glyph_index < new_glyphs_count; id++) { + glyph = glyph_tab + *id; + if (glyph->name_index >= NMACGLYPHS) { + s = glyph->name; + l = strlen(s); + put_byte(l); + while (l-- > 0) + put_char(*s++); + } + } + } + ttf_set_chksm(tab); +} + +static void ttf_init_font(int n) +{ + int i, k; + for (i = 1, k = 0; i <= n; i <<= 1, k++); + put_fixed(0x00010000); /* font version */ + put_ushort(n); /* number of tables */ + put_ushort(i << 3); /* search range */ + put_ushort(k - 1); /* entry selector */ + put_ushort((n<<4) - (i<<3)); /* range shift */ + ttf_seek_outbuf(TABDIR_OFF + n*4*TTF_ULONG_SIZE); +} + +static void ttf_subset_font(void) +{ + ttf_init_font(new_ntabs); + if (ttf_name_lookup("PCLT", false) != NULL) + ttf_copytab("PCLT"); + if (ttf_name_lookup("fpgm", false) != NULL) + ttf_copytab("fpgm"); + if (ttf_name_lookup("cvt ", false) != NULL) + ttf_copytab("cvt "); + if (ttf_name_lookup("prep", false) != NULL) + ttf_copytab("prep"); + ttf_reindex_glyphs(); + ttf_write_glyf(); + ttf_write_loca(); + ttf_write_OS2(); + ttf_write_head(); + ttf_write_hhea(); + ttf_write_htmx(); + ttf_write_mapx(); + ttf_write_name(); + ttf_write_post(); + ttf_write_cmap(); + ttf_write_dirtab(); +} + +static void ttf_copy_font(void) +{ + dirtab_entry *tab; + ttf_init_font(ntabs); + for (tab = dir_tab; tab - dir_tab < ntabs; tab++) { + if (strncmp(tab->tag, "head", 4) == 0) + ttf_write_head(); + else + ttf_copytab(tab->tag); + } + ttf_write_dirtab(); +} + +void writettf() +{ + set_cur_file_name(fm_cur->ff_name); + if (is_subsetted(fm_cur) && !(is_reencoded(fm_cur))) { + pdftex_warn("encoding vector required for TrueType font subsetting"); + cur_file_name = NULL; + return; + } + if (!ttf_open()) { + pdftex_fail("cannot open TrueType font file for reading"); + } + cur_file_name = (char*)nameoffile + 1; + if (!is_included(fm_cur)) + tex_printf("{%s", cur_file_name); + else if (is_subsetted(fm_cur)) + tex_printf("<%s", cur_file_name); + else + tex_printf("<<%s", cur_file_name); + fontfile_found = true; + new_glyphs_count = 2; + new_ntabs = DEFAULT_NTABS; + dir_tab = NULL; + glyph_tab = NULL; + glyph_index = NULL; + glyph_name_buf = NULL; + name_tab = NULL; + name_buf = NULL; + ttf_read_font(); + if (is_included(fm_cur)) { + pdfsaveoffset = pdfoffset(); + pdfflush(); + if (is_subsetted(fm_cur)) { + ttf_copy_encoding(); + make_subset_tag(fm_cur, fm_cur->encoding->glyph_names); + ttf_subset_font(); + } + else + ttf_copy_font(); + ttf_length = ttf_offset(); + } + xfree(dir_tab); + xfree(glyph_tab); + xfree(glyph_index); + xfree(glyph_name_buf); + xfree(name_tab); + xfree(name_buf); + ttf_close(); + if (!is_included(fm_cur)) + tex_printf("}"); + else if (is_subsetted(fm_cur)) + tex_printf(">"); + else + tex_printf(">>"); + cur_file_name = NULL; +} + +void writeotf() +{ + dirtab_entry *tab; + long i; + set_cur_file_name(fm_cur->ff_name); + if (!open_input(&ttf_file, kpse_type1_format, FOPEN_RBIN_MODE)) { + pdftex_fail("cannot open OpenType font file for reading"); + } + cur_file_name = (char*)nameoffile + 1; + tex_printf("<<%s", cur_file_name); + fontfile_found = true; + dir_tab = NULL; + glyph_tab = NULL; + ttf_read_tabdir(); + /* read font parameters */ + if (ttf_name_lookup("head", false) != NULL) + ttf_read_head(); + if (ttf_name_lookup("hhea", false) != NULL) + ttf_read_hhea(); + if (ttf_name_lookup("PCLT", false) != NULL) + ttf_read_pclt(); + if (ttf_name_lookup("post", false) != NULL) + ttf_read_post(); + /* copy font file */ + tab = ttf_seek_tab("CFF ", 0); + for (i = tab->length; i > 0; i--) + copy_char(); + xfree(dir_tab); + ttf_close(); + tex_printf(">>"); + cur_file_name = NULL; +} + +/* + To calculate the checkSum for the 'head' table which itself includes the + checkSumAdjustment entry for the entire font, do the following: + + * Set the checkSumAdjustment to 0. + * Calculate the checksum for all the tables including the 'head' table + and enter that value into the table directory. + * Calculate the checksum for the entire font. + * Subtract that value from the hex value B1B0AFBA. + * Store the result in checkSumAdjustment. + + The checkSum for the 'head table which includes the checkSumAdjustment + entry for the entire font is now incorrect. That is not a problem. Do not + change it. An application attempting to verify that the 'head' table has + not changed should calculate the checkSum for that table by not including + the checkSumAdjustment value, and compare the result with the entry in the + table directory. + + The table directory also includes the offset of the associated tagged + table from the beginning of the font file and the length of that table. + + + */ diff --git a/Build/source/texk/web2c/pdftexdir/writettf.h b/Build/source/texk/web2c/pdftexdir/writettf.h new file mode 100644 index 00000000000..eca53cdfe30 --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/writettf.h @@ -0,0 +1,130 @@ +/* +Copyright (c) 1996-2002 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/writettf.h#1 $ +*/ + +typedef signed char TTF_CHAR; +typedef unsigned char TTF_BYTE; +typedef signed short TTF_SHORT; +typedef unsigned short TTF_USHORT; +typedef signed long TTF_LONG; +typedef unsigned long TTF_ULONG; +typedef unsigned long TTF_FIXED; +typedef unsigned short TTF_FUNIT; +typedef signed short TTF_FWORD; +typedef unsigned short TTF_UFWORD; +typedef unsigned short TTF_F2DOT14; + +#define TTF_CHAR_SIZE 1 +#define TTF_BYTE_SIZE 1 +#define TTF_SHORT_SIZE 2 +#define TTF_USHORT_SIZE 2 +#define TTF_LONG_SIZE 4 +#define TTF_ULONG_SIZE 4 +#define TTF_FIXED_SIZE 4 +#define TTF_FWORD_SIZE 2 +#define TTF_UFWORD_SIZE 2 +#define TTF_F2DOT14_SIZE 2 + +#define ARG_1_AND_2_ARE_WORDS (1<<0) +#define ARGS_ARE_XY_VALUES (1<<1) +#define ROUND_XY_TO_GRID (1<<2) +#define WE_HAVE_A_SCALE (1<<3) +#define RESERVED (1<<4) +#define MORE_COMPONENTS (1<<5) +#define WE_HAVE_AN_X_AND_Y_SCALE (1<<6) +#define WE_HAVE_A_TWO_BY_TWO (1<<7) +#define WE_HAVE_INSTRUCTIONS (1<<8) +#define USE_MY_METRICS (1<<9) + +#define get_type(t) ((t)ttf_getnum(t##_SIZE)) +#define ttf_skip(n) ttf_getnum(n) + +#define get_byte() get_type(TTF_BYTE) +#define get_char() get_type(TTF_CHAR) +#define get_ushort() get_type(TTF_USHORT) +#define get_short() get_type(TTF_SHORT) +#define get_ulong() get_type(TTF_ULONG) +#define get_long() get_type(TTF_LONG) +#define get_fixed() get_type(TTF_FIXED) +#define get_funit() get_type(TTF_FUNIT) +#define get_fword() get_type(TTF_FWORD) +#define get_ufword() get_type(TTF_UFWORD) +#define get_f2dot14() get_type(TTF_F2DOT14) + +#define put_num(t,n) ((t)ttf_putnum(t##_SIZE, n)) + +#define put_char(n) put_num(TTF_CHAR, n) +#define put_byte(n) put_num(TTF_BYTE, n) +#define put_short(n) put_num(TTF_SHORT, n) +#define put_ushort(n) put_num(TTF_USHORT, n) +#define put_long(n) put_num(TTF_LONG, n) +#define put_ulong(n) put_num(TTF_ULONG, n) +#define put_fixed(n) put_num(TTF_FIXED, n) +#define put_funit(n) put_num(TTF_FUNIT, n) +#define put_fword(n) put_num(TTF_FWORD, n) +#define put_ufword(n) put_num(TTF_UFWORD, n) +#define put_f2dot14(n) put_num(TTF_F2DOT14, n) + +#define copy_byte() put_byte(get_byte()) +#define copy_char() put_char(get_char()) +#define copy_ushort() put_ushort(get_ushort()) +#define copy_short() put_short(get_short()) +#define copy_ulong() put_ulong(get_ulong()) +#define copy_long() put_long(get_long()) +#define copy_fixed() put_fixed(get_fixed()) +#define copy_funit() put_funit(get_funit()) +#define copy_fword() put_fword(get_fword()) +#define copy_ufword() put_ufword(get_ufword()) +#define copy_f2dot14() put_f2dot14(get_f2dot14()) + +#define is_unicode_mapping(e) \ + (e->platform_id == 0 || (e->platform_id == 3 || e->encoding_id == 1)) + + +#define NMACGLYPHS 258 +#define TABDIR_OFF 12 +#define ENC_BUF_SIZE 1024 + +#define GLYPH_PREFIX_INDEX "index" +#define GLYPH_PREFIX_UNICODE "uni" + +#define NOGLYPH_ASSIGNED_YET 0xFFFF /* indicating that no glyph is assigned to + an unicode */ +typedef struct { + char tag[4]; + TTF_ULONG checksum; + TTF_ULONG offset; + TTF_ULONG length; +} dirtab_entry; + +typedef struct { + TTF_USHORT platform_id; + TTF_USHORT encoding_id; + TTF_ULONG offset; + TTF_USHORT format; +} cmap_entry; + +typedef struct { + TTF_USHORT endCode; + TTF_USHORT startCode; + TTF_USHORT idDelta; + TTF_USHORT idRangeOffset; +} seg_entry; diff --git a/Build/source/texk/web2c/pdftexdir/writezip.c b/Build/source/texk/web2c/pdftexdir/writezip.c new file mode 100644 index 00000000000..3669397617c --- /dev/null +++ b/Build/source/texk/web2c/pdftexdir/writezip.c @@ -0,0 +1,82 @@ +/* +Copyright (c) 1996-2002 Han The Thanh, <thanh@pdftex.org> + +This file is part of pdfTeX. + +pdfTeX 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. + +pdfTeX 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with pdfTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/writezip.c#7 $ +*/ + +#include "ptexlib.h" +#include "zlib.h" + +static const char perforce_id[] = + "$Id: //depot/Build/source.development/TeX/texk/web2c/pdftexdir/writezip.c#7 $"; + +#define ZIP_BUF_SIZE 32768 + +#define check_err(f, fn) \ + if (f != Z_OK) \ + pdftex_fail("zlib: %s() failed", fn) + + +static char zipbuf[ZIP_BUF_SIZE]; +static z_stream c_stream; /* compression stream */ + +void writezip(boolean finish) +{ + int err; + + if (!getpdfcompresslevel()) { + if (pdfptr) { + pdfgone += xfwrite(pdfbuf, 1, pdfptr, pdffile); + pdfstreamlength += pdfptr; + } + return; + } + + cur_file_name = NULL; + if (pdfstreamlength == 0) { + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + check_err(deflateInit(&c_stream, getpdfcompresslevel()), "deflateInit"); + c_stream.next_out = (Bytef*)zipbuf; + c_stream.avail_out = ZIP_BUF_SIZE; + } + c_stream.next_in = pdfbuf; + c_stream.avail_in = pdfptr; + for(;;) { + if (c_stream.avail_out == 0) { + pdfgone += xfwrite(zipbuf, 1, ZIP_BUF_SIZE, pdffile); + c_stream.next_out = (Bytef*)zipbuf; + c_stream.avail_out = ZIP_BUF_SIZE; + } + err = deflate(&c_stream, finish ? Z_FINISH : Z_NO_FLUSH); + if (finish && err == Z_STREAM_END) + break; + check_err(err, "deflate"); + if (!finish && c_stream.avail_in == 0) + break; + } + if (finish) { + if (c_stream.avail_out < ZIP_BUF_SIZE) /* at least one byte has been output */ + pdfgone += xfwrite(zipbuf, 1, ZIP_BUF_SIZE - c_stream.avail_out, pdffile); + check_err(deflateEnd(&c_stream), "deflateEnd"); + xfflush(pdffile); + } + pdfstreamlength = c_stream.total_out; +} |