From 17aeed8e129118bdb3b7eb0ef3a18241dcda40eb Mon Sep 17 00:00:00 2001 From: Jonathan Kew Date: Wed, 21 Nov 2007 12:32:29 +0000 Subject: merged XeTeX 0.997 from SIL repository git-svn-id: svn://tug.org/texlive/trunk@5537 c570f23f-e606-0410-a88d-b1316a301751 --- Build/source/texk/web2c/lib/texmfmp.c | 25 +- Build/source/texk/web2c/texmfmp-help.h | 8 +- Build/source/texk/web2c/texmfmp.h | 22 + .../source/texk/web2c/xetexdir/FontTableCache.cpp | 18 +- Build/source/texk/web2c/xetexdir/FontTableCache.h | 5 +- Build/source/texk/web2c/xetexdir/MathTable.h | 6 + Build/source/texk/web2c/xetexdir/XeTeXFontInst.cpp | 5 + Build/source/texk/web2c/xetexdir/XeTeXFontInst.h | 3 + Build/source/texk/web2c/xetexdir/XeTeXFontMgr.cpp | 10 +- Build/source/texk/web2c/xetexdir/XeTeXGrLayout.cpp | 173 + Build/source/texk/web2c/xetexdir/XeTeXGrLayout.h | 198 + .../texk/web2c/xetexdir/XeTeXLayoutInterface.cpp | 411 +- .../texk/web2c/xetexdir/XeTeXLayoutInterface.h | 33 +- .../texk/web2c/xetexdir/XeTeXOTLayoutEngine.cpp | 211 +- .../texk/web2c/xetexdir/XeTeXOTLayoutEngine.h | 19 +- Build/source/texk/web2c/xetexdir/XeTeXOTMath.cpp | 65 +- Build/source/texk/web2c/xetexdir/XeTeXOTMath.h | 5 +- Build/source/texk/web2c/xetexdir/XeTeX_ext.c | 845 +- Build/source/texk/web2c/xetexdir/XeTeX_ext.h | 18 +- Build/source/texk/web2c/xetexdir/XeTeX_mac.c | 152 +- Build/source/texk/web2c/xetexdir/XeTeX_pic.c | 16 + Build/source/texk/web2c/xetexdir/jpegimage.c | 139 + Build/source/texk/web2c/xetexdir/jpegimage.h | 1 + Build/source/texk/web2c/xetexdir/pdfimage.cpp | 22 + Build/source/texk/web2c/xetexdir/pdfimage.h | 2 + Build/source/texk/web2c/xetexdir/pool2c.pl | 74 + Build/source/texk/web2c/xetexdir/trans.h | 36 +- .../texk/web2c/xetexdir/unicode-char-prep.pl | 228 +- Build/source/texk/web2c/xetexdir/xetex-new.ch | 6383 -------------- Build/source/texk/web2c/xetexdir/xetex-noenc.ch | 1144 --- Build/source/texk/web2c/xetexdir/xetex-otmath.ch | 667 -- Build/source/texk/web2c/xetexdir/xetex-upwards.ch | 244 - Build/source/texk/web2c/xetexdir/xetex.ch | 8938 ++++++++++++++++++++ Build/source/texk/web2c/xetexdir/xetex.defines | 21 +- Build/source/texk/web2c/xetexdir/xetex.h | 2 +- Build/source/texk/web2c/xetexdir/xetex.mk | 58 +- Build/source/texk/web2c/xetexdir/xetexextra.in | 2 +- Build/source/texk/xdv2pdf/xdv2pdf.cpp | 47 +- Build/source/texk/xdv2pdf/xdv2pdf_globals.h | 3 + Build/source/texk/xdv2pdf/xdv2pdf_specials.cpp | 80 +- 40 files changed, 11368 insertions(+), 8971 deletions(-) create mode 100644 Build/source/texk/web2c/xetexdir/XeTeXGrLayout.cpp create mode 100644 Build/source/texk/web2c/xetexdir/XeTeXGrLayout.h create mode 100644 Build/source/texk/web2c/xetexdir/pool2c.pl delete mode 100644 Build/source/texk/web2c/xetexdir/xetex-new.ch delete mode 100644 Build/source/texk/web2c/xetexdir/xetex-noenc.ch delete mode 100644 Build/source/texk/web2c/xetexdir/xetex-otmath.ch delete mode 100644 Build/source/texk/web2c/xetexdir/xetex-upwards.ch create mode 100644 Build/source/texk/web2c/xetexdir/xetex.ch diff --git a/Build/source/texk/web2c/lib/texmfmp.c b/Build/source/texk/web2c/lib/texmfmp.c index 09f5f095fae..8a2cc4896d9 100644 --- a/Build/source/texk/web2c/lib/texmfmp.c +++ b/Build/source/texk/web2c/lib/texmfmp.c @@ -401,14 +401,7 @@ topenin P1H(void) case 0: ; }; rval -= offsetsFromUTF8[extraBytes]; - /* now rval is a USV; if it's >=64K, we need to put surrogates in the buffer */ - if (rval > 0xFFFF) { - rval -= 0x10000; - buffer[k++] = 0xd800 + rval / 0x0400; - buffer[k++] = 0xdc00 + rval % 0x0400; - } - else - buffer[k++] = rval; + buffer[k++] = rval; } #else char *ptr = &(argv[i][0]); @@ -1810,13 +1803,21 @@ swap_items P3C(char *, p, int, nitems, int, size) OUT_FILE. */ void +#ifdef XeTeX +do_dump P4C(char *, p, int, item_size, int, nitems, gzFile, out_file) +#else do_dump P4C(char *, p, int, item_size, int, nitems, FILE *, out_file) +#endif { #if !defined (WORDS_BIGENDIAN) && !defined (NO_DUMP_SHARE) swap_items (p, nitems, item_size); #endif +#ifdef XeTeX + if (gzwrite (out_file, p, item_size * nitems) != item_size * nitems) +#else if (fwrite (p, item_size, nitems, out_file) != nitems) +#endif { fprintf (stderr, "! Could not write %d %d-byte item(s).\n", nitems, item_size); @@ -1834,9 +1835,17 @@ do_dump P4C(char *, p, int, item_size, int, nitems, FILE *, out_file) /* Here is the dual of the writing routine. */ void +#ifdef XeTeX +do_undump P4C(char *, p, int, item_size, int, nitems, gzFile, in_file) +#else do_undump P4C(char *, p, int, item_size, int, nitems, FILE *, in_file) +#endif { +#ifdef XeTeX + if (gzread (in_file, p, item_size * nitems) != item_size * nitems) +#else if (fread (p, item_size, nitems, in_file) != nitems) +#endif FATAL2 ("Could not undump %d %d-byte item(s)", nitems, item_size); #if !defined (WORDS_BIGENDIAN) && !defined (NO_DUMP_SHARE) diff --git a/Build/source/texk/web2c/texmfmp-help.h b/Build/source/texk/web2c/texmfmp-help.h index c21afa2796b..93737b9af5e 100644 --- a/Build/source/texk/web2c/texmfmp-help.h +++ b/Build/source/texk/web2c/texmfmp-help.h @@ -427,13 +427,7 @@ const_string XETEXHELP[] = { "-mltex enable MLTeX extensions such as \\charsubdef", "-output-comment=STRING use STRING for XDV file comment instead of date", "-output-directory=DIR use DIR as the directory to write files to", - "-output-driver=CMD use CMD as the XDV-to-PDF driver instead of " -#ifdef XETEX_MAC - "xdv2pdf" -#else - "xdvipdfmx" -#endif - , + "-output-driver=CMD use CMD as the XDV-to-PDF driver instead of xdvipdfmx", "-no-pdf generate XDV (extended DVI) output rather than PDF", "[-no]-parse-first-line disable/enable parsing of the first line of the", " input file", diff --git a/Build/source/texk/web2c/texmfmp.h b/Build/source/texk/web2c/texmfmp.h index ba778ccc3a8..edf01750e73 100644 --- a/Build/source/texk/web2c/texmfmp.h +++ b/Build/source/texk/web2c/texmfmp.h @@ -6,6 +6,10 @@ #include /* for IS_DIR_SEP, used in the change files */ #include /* for kpse_make_tex_discard_errors */ +#ifdef XeTeX +#include +#endif + #ifdef XeTeX /* added typedefs for unicodefile and voidpointer */ #define XETEX_UNICODE_FILE_DEFINED 1 @@ -217,9 +221,22 @@ extern void setupboundvariable P3H(integer *, const_string, integer); #define ofmopenin(f) open_input (&(f), kpse_ofm_format, FOPEN_RBIN_MODE) #define bopenout(f) open_output (&(f), FOPEN_WBIN_MODE) #define bclose aclose +#ifdef XeTeX +/* f is declared as gzFile (typedef'd as void *), but we temporarily + use it for a FILE * so that we can use the standard open calls */ +#define wopenin(f) (open_input ((FILE**)&(f), DUMP_FORMAT, FOPEN_RBIN_MODE) \ + && (f = gzdopen(fileno((FILE*)f), FOPEN_RBIN_MODE))) +#define wopenout(f) (open_output ((FILE**)&(f), FOPEN_WBIN_MODE) \ + && (f = gzdopen(fileno((FILE*)f), FOPEN_WBIN_MODE)) \ + && (gzsetparams(f, 1, Z_DEFAULT_STRATEGY) == Z_OK)) +#define wclose(f) gzclose(f) +#define weof(f) gzeof(f) +#else #define wopenin(f) open_input (&(f), DUMP_FORMAT, FOPEN_RBIN_MODE) #define wopenout bopenout #define wclose aclose +#endif + #ifdef XeTeX #define uopenin(f,p,m,d) u_open_in(&(f), p, FOPEN_RBIN_MODE, m, d) #endif @@ -286,8 +303,13 @@ extern void paintrow (/*screenrow, pixelcolor, transspec, screencol*/); } while (0) /* We define the routines to do the actual work in texmf.c. */ +#ifdef XeTeX +extern void do_dump P4H(char *, int, int, gzFile); +extern void do_undump P4H(char *, int, int, gzFile); +#else extern void do_dump P4H(char *, int, int, FILE *); extern void do_undump P4H(char *, int, int, FILE *); +#endif /* Use the above for all the other dumping and undumping. */ #define generic_dump(x) dumpthings (x, 1) diff --git a/Build/source/texk/web2c/xetexdir/FontTableCache.cpp b/Build/source/texk/web2c/xetexdir/FontTableCache.cpp index af5cd710a00..1e2a6c4237b 100644 --- a/Build/source/texk/web2c/xetexdir/FontTableCache.cpp +++ b/Build/source/texk/web2c/xetexdir/FontTableCache.cpp @@ -48,6 +48,7 @@ struct FontTableCacheEntry { LETag tag; const void *table; + le_uint32 size; }; FontTableCache::FontTableCache() @@ -69,6 +70,7 @@ FontTableCache::initialize() for (int i = 0; i < fTableCacheSize; i += 1) { fTableCache[i].tag = 0; fTableCache[i].table = NULL; + fTableCache[i].size = 0; } } @@ -84,27 +86,33 @@ void FontTableCache::dispose() fTableCache[i].tag = 0; fTableCache[i].table = NULL; + fTableCache[i].size = 0; } fTableCacheCurr = 0; } -const void *FontTableCache::find(LETag tableTag) const +const void *FontTableCache::find(LETag tableTag, le_uint32 *tableSize) const { for (int i = 0; i < fTableCacheCurr; i += 1) { if (fTableCache[i].tag == tableTag) { + if (tableSize != NULL) + *tableSize = fTableCache[i].size; return fTableCache[i].table; } } - const void *table = readFontTable(tableTag); + le_uint32 length; + const void *table = readFontTable(tableTag, length); - ((FontTableCache *) this)->add(tableTag, table); + ((FontTableCache *) this)->add(tableTag, table, length); + if (tableSize != NULL) + *tableSize = length; return table; } -void FontTableCache::add(LETag tableTag, const void *table) +void FontTableCache::add(LETag tableTag, const void *table, le_uint32 length) { if (fTableCacheCurr >= fTableCacheSize) { le_int32 newSize = fTableCacheSize + TABLE_CACHE_GROW; @@ -114,6 +122,7 @@ void FontTableCache::add(LETag tableTag, const void *table) for (le_int32 i = fTableCacheSize; i < newSize; i += 1) { fTableCache[i].tag = 0; fTableCache[i].table = NULL; + fTableCache[i].size = 0; } fTableCacheSize = newSize; @@ -121,6 +130,7 @@ void FontTableCache::add(LETag tableTag, const void *table) fTableCache[fTableCacheCurr].tag = tableTag; fTableCache[fTableCacheCurr].table = table; + fTableCache[fTableCacheCurr].size = length; fTableCacheCurr += 1; } diff --git a/Build/source/texk/web2c/xetexdir/FontTableCache.h b/Build/source/texk/web2c/xetexdir/FontTableCache.h index 03d71ac7110..a7525637b69 100644 --- a/Build/source/texk/web2c/xetexdir/FontTableCache.h +++ b/Build/source/texk/web2c/xetexdir/FontTableCache.h @@ -51,19 +51,20 @@ public: virtual ~FontTableCache(); - const void *find(LETag tableTag) const; + const void *find(LETag tableTag, le_uint32 *tableSize = NULL) const; void flush(); protected: virtual const void *readFontTable(LETag tableTag) const = 0; + virtual const void *readFontTable(LETag tableTag, le_uint32 &length) const = 0; private: void initialize(); void dispose(); - void add(LETag tableTag, const void *table); + void add(LETag tableTag, const void *table, le_uint32 length); FontTableCacheEntry *fTableCache; le_int32 fTableCacheCurr; diff --git a/Build/source/texk/web2c/xetexdir/MathTable.h b/Build/source/texk/web2c/xetexdir/MathTable.h index 1c27a67fee0..61642e34fe6 100644 --- a/Build/source/texk/web2c/xetexdir/MathTable.h +++ b/Build/source/texk/web2c/xetexdir/MathTable.h @@ -216,4 +216,10 @@ typedef struct { MathValueRecord italicsCorrection[ANY_NUMBER]; } MathItalicsCorrectionInfo; +typedef struct { + le_uint16 coverage; + le_uint16 topAccentAttachmentCount; + MathValueRecord topAccentAttachment[ANY_NUMBER]; +} MathTopAccentAttachment; + #endif diff --git a/Build/source/texk/web2c/xetexdir/XeTeXFontInst.cpp b/Build/source/texk/web2c/xetexdir/XeTeXFontInst.cpp index fc21a6837a0..90f3a197fb0 100644 --- a/Build/source/texk/web2c/xetexdir/XeTeXFontInst.cpp +++ b/Build/source/texk/web2c/xetexdir/XeTeXFontInst.cpp @@ -166,6 +166,11 @@ const void *XeTeXFontInst::getFontTable(LETag tableTag) const return FontTableCache::find(tableTag); } +const void *XeTeXFontInst::getFontTable(LETag tableTag, le_uint32 *length) const +{ + return FontTableCache::find(tableTag, length); +} + const void *XeTeXFontInst::readFontTable(LETag tableTag) const { le_uint32 len; diff --git a/Build/source/texk/web2c/xetexdir/XeTeXFontInst.h b/Build/source/texk/web2c/xetexdir/XeTeXFontInst.h index b20f6d5ab40..7ebfe080c1c 100644 --- a/Build/source/texk/web2c/xetexdir/XeTeXFontInst.h +++ b/Build/source/texk/web2c/xetexdir/XeTeXFontInst.h @@ -63,6 +63,8 @@ extern "C" { class XeTeXFontInst : public LEFontInstance, protected FontTableCache { +friend class XeTeXGrFont; + protected: float fPointSize; @@ -108,6 +110,7 @@ public: virtual void initialize(LEErrorCode &status); virtual const void *getFontTable(LETag tableTag) const; + virtual const void *getFontTable(LETag tableTag, le_uint32* length) const; virtual const char *getFilename() const { diff --git a/Build/source/texk/web2c/xetexdir/XeTeXFontMgr.cpp b/Build/source/texk/web2c/xetexdir/XeTeXFontMgr.cpp index 62c787da5bb..15c6a600c79 100644 --- a/Build/source/texk/web2c/xetexdir/XeTeXFontMgr.cpp +++ b/Build/source/texk/web2c/xetexdir/XeTeXFontMgr.cpp @@ -212,7 +212,7 @@ XeTeXFontMgr::findFont(const char* name, char* variant, double ptSize) varString.append("USP"); goto skip_to_slash; } - if (strncmp(cp, "PAN", 5) == 0) { + if (strncmp(cp, "PAN", 3) == 0) { sReqEngine = 'P'; cp += 3; if (varString.length() > 0 && *(varString.end() - 1) != '/') @@ -220,15 +220,15 @@ XeTeXFontMgr::findFont(const char* name, char* variant, double ptSize) varString.append("PAN"); goto skip_to_slash; } - if (strncmp(cp, "GRA", 8) == 0) { +*/ + if (strncmp(cp, "GR", 2) == 0) { sReqEngine = 'G'; - cp += 3; + cp += 2; if (varString.length() > 0 && *(varString.end() - 1) != '/') varString.append("/"); - varString.append("GRA"); + varString.append("GR"); goto skip_to_slash; } -*/ if (*cp == 'S') { char* start = cp; ++cp; diff --git a/Build/source/texk/web2c/xetexdir/XeTeXGrLayout.cpp b/Build/source/texk/web2c/xetexdir/XeTeXGrLayout.cpp new file mode 100644 index 00000000000..ab0124a820d --- /dev/null +++ b/Build/source/texk/web2c/xetexdir/XeTeXGrLayout.cpp @@ -0,0 +1,173 @@ +/****************************************************************************\ + Part of the XeTeX typesetting system + copyright (c) 1994-2007 by SIL International + written by Jonathan Kew + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL SIL INTERNATIONAL BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of SIL International +shall not be used in advertising or otherwise to promote the sale, +use or other dealings in this Software without prior written +authorization from SIL International. +\****************************************************************************/ + +#include "XeTeX_ext.h" +#include "XeTeXswap.h" + +#include "XeTeXGrLayout.h" + + +/* XeTeXGrFont class */ + +XeTeXGrFont::XeTeXGrFont(const XeTeXFontInst* inFont, const char* name) + : Font() + , fXeTeXFont(inFont) + , fName(NULL) +{ + fName = strdup(name); + gr::Font::SetFlushMode(gr::kflushManual); +} + +XeTeXGrFont::XeTeXGrFont(const XeTeXGrFont& orig) + : Font(orig) + , fXeTeXFont(orig.fXeTeXFont) + , fName(NULL) +{ + fName = strdup(orig.fName); +} + +XeTeXGrFont::~XeTeXGrFont() +{ + delete[] fName; +} + +XeTeXGrFont * +XeTeXGrFont::copyThis() +{ + XeTeXGrFont* rval = new XeTeXGrFont(*this); + return rval; +} + +void +XeTeXGrFont::UniqueCacheInfo(std::wstring & stuFace, bool & fBold, bool & fItalic) +{ + int len = strlen(fName); + wchar_t* wname = new wchar_t[len + 1]; + mbstowcs(wname, fName, len); + stuFace.assign(wname, wcslen(wname)); + delete[] wname; + + fBold = false; + fItalic = false; +} + +const void * +XeTeXGrFont::getTable(gr::fontTableId32 tableID, size_t * pcbSize) +{ + le_uint32 length; + LETag tag = tableID; + const void *rval = fXeTeXFont->getFontTable(tag, &length); + *pcbSize = length; + return rval; +} + +void +XeTeXGrFont::getFontMetrics(float * pAscent, float * pDescent, float * pEmSquare) +{ + if (pAscent) + *pAscent = fXeTeXFont->getExactAscent(); + if (pDescent) + *pDescent = - fXeTeXFont->getExactDescent(); + if (pEmSquare) + *pEmSquare = fXeTeXFont->getXPixelsPerEm(); +} + + +/* XeTeXGrTextSource class */ + +void +XeTeXGrTextSource::setText(const UniChar* iText, size_t iLen) +{ + fTextBuffer = iText; + fTextLength = iLen; +} + +void +XeTeXGrTextSource::setFeatures(int nFeatures, const int* featureIDs, const int* featureValues) +{ + if (fFeatureSettings != NULL) + delete[] fFeatureSettings; + + fNumFeatures = nFeatures; + if (nFeatures == 0) + fFeatureSettings = NULL; + else { + gr::FeatureSetting* newFeatures = new gr::FeatureSetting[nFeatures]; + for (int i = 0; i < nFeatures; ++i) { + newFeatures[i].id = featureIDs[i]; + newFeatures[i].value = featureValues[i]; + } + fFeatureSettings = newFeatures; + } +} + +void +XeTeXGrTextSource::setFeatures(int nFeatures, const gr::FeatureSetting* features) +{ + if (fFeatureSettings != NULL) + delete[] fFeatureSettings; + + fNumFeatures = nFeatures; + if (nFeatures == 0) + fFeatureSettings = NULL; + else { + gr::FeatureSetting* newFeatures = new gr::FeatureSetting[nFeatures]; + for (int i = 0; i < nFeatures; ++i) + newFeatures[i] = features[i]; + fFeatureSettings = newFeatures; + } +} + +void +XeTeXGrTextSource::setLanguage(UInt32 iLanguage) +{ + fLanguage.rgch[0] = (iLanguage >> 24) & 0xff; + fLanguage.rgch[1] = (iLanguage >> 16) & 0xff; + fLanguage.rgch[2] = (iLanguage >> 8) & 0xff; + fLanguage.rgch[3] = iLanguage & 0xff; +} + +size_t +XeTeXGrTextSource::fetch(gr::toffset startChar, size_t n, gr::utf16* buffer) +{ + for (size_t i = 0; i < n; ++i) + buffer[i] = fTextBuffer[i]; + return n; +} + +size_t +XeTeXGrTextSource::getFontFeatures(gr::toffset charIndex, gr::FeatureSetting properties[64]) +{ + for (int i = 0; i < fNumFeatures; ++i) + properties[i] = fFeatureSettings[i]; + return fNumFeatures; +} + +const gr::isocode XeTeXGrTextSource::kUnknownLanguage = { 0, 0, 0, 0 }; diff --git a/Build/source/texk/web2c/xetexdir/XeTeXGrLayout.h b/Build/source/texk/web2c/xetexdir/XeTeXGrLayout.h new file mode 100644 index 00000000000..8800fbdef80 --- /dev/null +++ b/Build/source/texk/web2c/xetexdir/XeTeXGrLayout.h @@ -0,0 +1,198 @@ +/****************************************************************************\ + Part of the XeTeX typesetting system + copyright (c) 1994-2007 by SIL International + written by Jonathan Kew + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL SIL INTERNATIONAL BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of SIL International +shall not be used in advertising or otherwise to promote the sale, +use or other dealings in this Software without prior written +authorization from SIL International. +\****************************************************************************/ + +#ifndef __XETEX_GR_LAYOUT__ +#define __XETEX_GR_LAYOUT__ + +#include "XeTeXFontInst.h" + +#include "graphite/GrClient.h" + +#include "graphite/Font.h" +#include "graphite/Segment.h" +#include "graphite/ITextSource.h" + +class XeTeXGrFont + : public gr::Font +{ +public: + XeTeXGrFont(const XeTeXFontInst* inFont, const char* name); + XeTeXGrFont(const XeTeXGrFont& orig); + + virtual ~XeTeXGrFont(); + + /** + * Returns a copy of the recipient. Specifically needed to store the + * Font in a segment. + * @internal + * @return pointer to copy + */ + virtual XeTeXGrFont * copyThis(); + + /** + * Return wether the font is bold. + * @return true when bold + */ + virtual bool bold() { return false; } + + /** + * Return wether the font is italic. + * @return true when italic + */ + virtual bool italic() { return false; } + + /** + * Returns the font ascent. + * Value is the same as that returned by getFontMetrics() + * @return the font ascent in device co-ordinates + */ + virtual float ascent() { return fXeTeXFont->getExactAscent(); } + + /** + * Returns the font descent. + * Value is the same as that returned by getFontMetrics() + * @return the font descent in device co-ordinates + */ + virtual float descent() { return - fXeTeXFont->getExactDescent(); } + + /** + * Returns the total height of the font. + * @return font height in device co-ordinates + */ + virtual float height() { return ascent() + descent(); } + + /** + * Returns the x and y resolution of the device co-ordinate space. + */ + virtual unsigned int getDPIx() { return 72; } /* I think this is irrelevant in XeTeX */ + virtual unsigned int getDPIy() { return 72; } + + /** + * Returns a pointer to the start of a table in the font. + * If the Font class cannot easily determine the length of the table, + * it may set 0 as the length (while returning a non-NULL pointer to + * the table). This means that certain kinds of error checking cannot + * be done by the Graphite engine. + * Throws an exception if there is some other error in reading the + * table, or if the table asked for is not in the font. + * @param tableID the TTF ID of the table. + * @param pcbSize pointer to a size_t to hold the table size. + * @return address of the buffer containing the table or 0 + */ + virtual const void * getTable(gr::fontTableId32 tableID, size_t * pcbSize); + + /** + * Fetches the basic metrics of the font in device co-ordinates + * (normaly pixels). + * @param pAscent pointer to hold font ascent. + * @param pDescent pointer to hold font descent. + * @param pEmSquare pointer to hold font EM square. + */ + virtual void getFontMetrics(float * pAscent, float * pDescent = NULL, float * pEmSquare = NULL); + +protected: + virtual void UniqueCacheInfo(std::wstring & stuFace, bool & fBold, bool & fItalic); + + const XeTeXFontInst* fXeTeXFont; + const char* fName; +}; + +class XeTeXGrTextSource + : public gr::ITextSource +{ +public: + XeTeXGrTextSource(int dirLevel, const UniChar* iText = NULL, size_t iLen = 0) + : fDirLevel(dirLevel) + , fTextBuffer(iText) + , fTextLength(iLen) + , fLanguage(kUnknownLanguage) + , fNumFeatures(0) + , fFeatureSettings(NULL) + { } + + virtual ~XeTeXGrTextSource() + { } + + void setText(const UniChar* iText, size_t iLen); + + void setFeatures(int nFeatures, const int* featureIDs, const int* featureValues); + void setFeatures(int nFeatures, const gr::FeatureSetting* features); + + void setLanguage(gr::isocode iLanguage) + { fLanguage = iLanguage; } + + void setLanguage(UInt32 iLanguage); + + virtual gr::UtfType utfEncodingForm() + { return gr::kutf16; } + + virtual size_t fetch(gr::toffset startChar, size_t n, gr::utf32* buffer) + { throw; } + + virtual size_t fetch(gr::toffset startChar, size_t n, gr::utf8* buffer) + { throw; } + + virtual size_t fetch(gr::toffset startChar, size_t n, gr::utf16* buffer); + + virtual size_t getLength() + { return fTextLength; } + + virtual std::pair propertyRange(gr::toffset charIndex) + { return std::pair(0, fTextLength); } + + virtual bool sameSegment(gr::toffset firstChar, gr::toffset secondChar) + { return true; } + + virtual bool getRightToLeft(gr::toffset charIndex) + { return (fDirLevel & 1) != 0; } + + virtual unsigned int getDirectionDepth(gr::toffset charIndex) + { return fDirLevel; } + + virtual float getVerticalOffset(gr::toffset charIndex) + { return 0.0; } + + virtual gr::isocode getLanguage(gr::toffset charIndex) + { return fLanguage; } + + virtual size_t getFontFeatures(gr::toffset charIndex, gr::FeatureSetting properties[64]); + +protected: + int fDirLevel; + const UInt16* fTextBuffer; + size_t fTextLength; + gr::isocode fLanguage; + size_t fNumFeatures; + const gr::FeatureSetting* fFeatureSettings; + + static const gr::isocode kUnknownLanguage; +}; + +#endif /* __XETEX_GR_LAYOUT__ */ diff --git a/Build/source/texk/web2c/xetexdir/XeTeXLayoutInterface.cpp b/Build/source/texk/web2c/xetexdir/XeTeXLayoutInterface.cpp index a591d7a05a4..f093950bd9a 100644 --- a/Build/source/texk/web2c/xetexdir/XeTeXLayoutInterface.cpp +++ b/Build/source/texk/web2c/xetexdir/XeTeXLayoutInterface.cpp @@ -41,14 +41,20 @@ authorization from SIL International. #include "XeTeXswap.h" +#include "XeTeXGrLayout.h" + #include "Features.h" #include "ScriptAndLanguage.h" #include "unicode/ubidi.h" +#include "unicode/utext.h" #include struct XeTeXLayoutEngine_rec + /* this is used for both ICU and Graphite, because so much of the font stuff is common; + however, it is not possible to call ICU-specific things like layoutChars for a + Graphite-based engine, or Graphite functions for an ICU one! */ { LayoutEngine* layoutEngine; XeTeXFontInst* font; @@ -58,6 +64,11 @@ struct XeTeXLayoutEngine_rec UInt32* addedFeatures; UInt32* removedFeatures; UInt32 rgbValue; + float extend; + float slant; + gr::Segment* grSegment; + XeTeXGrFont* grFont; + XeTeXGrTextSource* grSource; }; /*******************************************************************/ @@ -314,6 +325,175 @@ UInt32 getIndFeature(XeTeXFont font, UInt32 script, UInt32 language, UInt32 inde return 0; } +UInt32 countGraphiteFeatures(XeTeXLayoutEngine engine) +{ + std::pair fi = engine->grFont->getFeatures(); + UInt32 rval = 0; + while (fi.first != fi.second) { + ++rval; + ++fi.first; + } + return rval; +} + +UInt32 getGraphiteFeatureCode(XeTeXLayoutEngine engine, UInt32 index) +{ + std::pair fi = engine->grFont->getFeatures(); + while (index > 0 && fi.first != fi.second) { + --index; + ++fi.first; + } + if (fi.first != fi.second) + return *fi.first; + return 0; +} + +UInt32 countGraphiteFeatureSettings(XeTeXLayoutEngine engine, UInt32 feature) +{ + std::pair fi = engine->grFont->getFeatures(); + while (fi.first != fi.second && *fi.first != feature) + ++fi.first; + if (fi.first != fi.second) { + std::pair + si = engine->grFont->getFeatureSettings(fi.first); + UInt32 rval = 0; + while (si.first != si.second) { + ++rval; + ++si.first; + } + return rval; + } + return 0; +} + +UInt32 getGraphiteFeatureSettingCode(XeTeXLayoutEngine engine, UInt32 feature, UInt32 index) +{ + std::pair fi = engine->grFont->getFeatures(); + while (fi.first != fi.second && *fi.first != feature) + ++fi.first; + if (fi.first != fi.second) { + std::pair + si = engine->grFont->getFeatureSettings(fi.first); + while (index > 0 && si.first != si.second) { + --index; + ++si.first; + } + if (si.first != si.second) + return *si.first; + } + return 0; +} + +UInt32 getGraphiteFeatureDefaultSetting(XeTeXLayoutEngine engine, UInt32 feature) +{ + std::pair fi = engine->grFont->getFeatures(); + while (fi.first != fi.second && *fi.first != feature) + ++fi.first; + if (fi.first != fi.second) { + gr::FeatureSettingIterator si = engine->grFont->getDefaultFeatureValue(fi.first); + return *si; + } + return 0; +} + +void getGraphiteFeatureLabel(XeTeXLayoutEngine engine, UInt32 feature, unsigned short* buf) +{ + buf[0] = 0; + std::pair fi = engine->grFont->getFeatures(); + while (fi.first != fi.second && *fi.first != feature) + ++fi.first; + if (fi.first != fi.second) { + engine->grFont->getFeatureLabel(fi.first, 0x0409, buf); + } +} + +void getGraphiteFeatureSettingLabel(XeTeXLayoutEngine engine, UInt32 feature, UInt32 setting, unsigned short* buf) +{ + buf[0] = 0; + std::pair fi = engine->grFont->getFeatures(); + while (fi.first != fi.second && *fi.first != feature) + ++fi.first; + if (fi.first != fi.second) { + std::pair + si = engine->grFont->getFeatureSettings(fi.first); + while (si.first != si.second && *si.first != setting) + ++si.first; + if (si.first != si.second) { + engine->grFont->getFeatureSettingLabel(si.first, 0x0409, buf); + } + } +} + +long findGraphiteFeatureNamed(XeTeXLayoutEngine engine, const char* name, int namelength) +{ + long rval = -1; + UErrorCode status = (UErrorCode)0; + + std::pair features = engine->grFont->getFeatures(); + while (features.first != features.second) { + gr::utf16 label[128]; + if (engine->grFont->getFeatureLabel(features.first, 0x409, &label[0])) { + UText* ut1 = utext_openUTF8(NULL, name, namelength, &status); + UText* ut2 = utext_openUChars(NULL, &label[0], -1, &status); + UChar32 ch1 = 0, ch2 = 0; + while (ch1 != U_SENTINEL) { + ch1 = utext_next32(ut1); + ch2 = utext_next32(ut2); + if (ch1 != ch2) + break; + } + ut1 = utext_close(ut1); + ut2 = utext_close(ut2); + if (ch1 == ch2) { + rval = *features.first; + break; + } + } + ++features.first; + } + + return rval; +} + +long findGraphiteFeatureSettingNamed(XeTeXLayoutEngine engine, UInt32 feature, const char* name, int namelength) +{ + long rval = -1; + UErrorCode status = (UErrorCode)0; + + std::pair features = engine->grFont->getFeatures(); + while (features.first != features.second) { + if (*features.first == feature) { + std::pair + settings = engine->grFont->getFeatureSettings(features.first); + while (settings.first != settings.second) { + gr::utf16 label[128]; + if (engine->grFont->getFeatureSettingLabel(settings.first, 0x409, &label[0])) { + UText* ut1 = utext_openUTF8(NULL, name, namelength, &status); + UText* ut2 = utext_openUChars(NULL, &label[0], -1, &status); + UChar32 ch1 = 0, ch2 = 0; + while (ch1 != U_SENTINEL) { + ch1 = utext_next32(ut1); + ch2 = utext_next32(ut2); + if (ch1 != ch2) + break; + } + ut1 = utext_close(ut1); + ut2 = utext_close(ut2); + if (ch1 == ch2) { + rval = *settings.first; + break; + } + } + ++settings.first; + } + break; + } + } + + return rval; + +} + float getGlyphWidth(XeTeXFont font, UInt32 gid) { LEPoint adv; @@ -332,8 +512,19 @@ XeTeXFont getFont(XeTeXLayoutEngine engine) return (XeTeXFont)(engine->font); } +float getExtendFactor(XeTeXLayoutEngine engine) +{ + return engine->extend; +} + +float getSlantFactor(XeTeXLayoutEngine engine) +{ + return engine->slant; +} + XeTeXLayoutEngine createLayoutEngine(PlatformFontRef fontRef, XeTeXFont font, UInt32 scriptTag, UInt32 languageTag, - UInt32* addFeatures, SInt32* addParams, UInt32* removeFeatures, UInt32 rgbValue) + UInt32* addFeatures, SInt32* addParams, UInt32* removeFeatures, UInt32 rgbValue, + float extend, float slant) { LEErrorCode status = LE_NO_ERROR; XeTeXLayoutEngine result = new XeTeXLayoutEngine_rec; @@ -344,6 +535,13 @@ XeTeXLayoutEngine createLayoutEngine(PlatformFontRef fontRef, XeTeXFont font, UI result->addedFeatures = addFeatures; result->removedFeatures = removeFeatures; result->rgbValue = rgbValue; + result->extend = extend; + result->slant = slant; + + result->grSegment = NULL; + result->grSource = NULL; + result->grFont = NULL; + result->layoutEngine = XeTeXOTLayoutEngine::LayoutEngineFactory((XeTeXFontInst*)font, scriptTag, languageTag, (LETag*)addFeatures, (le_int32*)addParams, (LETag*)removeFeatures, status); if (LE_FAILURE(status) || result->layoutEngine == NULL) { @@ -358,6 +556,9 @@ void deleteLayoutEngine(XeTeXLayoutEngine engine) { delete engine->layoutEngine; delete engine->font; + delete engine->grSegment; + delete engine->grSource; + delete engine->grFont; } SInt32 layoutChars(XeTeXLayoutEngine engine, UInt16 chars[], SInt32 offset, SInt32 count, SInt32 max, @@ -381,6 +582,11 @@ void getGlyphPositions(XeTeXLayoutEngine engine, float positions[], SInt32* stat { LEErrorCode success = (LEErrorCode)*status; engine->layoutEngine->getGlyphPositions(positions, success); + + if (engine->extend != 1.0 || engine->slant != 0.0) + for (int i = 0; i <= engine->layoutEngine->getGlyphCount(); ++i) + positions[2*i] = positions[2*i] * engine->extend - positions[2*i+1] * engine->slant; + *status = success; } @@ -388,6 +594,10 @@ void getGlyphPosition(XeTeXLayoutEngine engine, SInt32 index, float* x, float* y { LEErrorCode success = (LEErrorCode)*status; engine->layoutEngine->getGlyphPosition(index, *x, *y, success); + + if (engine->extend != 1.0 || engine->slant != 0.0) + *x = *x * engine->extend - *y * engine->slant; + *status = success; } @@ -664,3 +874,202 @@ GetFontCharRange_AAT(ATSUStyle style, int reqFirst) } } #endif + +/* Graphite interface */ + +gr::LayoutEnvironment layoutEnv; + +XeTeXLayoutEngine createGraphiteEngine(PlatformFontRef fontRef, XeTeXFont font, + const char* name, + UInt32 rgbValue, int rtl, UInt32 languageTag, + float extend, float slant, + int nFeatures, const int* featureIDs, const int* featureValues) +{ + // check if the font supports graphite, and return NULL if not + const UInt32 kttiSilf = 0x53696C66; // from GrConstants.h + if (getFontTablePtr(font, kttiSilf) == NULL) + return NULL; + + XeTeXLayoutEngine result = new XeTeXLayoutEngine_rec; + result->fontRef = fontRef; + result->font = (XeTeXFontInst*)font; + result->scriptTag = 0; + result->languageTag = languageTag; + result->addedFeatures = NULL; + result->removedFeatures = NULL; + result->rgbValue = rgbValue; + result->extend = extend; + result->slant = slant; + result->layoutEngine = NULL; + + result->grFont = new XeTeXGrFont(result->font, name); + + result->grSource = new XeTeXGrTextSource(rtl); + result->grSource->setFeatures(nFeatures, featureIDs, featureValues); + if (languageTag != 0) + result->grSource->setLanguage(languageTag); + + result->grSegment = NULL; + + layoutEnv.setDumbFallback(true); + + return result; +} + +int +makeGraphiteSegment(XeTeXLayoutEngine engine, const UniChar* txtPtr, int txtLen) +{ + if (engine->grSegment) { + delete engine->grSegment; + engine->grSegment = NULL; + } + + engine->grSource->setText(txtPtr, txtLen); + try { + engine->grSegment = new gr::RangeSegment(engine->grFont, engine->grSource, &layoutEnv); + } + catch (gr::FontException f) { + fprintf(stderr, "*** makeGraphiteSegment: font error %d, returning 0\n", (int)f.errorCode); + return 0; + } + catch (...) { + fprintf(stderr, "*** makeGraphiteSegment: segment creation failed, returning 0\n"); + return 0; + } + + return engine->grSegment->glyphs().second - engine->grSegment->glyphs().first; +} + +void +getGraphiteGlyphInfo(XeTeXLayoutEngine engine, int index, UInt16* glyphID, float* x, float* y) +{ + if (engine->grSegment == NULL) { + *glyphID = 0; + *x = *y = 0.0; + return; + } + gr::GlyphIterator i = engine->grSegment->glyphs().first + index; + *glyphID = i->glyphID(); + if (engine->extend != 1.0 || engine->slant != 0.0) + *x = i->origin() * engine->extend + i->yOffset() * engine->slant; + else + *x = i->origin(); + *y = - i->yOffset(); +} + +float +graphiteSegmentWidth(XeTeXLayoutEngine engine) +{ + if (engine->grSegment == NULL) + return 0.0; + //return engine->grSegment->advanceWidth(); // can't use this because it ignores trailing WS + try { + return engine->extend * engine->grSegment->getRangeWidth(0, engine->grSource->getLength(), false, false, false); + } + catch (gr::FontException f) { + fprintf(stderr, "*** graphiteSegmentWidth: font error %d, returning 0.0\n", (int)f.errorCode); + return 0.0; + } + catch (...) { + fprintf(stderr, "*** graphiteSegmentWidth: getRangeWidth failed, returning 0.0\n"); + return 0.0; + } +} + +/* line-breaking uses its own private textsource and segment, not the engine's ones */ +static XeTeXGrTextSource* lbSource = NULL; +static gr::Segment* lbSegment = NULL; +static XeTeXLayoutEngine lbEngine = NULL; + +void +initGraphiteBreaking(XeTeXLayoutEngine engine, const UniChar* txtPtr, int txtLen) +{ + if (lbSource == NULL) + lbSource = new XeTeXGrTextSource(0); + + if (lbSegment != NULL) { + delete lbSegment; + lbSegment = NULL; + } + + lbSource->setText(txtPtr, txtLen); + + if (lbEngine != engine) { + gr::FeatureSetting features[64]; + size_t nFeatures = engine->grSource->getFontFeatures(0, features); + lbSource->setFeatures(nFeatures, &features[0]); + lbEngine = engine; + } + + try { + lbSegment = new gr::RangeSegment(engine->grFont, lbSource, &layoutEnv); + } + catch (gr::FontException f) { + fprintf(stderr, "*** initGraphiteBreaking: font error %d\n", (int)f.errorCode); + } + catch (...) { + fprintf(stderr, "*** initGraphiteBreaking: segment creation failed\n"); + } +} + +int +findNextGraphiteBreak(int iOffset, int iBrkVal) +{ + if (lbSegment == NULL) + return -1; + if (iOffset < lbSource->getLength()) { + while (++iOffset < lbSource->getLength()) { + const gr::GlyphSetIterator& gsi = lbSegment->charToGlyphs(iOffset).first; + if (gsi == lbSegment->charToGlyphs(iOffset).second) + continue; + if (gsi->breakweight() < gr::klbNoBreak && gsi->breakweight() >= -(gr::LineBrk)iBrkVal) + return iOffset; + if (gsi->breakweight() > gr::klbNoBreak && gsi->breakweight() <= (gr::LineBrk)iBrkVal) + return iOffset + 1; + } + return lbSource->getLength(); + } + else + return -1; +} + + +int usingOpenType(XeTeXLayoutEngine engine) +{ + return engine->layoutEngine != NULL; +} + +int usingGraphite(XeTeXLayoutEngine engine) +{ + return engine->grFont != NULL; +} + +int +findGraphiteFeature(XeTeXLayoutEngine engine, const char* s, const char* e, int* f, int* v) + /* s...e is a "feature=setting" string; look for this in the font */ +{ + while (*s == ' ' || *s == '\t') + ++s; + const char* cp = s; + while (cp < e && *cp != '=') + ++cp; + if (cp == e) + return 0; + + *f = findGraphiteFeatureNamed(engine, s, cp - s); + if (*f == -1) + return 0; + + ++cp; + while (cp < e && (*cp == ' ' || *cp == '\t')) + ++cp; + if (cp == e) + return 0; + + *v = findGraphiteFeatureSettingNamed(engine, *f, cp, e - cp); + if (*v == -1) + return 0; + + return 1; +} + diff --git a/Build/source/texk/web2c/xetexdir/XeTeXLayoutInterface.h b/Build/source/texk/web2c/xetexdir/XeTeXLayoutInterface.h index d92cca16d91..482625588b2 100644 --- a/Build/source/texk/web2c/xetexdir/XeTeXLayoutInterface.h +++ b/Build/source/texk/web2c/xetexdir/XeTeXLayoutInterface.h @@ -84,13 +84,17 @@ float getGlyphWidth(XeTeXFont font, UInt32 gid); UInt32 countGlyphs(XeTeXFont font); XeTeXLayoutEngine createLayoutEngine(PlatformFontRef fontRef, XeTeXFont font, UInt32 scriptTag, UInt32 languageTag, - UInt32* addFeatures, SInt32* addParams, UInt32* removeFeatures, UInt32 rgbValue); + UInt32* addFeatures, SInt32* addParams, UInt32* removeFeatures, UInt32 rgbValue, + float extend, float slant); void deleteLayoutEngine(XeTeXLayoutEngine engine); XeTeXFont getFont(XeTeXLayoutEngine engine); PlatformFontRef getFontRef(XeTeXLayoutEngine engine); +float getExtendFactor(XeTeXLayoutEngine engine); +float getSlantFactor(XeTeXLayoutEngine engine); + SInt32 layoutChars(XeTeXLayoutEngine engine, UInt16* chars, SInt32 offset, SInt32 count, SInt32 max, char rightToLeft, float x, float y, SInt32* status); @@ -136,6 +140,33 @@ const char* getGlyphName(XeTeXFont font, UInt16 gid, int* len); int getFontCharRange(XeTeXLayoutEngine engine, int reqFirst); +/* graphite interface functions... */ +XeTeXLayoutEngine createGraphiteEngine(PlatformFontRef fontRef, XeTeXFont font, + const char* name, + UInt32 rgbValue, int rtl, UInt32 languageTag, + float extend, float slant, + int nFeatures, const int* featureIDs, const int* featureValues); +int makeGraphiteSegment(XeTeXLayoutEngine engine, const UniChar* txtPtr, int txtLen); +void getGraphiteGlyphInfo(XeTeXLayoutEngine engine, int index, UInt16* glyphID, float* x, float* y); +float graphiteSegmentWidth(XeTeXLayoutEngine engine); +void initGraphiteBreaking(XeTeXLayoutEngine engine, const UniChar* txtPtr, int txtLen); +int findNextGraphiteBreak(int iOffset, int iBrkVal); + +int usingOpenType(XeTeXLayoutEngine engine); +int usingGraphite(XeTeXLayoutEngine engine); + +int findGraphiteFeature(XeTeXLayoutEngine engine, const char* s, const char* e, int* f, int* v); + +UInt32 countGraphiteFeatures(XeTeXLayoutEngine engine); +UInt32 getGraphiteFeatureCode(XeTeXLayoutEngine engine, UInt32 index); +UInt32 countGraphiteFeatureSettings(XeTeXLayoutEngine engine, UInt32 feature); +UInt32 getGraphiteFeatureSettingCode(XeTeXLayoutEngine engine, UInt32 feature, UInt32 index); +UInt32 getGraphiteFeatureDefaultSetting(XeTeXLayoutEngine engine, UInt32 feature); +void getGraphiteFeatureLabel(XeTeXLayoutEngine engine, UInt32 feature, unsigned short* buf); +void getGraphiteFeatureSettingLabel(XeTeXLayoutEngine engine, UInt32 feature, UInt32 setting, unsigned short* buf); +long findGraphiteFeatureNamed(XeTeXLayoutEngine engine, const char* name, int namelength); +long findGraphiteFeatureSettingNamed(XeTeXLayoutEngine engine, UInt32 feature, const char* name, int namelength); + #ifdef __cplusplus }; #endif diff --git a/Build/source/texk/web2c/xetexdir/XeTeXOTLayoutEngine.cpp b/Build/source/texk/web2c/xetexdir/XeTeXOTLayoutEngine.cpp index d8ef3ed3a04..80a787b3469 100644 --- a/Build/source/texk/web2c/xetexdir/XeTeXOTLayoutEngine.cpp +++ b/Build/source/texk/web2c/xetexdir/XeTeXOTLayoutEngine.cpp @@ -54,6 +54,12 @@ static le_int32 getLanguageCode(LETag languageTag) return -1; } +/* + * XeTeXOTLayoutEngine + */ + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(XeTeXOTLayoutEngine) + LayoutEngine* XeTeXOTLayoutEngine::LayoutEngineFactory (const XeTeXFontInst* fontInstance, LETag scriptTag, LETag languageTag, @@ -62,11 +68,13 @@ LayoutEngine* XeTeXOTLayoutEngine::LayoutEngineFactory LEErrorCode &success) { static le_uint32 gsubTableTag = LE_GSUB_TABLE_TAG; + static le_uint32 gposTableTag = LE_GPOS_TABLE_TAG; if (LE_FAILURE(success)) return NULL; const GlyphSubstitutionTableHeader* gsubTable = (const GlyphSubstitutionTableHeader*)fontInstance->getFontTable(gsubTableTag); + const GlyphPositioningTableHeader* gposTable = (const GlyphPositioningTableHeader*)fontInstance->getFontTable(gposTableTag); LayoutEngine *result = NULL; le_uint32 scriptCode = getScriptCode(scriptTag); @@ -74,7 +82,8 @@ LayoutEngine* XeTeXOTLayoutEngine::LayoutEngineFactory le_int32 typoFlags = 3; - if (gsubTable != NULL && gsubTable->coversScript(scriptTag)) { + if ((gsubTable != NULL && gsubTable->coversScript(scriptTag)) + || (gposTable != NULL && gposTable->coversScript(scriptTag))) { switch (scriptCode) { case bengScriptCode: case devaScriptCode: @@ -102,7 +111,7 @@ LayoutEngine* XeTeXOTLayoutEngine::LayoutEngineFactory case hiraScriptCode: case kanaScriptCode: case hrktScriptCode: - result = new XeTeXHanLayoutEngine(fontInstance, scriptTag, languageTag, gsubTable, addFeatures, addParams, removeFeatures); + result = new XeTeXHanLayoutEngine(fontInstance, scriptTag, languageTag, gsubTable, gposTable, addFeatures, addParams, removeFeatures); break; case khmrScriptCode: @@ -110,7 +119,7 @@ LayoutEngine* XeTeXOTLayoutEngine::LayoutEngineFactory break; default: - result = new XeTeXOTLayoutEngine(fontInstance, scriptTag, languageTag, gsubTable, addFeatures, addParams, removeFeatures); + result = new XeTeXOTLayoutEngine(fontInstance, scriptTag, languageTag, gsubTable, gposTable, addFeatures, addParams, removeFeatures); break; } } @@ -149,21 +158,13 @@ LayoutEngine* XeTeXOTLayoutEngine::LayoutEngineFactory return result; } -/* - * XeTeXOTLayoutEngine - */ - -const char XeTeXOTLayoutEngine::fgClassID=0; - XeTeXOTLayoutEngine::XeTeXOTLayoutEngine( const LEFontInstance* fontInstance, LETag scriptTag, LETag languageTag, - const GlyphSubstitutionTableHeader* gsubTable, + const GlyphSubstitutionTableHeader* gsubTable, const GlyphPositioningTableHeader* gposTable, const LETag* addFeatures, const le_int32* addParams, const LETag* removeFeatures) : OpenTypeLayoutEngine(fontInstance, getScriptCode(scriptTag), getLanguageCode(languageTag), 3, gsubTable) { - static le_uint32 gposTableTag = LE_GPOS_TABLE_TAG; - - fDefaultFeatures = fFeatureList; + fDefaultFeatureMap = fFeatureMap; // check the result of setScriptAndLanguageTags(), in case they were unknown to ICU if (fScriptTag != scriptTag || fLangSysTag != languageTag) { @@ -172,7 +173,6 @@ XeTeXOTLayoutEngine::XeTeXOTLayoutEngine( // reset the GPOS if the tags changed fGPOSTable = NULL; - const GlyphPositioningTableHeader *gposTable = (const GlyphPositioningTableHeader *) getFontTable(gposTableTag); if (gposTable != NULL && gposTable->coversScriptAndLanguage(fScriptTag, fLangSysTag)) { fGPOSTable = gposTable; } @@ -183,8 +183,8 @@ XeTeXOTLayoutEngine::XeTeXOTLayoutEngine( XeTeXOTLayoutEngine::~XeTeXOTLayoutEngine() { - if (fFeatureList != NULL && fFeatureList != fDefaultFeatures) - LE_DELETE_ARRAY(fFeatureList); + if (fFeatureMap != NULL && fFeatureMap != fDefaultFeatureMap) + LE_DELETE_ARRAY(fFeatureMap); if (fFeatureParamList != NULL) LE_DELETE_ARRAY(fFeatureParamList); } @@ -194,69 +194,104 @@ void XeTeXOTLayoutEngine::adjustFeatures(const LETag* addTags, const le_int32* a // bail out if nothing was requested! if ((addTags == NULL || *addTags == emptyTag) && (removeTags == NULL || *removeTags == emptyTag)) return; - - // count the max possible number of tags we might end up with - le_uint32 count = 0; - const LETag* pTag = fFeatureList; - while (*pTag++ != emptyTag) - count++; - if (addTags != NULL && *addTags != emptyTag) { - pTag = addTags; - while (*pTag++ != emptyTag) - count++; + + // figure out total tag count: initial set - removed tags + added tags omitting duplicates + le_int32 totalCount = 0; + for (le_int32 i = 0; i < fFeatureMapCount; ++i) { + // skip any that are disabled by the mask + if ((fFeatureMask & fFeatureMap[i].mask) != 0) { + bool remove = false; + for (const LETag* r = removeTags; r != NULL && *r != emptyTag; ++r) + if (*r == fFeatureMap[i].tag) { + remove = true; + break; + } + if (!remove) + ++totalCount; + } } - - // allocate new array for the tag list, big enough for max count - LETag* newList = LE_NEW_ARRAY(LETag, count + 1); - - // copy the existing tags, skipping any in the remove list - LETag* dest = newList; - le_int32* newParams = LE_NEW_ARRAY(le_int32, count); - le_int32* dest2 = newParams; - pTag = fFeatureList; - while (*pTag != emptyTag) { - const LETag* t = removeTags; - if (t != NULL) - while (*t != emptyTag) - if (*t == *pTag) + for (const LETag* a = addTags; a != NULL && *a != emptyTag; ++a) { + // before counting an add tag, check original map, and check for duplicates in list + bool add = true; + for (le_int32 i = 0; i < fFeatureMapCount; ++i) + if (*a == fFeatureMap[i].tag) { + if ((fFeatureMask & fFeatureMap[i].mask) != 0) + add = false; + break; + } + if (add) { + for (const LETag* t = addTags; t != a; ++t) + if (*a == *t) { + add = false; break; - else - t++; - if (t == NULL || *t == emptyTag) { - *dest++ = *pTag; - *dest2++ = 0; + } } - pTag++; + if (add) + ++totalCount; } - // copy the added tags and parameters, skipping any already present - pTag = addTags; - const le_int32* pParam = addParams; - if (pTag != NULL) - while (*pTag != emptyTag) { - const LETag* t = newList; - while (t < dest) - if (*t == *pTag) + if (totalCount > 32) + fprintf(stderr, "\n*** feature count exceeds mask size; some features will be ignored\n"); + + // allocate new map + FeatureMap* newFeatureMap = LE_NEW_ARRAY(FeatureMap, totalCount); + le_int32 newFeatureCount = 0; + le_int32* newParamList = (addParams == NULL) ? NULL : LE_NEW_ARRAY(le_int32, totalCount); + + // copy the features into the map and assign mask bits + FeatureMask newFeatureMask = 0; + FeatureMask maskBit = 0x80000000UL; + for (le_int32 i = 0; i < fFeatureMapCount; ++i) { + bool remove = false; + if ((fFeatureMask & fFeatureMap[i].mask) == 0) + remove = true; + else + for (const LETag* r = removeTags; r != NULL && *r != emptyTag; ++r) + if (*r == fFeatureMap[i].tag) { + remove = true; break; - else - t++; - if (t == dest) { - *dest++ = *pTag; - *dest2++ = *pParam; + } + if (!remove) { + newFeatureMap[newFeatureCount].tag = fFeatureMap[i].tag; + newFeatureMap[newFeatureCount].mask = maskBit; + if (newParamList != NULL) + newParamList[newFeatureCount] = 0; + ++newFeatureCount; + newFeatureMask |= maskBit; + maskBit >>= 1; + } + } + const le_int32* param = addParams; + for (const LETag* a = addTags; a != NULL && *a != emptyTag; ++a) { + bool add = true; + for (le_int32 i = 0; i < fFeatureMapCount; ++i) + if (*a == fFeatureMap[i].tag) { + if ((fFeatureMask & fFeatureMap[i].mask) != 0) + add = false; + break; } - pTag++; - pParam++; + if (add) { + for (const LETag* t = addTags; t != a; ++t) + if (*a == *t) { + add = false; + break; + } } - - // terminate the new list - *dest = emptyTag; - - // delete the previous list, unless it was the static default array - if (fFeatureList != fDefaultFeatures) - LE_DELETE_ARRAY(fFeatureList); - - fFeatureList = newList; - fFeatureParamList = newParams; + if (add) { + newFeatureMap[newFeatureCount].tag = *a; + newFeatureMap[newFeatureCount].mask = maskBit; + if (newParamList != NULL) + newParamList[newFeatureCount] = *param++; + ++newFeatureCount; + newFeatureMask |= maskBit; + maskBit >>= 1; + } + } + + fFeatureMask = newFeatureMask; + fFeatureMap = newFeatureMap; + fFeatureMapCount = newFeatureCount; + fFeatureParamList = newParamList; } @@ -264,7 +299,7 @@ void XeTeXOTLayoutEngine::adjustFeatures(const LETag* addTags, const le_int32* a * XeTeXHanLayoutEngine */ -const char XeTeXHanLayoutEngine::fgClassID=0; +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(XeTeXHanLayoutEngine) static const LETag loclFeatureTag = LE_LOCL_FEATURE_TAG; static const LETag smplFeatureTag = LE_SMPL_FEATURE_TAG; @@ -272,18 +307,36 @@ static const LETag tradFeatureTag = LE_TRAD_FEATURE_TAG; static const LETag vertFeatureTag = LE_VERT_FEATURE_TAG; static const LETag vrt2FeatureTag = LE_VRT2_FEATURE_TAG; -static const LETag horizontalFeatures[] = {loclFeatureTag, emptyTag}; -static const LETag verticalFeatures[] = {loclFeatureTag, vrt2FeatureTag, vertFeatureTag, emptyTag}; +#define loclFeatureMask 0x80000000UL +#define smplFeatureMask 0x40000000UL +#define tradFeatureMask 0x20000000UL +#define vertFeatureMask 0x10000000UL +#define vrt2FeatureMask 0x08000000UL + +static const FeatureMap featureMap[] = { + {loclFeatureTag, loclFeatureMask}, + {smplFeatureTag, smplFeatureMask}, + {tradFeatureTag, tradFeatureMask}, + {vertFeatureTag, vertFeatureMask}, + {vrt2FeatureTag, vrt2FeatureMask}, +}; +static const le_int32 featureMapCount = LE_ARRAY_SIZE(featureMap); + +#define HORIZ_FEATURES (loclFeatureMask) +#define VERT_FEATURES (loclFeatureMask|vertFeatureMask|vrt2FeatureMask) XeTeXHanLayoutEngine::XeTeXHanLayoutEngine(const XeTeXFontInst *fontInstance, LETag scriptTag, LETag languageTag, - const GlyphSubstitutionTableHeader *gsubTable, + const GlyphSubstitutionTableHeader *gsubTable, const GlyphPositioningTableHeader *gposTable, const LETag *addFeatures, const le_int32* addParams, const LETag *removeFeatures) - : XeTeXOTLayoutEngine(fontInstance, scriptTag, languageTag, gsubTable, NULL, NULL, NULL) + : XeTeXOTLayoutEngine(fontInstance, scriptTag, languageTag, gsubTable, gposTable, NULL, NULL, NULL) { - // reset the default feature list - fFeatureList = fontInstance->getLayoutDirVertical() ? verticalFeatures : horizontalFeatures; - fDefaultFeatures = fFeatureList; + // reset the feature map and default features + fFeatureMap = featureMap; + fDefaultFeatureMap = fFeatureMap; + fFeatureMapCount = featureMapCount; + + fFeatureMask = fontInstance->getLayoutDirVertical() ? VERT_FEATURES : HORIZ_FEATURES; // then apply any adjustments adjustFeatures(addFeatures, addParams, removeFeatures); diff --git a/Build/source/texk/web2c/xetexdir/XeTeXOTLayoutEngine.h b/Build/source/texk/web2c/xetexdir/XeTeXOTLayoutEngine.h index 48f48e58abb..2800ab21b76 100644 --- a/Build/source/texk/web2c/xetexdir/XeTeXOTLayoutEngine.h +++ b/Build/source/texk/web2c/xetexdir/XeTeXOTLayoutEngine.h @@ -1,6 +1,6 @@ /****************************************************************************\ Part of the XeTeX typesetting system - copyright (c) 1994-2006 by SIL International + copyright (c) 1994-2007 by SIL International written by Jonathan Kew Permission is hereby granted, free of charge, to any person obtaining @@ -43,6 +43,7 @@ class XeTeXOTLayoutEngine : public OpenTypeLayoutEngine public: XeTeXOTLayoutEngine(const LEFontInstance* fontInstance, LETag scriptTag, LETag languageTag, const GlyphSubstitutionTableHeader* gsubTable, + const GlyphPositioningTableHeader* gposTable, const LETag* addFeatures, const le_int32* addParams, const LETag* removeFeatures); @@ -50,8 +51,8 @@ public: virtual void adjustFeatures(const LETag* addTags, const le_int32* addParams, const LETag* removeTags); - virtual inline UClassID getDynamicClassID() const { return getStaticClassID(); } - static inline UClassID getStaticClassID() { return (UClassID)&fgClassID; } + virtual UClassID getDynamicClassID() const; + static UClassID getStaticClassID(); static LayoutEngine* LayoutEngineFactory (const XeTeXFontInst* fontInstance, @@ -61,11 +62,9 @@ public: LEErrorCode &success); protected: - const LETag* fDefaultFeatures; + const FeatureMap* fDefaultFeatureMap; private: - static const char fgClassID; - }; class XeTeXHanLayoutEngine : public XeTeXOTLayoutEngine @@ -73,16 +72,14 @@ class XeTeXHanLayoutEngine : public XeTeXOTLayoutEngine public: XeTeXHanLayoutEngine(const XeTeXFontInst *fontInstance, LETag scriptTag, LETag languageTag, const GlyphSubstitutionTableHeader *gsubTable, + const GlyphPositioningTableHeader* gposTable, const LETag* addFeatures, const le_int32* addParams, const LETag* removeFeatures); virtual ~XeTeXHanLayoutEngine(); - virtual inline UClassID getDynamicClassID() const { return getStaticClassID(); } - static inline UClassID getStaticClassID() { return (UClassID)&fgClassID; } - -private: - static const char fgClassID; + virtual UClassID getDynamicClassID() const; + static UClassID getStaticClassID(); }; #endif diff --git a/Build/source/texk/web2c/xetexdir/XeTeXOTMath.cpp b/Build/source/texk/web2c/xetexdir/XeTeXOTMath.cpp index a3b4d0c630f..3aebc8b9a97 100644 --- a/Build/source/texk/web2c/xetexdir/XeTeXOTMath.cpp +++ b/Build/source/texk/web2c/xetexdir/XeTeXOTMath.cpp @@ -75,7 +75,7 @@ getotmathconstant(int f, int n) { int rval = 0; - if (fontarea[f] == OT_FONT_FLAG) { + if (fontarea[f] == OTGR_FONT_FLAG) { XeTeXFontInst* font = (XeTeXFontInst*)getFont((XeTeXLayoutEngine)fontlayoutengine[f]); rval = X2Fix(getMathConstant(font, (mathConstantIndex)n) * Fix2X(fontsize[f]) / font->getUnitsPerEM()); } @@ -191,12 +191,12 @@ getnativemathexparam(int f, int n) } int -getotmathvariant(int f, int g, int v, int* adv) +getotmathvariant(int f, int g, int v, int* adv, int horiz) { int rval = g; *adv = -1; - if (fontarea[f] == OT_FONT_FLAG) { + if (fontarea[f] == OTGR_FONT_FLAG) { XeTeXFontInst* font = (XeTeXFontInst*)getFont((XeTeXLayoutEngine)fontlayoutengine[f]); const char* table = (const char*)font->getFontTable(kMATHTableTag); @@ -208,13 +208,15 @@ getotmathvariant(int f, int g, int v, int* adv) return rval; const MathVariants* variants = (const MathVariants*)(table + offset); - offset = SWAPW(variants->vertGlyphCoverage); + offset = horiz ? SWAPW(variants->horizGlyphCoverage) : SWAPW(variants->vertGlyphCoverage); if (offset == 0) return rval; const CoverageTable* coverage = (const CoverageTable*)(((const char*)variants) + offset); le_int32 index = coverage->getGlyphCoverage(g); if (index >= 0) { + if (horiz) + index += SWAPW(variants->vertGlyphCount); const MathGlyphConstruction* construction = (const MathGlyphConstruction*)(((const char*)variants) + SWAPW(variants->vertGlyphConstruction[index])); if (v < SWAPW(construction->variantCount)) { @@ -229,11 +231,11 @@ getotmathvariant(int f, int g, int v, int* adv) } void* -getotassemblyptr(int f, int g) +getotassemblyptr(int f, int g, int horiz) { void* rval = NULL; - if (fontarea[f] == OT_FONT_FLAG) { + if (fontarea[f] == OTGR_FONT_FLAG) { XeTeXFontInst* font = (XeTeXFontInst*)getFont((XeTeXLayoutEngine)fontlayoutengine[f]); const char* table = (const char*)font->getFontTable(kMATHTableTag); @@ -245,13 +247,15 @@ getotassemblyptr(int f, int g) return rval; const MathVariants* variants = (const MathVariants*)(table + offset); - offset = SWAPW(variants->vertGlyphCoverage); + offset = horiz ? SWAPW(variants->horizGlyphCoverage) : SWAPW(variants->vertGlyphCoverage); if (offset == 0) return rval; const CoverageTable* coverage = (const CoverageTable*)(((const char*)variants) + offset); le_int32 index = coverage->getGlyphCoverage(g); if (index >= 0) { + if (horiz) + index += SWAPW(variants->vertGlyphCount); const MathGlyphConstruction* construction = (const MathGlyphConstruction*)(((const char*)variants) + SWAPW(variants->vertGlyphConstruction[index])); offset = SWAPW(construction->glyphAssembly); @@ -268,7 +272,7 @@ getotmathitalcorr(int f, int g) { int rval = 0; - if (fontarea[f] == OT_FONT_FLAG) { + if (fontarea[f] == OTGR_FONT_FLAG) { XeTeXFontInst* font = (XeTeXFontInst*)getFont((XeTeXLayoutEngine)fontlayoutengine[f]); const char* table = (const char*)font->getFontTable(kMATHTableTag); @@ -298,12 +302,49 @@ getotmathitalcorr(int f, int g) return rval; } +int +getotmathaccentpos(int f, int g) +{ + int rval = 0x7fffffffUL; + + if (fontarea[f] == OTGR_FONT_FLAG) { + XeTeXFontInst* font = (XeTeXFontInst*)getFont((XeTeXLayoutEngine)fontlayoutengine[f]); + + const char* table = (const char*)font->getFontTable(kMATHTableTag); + if (table == NULL) + return rval; + + le_uint16 offset = SWAPW(((const MathTableHeader*)table)->mathGlyphInfo); + if (offset == 0) + return rval; + const MathGlyphInfo* glyphInfo = (const MathGlyphInfo*)(table + offset); + + offset = SWAPW(glyphInfo->mathTopAccentAttachment); + if (offset == 0) + return rval; + const MathTopAccentAttachment* accentAttachment = (const MathTopAccentAttachment*)(((const char*)glyphInfo) + offset); + + offset = SWAPW(accentAttachment->coverage); + if (offset == 0) + return rval; + const CoverageTable* coverage = (const CoverageTable*)(((const char*)accentAttachment) + offset); + + le_int32 index = coverage->getGlyphCoverage(g); + if (index >= 0 && index < SWAPW(accentAttachment->topAccentAttachmentCount)) { + rval = (le_int16)SWAPW(accentAttachment->topAccentAttachment[index].value); + rval = X2Fix(rval * Fix2X(fontsize[f]) / font->getUnitsPerEM()); + } + } + + return rval; +} + int otminconnectoroverlap(int f) { int rval = 0; - if (fontarea[f] == OT_FONT_FLAG) { + if (fontarea[f] == OTGR_FONT_FLAG) { XeTeXFontInst* font = (XeTeXFontInst*)getFont((XeTeXLayoutEngine)fontlayoutengine[f]); const char* table = (const char*)font->getFontTable(kMATHTableTag); @@ -344,7 +385,7 @@ otpartstartconnector(int f, const GlyphAssembly* a, int i) { int rval = 0; - if (fontarea[f] == OT_FONT_FLAG) { + if (fontarea[f] == OTGR_FONT_FLAG) { XeTeXFontInst* font = (XeTeXFontInst*)getFont((XeTeXLayoutEngine)fontlayoutengine[f]); rval = X2Fix(SWAPW(a->partRecords[i].startConnectorLength) * Fix2X(fontsize[f]) / font->getUnitsPerEM()); } @@ -357,7 +398,7 @@ otpartendconnector(int f, const GlyphAssembly* a, int i) { int rval = 0; - if (fontarea[f] == OT_FONT_FLAG) { + if (fontarea[f] == OTGR_FONT_FLAG) { XeTeXFontInst* font = (XeTeXFontInst*)getFont((XeTeXLayoutEngine)fontlayoutengine[f]); rval = X2Fix(SWAPW(a->partRecords[i].endConnectorLength) * Fix2X(fontsize[f]) / font->getUnitsPerEM()); } @@ -370,7 +411,7 @@ otpartfulladvance(int f, const GlyphAssembly* a, int i) { int rval = 0; - if (fontarea[f] == OT_FONT_FLAG) { + if (fontarea[f] == OTGR_FONT_FLAG) { XeTeXFontInst* font = (XeTeXFontInst*)getFont((XeTeXLayoutEngine)fontlayoutengine[f]); rval = X2Fix(SWAPW(a->partRecords[i].fullAdvance) * Fix2X(fontsize[f]) / font->getUnitsPerEM()); } diff --git a/Build/source/texk/web2c/xetexdir/XeTeXOTMath.h b/Build/source/texk/web2c/xetexdir/XeTeXOTMath.h index a1d535923ef..5bb5bc83f23 100644 --- a/Build/source/texk/web2c/xetexdir/XeTeXOTMath.h +++ b/Build/source/texk/web2c/xetexdir/XeTeXOTMath.h @@ -40,9 +40,10 @@ extern "C" { int getnativemathsyparam(int f, int n); int getnativemathexparam(int f, int n); int getotmathconstant(int f, int n); - int getotmathvariant(int f, int g, int v, int* adv); - void* getotassemblyptr(int f, int g); + int getotmathvariant(int f, int g, int v, int* adv, int horiz); + void* getotassemblyptr(int f, int g, int horiz); int getotmathitalcorr(int f, int g); + int getotmathaccentpos(int f, int g); int otpartcount(const GlyphAssembly* a); int otpartglyph(const GlyphAssembly* a, int i); int otpartisextender(const GlyphAssembly* a, int i); diff --git a/Build/source/texk/web2c/xetexdir/XeTeX_ext.c b/Build/source/texk/web2c/xetexdir/XeTeX_ext.c index a4b467bb10c..d9904176d7e 100644 --- a/Build/source/texk/web2c/xetexdir/XeTeX_ext.c +++ b/Build/source/texk/web2c/xetexdir/XeTeX_ext.c @@ -37,12 +37,8 @@ authorization from SIL International. #include "png.h" #endif -#include "zlib.h" - #define EXTERN extern -#define Byte my_Byte /* hack to work around typedef conflict with zlib */ #include "xetexd.h" -#undef Byte #ifdef XETEX_MAC #undef input /* this is defined in texmfmp.h, but we don't need it and it confuses the carbon headers */ @@ -54,6 +50,8 @@ authorization from SIL International. #include #include FT_FREETYPE_H +#include "zlib.h" + #include "TECkit_Engine.h" #include @@ -170,11 +168,7 @@ const UInt32 byteMark = 0x00000080UL; /* if the user specifies a paper size or output driver program */ string papersize; -#ifdef XETEX_MAC -string outputdriver = "xdv2pdf"; /* default for backward compatibility on Mac OS X */ -#else -string outputdriver = "xdvipdfmx -q -E"; /* else default to portable xdvipdfmx driver */ -#endif +string outputdriver = "xdvipdfmx -q -E"; /* default to portable xdvipdfmx driver */ void initversionstring(char **versions) @@ -326,11 +320,19 @@ static char* byteBuffer = NULL; /* now apply the mapping to turn external bytes into Unicode characters in buffer */ cnv = (UConverter*)(f->conversionData); - outLen = ucnv_toUChars(cnv, &buffer[first], (bufsize - first), byteBuffer, bytesRead, &errorCode); +#ifdef WORDS_BIGENDIAN +#define UCNV_UTF32_NativeEndian UCNV_UTF32_BigEndian +#else +#define UCNV_UTF32_NativeEndian UCNV_UTF32_LittleEndian +#endif + outLen = ucnv_toAlgorithmic(UCNV_UTF32_NativeEndian, cnv, + (char*)&buffer[first], sizeof(*buffer) * (bufsize - first), + byteBuffer, bytesRead, &errorCode); if (errorCode != 0) { fprintf(stderr, "! Unicode conversion failed: error code = %d\n", (int)errorCode); return false; } + outLen /= sizeof(*buffer); last = first + outLen; buffer[last] = ' '; @@ -438,6 +440,14 @@ getencodingmodeandinfo(integer* info) } } +void +printcstring(const char* str) +{ + if (str != NULL) + while (*str) + printvisiblechar(*(str++)); +} + void printutf8str(const unsigned char* str, int len) { @@ -464,7 +474,7 @@ load_mapping_file(const char* s, const char* e) mapPath = kpse_find_file(buffer, kpse_miscfonts_format, 1); if (mapPath) { - FILE* mapFile = fopen(mapPath, "rb"); + FILE* mapFile = fopen(mapPath, FOPEN_RBIN_MODE); free(mapPath); if (mapFile) { UInt32 mappingSize; @@ -495,8 +505,43 @@ load_mapping_file(const char* s, const char* e) return cnv; } +double +read_double(const char** s) +{ + int neg = 0; + double val = 0.0; + const char* cp = *s; + + while (*cp == ' '|| *cp == '\t') + ++cp; + if (*cp == '-') { + neg = 1; + ++cp; + } + else if (*cp == '+') { + ++cp; + } + + while (*cp >= '0' && *cp <= '9') { + val = val * 10.0 + *cp - '0'; + ++cp; + } + if (*cp == '.') { + double dec = 10.0; + ++cp; + while (*cp >= '0' && *cp <= '9') { + val = val + (*cp - '0') / dec; + ++cp; + dec = dec * 10.0; + } + } + *s = cp; + + return neg ? -val : val; +} + static UInt32 -read_tag(const char* cp) +read_tag(const char* cp, char padChar) { UInt32 tag = 0; int i; @@ -507,7 +552,7 @@ read_tag(const char* cp) ++cp; } else - tag += ' '; + tag += padChar; } return tag; } @@ -543,6 +588,42 @@ read_tag_with_param(const char* cp, SInt32* param) return tag; } +unsigned int +read_rgb_a(const char** cp) +{ + UInt32 rgbValue = 0; + UInt32 alpha = 0; + int i; + for (i = 0; i < 6; ++i) { + if ((**cp >= '0') && (**cp <= '9')) + rgbValue = (rgbValue << 4) + **cp - '0'; + else if ((**cp >= 'A') && (**cp <= 'F')) + rgbValue = (rgbValue << 4) + **cp - 'A' + 10; + else if ((**cp >= 'a') && (**cp <= 'f')) + rgbValue = (rgbValue << 4) + **cp - 'a' + 10; + else + return 0x000000FF; + (*cp)++; + } + rgbValue <<= 8; + for (i = 0; i < 2; ++i) { + if ((**cp >= '0') && (**cp <= '9')) + alpha = (alpha << 4) + **cp - '0'; + else if ((**cp >= 'A') && (**cp <= 'F')) + alpha = (alpha << 4) + **cp - 'A' + 10; + else if ((**cp >= 'a') && (**cp <= 'f')) + alpha = (alpha << 4) + **cp - 'a' + 10; + else + break; + (*cp)++; + } + if (i == 2) + rgbValue += alpha; + else + rgbValue += 0xFF; + return rgbValue; +} + static void* loadOTfont(PlatformFontRef fontRef, XeTeXFont font, Fixed scaled_size, const char* cp1) { @@ -564,6 +645,9 @@ loadOTfont(PlatformFontRef fontRef, XeTeXFont font, Fixed scaled_size, const cha UInt32 rgbValue = 0x000000FF; + double extend = 1.0; + double slant = 0.0; + /* scan the feature string (if any) */ if (cp1 != NULL) { while (*cp1) { @@ -582,7 +666,7 @@ loadOTfont(PlatformFontRef fontRef, XeTeXFont font, Fixed scaled_size, const cha cp3 = cp1 + 6; if (*cp3 != '=') goto bad_option; - scriptTag = read_tag(cp3 + 1); + scriptTag = read_tag(cp3 + 1, ' '); goto next_option; } @@ -590,7 +674,7 @@ loadOTfont(PlatformFontRef fontRef, XeTeXFont font, Fixed scaled_size, const cha cp3 = cp1 + 8; if (*cp3 != '=') goto bad_option; - languageTag = read_tag(cp3 + 1); + languageTag = read_tag(cp3 + 1, ' '); goto next_option; } @@ -602,81 +686,47 @@ loadOTfont(PlatformFontRef fontRef, XeTeXFont font, Fixed scaled_size, const cha goto next_option; } + if (strncmp(cp1, "extend", 6) == 0) { + cp3 = cp1 + 6; + if (*cp3 != '=') + goto bad_option; + ++cp3; + extend = read_double(&cp3); + goto next_option; + } + + if (strncmp(cp1, "slant", 5) == 0) { + cp3 = cp1 + 5; + if (*cp3 != '=') + goto bad_option; + ++cp3; + slant = read_double(&cp3); + goto next_option; + } + if (strncmp(cp1, "color", 5) == 0) { - unsigned alpha = 0; - int i; + const char* s; cp3 = cp1 + 5; if (*cp3 != '=') goto bad_option; ++cp3; - - rgbValue = 0; - for (i = 0; i < 6; ++i) { - if ((*cp3 >= '0') && (*cp3 <= '9')) - rgbValue = (rgbValue << 4) + *cp3 - '0'; - else if ((*cp3 >= 'A') && (*cp3 <= 'F')) - rgbValue = (rgbValue << 4) + *cp3 - 'A' + 10; - else if ((*cp3 >= 'a') && (*cp3 <= 'f')) - rgbValue = (rgbValue << 4) + *cp3 - 'a' + 10; - else - goto bad_option; - ++cp3; - } - rgbValue <<= 8; - for (i = 0; i < 2; ++i) { - if ((*cp3 >= '0') && (*cp3 <= '9')) - alpha = (alpha << 4) + *cp3 - '0'; - else if ((*cp3 >= 'A') && (*cp3 <= 'F')) - alpha = (alpha << 4) + *cp3 - 'A' + 10; - else if ((*cp3 >= 'a') && (*cp3 <= 'f')) - alpha = (alpha << 4) + *cp3 - 'a' + 10; - else - break; - ++cp3; - } - if (i == 2) - rgbValue += alpha; + s = cp3; + rgbValue = read_rgb_a(&cp3); + if ((cp3 == s+6) || (cp3 == s+8)) + loadedfontflags |= FONT_FLAGS_COLORED; else - rgbValue += 0xFF; - - loadedfontflags |= FONT_FLAGS_COLORED; - + goto bad_option; goto next_option; } if (strncmp(cp1, "letterspace", 11) == 0) { - int sign = 1; - double val = 0.0; - + double val; cp3 = cp1 + 11; if (*cp3 != '=') goto bad_option; ++cp3; - - if (*cp3 == '-') { - sign = -1; - ++cp3; - } - else if (*cp3 == '+') { - ++cp3; - } - - while (*cp3 >= '0' && *cp3 <= '9') { - val = val * 10.0 + *cp3 - '0'; - ++cp3; - } - if (*cp3 == '.' || *cp3 == ',') { - double dec = 10.0; - ++cp3; - while (*cp3 >= '0' && *cp3 <= '9') { - val = val + (*cp3 - '0') / dec; - ++cp3; - dec = dec * 10.0; - } - } - - loadedfontletterspace = sign * (val / 100.0) * scaled_size; - + val = read_double(&cp3); + loadedfontletterspace = (val / 100.0) * scaled_size; goto next_option; } @@ -698,7 +748,7 @@ loadOTfont(PlatformFontRef fontRef, XeTeXFont font, Fixed scaled_size, const cha } if (*cp1 == '-') { - tag = read_tag(cp1 + 1); + tag = read_tag(cp1 + 1, ' '); ++nRemoved; if (nRemoved == 1) removeFeatures = xmalloc(sizeof(UInt32)); @@ -710,9 +760,9 @@ loadOTfont(PlatformFontRef fontRef, XeTeXFont font, Fixed scaled_size, const cha if (strncmp(cp1, "vertical", 8) == 0) { cp3 = cp2; - if (*cp3 == ';' || *cp3 == ':') + if (*cp3 == ';' || *cp3 == ':' || *cp3 == ',') --cp3; - while (*cp3 == ' ' || *cp3 == '\t') + while (*cp3 == '\0' || *cp3 == ' ' || *cp3 == '\t') --cp3; if (*cp3) ++cp3; @@ -746,9 +796,10 @@ loadOTfont(PlatformFontRef fontRef, XeTeXFont font, Fixed scaled_size, const cha setFontLayoutDir(font, 1); engine = createLayoutEngine(fontRef, font, scriptTag, languageTag, - addFeatures, addParams, removeFeatures, rgbValue); + addFeatures, addParams, removeFeatures, rgbValue, + extend, slant); if (engine == 0) { - deleteFont(font); + // only free these if creation failed, otherwise the engine now owns them if (addFeatures) free(addFeatures); if (addParams) @@ -757,16 +808,210 @@ loadOTfont(PlatformFontRef fontRef, XeTeXFont font, Fixed scaled_size, const cha free(removeFeatures); } else - nativefonttypeflag = OT_FONT_FLAG; + nativefonttypeflag = OTGR_FONT_FLAG; + + return engine; +} + +static int +readFeatureNumber(const char* s, const char* e, int* f, int* v) +{ + *f = 0; + *v = 0; + if (*s < '0' || *s > '9') + return 0; + while (*s >= '0' && *s <= '9') + *f = *f * 10 + *s++ - '0'; + while ((*s == ' ') || (*s == '\t')) + ++s; + if (*s++ != '=') + return 0; + if (*s < '0' || *s > '9') + return 0; + while (*s >= '0' && *s <= '9') + *v = *v * 10 + *s++ - '0'; + while ((*s == ' ') || (*s == '\t')) + ++s; + if (s != e) + return 0; + return 1; +} + +#define MAX_GRAPHITE_FEATURES 64 + +static void* +loadGraphiteFont(PlatformFontRef fontRef, XeTeXFont font, Fixed scaled_size, const char* cp1, const char* faceName) +{ + XeTeXLayoutEngine engine = NULL; + + const char* cp2; + const char* cp3; + + UInt32 tag; + + UInt32 rgbValue = 0x000000FF; + UInt32 languageTag = 0; + + double extend = 1.0; + double slant = 0.0; + int rtl = 0; + + int featureIDs[MAX_GRAPHITE_FEATURES]; + int featureValues[MAX_GRAPHITE_FEATURES]; + int nFeatures = 0; + int id, val; + + /* create a default engine so we can query the font for Graphite features; + because of font caching, it's cheap to discard this and create the real one later */ + engine = createGraphiteEngine(fontRef, font, faceName, rgbValue, rtl, languageTag, + extend, slant, 0, NULL, NULL); + if (engine == NULL) + return NULL; + + /* scan the feature string (if any) */ + if (cp1 != NULL) { + while (*cp1) { + if ((*cp1 == ':') || (*cp1 == ';') || (*cp1 == ',')) + ++cp1; + while ((*cp1 == ' ') || (*cp1 == '\t')) /* skip leading whitespace */ + ++cp1; + if (*cp1 == 0) /* break if end of string */ + break; + + cp2 = cp1; + while (*cp2 && (*cp2 != ':') && (*cp2 != ';') && (*cp2 != ',')) + ++cp2; + + if (strncmp(cp1, "language", 8) == 0) { + cp3 = cp1 + 8; + if (*cp3 != '=') + goto bad_option; + languageTag = read_tag(cp3 + 1, '\0'); + goto next_option; + } + + if (strncmp(cp1, "mapping", 7) == 0) { + cp3 = cp1 + 7; + if (*cp3 != '=') + goto bad_option; + loadedfontmapping = load_mapping_file(cp3 + 1, cp2); + goto next_option; + } + + if (strncmp(cp1, "extend", 6) == 0) { + cp3 = cp1 + 6; + if (*cp3 != '=') + goto bad_option; + ++cp3; + extend = read_double(&cp3); + goto next_option; + } + + if (strncmp(cp1, "slant", 5) == 0) { + cp3 = cp1 + 5; + if (*cp3 != '=') + goto bad_option; + ++cp3; + slant = read_double(&cp3); + goto next_option; + } + + if (strncmp(cp1, "color", 5) == 0) { + const char* s; + cp3 = cp1 + 5; + if (*cp3 != '=') + goto bad_option; + ++cp3; + s = cp3; + rgbValue = read_rgb_a(&cp3); + if ((cp3 == s+6) || (cp3 == s+8)) + loadedfontflags |= FONT_FLAGS_COLORED; + else + goto bad_option; + goto next_option; + } + + if (strncmp(cp1, "letterspace", 11) == 0) { + double val; + cp3 = cp1 + 11; + if (*cp3 != '=') + goto bad_option; + ++cp3; + val = read_double(&cp3); + loadedfontletterspace = (val / 100.0) * scaled_size; + goto next_option; + } + + if (readFeatureNumber(cp1, cp2, &id, &val) + || findGraphiteFeature(engine, cp1, cp2, &id, &val)) { + if (nFeatures < MAX_GRAPHITE_FEATURES) { + featureIDs[nFeatures] = id; + featureValues[nFeatures] = val; + ++nFeatures; + } + goto next_option; + } + + if (strncmp(cp1, "rtl", 3) == 0) { + cp3 = cp2; + if (*cp3 == ';' || *cp3 == ':') + --cp3; + while (*cp3 == '\0' || *cp3 == ' ' || *cp3 == '\t') + --cp3; + if (*cp3) + ++cp3; + if (cp3 == cp1 + 3) { + rtl = 1; + goto next_option; + } + } + +/* + if (strncmp(cp1, "vertical", 8) == 0) { + cp3 = cp2; + if (*cp3 == ';' || *cp3 == ':') + --cp3; + while (*cp3 == '\0' || *cp3 == ' ' || *cp3 == '\t') + --cp3; + if (*cp3) + ++cp3; + if (cp3 == cp1 + 8) { + loadedfontflags |= FONT_FLAGS_VERTICAL; + goto next_option; + } + } +*/ + + bad_option: + fontfeaturewarning(cp1, cp2 - cp1, 0, 0); + + next_option: + cp1 = cp2; + } + + } + + if ((loadedfontflags & FONT_FLAGS_COLORED) == 0) + rgbValue = 0x000000FF; + + if ((loadedfontflags & FONT_FLAGS_VERTICAL) != 0) + setFontLayoutDir(font, 1); + +// deleteLayoutEngine(engine); + engine = createGraphiteEngine(fontRef, font, faceName, rgbValue, rtl, languageTag, + extend, slant, nFeatures, &featureIDs[0], &featureValues[0]); + if (engine != NULL) + nativefonttypeflag = OTGR_FONT_FLAG; return engine; } static void -splitFontName(char* name, char** var, char** feat, char** end) +splitFontName(char* name, char** var, char** feat, char** end, int* index) { *var = NULL; *feat = NULL; + *index = 0; if (*name == '[') { int withinFileName = 1; #ifdef WIN32 @@ -784,8 +1029,12 @@ splitFontName(char* name, char** var, char** feat, char** end) #ifdef WIN32 && !((name - start == 1) && isalpha(*start)) #endif - ) - *var = name; + ) { + ++name; + while (*name >= '0' && *name <= '9') + *index = *index * 10 + *name++ - '0'; + --name; + } else if (!withinFileName && *feat == NULL) *feat = name; } @@ -813,7 +1062,7 @@ void* findnativefont(unsigned char* uname, integer scaled_size) /* scaled_size here is in TeX points */ { - void* rval = 0; + void* rval = NULL; char* nameString; char* var; char* feat; @@ -823,13 +1072,13 @@ findnativefont(unsigned char* uname, integer scaled_size) char* featString = NULL; PlatformFontRef fontRef; XeTeXFont font; + int index = 0; loadedfontmapping = NULL; loadedfontflags = 0; loadedfontletterspace = 0; - splitFontName(name, &var, &feat, &end); - + splitFontName(name, &var, &feat, &end, &index); nameString = xmalloc(var - name + 1); strncpy(nameString, name, var - name); nameString[var - name] = 0; @@ -854,16 +1103,16 @@ findnativefont(unsigned char* uname, integer scaled_size) if (path == NULL) path = kpse_find_file(nameString + 1, kpse_type1_format, 0); if (path != NULL) { - int index = 0; - if (varString != NULL) { - char* cp; - for (cp = varString; *cp && isdigit(*cp); ++cp) - index = index * 10 + *cp - '0'; - } font = createFontFromFile(path, index, scaled_size); if (font != NULL) { - rval = loadOTfont(0, font, scaled_size, featString); - if (rval == 0) + if (varString && strncmp(varString, "/GR", 3) == 0) { + rval = loadGraphiteFont(0, font, scaled_size, featString, nameString); + if (rval == NULL) + graphitewarning(); + } + if (rval == NULL) /* graphite wasn't requested, or failed to initialize */ + rval = loadOTfont(0, font, scaled_size, featString); + if (rval == NULL) deleteFont(font); } } @@ -892,16 +1141,24 @@ findnativefont(unsigned char* uname, integer scaled_size) font = createFont(fontRef, scaled_size); if (font != 0) { + if (getReqEngine() == 'G') { + rval = loadGraphiteFont(fontRef, font, scaled_size, featString, nameString); + if (rval == NULL) + graphitewarning(); + } + if (rval == NULL) { #ifdef XETEX_MAC - if (getReqEngine() == 'I' || getFontTablePtr(font, kGSUB) != 0 || getFontTablePtr(font, kGPOS) != 0) + if (getReqEngine() == 'I' || getReqEngine() == 'G' || + getFontTablePtr(font, kGSUB) != NULL || getFontTablePtr(font, kGPOS) != NULL) #endif - rval = loadOTfont(fontRef, font, scaled_size, featString); - if (rval == 0) + rval = loadOTfont(fontRef, font, scaled_size, featString); + } + if (rval == NULL) deleteFont(font); } #ifdef XETEX_MAC - if (rval == 0) { + if (rval == NULL) { load_aat: rval = loadAATfont(fontRef, scaled_size, featString); } @@ -939,7 +1196,7 @@ releasefontengine(void* engine, int type_flag) } else #endif - if (type_flag == OT_FONT_FLAG) { + if (type_flag == OTGR_FONT_FLAG) { deleteLayoutEngine((XeTeXLayoutEngine)engine); } } @@ -956,7 +1213,8 @@ otgetfontmetrics(void* pEngine, scaled* ascent, scaled* descent, scaled* xheight *ascent = X2Fix(a); *descent = X2Fix(d); - *slant = getSlant(getFont(engine)); + *slant = X2Fix(Fix2X(getSlant(getFont(engine))) * getExtendFactor(engine) + + getSlantFactor(engine)); glyphID = mapCharToGlyph(engine, 'x'); if (glyphID != 0) { @@ -984,7 +1242,11 @@ otfontget(integer what, void* pEngine) case XeTeX_count_glyphs: return countGlyphs(fontInst); break; - + + case XeTeX_count_features: /* ie Graphite features */ + return countGraphiteFeatures(engine); + break; + case XeTeX_OT_count_scripts: return countScripts(fontInst); break; @@ -1006,6 +1268,17 @@ otfontget1(integer what, void* pEngine, integer param) case XeTeX_OT_script_code: return getIndScript(fontInst, param); break; + + /* for graphite fonts...*/ + case XeTeX_feature_code: + return getGraphiteFeatureCode(engine, param); + break; + case XeTeX_is_exclusive_feature: + return 1; + break; + case XeTeX_count_selectors: + return countGraphiteFeatureSettings(engine, param); + break; } return 0; } @@ -1024,6 +1297,14 @@ otfontget2(integer what, void* pEngine, integer param1, integer param2) case XeTeX_OT_count_features: return countFeatures(fontInst, param1, param2); break; + + /* for graphite fonts */ + case XeTeX_selector_code: + return getGraphiteFeatureSettingCode(engine, param1, param2); + break; + case XeTeX_is_default_selector: + return getGraphiteFeatureDefaultSetting(engine, param1) == param2; + break; } return 0; @@ -1044,6 +1325,51 @@ otfontget3(integer what, void* pEngine, integer param1, integer param2, integer return 0; } +void +grprintfontname(integer what, void* pEngine, integer param1, integer param2) +{ + unsigned short name[128]; /* graphite API specifies size 128 */ + int n = 0; + XeTeXLayoutEngine engine = (XeTeXLayoutEngine)pEngine; + switch (what) { + case XeTeX_feature_name: + getGraphiteFeatureLabel(engine, param1, &name[0]); + break; + case XeTeX_selector_name: + getGraphiteFeatureSettingLabel(engine, param1, param2, &name[0]); + break; + } + while (name[n] != 0 && n < 128) + ++n; + printchars(&name[0], n); +} + +integer +grfontgetnamed(integer what, void* pEngine) +{ + long rval = -1; + XeTeXLayoutEngine engine = (XeTeXLayoutEngine)pEngine; + switch (what) { + case XeTeX_find_feature_by_name: + rval = findGraphiteFeatureNamed(engine, (const char*)nameoffile + 1, namelength); + break; + } + return rval; +} + +integer +grfontgetnamed1(integer what, void* pEngine, integer param) +{ + long rval = -1; + XeTeXLayoutEngine engine = (XeTeXLayoutEngine)pEngine; + switch (what) { + case XeTeX_find_selector_by_name: + rval = findGraphiteFeatureSettingNamed(engine, param, (const char*)nameoffile + 1, namelength); + break; + } + return rval; +} + #define XDV_FLAG_FONTTYPE_ATSUI 0x0001 #define XDV_FLAG_FONTTYPE_ICU 0x0002 @@ -1051,6 +1377,8 @@ otfontget3(integer what, void* pEngine, integer param1, integer param2, integer #define XDV_FLAG_COLORED 0x0200 #define XDV_FLAG_FEATURES 0x0400 #define XDV_FLAG_VARIATIONS 0x0800 +#define XDV_FLAG_EXTEND 0x1000 +#define XDV_FLAG_SLANT 0x2000 #ifdef XETEX_MAC static UInt32 @@ -1152,6 +1480,8 @@ makefontdef(integer f) int fontDefLength; char* cp; PlatformFontRef fontRef = 0; + float extend = 1.0; + float slant = 0.0; #ifdef XETEX_MAC ATSUStyle style = NULL; @@ -1177,11 +1507,16 @@ makefontdef(integer f) ATSUGetAttribute(style, kATSURGBAlphaColorTag, sizeof(ATSURGBAlphaColor), &atsuColor, 0); rgba = atsuColorToRGBA32(atsuColor); + CGAffineTransform t; + ATSUGetAttribute(style, kATSUFontMatrixTag, sizeof(CGAffineTransform), &t, 0); + extend = t.a; + slant = t.b; + ATSUGetAttribute(style, kATSUSizeTag, sizeof(Fixed), &size, 0); } else #endif - if (fontarea[f] == OT_FONT_FLAG) { + if (fontarea[f] == OTGR_FONT_FLAG) { XeTeXLayoutEngine engine; flags = XDV_FLAG_FONTTYPE_ICU; @@ -1199,6 +1534,9 @@ makefontdef(integer f) if ((fontflags[f] & FONT_FLAGS_VERTICAL) != 0) flags |= XDV_FLAG_VERTICAL; + extend = getExtendFactor(engine); + slant = getSlantFactor(engine); + size = X2Fix(getPointSize(engine)); } else { @@ -1242,7 +1580,16 @@ makefontdef(integer f) flags |= XDV_FLAG_VARIATIONS; } #endif - + + if (extend != 1.0) { + fontDefLength += 4; + flags |= XDV_FLAG_EXTEND; + } + if (slant != 0.0) { + fontDefLength += 4; + flags |= XDV_FLAG_SLANT; + } + if (fontDefLength > xdvBufSize) { if (xdvbuffer != NULL) free(xdvbuffer); @@ -1296,6 +1643,17 @@ makefontdef(integer f) } } #endif + + if (flags & XDV_FLAG_EXTEND) { + Fixed f = X2Fix(extend); + *(UInt32*)(cp) = SWAP32(f); + cp += 4; + } + if (flags & XDV_FLAG_SLANT) { + Fixed f = X2Fix(slant); + *(UInt32*)(cp) = SWAP32(f); + cp += 4; + } return fontDefLength; } @@ -1365,7 +1723,7 @@ getnativecharheightdepth(integer font, integer ch, scaled* height, scaled* depth } else #endif - if (fontarea[font] == OT_FONT_FLAG) { + if (fontarea[font] == OTGR_FONT_FLAG) { XeTeXLayoutEngine engine = (XeTeXLayoutEngine)fontlayoutengine[font]; int gid = mapCharToGlyph(engine, ch); getGlyphHeightDepth(engine, gid, &ht, &dp); @@ -1415,7 +1773,7 @@ getnativecharsidebearings(integer font, integer ch, scaled* lsb, scaled* rsb) } else #endif - if (fontarea[font] == OT_FONT_FLAG) { + if (fontarea[font] == OTGR_FONT_FLAG) { XeTeXLayoutEngine engine = (XeTeXLayoutEngine)fontlayoutengine[font]; int gid = mapCharToGlyph(engine, ch); getGlyphSidebearings(engine, gid, &l, &r); @@ -1452,7 +1810,7 @@ getnativecharwd(integer f, integer c) } else #endif - if (fontarea[f] == OT_FONT_FLAG) { + if (fontarea[f] == OTGR_FONT_FLAG) { XeTeXLayoutEngine engine = (XeTeXLayoutEngine)fontlayoutengine[f]; int gid = mapCharToGlyph(engine, c); wd = X2Fix(getGlyphWidthFromEngine(engine, gid)); @@ -1500,46 +1858,104 @@ measure_native_node(void* pNode, int use_glyph_metrics) } else #endif - if (fontarea[f] == OT_FONT_FLAG) { - /* using this font in OT Layout mode, so fontlayoutengine[f] is actually a XeTeXLayoutEngine */ - + if (fontarea[f] == OTGR_FONT_FLAG) { XeTeXLayoutEngine engine = (XeTeXLayoutEngine)(fontlayoutengine[f]); - /* need to find direction runs within the text, and call layoutChars separately for each */ - - int nGlyphs; - UBiDiDirection dir; - float x, y; - void* glyph_info = 0; - static float* positions = 0; - static UInt32* glyphs = 0; - static int maxGlyphs = 0; - FixedPoint* locations; UInt16* glyphIDs; int realGlyphCount = 0; - UBiDi* pBiDi = ubidi_open(); - - UErrorCode errorCode = (UErrorCode)0; - ubidi_setPara(pBiDi, txtPtr, txtLen, getDefaultDirection(engine), NULL, &errorCode); + if (usingOpenType(engine)) { + /* using this font in OT Layout mode, so fontlayoutengine[f] is actually a XeTeXLayoutEngine */ + + /* need to find direction runs within the text, and call layoutChars separately for each */ + + int nGlyphs; + UBiDiDirection dir; + float x, y; + void* glyph_info = 0; + static float* positions = 0; + static UInt32* glyphs = 0; + static int maxGlyphs = 0; + + UBiDi* pBiDi = ubidi_open(); + + UErrorCode errorCode = (UErrorCode)0; + ubidi_setPara(pBiDi, txtPtr, txtLen, getDefaultDirection(engine), NULL, &errorCode); + + dir = ubidi_getDirection(pBiDi); + if (dir == UBIDI_MIXED) { + /* we actually do the layout twice here, once to count glyphs and then again to get them; + // which is inefficient, but i figure that MIXED is a relatively rare occurrence, so i can't be + // bothered to deal with the memory reallocation headache of doing it differently + */ + int nRuns = ubidi_countRuns(pBiDi, &errorCode); + double wid = 0; + long totalGlyphs = 0; + int i, runIndex; + int32_t logicalStart, length; + OSStatus status = 0; + for (runIndex = 0; runIndex < nRuns; ++runIndex) { + dir = ubidi_getVisualRun(pBiDi, runIndex, &logicalStart, &length); + nGlyphs = layoutChars(engine, (UniChar*)txtPtr, logicalStart, length, txtLen, (dir == UBIDI_RTL), 0.0, 0.0, &status); + totalGlyphs += nGlyphs; + + if (nGlyphs >= maxGlyphs) { + if (glyphs != 0) { + free(glyphs); + free(positions); + } + maxGlyphs = nGlyphs + 20; + glyphs = xmalloc(maxGlyphs * sizeof(UInt32)); + positions = xmalloc((maxGlyphs * 2 + 2) * sizeof(float)); + } + + getGlyphs(engine, glyphs, &status); + for (i = 0; i < nGlyphs; ++i) + if (glyphs[i] < 0xfffe) + ++realGlyphCount; + } + + if (realGlyphCount > 0) { + double x, y; + glyph_info = xmalloc(realGlyphCount * native_glyph_info_size); + locations = (FixedPoint*)glyph_info; + glyphIDs = (UInt16*)(locations + realGlyphCount); + realGlyphCount = 0; + + x = y = 0.0; + for (runIndex = 0; runIndex < nRuns; ++runIndex) { + dir = ubidi_getVisualRun(pBiDi, runIndex, &logicalStart, &length); + nGlyphs = layoutChars(engine, (UniChar*)txtPtr, logicalStart, length, txtLen, + (dir == UBIDI_RTL), 0, 0, &status); - dir = ubidi_getDirection(pBiDi); - if (dir == UBIDI_MIXED) { - /* we actually do the layout twice here, once to count glyphs and then again to get them; - // which is inefficient, but i figure that MIXED is a relatively rare occurrence, so i can't be - // bothered to deal with the memory reallocation headache of doing it differently - */ - int nRuns = ubidi_countRuns(pBiDi, &errorCode); - double wid = 0; - long totalGlyphs = 0; - int i, runIndex; - int32_t logicalStart, length; - OSStatus status = 0; - for (runIndex = 0; runIndex < nRuns; ++runIndex) { - dir = ubidi_getVisualRun(pBiDi, runIndex, &logicalStart, &length); - nGlyphs = layoutChars(engine, (UniChar*)txtPtr, logicalStart, length, txtLen, (dir == UBIDI_RTL), 0.0, 0.0, &status); - totalGlyphs += nGlyphs; + getGlyphs(engine, glyphs, &status); + getGlyphPositions(engine, positions, &status); + + for (i = 0; i < nGlyphs; ++i) { + if (glyphs[i] < 0xfffe) { + glyphIDs[realGlyphCount] = glyphs[i]; + locations[realGlyphCount].x = X2Fix(positions[2*i] + x); + locations[realGlyphCount].y = X2Fix(positions[2*i+1] + y); + ++realGlyphCount; + } + } + x += positions[2*i]; + y += positions[2*i+1]; + } + wid = x; + } + + node_width(node) = X2Fix(wid); + native_glyph_count(node) = realGlyphCount; + native_glyph_info_ptr(node) = glyph_info; + } + else { + int i; + OSStatus status = 0; + nGlyphs = layoutChars(engine, (UniChar*)txtPtr, 0, txtLen, txtLen, (dir == UBIDI_RTL), 0.0, 0.0, &status); + getGlyphPosition(engine, nGlyphs, &x, &y, &status); + node_width(node) = X2Fix(x); if (nGlyphs >= maxGlyphs) { if (glyphs != 0) { @@ -1550,29 +1966,18 @@ measure_native_node(void* pNode, int use_glyph_metrics) glyphs = xmalloc(maxGlyphs * sizeof(UInt32)); positions = xmalloc((maxGlyphs * 2 + 2) * sizeof(float)); } - getGlyphs(engine, glyphs, &status); + getGlyphPositions(engine, positions, &status); + for (i = 0; i < nGlyphs; ++i) if (glyphs[i] < 0xfffe) ++realGlyphCount; - } - - if (realGlyphCount > 0) { - double x, y; - glyph_info = xmalloc(realGlyphCount * native_glyph_info_size); - locations = (FixedPoint*)glyph_info; - glyphIDs = (UInt16*)(locations + realGlyphCount); - realGlyphCount = 0; - - x = y = 0.0; - for (runIndex = 0; runIndex < nRuns; ++runIndex) { - dir = ubidi_getVisualRun(pBiDi, runIndex, &logicalStart, &length); - nGlyphs = layoutChars(engine, (UniChar*)txtPtr, logicalStart, length, txtLen, - (dir == UBIDI_RTL), x, y, &status); - getGlyphs(engine, glyphs, &status); - getGlyphPositions(engine, positions, &status); - + if (realGlyphCount > 0) { + glyph_info = xmalloc(realGlyphCount * native_glyph_info_size); + locations = (FixedPoint*)glyph_info; + glyphIDs = (UInt16*)(locations + realGlyphCount); + realGlyphCount = 0; for (i = 0; i < nGlyphs; ++i) { if (glyphs[i] < 0xfffe) { glyphIDs[realGlyphCount] = glyphs[i]; @@ -1581,60 +1986,39 @@ measure_native_node(void* pNode, int use_glyph_metrics) ++realGlyphCount; } } - x = positions[2*i]; - y = positions[2*i+1]; } - wid = x; + + native_glyph_count(node) = realGlyphCount; + native_glyph_info_ptr(node) = glyph_info; } - - node_width(node) = X2Fix(wid); - native_glyph_count(node) = realGlyphCount; - native_glyph_info_ptr(node) = glyph_info; + + ubidi_close(pBiDi); + } - else { - int i; - OSStatus status = 0; - nGlyphs = layoutChars(engine, (UniChar*)txtPtr, 0, txtLen, txtLen, (dir == UBIDI_RTL), 0.0, 0.0, &status); - getGlyphPosition(engine, nGlyphs, &x, &y, &status); - node_width(node) = X2Fix(x); - - if (nGlyphs >= maxGlyphs) { - if (glyphs != 0) { - free(glyphs); - free(positions); - } - maxGlyphs = nGlyphs + 20; - glyphs = xmalloc(maxGlyphs * sizeof(UInt32)); - positions = xmalloc((maxGlyphs * 2 + 2) * sizeof(float)); - } - getGlyphs(engine, glyphs, &status); - getGlyphPositions(engine, positions, &status); - - for (i = 0; i < nGlyphs; ++i) - if (glyphs[i] < 0xfffe) - ++realGlyphCount; - + else { + /* using Graphite */ + void* glyph_info = NULL; + realGlyphCount = makeGraphiteSegment(engine, (UniChar*)txtPtr, txtLen); + if (realGlyphCount > 0) { + int i; glyph_info = xmalloc(realGlyphCount * native_glyph_info_size); locations = (FixedPoint*)glyph_info; glyphIDs = (UInt16*)(locations + realGlyphCount); - realGlyphCount = 0; - for (i = 0; i < nGlyphs; ++i) { - if (glyphs[i] < 0xfffe) { - glyphIDs[realGlyphCount] = glyphs[i]; - locations[realGlyphCount].x = X2Fix(positions[2*i]); - locations[realGlyphCount].y = X2Fix(positions[2*i+1]); - ++realGlyphCount; - } + for (i = 0; i < realGlyphCount; ++i) { + float x, y; + getGraphiteGlyphInfo(engine, i, &(glyphIDs[i]), &x, &y); + locations[i].x = X2Fix(x); + locations[i].y = X2Fix(y); } } + node_width(node) = X2Fix(graphiteSegmentWidth(engine)); + native_glyph_count(node) = realGlyphCount; native_glyph_info_ptr(node) = glyph_info; } - ubidi_close(pBiDi); - if (fontletterspace[f] != 0) { Fixed lsDelta = 0; Fixed lsUnit = fontletterspace[f]; @@ -1681,7 +2065,7 @@ measure_native_node(void* pNode, int use_glyph_metrics) GetGlyphBBox_AAT((ATSUStyle)(fontlayoutengine[f]), glyphIDs[i], &bbox); else #endif - if (fontarea[f] == OT_FONT_FLAG) + if (fontarea[f] == OTGR_FONT_FLAG) getGlyphBounds((XeTeXLayoutEngine)(fontlayoutengine[f]), glyphIDs[i], &bbox); cacheGlyphBBox(f, glyphIDs[i], &bbox); @@ -1715,7 +2099,7 @@ get_native_ital_corr(void* pNode) return X2Fix(GetGlyphItalCorr_AAT((ATSUStyle)(fontlayoutengine[f]), glyphIDs[n-1])) + fontletterspace[f]; #endif - if (fontarea[f] == OT_FONT_FLAG) + if (fontarea[f] == OTGR_FONT_FLAG) return X2Fix(getGlyphItalCorr((XeTeXLayoutEngine)(fontlayoutengine[f]), glyphIDs[n-1])) + fontletterspace[f]; } @@ -1735,7 +2119,7 @@ get_native_glyph_ital_corr(void* pNode) if (fontarea[f] == AAT_FONT_FLAG) return X2Fix(GetGlyphItalCorr_AAT((ATSUStyle)(fontlayoutengine[f]), gid)); #endif - if (fontarea[f] == OT_FONT_FLAG) + if (fontarea[f] == OTGR_FONT_FLAG) return X2Fix(getGlyphItalCorr((XeTeXLayoutEngine)(fontlayoutengine[f]), gid)); return 0; /* can't actually happen */ @@ -1763,7 +2147,7 @@ measure_native_glyph(void* pNode, int use_glyph_metrics) } else #endif - if (fontarea[f] == OT_FONT_FLAG) { + if (fontarea[f] == OTGR_FONT_FLAG) { XeTeXLayoutEngine engine = (XeTeXLayoutEngine)fontlayoutengine[f]; XeTeXFont fontInst = getFont(engine); node_width(node) = X2Fix(getGlyphWidth(fontInst, gid)); @@ -1795,7 +2179,7 @@ mapchartoglyph(integer font, integer ch) return MapCharToGlyph_AAT((ATSUStyle)(fontlayoutengine[font]), ch); else #endif - if (fontarea[font] == OT_FONT_FLAG) + if (fontarea[font] == OTGR_FONT_FLAG) return mapCharToGlyph((XeTeXLayoutEngine)(fontlayoutengine[font]), ch); else { fprintf(stderr, "\n! Internal error: bad native font flag\n"); @@ -1812,7 +2196,7 @@ mapglyphtoindex(integer font) return MapGlyphToIndex_AAT((ATSUStyle)(fontlayoutengine[font]), (const char*)nameoffile + 1); else #endif - if (fontarea[font] == OT_FONT_FLAG) + if (fontarea[font] == OTGR_FONT_FLAG) return mapGlyphToIndex((XeTeXLayoutEngine)(fontlayoutengine[font]), (const char*)nameoffile + 1); else { fprintf(stderr, "\n! Internal error: bad native font flag\n"); @@ -1828,7 +2212,7 @@ getfontcharrange(integer font, int first) return GetFontCharRange_AAT((ATSUStyle)(fontlayoutengine[font]), first); else #endif - if (fontarea[font] == OT_FONT_FLAG) + if (fontarea[font] == OTGR_FONT_FLAG) return getFontCharRange((XeTeXLayoutEngine)(fontlayoutengine[font]), first); else { fprintf(stderr, "\n! Internal error: bad native font flag\n"); @@ -1900,6 +2284,13 @@ atsugetfontmetrics(ATSUStyle style, Fixed* ascent, Fixed* descent, Fixed* xheigh } } + CGAffineTransform t; + ATSUGetAttribute(style, kATSUFontMatrixTag, sizeof(CGAffineTransform), &t, 0); + if (t.a != 1.0) + *slant = X2Fix(Fix2X(*slant) * t.a); + if (t.b != 0.0) + *slant += X2Fix(t.b); + if (0 && metrics.xHeight != 0.0) { /* currently not using this, as the values from ATS don't seem quite what I'd expect */ *xheight = X2Fix(metrics.xHeight * floatSize); @@ -2229,7 +2620,7 @@ printglyphname(integer font, integer gid) } else #endif - if (fontarea[font] == OT_FONT_FLAG) { + if (fontarea[font] == OTGR_FONT_FLAG) { XeTeXLayoutEngine engine = (XeTeXLayoutEngine)fontlayoutengine[font]; s = (char*)getGlyphName(getFont(engine), gid, &len); } @@ -2322,13 +2713,15 @@ open_dvi_output(FILE** fptr) } } -void +int dviclose(FILE* fptr) { - if (nopdfoutput) - fclose(fptr); + if (nopdfoutput) { + if (fclose(fptr) != 0) + return errno; + } else - pclose(fptr); + return pclose(fptr); } int @@ -2357,11 +2750,6 @@ get_uni_c(UFILE* f) case 0: ; }; rval -= offsetsFromUTF8[extraBytes]; - if (rval > 0xFFFF) { - rval -= 0x10000; - f->savedChar = 0xdc00 + rval % 0x0400; - rval = 0xd800 + rval / 0x0400; - } } break; @@ -2369,11 +2757,36 @@ get_uni_c(UFILE* f) rval = getc(f->f); rval <<= 8; rval += getc(f->f); + if (rval >= 0xd800 && rval <= 0xdbff) { + int lo = getc(f->f); + lo <<= 8; + lo += getc(f->f); + if (lo >= 0xdc00 && lo <= 0xdfff) + rval = 0x10000 + (rval - 0xd800) * 0x400 + (lo - 0xdc00); + else { + rval = 0xfffd; + f->savedChar = lo; + } + } + else if (rval >= 0xdc00 && rval <= 0xdfff) + rval = 0xfffd; break; case UTF16LE: rval = getc(f->f); rval += (getc(f->f) << 8); + if (rval >= 0xd800 && rval <= 0xdbff) { + int lo = getc(f->f); + lo += (getc(f->f) << 8); + if (lo >= 0xdc00 && lo <= 0xdfff) + rval = 0x10000 + (rval - 0xd800) * 0x400 + (lo - 0xdc00); + else { + rval = 0xfffd; + f->savedChar = lo; + } + } + else if (rval >= 0xdc00 && rval <= 0xdfff) + rval = 0xfffd; break; case RAW: diff --git a/Build/source/texk/web2c/xetexdir/XeTeX_ext.h b/Build/source/texk/web2c/xetexdir/XeTeX_ext.h index 9e37b3ca63e..b273bc7dabd 100644 --- a/Build/source/texk/web2c/xetexdir/XeTeX_ext.h +++ b/Build/source/texk/web2c/xetexdir/XeTeX_ext.h @@ -58,8 +58,8 @@ typedef INTEGER_TYPE integer; typedef struct UFILE* unicodefile; #endif -#define AAT_FONT_FLAG 65535 -#define OT_FONT_FLAG 65534 +#define AAT_FONT_FLAG 0xFFFFU +#define OTGR_FONT_FLAG 0xFFFEU #define FONT_FLAGS_COLORED 0x01 #define FONT_FLAGS_VERTICAL 0x02 @@ -221,6 +221,7 @@ extern "C" { void linebreakstart(integer localeStrNum, const UniChar* text, integer textLength); int linebreaknext(); int getencodingmodeandinfo(integer* info); + void printcstring(const char* str); void printutf8str(const unsigned char* str, int len); void printchars(const unsigned short* str, int len); void* load_mapping_file(const char* s, const char* e); @@ -255,15 +256,20 @@ extern "C" { integer getfontcharrange(integer font, int first); void printglyphname(integer font, integer gid); - double read_double(const char** s); - unsigned int read_rgb_a(const char** cp); - + void grprintfontname(integer what, void* pEngine, integer param1, integer param2); + integer grfontgetnamed(integer what, void* pEngine); + integer grfontgetnamed1(integer what, void* pEngine, integer param); + + double read_double(const char** s); + unsigned int read_rgb_a(const char** cp); + const char* getGlyphNamePtr(const char* buffer, int tableSize, UInt16 gid, int* len); + int countpdffilepages(); int find_pic_file(char** path, realrect* bounds, int pdfBoxType, int page); int u_open_in(unicodefile* f, integer filefmt, const char* fopen_mode, integer mode, integer encodingData); int open_dvi_output(FILE** fptr); - void dviclose(FILE* fptr); + int dviclose(FILE* fptr); int get_uni_c(UFILE* f); int input_line(UFILE* f); void makeutf16name(); diff --git a/Build/source/texk/web2c/xetexdir/XeTeX_mac.c b/Build/source/texk/web2c/xetexdir/XeTeX_mac.c index 4c64a65feb4..121e431ca0d 100644 --- a/Build/source/texk/web2c/xetexdir/XeTeX_mac.c +++ b/Build/source/texk/web2c/xetexdir/XeTeX_mac.c @@ -633,6 +633,9 @@ loadAATfont(ATSFontRef fontRef, long scaled_size, const char* cp1) ATSUFontID fontID = FMGetFontFromATSFontRef(fontRef); ATSUStyle style = 0; OSStatus status = ATSUCreateStyle(&style); + double extend = 1.0; + double slant = 0.0; + if (status == noErr) { UInt32 rgbValue; Fixed tracking = 0x80000000; @@ -785,44 +788,36 @@ loadAATfont(ATSFontRef fontRef, long scaled_size, const char* cp1) goto next_option; } + if (strncmp(cp1, "extend", 6) == 0) { + cp3 = cp1 + 6; + if (*cp3 != '=') + goto bad_option; + ++cp3; + extend = read_double(&cp3); + goto next_option; + } + + if (strncmp(cp1, "slant", 5) == 0) { + cp3 = cp1 + 5; + if (*cp3 != '=') + goto bad_option; + ++cp3; + slant = read_double(&cp3); + goto next_option; + } + if (strncmp(cp1, "color", 5) == 0) { + const char* s; cp3 = cp1 + 5; if (*cp3 != '=') goto bad_option; ++cp3; - rgbValue = 0; - unsigned alpha = 0; - int i; - for (i = 0; i < 6; ++i) { - if (*cp3 >= '0' && *cp3 <= '9') - rgbValue = (rgbValue << 4) + *cp3 - '0'; - else if (*cp3 >= 'A' && *cp3 <= 'F') - rgbValue = (rgbValue << 4) + *cp3 - 'A' + 10; - else if (*cp3 >= 'a' && *cp3 <= 'f') - rgbValue = (rgbValue << 4) + *cp3 - 'a' + 10; - else - goto bad_option; - ++cp3; - } - rgbValue <<= 8; - for (i = 0; i < 2; ++i) { - if (*cp3 >= '0' && *cp3 <= '9') - alpha = (alpha << 4) + *cp3 - '0'; - else if (*cp3 >= 'A' && *cp3 <= 'F') - alpha = (alpha << 4) + *cp3 - 'A' + 10; - else if (*cp3 >= 'a' && *cp3 <= 'f') - alpha = (alpha << 4) + *cp3 - 'a' + 10; - else - break; - ++cp3; - } - if (i == 2) - rgbValue += alpha; + s = cp3; + rgbValue = read_rgb_a(&cp3); + if ((cp3 == s+6) || (cp3 == s+8)) + loadedfontflags |= FONT_FLAGS_COLORED; else - rgbValue += 0xFF; - - loadedfontflags |= FONT_FLAGS_COLORED; - + goto bad_option; goto next_option; } @@ -831,33 +826,8 @@ loadAATfont(ATSFontRef fontRef, long scaled_size, const char* cp1) if (*cp3 != '=') goto bad_option; ++cp3; - - int sign = 1; - if (*cp3 == '-') { - sign = -1; - ++cp3; - } - else if (*cp3 == '+') { - ++cp3; - } - - double val = 0.0; - while (*cp3 >= '0' && *cp3 <= '9') { - val = val * 10.0 + *cp3 - '0'; - ++cp3; - } - if (*cp3 == '.' || *cp3 == ',') { - ++cp3; - double dec = 10.0; - while (*cp3 >= '0' && *cp3 <= '9') { - val = val + (*cp3 - '0') / dec; - ++cp3; - dec = dec * 10.0; - } - } - - tracking = sign * X2Fix(val); - + double val = read_double(&cp3); + tracking = X2Fix(val); goto next_option; } @@ -866,33 +836,8 @@ loadAATfont(ATSFontRef fontRef, long scaled_size, const char* cp1) if (*cp3 != '=') goto bad_option; ++cp3; - - int sign = 1; - if (*cp3 == '-') { - sign = -1; - ++cp3; - } - else if (*cp3 == '+') { - ++cp3; - } - - double val = 0.0; - while (*cp3 >= '0' && *cp3 <= '9') { - val = val * 10.0 + *cp3 - '0'; - ++cp3; - } - if (*cp3 == '.' || *cp3 == ',') { - ++cp3; - double dec = 10.0; - while (*cp3 >= '0' && *cp3 <= '9') { - val = val + (*cp3 - '0') / dec; - ++cp3; - dec = dec * 10.0; - } - } - - loadedfontletterspace = sign * (val / 100.0) * scaled_size; - + double val = read_double(&cp3); + loadedfontletterspace = (val / 100.0) * scaled_size; goto next_option; } @@ -903,7 +848,7 @@ loadAATfont(ATSFontRef fontRef, long scaled_size, const char* cp1) cp3 = cp2; if (*cp3 == ';' || *cp3 == ':') --cp3; - while (*cp3 == ' ' || *cp3 == '\t') + while (*cp3 == '\0' || *cp3 == ' ' || *cp3 == '\t') --cp3; if (*cp3) ++cp3; @@ -949,6 +894,14 @@ loadAATfont(ATSFontRef fontRef, long scaled_size, const char* cp1) ATSUSetAttributes(style, 1, tags, sizes, attrs); } + if (extend != 1.0 || slant != 0.0) { + CGAffineTransform t = { extend, slant, 0, 1.0, 0, 0 }; + tags[0] = kATSUFontMatrixTag; + sizes[0] = sizeof(CGAffineTransform); + attrs[0] = &t; + ATSUSetAttributes(style, 1, tags, sizes, attrs); + } + free((char*)featureTypes); free((char*)selectorValues); free((char*)axes); @@ -960,6 +913,31 @@ loadAATfont(ATSFontRef fontRef, long scaled_size, const char* cp1) return style; } +int +countpdffilepages() +{ + int rval = 0; + + char* pic_path = kpse_find_file((char*)nameoffile + 1, kpse_pict_format, 1); + CFURLRef picFileURL = NULL; + if (pic_path) { + picFileURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (UInt8*)pic_path, strlen(pic_path), false); + if (picFileURL != NULL) { + FSRef picFileRef; + CFURLGetFSRef(picFileURL, &picFileRef); + CGPDFDocumentRef document = CGPDFDocumentCreateWithURL(picFileURL); + if (document != NULL) { + rval = CGPDFDocumentGetNumberOfPages(document); + CGPDFDocumentRelease(document); + } + CFRelease(picFileURL); + } + free(pic_path); + } + + return rval; +} + int find_pic_file(char** path, realrect* bounds, int pdfBoxType, int page) { diff --git a/Build/source/texk/web2c/xetexdir/XeTeX_pic.c b/Build/source/texk/web2c/xetexdir/XeTeX_pic.c index a511b848038..9491e9d1a8a 100644 --- a/Build/source/texk/web2c/xetexdir/XeTeX_pic.c +++ b/Build/source/texk/web2c/xetexdir/XeTeX_pic.c @@ -32,6 +32,22 @@ XeTeX_pic.c #include "jpegimage.h" #include "bmpimage.h" + +int +countpdffilepages() +{ + int rval = 0; + + char* pic_path = kpse_find_file((char*)nameoffile + 1, kpse_pict_format, 1); + if (pic_path) { + rval = pdf_count_pages(pic_path); + free(pic_path); + } + + return rval; +} + + /* locate picture file from /nameoffile+1/ using kpathsearch pdfBoxType indicates which pdf bounding box to use (0 for \XeTeXpicfile) diff --git a/Build/source/texk/web2c/xetexdir/jpegimage.c b/Build/source/texk/web2c/xetexdir/jpegimage.c index a70c4241c35..fafdb637c10 100644 --- a/Build/source/texk/web2c/xetexdir/jpegimage.c +++ b/Build/source/texk/web2c/xetexdir/jpegimage.c @@ -240,6 +240,134 @@ read_APP14_Adobe (struct JPEG_info *j_info, FILE *fp, unsigned short length) return 7; } +static unsigned long +read_exif_bytes(unsigned char **p, int n, int b) +{ + unsigned long rval = 0; + unsigned char *pp = *p; + if (b) { + switch (n) { + case 4: + rval += *pp++; rval <<= 8; + rval += *pp++; rval <<= 8; + case 2: + rval += *pp++; rval <<= 8; + rval += *pp; + break; + } + } + else { + pp += n; + switch (n) { + case 4: + rval += *--pp; rval <<= 8; + rval += *--pp; rval <<= 8; + case 2: + rval += *--pp; rval <<= 8; + rval += *--pp; + break; + } + } + *p += n; + return rval; +} + +static unsigned short +read_APP1_Exif (struct JPEG_info *j_info, FILE *fp, unsigned short length) +{ + /* this doesn't save the data, just reads the tags we need */ + /* based on info from http://www.exif.org/Exif2-2.PDF */ + unsigned char *buffer = NEW(length, unsigned char); + unsigned char *p, *rp; + unsigned char *tiff_header; + char bigendian; + int i; + double rational_value; + int num_fields, tag, type, count, value, num, den; + double xres = 72.0; + double yres = 72.0; + double res_unit = 1.0; + fread(buffer, length, 1, fp); + p = buffer; + while ((p < buffer + length) && (*p == 0)) + ++p; + tiff_header = p; + if ((*p == 'M') && (*(p+1) == 'M')) + bigendian = 1; + else if ((*p == 'I') && (*(p+1) == 'I')) + bigendian = 0; + else + goto err; + p += 2; + i = read_exif_bytes(&p, 2, bigendian); + if (i != 42) + goto err; + i = read_exif_bytes(&p, 4, bigendian); + p = tiff_header + i; + num_fields = read_exif_bytes(&p, 2, bigendian); + while (num_fields-- > 0) { + tag = read_exif_bytes(&p, 2, bigendian); + type = read_exif_bytes(&p, 2, bigendian); + count = read_exif_bytes(&p, 4, bigendian); + switch (type) { + case 1: /* byte */ + value = *p++; + p += 3; + break; + case 3: /* short */ + value = read_exif_bytes(&p, 2, bigendian); + p += 2; + break; + case 4: /* long */ + case 9: /* slong */ + value = read_exif_bytes(&p, 4, bigendian); + break; + case 5: /* rational */ + case 10: /* srational */ + value = read_exif_bytes(&p, 4, bigendian); + rp = tiff_header + value; + num = read_exif_bytes(&rp, 4, bigendian); + den = read_exif_bytes(&rp, 4, bigendian); + break; + case 7: /* undefined */ + value = *p++; + p += 3; + break; + case 2: /* ascii */ + default: + p += 4; + break; + } + switch (tag) { + case 282: /* x res */ + if (den != 0) + xres = num / den; + break; + case 283: /* y res */ + if (den != 0) + yres = num / den; + break; + case 296: /* res unit */ + switch (value) { + case 2: + res_unit = 1.0; + break; + case 3: + res_unit = 2.54; + break; + } + } + } + + + j_info->xdpi = xres * res_unit; + j_info->ydpi = yres * res_unit; + +err: + RELEASE(buffer); + return length; +} + static unsigned short read_APP0_JFIF (struct JPEG_info *j_info, FILE *fp, unsigned short length) { @@ -364,6 +492,17 @@ JPEG_scan_file (struct JPEG_info *j_info, FILE *fp) } seek_relative(fp, length); break; + case JM_APP1: + if (length > 5) { + if (fread(app_sig, sizeof(char), 5, fp) != 5) + return -1; + length -= 5; + if (!memcmp(app_sig, "Exif\000", 5)) { + length -= read_APP1_Exif(j_info, fp, length); + } + } + seek_relative(fp, length); + break; case JM_APP2: if (length >= 14) { if (fread(app_sig, sizeof(char), 12, fp) != 12) diff --git a/Build/source/texk/web2c/xetexdir/jpegimage.h b/Build/source/texk/web2c/xetexdir/jpegimage.h index 03ef4ea56a3..5099138027e 100644 --- a/Build/source/texk/web2c/xetexdir/jpegimage.h +++ b/Build/source/texk/web2c/xetexdir/jpegimage.h @@ -87,6 +87,7 @@ typedef enum { JM_EXP = 0xdf, JM_APP0 = 0xe0, + JM_APP1 = 0xe1, JM_APP2 = 0xe2, JM_APP14 = 0xee, JM_APP15 = 0xef, diff --git a/Build/source/texk/web2c/xetexdir/pdfimage.cpp b/Build/source/texk/web2c/xetexdir/pdfimage.cpp index 21af77c6572..2c60d09c790 100644 --- a/Build/source/texk/web2c/xetexdir/pdfimage.cpp +++ b/Build/source/texk/web2c/xetexdir/pdfimage.cpp @@ -82,3 +82,25 @@ pdf_get_rect(char* filename, int page_num, int pdf_box, realrect* box) return 0; } + +int +pdf_count_pages(char* filename) +{ + int pages = 0; + GString* name = new GString(filename); + PDFDoc* doc = new PDFDoc(name); + + if (!doc) { + delete name; + return 0; + } + + /* if the doc got created, it now owns name, so we mustn't delete it! */ + + if (doc->isOk()) + pages = doc->getNumPages(); + + delete doc; + + return pages; +} diff --git a/Build/source/texk/web2c/xetexdir/pdfimage.h b/Build/source/texk/web2c/xetexdir/pdfimage.h index 0869c03aa1e..b2a77d9f311 100644 --- a/Build/source/texk/web2c/xetexdir/pdfimage.h +++ b/Build/source/texk/web2c/xetexdir/pdfimage.h @@ -20,6 +20,8 @@ extern "C" { extern int pdf_get_rect(char* filename, int page_num, int pdf_box, realrect* box); +extern int pdf_count_pages(char* filename); + #ifdef __cplusplus }; #endif diff --git a/Build/source/texk/web2c/xetexdir/pool2c.pl b/Build/source/texk/web2c/xetexdir/pool2c.pl new file mode 100644 index 00000000000..c2628deab46 --- /dev/null +++ b/Build/source/texk/web2c/xetexdir/pool2c.pl @@ -0,0 +1,74 @@ +#! /usr/bin/perl + +# Convert web .pool file into C source +# Result is an array of chars (bytes) containing the strings, +# each prefixed by a length byte. +# The function initpool() loads this data into TeX's pool. + +# usage: perl pool2c.pl NAME.pool +# writes output to ${NAME}_pool.c if only one arg provided + +die "expected pool name as argument" unless $#ARGV >= 0; +die "too many arguments" if $#ARGV > 1; + +$prog = `basename $ARGV[0] .pool`; +chomp($prog); + +$outfile = ($#ARGV == 1) ? $ARGV[1] : "${prog}_pool.c"; + +open IN, "< $ARGV[0]" or die "can't open input $ARGV[0]"; +open OUT, "> $outfile" or die "can't open output $outfile"; + +print OUT <<__EOT__; +/* This file is auto-generated from $ARGV[0] by pool2c.pl */ +#define EXTERN extern +#include "${prog}d.h" + +#include + +static unsigned char POOL[] = +__EOT__ +$pool_len = 0; +while () { + chomp; + if (m/^([0-9]{2})(.*)$/) { + ($len, $str) = ($1, $2); + if (length($str) != $len) { + die "*** pool string length error:\n$_\n"; + } + $str =~ s/(["\\])/\\$1/g; + $str =~ s/\?\?\?/\\?\\?\\?/g; + printf OUT "\t\"\\x%02X\" \"%s\"\n", $len, $str; + $pool_len += $len + 1; + } + elsif (m/^\*[0-9]+$/) { + last; + } + else { + die "*** unexpected line in pool file:\n$_\n"; + } +} + +close IN; + +print OUT <<__EOT__; + ; + +#define POOL_LEN $pool_len + +int initpool(int limit) { + int g = 0; + unsigned char *s = POOL; + while (s < POOL + POOL_LEN) { + int len = *s++; + if (poolptr + len >= limit) + return 0; + while (len-- > 0) + strpool[poolptr++] = *s++; + g = makestring(); + } + return g; +} +__EOT__ + +close OUT; diff --git a/Build/source/texk/web2c/xetexdir/trans.h b/Build/source/texk/web2c/xetexdir/trans.h index a1bb8780fb7..0d20308f8bf 100644 --- a/Build/source/texk/web2c/xetexdir/trans.h +++ b/Build/source/texk/web2c/xetexdir/trans.h @@ -64,33 +64,39 @@ typedef struct { float ht; } realrect; -#define xCoord(p) p.x -#define yCoord(p) p.y +#define xCoord(p) (p).x +#define yCoord(p) (p).y -#define wdField(r) r.wd -#define htField(r) r.ht +#define wdField(r) (r).wd +#define htField(r) (r).ht -#define aField(t) t.a -#define bField(t) t.b -#define cField(t) t.c -#define dField(t) t.d +#define aField(t) (t).a +#define bField(t) (t).b +#define cField(t) (t).c +#define dField(t) (t).d #ifdef XETEX_MAC /* transform fields have different names */ -#define txField(t) t.tx -#define tyField(t) t.ty +#define txField(t) (t).tx +#define tyField(t) (t).ty #else -#define txField(t) t.x -#define tyField(t) t.y +#define txField(t) (t).x +#define tyField(t) (t).y #endif -#define xField(t) t.x -#define yField(t) t.y +#define xField(t) (t).x +#define yField(t) (t).y -#define setPoint(P,X,Y) do { P.x = X; P.y = Y; } while (0) +#define setPoint(P,X,Y) do { (P).x = X; (P).y = Y; } while (0) +#ifdef __cplusplus +extern "C" { +#endif void makeidentity(transform* t); void makescale(transform* t, double xscale, double yscale); void maketranslation(transform* t, double dx, double dy); void makerotation(transform* t, double a); void transformpoint(realpoint* p, const transform* t); void transformconcat(transform* t1, const transform* t2); +#ifdef __cplusplus +}; +#endif #endif /* _TRANS_H_ */ diff --git a/Build/source/texk/web2c/xetexdir/unicode-char-prep.pl b/Build/source/texk/web2c/xetexdir/unicode-char-prep.pl index 8dd2581edcc..a77fc2f6f4c 100644 --- a/Build/source/texk/web2c/xetexdir/unicode-char-prep.pl +++ b/Build/source/texk/web2c/xetexdir/unicode-char-prep.pl @@ -30,31 +30,40 @@ # authorization from SIL International. # \****************************************************************************/ -# script to create unicode-letters.tex by processing UnicodeData.txt +# create unicode-letters.tex by processing Unicode data files +# UnicodeData.txt +# EastAsianWidth.txt +# LineBreak.txt -while (<>) { +# The intent of unicode-letters.tex is to initialize basic properties for most +# of the "letters" in Unicode, as follows: +# +# \catcode = 11 for everything with GC=L* +# \sfcode = 999 for everything that has a to-lowercase mapping +# \uccode, \lccode based on the case mapping fields +# \XeTeXmathcode = (7 1 #) for BMP letters, (0 1 #) for SMP +# \XeTeXspacingclass values based on a few of the Unicode line-break classes: +# 'CM' => 256, # combining marks = transparent +# 'ID' => 1, # ideograph +# 'OP' => 2, # opener +# 'CL' => 3, # closer +# 'NS' => 3, # non-starter +# 'EX' => 3, # exclamation +# 'IS' => 3, # infix sep (comma etc) +# 'QU' => 4, # ambiguous quote + +die "usage: perl $0 UnicodeData.txt EastAsianWidth.txt LineBreak.txt > unicode-letters.tex\n" + unless $#ARGV == 2; + +open Unidata, $ARGV[0] or die "can't read $ARGV[0]"; +while () { chomp; @u = split(/;/); - last if length($u[0]) > 4; - if ($u[1] =~ /First>/) { - $start = hex "0x$u[0]"; - $_ = <>; - chomp; - @u = split(/;/); - if ($u[1] =~ /Last>/) { - $end = hex "0x$u[0]"; - if ($u[2] =~ /^L/) { - foreach ($start .. $end) { - push(@letters, sprintf("%04X", $_)); - } - } - } - } - else { - $lccode{$u[0]} = $u[13] if $u[13] ne '' and length($u[13]) <= 4; - $lccode{$u[0]} = $u[0] if $u[13] eq '' and $u[2] =~ /^L/; - $uccode{$u[0]} = $u[12] if $u[12] ne '' and length($u[12]) <= 4; - $uccode{$u[0]} = $u[0] if $u[12] eq '' and $u[2] =~ /^L/; + unless ($u[1] =~ /) { } } } +close Unidata; $date = `date`; chomp $date; print << "__EOT__"; % Do not edit this file! -% Created from UnicodeData.txt by unicode-char-prep.pl on $date. +% Created from UnicodeData.txt, EastAsianWidth.txt, LineBreak.txt +% by unicode-char-prep.pl on $date. % In case of errors, fix the Perl script instead. __EOT__ print << '__EOT__'; + \begingroup \catcode`\{=1 \catcode`\}=2 \catcode`\#=6 + +\message{loading Unicode properties} + +% test whether xetex is new enough to set codes on supplementary-plane chars +% (requires version > 0.996) +\let\ifSupplementary=\iffalse +\def\Supplementarytrue{\let\ifSupplementary=\iftrue} +\ifnum\XeTeXversion>0 \Supplementarytrue +\else + \def\getrevnumber.#1-#2\end{\count255=#1 } + \expandafter\getrevnumber\XeTeXrevision-\end + \ifnum\count255>996 \Supplementarytrue \fi +\fi +% definitions for classes and case mappings based on UnicodeData.txt \def\C #1 #2 #3 {\global\uccode"#1="#2 \global\lccode"#1="#3 } % case mappings (non-letter) -\def\L #1 #2 #3 {\global\catcode"#1=11 \C #1 #2 #3 % letter with case mappings - \global\XeTeXmathcode"#1="7"01"#1 } % letters default to class 7 (var), fam 1 +\def\L #1 #2 #3 {\global\catcode"#1=11 % category: letter + \C #1 #2 #3 % with case mappings + \ifnum"#1="#3 \else \global\sfcode"#1=999 \fi % uppercase letters have sfcode=999 + \ifnum"#1<"10000 \global\XeTeXmathcode"#1="7"01"#1 % BMP letters default to class 7 (var), fam 1 + \else \global\XeTeXmathcode"#1="0"01"#1 % SMP letters class 0 (regular), fam 1 + \fi} \def\l #1 {\L #1 #1 #1 } % letter without case mappings \let\m=\l % combining mark - treated as uncased letter + __EOT__ + +$supp = 0; for (@letters) { + if ((hex $_ > 0xffff) and ($supp == 0)) { + print "\\ifSupplementary\n"; + $supp = 1; + } if (exists $uccode{$_} or exists $lccode{$_}) { if (($lccode{$_} eq $_) and ($uccode{$_} eq $_)) { print "\\l $_\n"; @@ -101,16 +138,157 @@ for (@letters) { print "\\l $_\n"; } } +if ($supp == 1) { + print "\\fi % end ifSupplementary\n"; + $supp = 0; +} + for (@casesym) { + if ((hex $_ > 0xffff) and ($supp == 0)) { + print "\\ifSupplementary\n"; + $supp = 1; + } print "\\C $_ "; print exists $uccode{$_} ? $uccode{$_} : "0"; print " "; print exists $lccode{$_} ? $lccode{$_} : "0"; print "\n"; } +if ($supp == 1) { + print "\\fi % end ifSupplementary\n"; + $supp = 0; +} + for (@marks) { + if ((hex $_ > 0xffff) and ($supp == 0)) { + print "\\ifSupplementary\n"; + $supp = 1; + } print "\\m $_\n"; } +if ($supp == 1) { + print "\\fi % end ifSupplementary\n"; + $supp = 0; +} + +print << '__EOT__'; + +% check whether the interchar toks features are present +\ifx\XeTeXinterchartoks\XeTeXcharclass + \def\next{\endgroup\endinput} +\else + \let\next\relax +\fi +\next + +__EOT__ + +open EAW, $ARGV[1] or die "can't read $ARGV[1]"; +while () { + chomp; + s/ *#.*//; + s/ +$//; + if (m/([0-9A-F]{4,6})(?:\.\.([0-9A-F]{4,6}))?;(.+)/) { + $s = $1; + $e = $2; + $w = $3; + $e = $s if $e eq ''; + for ($i = hex "0x$s"; $i <= hex "0x$e"; ++$i) { + $width[$i] = $w; + } + } +} +close EAW; + +%lineBreakClass = ( + 'CM' => 256, # combining marks = transparent + 'ID' => 1, # ideograph + 'OP' => 2, # opener + 'CL' => 3, # closer + 'NS' => 3, # non-starter + 'EX' => 3, # exclamation + 'IS' => 3, # infix sep (comma etc) +); + +print << '__EOT__'; +\message{and character classes} + +% definitions for script classes based on LineBreak.txt +__EOT__ + +foreach (keys %lineBreakClass) { + print "\\def\\$_ #1 #2 {\\set{#1}{#2}{\\global\\XeTeXcharclass\\n=$lineBreakClass{$_}"; + print " \\global\\catcode\\n=11" if m/ID/; + print " }}\n"; +} + +print << '__EOT__'; +\countdef\n=255 +\def\set#1#2#3{% execute setting "#3" with \n set to each value from #1 to #2 + \n="#1 \loop #3 \ifnum\n<"#2 \advance\n by 1 \repeat} +% copy \loop etc from plain.tex +\def\loop#1\repeat{\def\body{#1}\iterate} +\def\iterate{\body \let\next\iterate \else\let\next\relax\fi \next} +\let\repeat=\fi % this makes \loop...\if...\repeat skippable + +__EOT__ + +open LineBreak, $ARGV[2] or die "can't read $ARGV[2]"; +while () { + chomp; + s/ *#.*//; + s/ +$//; + if (m/([0-9A-F]{4,6})(?:\.\.([0-9A-F]{4,6}))?;(..)/) { + $s = $1; + $e = $2; + $lb = $3; + $e = $s if $e eq ''; + if (exists $lineBreakClass{$lb}) { + if ($lineBreakClass{$lb} == 1) { + # ideographs: set whole range to class 1 + print "\\$lb $s $e\n"; + } + else { + # punctuation, etc: only set these by default for chars with EAW = W, F, H + for ($i = hex "0x$s"; $i <= hex "0x$e"; ++$i) { + if ($width[$i] =~ /^[WFH]$/) { + printf "\\$lb %04X %04X\n", $i, $i; + } + } + } + } + } +} +close LineBreak; + print << '__EOT__'; + +% basic line-breaking support for CJK etc; override for more sophisticated spacing, +% automatic font changes, etc. + +\gdef\xtxHanGlue{\hskip0pt plus 0.1em\relax} % between ideographs +\gdef\xtxHanSpace{\hskip0.2em plus 0.2em minus 0.1em\relax} % before/after runs of CJK + +\global\XeTeXinterchartoks 0 1 = {\xtxHanSpace} +\global\XeTeXinterchartoks 0 2 = {\xtxHanSpace} +\global\XeTeXinterchartoks 0 3 = {\nobreak\xtxHanSpace} + +\global\XeTeXinterchartoks 1 0 = {\xtxHanSpace} +\global\XeTeXinterchartoks 2 0 = {\nobreak\xtxHanSpace} +\global\XeTeXinterchartoks 3 0 = {\xtxHanSpace} + +\global\XeTeXinterchartoks 1 1 = {\xtxHanGlue} +\global\XeTeXinterchartoks 1 2 = {\xtxHanGlue} +\global\XeTeXinterchartoks 1 3 = {\nobreak\xtxHanGlue} + +\global\XeTeXinterchartoks 2 1 = {\nobreak\xtxHanGlue} +\global\XeTeXinterchartoks 2 2 = {\nobreak\xtxHanGlue} +\global\XeTeXinterchartoks 2 3 = {\xtxHanGlue} + +\global\XeTeXinterchartoks 3 1 = {\xtxHanGlue} +\global\XeTeXinterchartoks 3 2 = {\xtxHanGlue} +\global\XeTeXinterchartoks 3 3 = {\nobreak\xtxHanGlue} + \endgroup + __EOT__ diff --git a/Build/source/texk/web2c/xetexdir/xetex-new.ch b/Build/source/texk/web2c/xetexdir/xetex-new.ch deleted file mode 100644 index 9293ecd23ad..00000000000 --- a/Build/source/texk/web2c/xetexdir/xetex-new.ch +++ /dev/null @@ -1,6383 +0,0 @@ -% /****************************************************************************\ -% Part of the XeTeX typesetting system -% copyright (c) 1994-2006 by SIL International -% written by Jonathan Kew -% -% Permission is hereby granted, free of charge, to any person obtaining -% a copy of this software and associated documentation files (the -% "Software"), to deal in the Software without restriction, including -% without limitation the rights to use, copy, modify, merge, publish, -% distribute, sublicense, and/or sell copies of the Software, and to -% permit persons to whom the Software is furnished to do so, subject to -% the following conditions: -% -% The above copyright notice and this permission notice shall be -% included in all copies or substantial portions of the Software. -% -% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -% EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -% MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -% NONINFRINGEMENT. IN NO EVENT SHALL SIL INTERNATIONAL BE LIABLE FOR -% ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF -% CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -% WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -% -% Except as contained in this notice, the name of SIL International -% shall not be used in advertising or otherwise to promote the sale, -% use or other dealings in this Software without prior written -% authorization from SIL International. -% \****************************************************************************/ - -% Changes for XeTeX -% ================= -% -% Procedure to build xetex from web sources: -% -% (1) build etex-web2c.web: -% ./tie -m etex.web ../../../../TeX/texk/web2c/tex.web ../../../../TeX/texk/web2c/etexdir/etex.ch ../../../../TeX/texk/web2c/etexdir/etex.fix -% -% (2) add xetex features, and remove enctex ones -% ./tie -m xetex.web etex.web xetex-new.ch xetex-noenc.ch -% -% (4) use otangle, web2c, etc.... -% ./otangle xetex.web -% ./web2c ........ - -@x -@* \[1] Introduction. -@y -@* \[1] Introduction. -@z - -@x -@d eTeX_version_string=='-2.2' {current \eTeX\ version} -@y -@d eTeX_version_string=='-2.2' {current \eTeX\ version} - -@d XeTeX_version=0 -@d XeTeX_revision==".996" -@d XeTeX_version_string=='-0.996-patch1' {current \XeTeX\ version} -@z - -@x -@d eTeX_banner_k=='This is e-TeXk, Version 3.141592',eTeX_version_string -@d eTeX_banner=='This is e-TeX, Version 3.141592',eTeX_version_string - {printed when \eTeX\ starts} -@# -@d TeX_banner_k=='This is TeXk, Version 3.141592' {printed when \TeX\ starts} -@d TeX_banner=='This is TeX, Version 3.141592' {printed when \TeX\ starts} -@# -@d banner==eTeX_banner -@d banner_k==eTeX_banner_k -@y -@d XeTeX_banner=='This is XeTeX, Version 3.141592',eTeX_version_string,XeTeX_version_string - {printed when \XeTeX\ starts} -@d XeTeX_banner_k=='This is XeTeXk, Version 3.141592',eTeX_version_string,XeTeX_version_string -@# -@d banner==XeTeX_banner -@d banner_k==XeTeX_banner_k -@z - -@x -@d TEX==ETEX {change program name into |ETEX|} -@y -@d TEX==XETEX {change program name into |XETEX|} -@z - -@x -@d TeXXeT_code=0 {the \TeXXeT\ feature is optional} -@# -@d eTeX_states=1 {number of \eTeX\ state variables in |eqtb|} -@y -@d TeXXeT_code=0 {the \TeXXeT\ feature is optional} -@# -@d XeTeX_dash_break_code = 1 {non-zero to enable breaks after en- and em-dashes} -@# -@d XeTeX_default_input_mode_code = 2 {input mode for newly opened files} -@d XeTeX_input_mode_auto = 0 -@d XeTeX_input_mode_utf8 = 1 -@d XeTeX_input_mode_utf16be = 2 -@d XeTeX_input_mode_utf16le = 3 -@d XeTeX_input_mode_raw = 4 -@d XeTeX_input_mode_icu_mapping = 5 -@# -@d XeTeX_default_input_encoding_code = 3 {str_number of encoding name if mode = ICU} -@# -@d eTeX_states=4 {number of \eTeX\ state variables in |eqtb|} -@z - -@x -@d hyph_prime=607 {another prime for hashing \.{\\hyphenation} exceptions; - if you change this, you should also change |iinf_hyphen_size|.} -@y -@d hyph_prime=607 {another prime for hashing \.{\\hyphenation} exceptions; - if you change this, you should also change |iinf_hyphen_size|.} - -@d biggest_char=65535 {the largest allowed character number; - must be |<=max_quarterword|} -@d too_big_char=65536 {|biggest_char+1|} -@d special_char=65537 {|biggest_char+2|} -@d number_chars=65536 {|biggest_char+1|} -@d biggest_reg=255 {the largest allowed register number; - must be |<=max_quarterword|} -@d number_regs=256 {|biggest_reg+1|} -@d font_biggest=255 {the real biggest font} -@d number_fonts=font_biggest-font_base+2 -@d number_math_families=256 -@d number_math_fonts=number_math_families+number_math_families+number_math_families -@d math_font_biggest=number_math_fonts-1 -@d text_size=0 {size code for the largest size in a family} -@d script_size=number_math_families {size code for the medium size in a family} -@d script_script_size=number_math_families+number_math_families {size code for the smallest size in a family} -@d biggest_lang=255 -@d too_big_lang=256 -@z - -@x -@* \[2] The character set. -@y -@* \[2] The character set. -@z - -@x -@ Characters of text that have been converted to \TeX's internal form -are said to be of type |ASCII_code|, which is a subrange of the integers. - -@= -@!ASCII_code=0..255; {eight-bit numbers} -@y -@ Characters of text that have been converted to \TeX's internal form -are said to be of type |ASCII_code|, which is a subrange of the integers. -For xetex, we rename |ASCII_code| as |UTF16_code|. But we also have a -new type |UTF8_code|, used when we construct filenames to pass to the -system libraries. - -@d ASCII_code==UTF16_code -@d packed_ASCII_code==packed_UTF16_code - -@= -@!ASCII_code=0..biggest_char; {16-bit numbers} -@!UTF8_code=0..255; {8-bit numbers} -@!UnicodeScalar=0..@"10FFFF; {Unicode scalars} -@z - -@x -@d last_text_char=255 {ordinal number of the largest element of |text_char|} -@y -@d last_text_char=biggest_char {ordinal number of the largest element of |text_char|} -@z - -@x -@* \[3] Input and output. -@y -@* \[3] Input and output. -@z - -@x -@!name_of_file:^text_char; -@!name_length:0..file_name_size;@/{this many characters are actually - relevant in |name_of_file| (the rest are blank)} -@y -@!name_of_file:^UTF8_code; {we build filenames in utf8 to pass to the OS} -@!name_of_file16:^UTF16_code; {but sometimes we need a utf16 version of the name} -@!name_length:0..file_name_size;@/{this many characters are actually - relevant in |name_of_file| (the rest are blank)} -@!name_length16:0..file_name_size; -@z - -@x -@d term_in==stdin {the terminal as an input file} -@y -@z - -@x -@!bound_default:integer; {temporary for setup} -@y -@!term_in:unicode_file; -@# -@!bound_default:integer; {temporary for setup} -@z - -@x -@* \[4] String handling. -@y -@* \[4] String handling. -@z - -@x -|str_start[s]<=j=@"10000) then length:=str_start_macro(s+1)-str_start_macro(s) -else if (s>=@"20) and (s<@"7F) then length:=1 -else if (s<=@"7F) then length:=3 -else if (s<@"100) then length:=4 -else length:=8 -end; -@z - -@x -@d cur_length == (pool_ptr - str_start[str_ptr]) -@y -@d cur_length == (pool_ptr - str_start_macro(str_ptr)) -@z - -@x -incr(str_ptr); str_start[str_ptr]:=pool_ptr; -@y -incr(str_ptr); str_start_macro(str_ptr):=pool_ptr; -@z - -@x -@d flush_string==begin decr(str_ptr); pool_ptr:=str_start[str_ptr]; -@y -@d flush_string==begin decr(str_ptr); pool_ptr:=str_start_macro(str_ptr); -@z - -@x -begin j:=str_start[s]; -while jstr_pool[k] then goto not_found; - incr(j); incr(k); -@y -if (length(s)=1) then begin - if s<65536 then begin - if t<65536 then begin - if s<>t then goto not_found; - end - else begin - if s<>str_pool[str_start_macro(t)] then goto not_found; - end; - end - else begin - if t<65536 then begin - if str_pool[str_start_macro(s)]<>t then goto not_found; - end - else begin - if str_pool[str_start_macro(s)]<>str_pool[str_start_macro(t)] then - goto not_found; - end; - end; - end -else begin - j:=str_start_macro(s); k:=str_start_macro(t); - while jstr_pool[k] then goto not_found; - incr(j); incr(k); - end; -@z - -@x -begin pool_ptr:=0; str_ptr:=0; str_start[0]:=0; -@y -begin pool_ptr:=0; str_ptr:=0; -@z - -@x -@ @d app_lc_hex(#)==l:=#; - if l<10 then append_char(l+"0")@+else append_char(l-10+"a") -@y -@ The first 65536 strings will consist of a single character only. -But we don't actually make them; they're simulated on the fly. -@z - -@x -for k:=0 to 255 do - begin if (@) then - begin append_char("^"); append_char("^"); - if k<@'100 then append_char(k+@'100) - else if k<@'200 then append_char(k-@'100) - else begin app_lc_hex(k div 16); app_lc_hex(k mod 16); - end; - end - else append_char(k); - g:=make_string; - end -@y -begin -str_ptr:=too_big_char; -str_start_macro(str_ptr):=pool_ptr; -end -@z - -@x -@= - (k<" ")or(k>"~") -@y -@= -{ this module is not used } -@z - -@x -name_of_file := xmalloc_array (ASCII_code, name_length + 1); -@y -name_of_file := xmalloc_array (UTF8_code, name_length + 1); -@z - -@x -else begin if (xord[m]<"0")or(xord[m]>"9")or@| - (xord[n]<"0")or(xord[n]>"9") then -@y -else begin if (m<"0")or(m>"9")or@| - (n<"0")or(n>"9") then -@z - -@x - l:=xord[m]*10+xord[n]-"0"*11; {compute the length} -@y - l:=m*10+n-"0"*11; {compute the length} -@z - -@x - append_char(xord[m]); -@y - append_char(m); -@z - -@x -loop@+ begin if (xord[n]<"0")or(xord[n]>"9") then -@y -loop@+ begin if (n<"0")or(n>"9") then -@z - -@x - a:=10*a+xord[n]-"0"; -@y - a:=10*a+n-"0"; -@z - -@x -@* \[5] On-line and off-line printing. -@y -@* \[5] On-line and off-line printing. -@z - -@x -procedure print_char(@!s:ASCII_code); {prints a single character} -label exit; -begin if @ then - if selector= -procedure print_char(@!s:ASCII_code); {prints a single character} -label exit; -var l: small_number; -begin if (selector>pseudo) and (not doing_special) then {"printing" to a new string, don't encode chars} - begin print_visible_char(s); return; - end; -if @ then - if selector= 128: encode as UTF8 } - if s<@"800 then begin - print_visible_char(@"C0 + s div @"40); - print_visible_char(@"80 + s mod @"40); - end - else begin - print_visible_char(@"E0 + s div @"1000); - print_visible_char(@"80 + (s mod @"1000) div @"40); - print_visible_char(@"80 + (s mod @"1000) mod @"40); - end -end; -exit:end; - -@ @= -doing_special: boolean; - -@ @= -doing_special:=false; -@z - -@x -procedure print(@!s:integer); {prints string |s|} -label exit; -var j:pool_pointer; {current character code position} -@!nl:integer; {new-line character to restore} -begin if s>=str_ptr then s:="???" {this can't happen} -@.???@> -else if s<256 then - if s<0 then s:="???" {can't happen} - else begin if (selector>pseudo) and (not special_printing) - and (not message_printing) then - begin print_char(s); return; {internal strings are not expanded} - end; - if (@) then - if selector0) and (not no_convert) and (mubyte_write[s]>0) then - s := mubyte_write[s] - else if xprn[s] or special_printing then - begin print_char(s); no_convert := false; return; end; - no_convert := false; - nl:=new_line_char; new_line_char:=-1; - {temporarily disable new-line character} - j:=str_start[s]; - while j=str_ptr then s:="???" {this can't happen} -@.???@> -else if spseudo then - begin print_char(s); return; {internal strings are not expanded} - end; - if (@) then - if selector= -procedure slow_print(@!s:integer); {prints string |s|} -var j:pool_pointer; {current character code position} -begin if (s>=str_ptr) or (s<256) then print(s) -else begin j:=str_start[s]; - while j; -if c>=0 then if c<256 then print(c); -@y -begin @; -if c>=0 then if c<=biggest_char then print_char(c); -@z - -@x -begin j:=str_start["m2d5c2l5x2v5i"]; v:=1000; -@y -begin j:=str_start_macro("m2d5c2l5x2v5i"); v:=1000; -@z - -@x -@p procedure print_current_string; {prints a yet-unmade string} -var j:pool_pointer; {points to current character code} -begin j:=str_start[str_ptr]; -@y -@p procedure print_current_string; {prints a yet-unmade string} -var j:pool_pointer; {points to current character code} -begin j:=str_start_macro(str_ptr); -@z - -@x -k:=first; while k < last do begin print_buffer(k) end; -@y -if last<>first then for k:=first to last-1 do print(buffer[k]); -@z - -@x -@* \[6] Reporting errors. -@y -@* \[6] Reporting errors. -@z - -@x - begin edit_name_start:=str_start[edit_file.name_field]; - edit_name_length:=str_start[edit_file.name_field+1] - - str_start[edit_file.name_field]; -@y - begin edit_name_start:=str_start_macro(edit_file.name_field); - edit_name_length:=str_start_macro(edit_file.name_field+1) - - str_start_macro(edit_file.name_field); -@z - -@x -@* \[7] Arithmetic with scaled dimensions. -@y -@* \[7] Arithmetic with scaled dimensions. -@z - -@x -@* \[8] Packed data. -@y -@* \[8] Packed data. -@z - -@x -@d min_quarterword=0 {smallest allowable value in a |quarterword|} -@d max_quarterword=255 {largest allowable value in a |quarterword|} -@d min_halfword==-@"FFFFFFF {smallest allowable value in a |halfword|} -@d max_halfword==@"FFFFFFF {largest allowable value in a |halfword|} -@y -@d min_quarterword=0 {smallest allowable value in a |quarterword|} -@d max_quarterword=@"FFFF {largest allowable value in a |quarterword|} -@d min_halfword==-@"FFFFFFF {smallest allowable value in a |halfword|} -@d max_halfword==@"3FFFFFFF {largest allowable value in a |halfword|} -@z - -@x -if (min_quarterword>0)or(max_quarterword<127) then bad:=11; -if (min_halfword>0)or(max_halfword<32767) then bad:=12; -@y -if (min_quarterword>0)or(max_quarterword<@"7FFF) then bad:=11; -if (min_halfword>0)or(max_halfword<@"3FFFFFFF) then bad:=12; -@z - -@x -if max_quarterword-min_quarterword<255 then bad:=19; -@y -if max_quarterword-min_quarterword<@"FFFF then bad:=19; -@z - -@x -@* \[9] Dynamic memory allocation. -@y -@* \[9] Dynamic memory allocation. -@z - -@x -@* \[10] Data structures for boxes and their friends. -@y -@* \[10] Data structures for boxes and their friends. -@z - -@x -@d whatsit_node=8 {|type| of special extension nodes} -@y -@d whatsit_node=8 {|type| of special extension nodes} - -{ added stuff here for native_word and picture nodes } -@d native_word_node=40 {|subtype| in whatsits that hold native_font words - (0-3 are used for open, write, close, special; 4 is language; pdfTeX uses up through 30-something) - -To support ``native'' fonts, we build |native_word_nodes|, which are variable size whatsits. -These have the same |width|, |depth|, and |height| fields as a |box_node|, at offsets 1-3, -and then a word containing a size field for the node, a font number, a length, and a glyph count. -Then there is a field containing a C pointer to a glyph info array; -this and the glyph count are set by |set_native_metrics|. -Copying and freeing of these nodes needs to take account of this! -This is followed by |length| bytes, for the actual characters of the string. -(Yes, we count in bytes, even though what we store there is UTF-16.) - -So |native_node_size|, which does not include any space for the actual text, is 6.} - -@d native_node_size=6 {size of a native_word node (plus the actual chars) -- see also xetex.h} -@d native_size(#)==mem[#+4].qqqq.b0 -@d native_font(#)==mem[#+4].qqqq.b1 -@d native_length(#)==mem[#+4].qqqq.b2 -@d native_glyph_count(#)==mem[#+4].qqqq.b3 -@d native_glyph_info_ptr(#)==mem[#+5].ptr -@d native_glyph_info_size=10 { number of bytes of info per glyph: 16-bit glyph ID, 32-bit x and y coords } - -@d free_native_glyph_info(#) == - begin - if native_glyph_info_ptr(#) <> null_ptr then begin - libc_free(native_glyph_info_ptr(#)); - native_glyph_info_ptr(#) := null_ptr; - native_glyph_count(#) := 0; - end - end - -@p procedure copy_native_glyph_info(src:pointer; dest:pointer); -var glyph_count:integer; -begin - if native_glyph_info_ptr(src) <> null_ptr then begin - glyph_count := native_glyph_count(src); - native_glyph_info_ptr(dest) := xmalloc_array(char, glyph_count * native_glyph_info_size); - memcpy(native_glyph_info_ptr(dest), native_glyph_info_ptr(src), glyph_count * native_glyph_info_size); - native_glyph_count(dest) := glyph_count; - end -end; - -@ There are also |glyph_nodes|; these are like |native_word_nodes| in having |width|, |depth|, and |height| fields, -but then they contain a glyph ID rather than size and length fields, and there's no subsidiary C pointer. - -@d glyph_node_size=5 -@d native_glyph==native_length {in |glyph_node|s, we store the glyph number here} - -@d pic_node=42 {|subtype| in whatsits that hold picture file references} -@d pdf_node=43 {|subtype| in whatsits that hold PDF page references} -@d glyph_node=44 {|subtype| in whatsits that hold glyph numbers} - -@d pdfbox_crop = 1 { |pic_box_type| values in PDF nodes } -@d pdfbox_media = 2 -@d pdfbox_bleed = 3 -@d pdfbox_trim = 4 -@d pdfbox_art = 5 - - -{Picture files are handled with nodes that include fields for the transform associated -with the picture, and a pathname for the picture file itself. -They also have -the |width|, |depth|, and |height| fields of a |box_node| at offsets 1-3. (|depth| will -always be zero, as it happens.) - -So |pic_node_size|, which does not include any space for the picture file pathname, is 7. - -pdf_nodes are just like pic_nodes, but generate a different xdv file code.} - -@d pic_node_size=8 { must sync with xetex.h } -@d pic_path_length(#)==mem[#+4].hh.b0 -@d pic_page(#)==mem[#+4].hh.b1 -@d pic_box_type(#)==mem[#+4].hh.rh { for PDF, unused in picfile } -@d pic_transform1(#)==mem[#+5].hh.lh -@d pic_transform2(#)==mem[#+5].hh.rh -@d pic_transform3(#)==mem[#+6].hh.lh -@d pic_transform4(#)==mem[#+6].hh.rh -@d pic_transform5(#)==mem[#+7].hh.lh -@d pic_transform6(#)==mem[#+7].hh.rh -@z - -@x -@* \[11] Memory layout. -@y -@* \[11] Memory layout. -@z - -@x -@* \[12] Displaying boxes. -@y -@* \[12] Displaying boxes. -@z - -@x -@ @= -case type(p) of -hlist_node,vlist_node,ins_node,whatsit_node,mark_node,adjust_node, - unset_node: print("[]"); -@y -@ @= -case type(p) of -hlist_node,vlist_node,ins_node,mark_node,adjust_node, - unset_node: print("[]"); -whatsit_node: if subtype(p)=native_word_node then begin - if native_font(p)<>font_in_short_display then begin - print_esc(font_id_text(native_font(p))); - print_char(" "); - font_in_short_display:=native_font(p); - end; - print_native_word(p); -end else - print("[]"); -@z - -@x -@p procedure show_node_list(@!p:integer); {prints a node list symbolically} -label exit; -var n:integer; {the number of items already printed at this level} -@y -@p procedure show_node_list(@!p:integer); {prints a node list symbolically} -label exit; -var n:integer; {the number of items already printed at this level} -i:integer; {temp index for printing chars of picfile paths} -@z - -@x -@* \[15] The command codes. -@y -@* \[15] The command codes. -@z - -@x -@d math_given=69 {math code defined by \.{\\mathchardef}} -@d last_item=70 {most recent item ( \.{\\lastpenalty}, - \.{\\lastkern}, \.{\\lastskip} )} -@d max_non_prefixed_command=70 {largest command code that can't be \.{\\global}} - -@ The next codes are special; they all relate to mode-independent -assignment of values to \TeX's internal registers or tables. -Codes that are |max_internal| or less represent internal quantities -that might be expanded by `\.{\\the}'. - -@d toks_register=71 {token list register ( \.{\\toks} )} -@d assign_toks=72 {special token list ( \.{\\output}, \.{\\everypar}, etc.~)} -@d assign_int=73 {user-defined integer ( \.{\\tolerance}, \.{\\day}, etc.~)} -@d assign_dimen=74 {user-defined length ( \.{\\hsize}, etc.~)} -@d assign_glue=75 {user-defined glue ( \.{\\baselineskip}, etc.~)} -@d assign_mu_glue=76 {user-defined muglue ( \.{\\thinmuskip}, etc.~)} -@d assign_font_dimen=77 {user-defined font dimension ( \.{\\fontdimen} )} -@d assign_font_int=78 {user-defined font integer ( \.{\\hyphenchar}, - \.{\\skewchar} )} -@d set_aux=79 {specify state info ( \.{\\spacefactor}, \.{\\prevdepth} )} -@d set_prev_graf=80 {specify state info ( \.{\\prevgraf} )} -@d set_page_dimen=81 {specify state info ( \.{\\pagegoal}, etc.~)} -@d set_page_int=82 {specify state info ( \.{\\deadcycles}, - \.{\\insertpenalties} )} - {( or \.{\\interactionmode} )} -@d set_box_dimen=83 {change dimension of box ( \.{\\wd}, \.{\\ht}, \.{\\dp} )} -@d set_shape=84 {specify fancy paragraph shape ( \.{\\parshape} )} - {(or \.{\\interlinepenalties}, etc.~)} -@d def_code=85 {define a character code ( \.{\\catcode}, etc.~)} -@d def_family=86 {declare math fonts ( \.{\\textfont}, etc.~)} -@d set_font=87 {set current font ( font identifiers )} -@d def_font=88 {define a font file ( \.{\\font} )} -@d register=89 {internal register ( \.{\\count}, \.{\\dimen}, etc.~)} -@d max_internal=89 {the largest code that can follow \.{\\the}} -@d advance=90 {advance a register or parameter ( \.{\\advance} )} -@d multiply=91 {multiply a register or parameter ( \.{\\multiply} )} -@d divide=92 {divide a register or parameter ( \.{\\divide} )} -@d prefix=93 {qualify a definition ( \.{\\global}, \.{\\long}, \.{\\outer} )} - {( or \.{\\protected} )} -@d let=94 {assign a command code ( \.{\\let}, \.{\\futurelet} )} -@d shorthand_def=95 {code definition ( \.{\\chardef}, \.{\\countdef}, etc.~)} - {or \.{\\charsubdef}} -@d read_to_cs=96 {read into a control sequence ( \.{\\read} )} - {( or \.{\\readline} )} -@d def=97 {macro definition ( \.{\\def}, \.{\\gdef}, \.{\\xdef}, \.{\\edef} )} -@d set_box=98 {set a box ( \.{\\setbox} )} -@d hyph_data=99 {hyphenation data ( \.{\\hyphenation}, \.{\\patterns} )} -@d set_interaction=100 {define level of interaction ( \.{\\batchmode}, etc.~)} -@d max_command=100 {the largest command code seen at |big_switch|} -@y -@d math_given=69 {math code defined by \.{\\mathchardef}} -@d XeTeX_math_given=70 -@d last_item=71 {most recent item ( \.{\\lastpenalty}, - \.{\\lastkern}, \.{\\lastskip} )} -@d max_non_prefixed_command=71 {largest command code that can't be \.{\\global}} - -@ The next codes are special; they all relate to mode-independent -assignment of values to \TeX's internal registers or tables. -Codes that are |max_internal| or less represent internal quantities -that might be expanded by `\.{\\the}'. - -@d toks_register=72 {token list register ( \.{\\toks} )} -@d assign_toks=73 {special token list ( \.{\\output}, \.{\\everypar}, etc.~)} -@d assign_int=74 {user-defined integer ( \.{\\tolerance}, \.{\\day}, etc.~)} -@d assign_dimen=75 {user-defined length ( \.{\\hsize}, etc.~)} -@d assign_glue=76 {user-defined glue ( \.{\\baselineskip}, etc.~)} -@d assign_mu_glue=77 {user-defined muglue ( \.{\\thinmuskip}, etc.~)} -@d assign_font_dimen=78 {user-defined font dimension ( \.{\\fontdimen} )} -@d assign_font_int=79 {user-defined font integer ( \.{\\hyphenchar}, - \.{\\skewchar} )} -@d set_aux=80 {specify state info ( \.{\\spacefactor}, \.{\\prevdepth} )} -@d set_prev_graf=81 {specify state info ( \.{\\prevgraf} )} -@d set_page_dimen=82 {specify state info ( \.{\\pagegoal}, etc.~)} -@d set_page_int=83 {specify state info ( \.{\\deadcycles}, - \.{\\insertpenalties} )} - {( or \.{\\interactionmode} )} -@d set_box_dimen=84 {change dimension of box ( \.{\\wd}, \.{\\ht}, \.{\\dp} )} -@d set_shape=85 {specify fancy paragraph shape ( \.{\\parshape} )} - {(or \.{\\interlinepenalties}, etc.~)} -@d def_code=86 {define a character code ( \.{\\catcode}, etc.~)} -@d XeTeX_def_code=87 {\.{\\XeTeXmathcode}, \.{\\XeTeXdelcode}} -@d def_family=88 {declare math fonts ( \.{\\textfont}, etc.~)} -@d set_font=89 {set current font ( font identifiers )} -@d def_font=90 {define a font file ( \.{\\font} )} -@d register=91 {internal register ( \.{\\count}, \.{\\dimen}, etc.~)} -@d max_internal=91 {the largest code that can follow \.{\\the}} -@d advance=92 {advance a register or parameter ( \.{\\advance} )} -@d multiply=93 {multiply a register or parameter ( \.{\\multiply} )} -@d divide=94 {divide a register or parameter ( \.{\\divide} )} -@d prefix=95 {qualify a definition ( \.{\\global}, \.{\\long}, \.{\\outer} )} - {( or \.{\\protected} )} -@d let=96 {assign a command code ( \.{\\let}, \.{\\futurelet} )} -@d shorthand_def=97 {code definition ( \.{\\chardef}, \.{\\countdef}, etc.~)} - {or \.{\\charsubdef}} -@d read_to_cs=98 {read into a control sequence ( \.{\\read} )} - {( or \.{\\readline} )} -@d def=99 {macro definition ( \.{\\def}, \.{\\gdef}, \.{\\xdef}, \.{\\edef} )} -@d set_box=100 {set a box ( \.{\\setbox} )} -@d hyph_data=101 {hyphenation data ( \.{\\hyphenation}, \.{\\patterns} )} -@d set_interaction=102 {define level of interaction ( \.{\\batchmode}, etc.~)} -@d max_command=102 {the largest command code seen at |big_switch|} -@z - -@x -@* \[17] The table of equivalents. -@y -@* \[17] The table of equivalents. -@z - -@x -In the first region we have 256 equivalents for ``active characters'' that -act as control sequences, followed by 256 equivalents for single-character -control sequences. -@y -In the first region we have |number_chars| equivalents for ``active characters'' -that act as control sequences, followed by |number_chars| equivalents for -single-character control sequences. -@z - -@x -@d single_base=active_base+256 {equivalents of one-character control sequences} -@d null_cs=single_base+256 {equivalent of \.{\\csname\\endcsname}} -@y -@d single_base=active_base+number_chars - {equivalents of one-character control sequences} -@d null_cs=single_base+number_chars {equivalent of \.{\\csname\\endcsname}} -@z - -@x -@ Region 3 of |eqtb| contains the 256 \.{\\skip} registers, as well as the -glue parameters defined here. It is important that the ``muskip'' -parameters have larger numbers than the others. -@y -@ Region 3 of |eqtb| contains the |number_regs| \.{\\skip} registers, -as well as the glue parameters defined here. It is important that the -``muskip'' parameters have larger numbers than the others. -@z - -@x -@d par_fill_skip_code=14 {glue on last line of paragraph} -@d thin_mu_skip_code=15 {thin space in math formula} -@d med_mu_skip_code=16 {medium space in math formula} -@d thick_mu_skip_code=17 {thick space in math formula} -@d glue_pars=18 {total number of glue parameters} -@y -@d par_fill_skip_code=14 {glue on last line of paragraph} -@d XeTeX_linebreak_skip_code=15 {glue introduced at potential linebreak location} -@d thin_mu_skip_code=16 {thin space in math formula} -@d med_mu_skip_code=17 {medium space in math formula} -@d thick_mu_skip_code=18 {thick space in math formula} -@d glue_pars=19 {total number of glue parameters} -@z - -@x -@d skip_base=glue_base+glue_pars {table of 256 ``skip'' registers} -@d mu_skip_base=skip_base+256 {table of 256 ``muskip'' registers} -@d local_base=mu_skip_base+256 {beginning of region 4} -@y -@d skip_base=glue_base+glue_pars {table of |number_regs| ``skip'' registers} -@d mu_skip_base=skip_base+number_regs - {table of |number_regs| ``muskip'' registers} -@d local_base=mu_skip_base+number_regs {beginning of region 4} -@z - -@x -@d par_fill_skip==glue_par(par_fill_skip_code) -@y -@d par_fill_skip==glue_par(par_fill_skip_code) -@d XeTeX_linebreak_skip==glue_par(XeTeX_linebreak_skip_code) -@z - -@x -par_fill_skip_code: print_esc("parfillskip"); -@y -par_fill_skip_code: print_esc("parfillskip"); -XeTeX_linebreak_skip_code: print_esc("XeTeXlinebreakskip"); -@z - -@x -primitive("parfillskip",assign_glue,glue_base+par_fill_skip_code);@/ -@!@:par_fill_skip_}{\.{\\parfillskip} primitive@> -@y -primitive("parfillskip",assign_glue,glue_base+par_fill_skip_code);@/ -@!@:par_fill_skip_}{\.{\\parfillskip} primitive@> -primitive("XeTeXlinebreakskip",assign_glue,glue_base+XeTeX_linebreak_skip_code);@/ -@z - -@x -@d toks_base=etex_toks {table of 256 token list registers} -@# -@d etex_pen_base=toks_base+256 {start of table of \eTeX's penalties} -@d inter_line_penalties_loc=etex_pen_base {additional penalties between lines} -@d club_penalties_loc=etex_pen_base+1 {penalties for creating club lines} -@d widow_penalties_loc=etex_pen_base+2 {penalties for creating widow lines} -@d display_widow_penalties_loc=etex_pen_base+3 {ditto, just before a display} -@d etex_pens=etex_pen_base+4 {end of table of \eTeX's penalties} -@# -@d box_base=etex_pens {table of 256 box registers} -@d cur_font_loc=box_base+256 {internal font number outside math mode} -@d xord_code_base=cur_font_loc+1 -@d xchr_code_base=xord_code_base+1 -@d xprn_code_base=xchr_code_base+1 -@d math_font_base=xprn_code_base+1 -@d cat_code_base=math_font_base+48 - {table of 256 command codes (the ``catcodes'')} -@d lc_code_base=cat_code_base+256 {table of 256 lowercase mappings} -@d uc_code_base=lc_code_base+256 {table of 256 uppercase mappings} -@d sf_code_base=uc_code_base+256 {table of 256 spacefactor mappings} -@d math_code_base=sf_code_base+256 {table of 256 math mode mappings} -@d char_sub_code_base=math_code_base+256 {table of character substitutions} -@d int_base=char_sub_code_base+256 {beginning of region 5} -@y -@d toks_base=etex_toks {table of number_regs token list registers} -@# -@d etex_pen_base=toks_base+number_regs {start of table of \eTeX's penalties} -@d inter_line_penalties_loc=etex_pen_base {additional penalties between lines} -@d club_penalties_loc=etex_pen_base+1 {penalties for creating club lines} -@d widow_penalties_loc=etex_pen_base+2 {penalties for creating widow lines} -@d display_widow_penalties_loc=etex_pen_base+3 {ditto, just before a display} -@d etex_pens=etex_pen_base+4 {end of table of \eTeX's penalties} -@# -@d box_base=etex_pens {table of number_regs box registers} -@d cur_font_loc=box_base+number_regs {internal font number outside math mode} -@d xord_code_base=cur_font_loc+1 -@d xchr_code_base=xord_code_base+1 -@d xprn_code_base=xchr_code_base+1 -@d math_font_base=xprn_code_base+1 -@d cat_code_base=math_font_base+number_math_fonts - {table of number_chars command codes (the ``catcodes'')} -@d lc_code_base=cat_code_base+number_chars {table of number_chars lowercase mappings} -@d uc_code_base=lc_code_base+number_chars {table of number_chars uppercase mappings} -@d sf_code_base=uc_code_base+number_chars {table of number_chars spacefactor mappings} -@d math_code_base=sf_code_base+number_chars {table of number_chars math mode mappings} -@d char_sub_code_base=math_code_base+number_chars {table of character substitutions} -@d int_base=char_sub_code_base+number_chars {beginning of region 5} -@z - -@x -@d var_code==@'70000 {math code meaning ``use the current family''} -@y -@d var_fam_class = 7 -@d active_math_char = @"1FFFFF -@d is_active_math_char(#) == math_char_field(#) = active_math_char -@d is_var_family(#) == math_class_field(#) = 7 -@z - -@x -for k:=output_routine_loc to toks_base+255 do -@y -for k:=output_routine_loc to toks_base+number_regs-1 do -@z - -@x -for k:=box_base+1 to box_base+255 do eqtb[k]:=eqtb[box_base]; -@y -for k:=box_base+1 to box_base+number_regs-1 do eqtb[k]:=eqtb[box_base]; -@z - -@x -for k:=math_font_base to math_font_base+47 do eqtb[k]:=eqtb[cur_font_loc]; -@y -for k:=math_font_base to math_font_base+number_math_fonts-1 do eqtb[k]:=eqtb[cur_font_loc]; -@z - -@x -for k:=0 to 255 do -@y -for k:=0 to number_chars-1 do -@z - -@x -for k:="0" to "9" do math_code(k):=hi(k+var_code); -@y -for k:="0" to "9" do math_code(k):=hi(k + set_class_field(var_fam_class)); -@z - -@x - math_code(k):=hi(k+var_code+@"100); - math_code(k+"a"-"A"):=hi(k+"a"-"A"+var_code+@"100);@/ -@y - math_code(k) := hi(k + set_family_field(1) + set_class_field(var_fam_class)); - math_code(k+"a"-"A") := hi(k+"a"-"A" + set_family_field(1) + set_class_field(var_fam_class));@/ -@z - -@x -begin if n=cur_font_loc then print("current font") -else if n -@y -primitive("errorcontextlines",assign_int,int_base+error_context_lines_code);@/ -@!@:error_context_lines_}{\.{\\errorcontextlines} primitive@> -primitive("XeTeXlinebreakpenalty",assign_int,int_base+XeTeX_linebreak_penalty_code);@/ -@z - -@x -for k:=0 to 255 do del_code(k):=-1; -del_code("."):=0; {this null delimiter is used in error recovery} -@y -for k:=0 to number_chars-1 do del_code(k):=-1; -del_code("."):=0; {this null delimiter is used in error recovery} -@z - -@x -@ The final region of |eqtb| contains the dimension parameters defined -here, and the 256 \.{\\dimen} registers. -@y -@ The final region of |eqtb| contains the dimension parameters defined -here, and the |number_regs| \.{\\dimen} registers. -@z - -@x -@d emergency_stretch_code=20 {reduces badnesses on final pass of line-breaking} -@d dimen_pars=21 {total number of dimension parameters} -@y -@d emergency_stretch_code=20 {reduces badnesses on final pass of line-breaking} -@d pdf_page_width_code=21 {page width of the PDF output} -@d pdf_page_height_code=22 {page height of the PDF output} -@d dimen_pars=23 {total number of dimension parameters} -@z - -@x -@d scaled_base=dimen_base+dimen_pars - {table of 256 user-defined \.{\\dimen} registers} -@d eqtb_size=scaled_base+255 {largest subscript of |eqtb|} -@y -@d scaled_base=dimen_base+dimen_pars - {table of |number_regs| user-defined \.{\\dimen} registers} -@d eqtb_size=scaled_base+biggest_reg {largest subscript of |eqtb|} -@z - -@x -@d emergency_stretch==dimen_par(emergency_stretch_code) -@y -@d emergency_stretch==dimen_par(emergency_stretch_code) -@d pdf_page_width == dimen_par(pdf_page_width_code) -@d pdf_page_height == dimen_par(pdf_page_height_code) -@z - -@x -emergency_stretch_code:print_esc("emergencystretch"); -@y -emergency_stretch_code:print_esc("emergencystretch"); -pdf_page_width_code: print_esc("pdfpagewidth"); -pdf_page_height_code: print_esc("pdfpageheight"); -@z - -@x -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("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@> -@z - -@x -for q:=active_base to box_base+255 do -@y -for q:=active_base to box_base+biggest_reg do -@z - -@x -@* \[18] The hash table. -@y -@* \[18] The hash table. -@z - -@x -while pool_ptr>str_start[str_ptr] do -@y -while pool_ptr>str_start_macro(str_ptr) do -@z - -@x -The conversion from control sequence to byte sequence for enc\TeX is -implemented here. Of course, the simplest way is to implement an array -of string pointers with |hash_size| length, but we assume that only a -few control sequences will need to be converted. So |mubyte_cswrite|, -an array with only 128 items, is used. The items point to the token -lists. First token includes a csname number and the second points the -string to be output. The third token includes the number of another -csname and fourth token its pointer to the string etc. We need to do -the sequential searching in one of the 128 token lists. -@y -@z - -@x -else begin k:=str_start[s]; l:=str_start[s+1]-k; -@y -else begin k:=str_start_macro(s); l:=str_start_macro(s+1)-k; -@z - -@x -primitive("delimiter",delim_num,0);@/ -@y -primitive("delimiter",delim_num,0);@/ -primitive("XeTeXdelimiter",delim_num,1);@/ -@z - -@x -primitive("mathaccent",math_accent,0);@/ -@y -primitive("mathaccent",math_accent,0);@/ -primitive("XeTeXmathaccent",math_accent,1);@/ -@z - -@x -primitive("mathchar",math_char_num,0);@/ -@!@:math_char_}{\.{\\mathchar} primitive@> -@y -primitive("mathchar",math_char_num,0);@/ -primitive("XeTeXmathcharnum",math_char_num,1);@/ -primitive("XeTeXmathchar",math_char_num,2);@/ -@!@:math_char_}{\.{\\mathchar} primitive@> -@z - -@x -primitive("radical",radical,0);@/ -@y -primitive("radical",radical,0);@/ -primitive("XeTeXradical",radical,1);@/ -@z - -@x -primitive("relax",relax,256); {cf.\ |scan_file_name|} -@y -primitive("relax",relax,too_big_char); {cf.\ |scan_file_name|} -@z - -@x -delim_num: print_esc("delimiter"); -@y -delim_num: if chr_code=1 then print_esc("XeTeXdelimiter") - else print_esc("delimiter"); -@z - -@x -end_cs_name: if chr_code = 10 then print_esc("endmubyte") - else print_esc("endcsname"); -@y -end_cs_name: print_esc("endcsname"); -@z - -@x -math_accent: print_esc("mathaccent"); -@y -math_accent: if chr_code=1 then print_esc("XeTeXmathaccent") - else print_esc("mathaccent"); -@z - -@x -math_char_num: print_esc("mathchar"); -@y -math_char_num: if chr_code=2 then print_esc("XeTeXmathchar") - else if chr_code=1 then print_esc("XeTeXmathcharnum") - else print_esc("mathchar"); -@z - -@x -radical: print_esc("radical"); -@y -radical: if chr_code=1 then print_esc("XeTeXradical") else print_esc("radical"); -@z - -@x -@* \[19] Saving and restoring equivalents. -@y -@* \[19] Saving and restoring equivalents. -@z - --- based on Omega; not needed with new xetex delimiter coding - x -@ The |eq_define| and |eq_word_define| routines take care of local definitions. - y -@# -procedure eq_word_define1(@!p:pointer;@!w:integer); -label exit; -begin if eTeX_ex and(read_cint1(eqtb[p])=w) then - begin assign_trace(p,"reassigning")@;@/ - return; - end; -assign_trace(p,"changing")@;@/ -if xeq_level[p]<>cur_level then - begin eq_save(p,xeq_level[p]); xeq_level[p]:=cur_level; - end; -set_cint1(eqtb[p],w); -assign_trace(p,"into")@;@/ -exit:end; - -@ The |eq_define| and |eq_word_define| routines take care of local definitions. - z - - x -@ Subroutine |save_for_after| puts a token on the stack for save-keeping. - y -@# -procedure geq_word_define1(@!p:pointer;@!w:integer); {global |eq_word_define1|} -begin assign_trace(p,"globally changing")@;@/ -begin set_cint1(eqtb[p],w); xeq_level[p]:=level_one; -end; -assign_trace(p,"into")@;@/ -end; - -@ Subroutine |save_for_after| puts a token on the stack for save-keeping. - z - -@x -@* \[20] Token lists. -@y -@* \[20] Token lists. -@z - -@x -A \TeX\ token is either a character or a control sequence, and it is -@^token@> -represented internally in one of two ways: (1)~A character whose ASCII -code number is |c| and whose command code is |m| is represented as the -number $2^8m+c$; the command code is in the range |1<=m<=14|. (2)~A control -sequence whose |eqtb| address is |p| is represented as the number -|cs_token_flag+p|. Here |cs_token_flag=@t$2^{12}-1$@>| is larger than -$2^8m+c$, yet it is small enough that |cs_token_flag+p< max_halfword|; -thus, a token fits comfortably in a halfword. -@y -A \TeX\ token is either a character or a control sequence, and it is -@^token@> -represented internally in one of two ways: (1)~A character whose ASCII -code number is |c| and whose command code is |m| is represented as the -number $2^16m+c$; the command code is in the range |1<=m<=14|. (2)~A control -sequence whose |eqtb| address is |p| is represented as the number -|cs_token_flag+p|. Here |cs_token_flag=@t$2^{20}-1$@>| is larger than -$2^8m+c$, yet it is small enough that |cs_token_flag+p< max_halfword|; -thus, a token fits comfortably in a halfword. -@z - -@x -@d cs_token_flag==@'7777 {amount added to the |eqtb| location in a - token that stands for a control sequence; is a multiple of~256, less~1} -@d left_brace_token=@'0400 {$2^8\cdot|left_brace|$} -@d left_brace_limit=@'1000 {$2^8\cdot(|left_brace|+1)$} -@d right_brace_token=@'1000 {$2^8\cdot|right_brace|$} -@d right_brace_limit=@'1400 {$2^8\cdot(|right_brace|+1)$} -@d math_shift_token=@'1400 {$2^8\cdot|math_shift|$} -@d tab_token=@'2000 {$2^8\cdot|tab_mark|$} -@d out_param_token=@'2400 {$2^8\cdot|out_param|$} -@d space_token=@'5040 {$2^8\cdot|spacer|+|" "|$} -@d letter_token=@'5400 {$2^8\cdot|letter|$} -@d other_token=@'6000 {$2^8\cdot|other_char|$} -@d match_token=@'6400 {$2^8\cdot|match|$} -@d end_match_token=@'7000 {$2^8\cdot|end_match|$} -@d protected_token=@'7001 {$2^8\cdot|end_match|+1$} -@y -@d cs_token_flag=@"FFFFF {amount added to the |eqtb| location in a - token that stands for a control sequence; is a multiple of~65536, less~1} -@d max_char_val=@"10000 {to separate char and command code} -@d left_brace_token=@"10000 {$2^16\cdot|left_brace|$} -@d left_brace_limit=@"20000 {$2^16\cdot(|left_brace|+1)$} -@d right_brace_token=@"20000 {$2^16\cdot|right_brace|$} -@d right_brace_limit=@"30000 {$2^16\cdot(|right_brace|+1)$} -@d math_shift_token=@"30000 {$2^16\cdot|math_shift|$} -@d tab_token=@"40000 {$2^16\cdot|tab_mark|$} -@d out_param_token=@"50000 {$2^16\cdot|out_param|$} -@d space_token=@"A0020 {$2^16\cdot|spacer|+|" "|$} -@d letter_token=@"B0000 {$2^16\cdot|letter|$} -@d other_token=@"C0000 {$2^16\cdot|other_char|$} -@d match_token=@"D0000 {$2^16\cdot|match|$} -@d end_match_token=@"E0000 {$2^16\cdot|end_match|$} - -@d protected_token=end_match_token+1 {$2^8\cdot|end_match|+1$} -@z - -@x -else begin m:=info(p) div @'400; c:=info(p) mod @'400; -@y -else begin m:=info(p) div max_char_val; c:=info(p) mod max_char_val; -@z - -@x -@* \[21] Introduction to the syntactic routines. -@y -@* \[21] Introduction to the syntactic routines. -@z - -@x -procedure print_cmd_chr(@!cmd:quarterword;@!chr_code:halfword); -var n:integer; {temp variable} -@y -procedure print_cmd_chr(@!cmd:quarterword;@!chr_code:halfword); -var n:integer; {temp variable} -@!font_name_str:str_number; {local vars for \.{\\fontname} quoting extension} -@!quote_char:UTF16_code; -@z - -@x -@* \[22] Input stacks and states. -@y -@* \[22] Input stacks and states. -@z - -@x -@!input_file : ^alpha_file; -@y -@!input_file : ^unicode_file; -@z - -@x -for q:=p to first_count-1 do print_char(trick_buf[q mod error_line]); -print_ln; -for q:=1 to n do print_char(" "); {print |n| spaces to begin line~2} -if m+n<=error_line then p:=first_count+m else p:=first_count+(error_line-n-3); -for q:=first_count to p-1 do print_char(trick_buf[q mod error_line]); -@y -for q:=p to first_count-1 do print_visible_char(trick_buf[q mod error_line]); -print_ln; -for q:=1 to n do print_visible_char(" "); {print |n| spaces to begin line~2} -if m+n<=error_line then p:=first_count+m else p:=first_count+(error_line-n-3); -for q:=first_count to p-1 do print_visible_char(trick_buf[q mod error_line]); -@z - -@x -@* \[23] Maintaining the input stacks. -@y -@* \[23] Maintaining the input stacks. -@z - -@x -if name>17 then a_close(cur_file); {forget it} -@y -if name>17 then u_close(cur_file); {forget it} -@z - -@x -@* \[24] Getting the next token. -@y -@* \[24] Getting the next token. -@z - -@x -primitive("par",par_end,256); {cf. |scan_file_name|} -@y -primitive("par",par_end,too_big_char); {cf. |scan_file_name|} -@z - -@x -@!c,@!cc:ASCII_code; {constituents of a possible expanded code} -@!d:2..3; {number of excess characters in an expanded code} -@y -@!c,@!cc,@!ccc,@!cccc:ASCII_code; {constituents of a possible expanded code} -@!d:2..7; {number of excess characters in an expanded code} -@z - -@x -@d hex_to_cur_chr== - if c<="9" then cur_chr:=c-"0" @+else cur_chr:=c-"a"+10; - if cc<="9" then cur_chr:=16*cur_chr+cc-"0" - else cur_chr:=16*cur_chr+cc-"a"+10 -@y -@d hex_to_cur_chr== - if c<="9" then cur_chr:=c-"0" @+else cur_chr:=c-"a"+10; - if cc<="9" then cur_chr:=16*cur_chr+cc-"0" - else cur_chr:=16*cur_chr+cc-"a"+10 -@d long_hex_to_cur_chr== - if c<="9" then cur_chr:=c-"0" @+else cur_chr:=c-"a"+10; - if cc<="9" then cur_chr:=16*cur_chr+cc-"0" - else cur_chr:=16*cur_chr+cc-"a"+10; - if ccc<="9" then cur_chr:=16*cur_chr+ccc-"0" - else cur_chr:=16*cur_chr+ccc-"a"+10; - if cccc<="9" then cur_chr:=16*cur_chr+cccc-"0" - else cur_chr:=16*cur_chr+cccc-"a"+10 -@z - -@x - begin c:=buffer[loc+1]; @+if c<@'200 then {yes we have an expanded char} -@y - begin if (cur_chr=buffer[loc+1]) and (cur_chr=buffer[loc+2]) and - ((loc+6)<=limit) then - begin c:=buffer[loc+3]; cc:=buffer[loc+4]; - ccc:=buffer[loc+5]; cccc:=buffer[loc+6]; - if is_hex(c) and is_hex(cc) and is_hex(ccc) and is_hex(cccc) then - begin loc:=loc+7; long_hex_to_cur_chr; goto reswitch; - end; - end; - c:=buffer[loc+1]; @+if c<@'200 then {yes we have an expanded char} -@z - -@x -begin if buffer[k]=cur_chr then @+if cat=sup_mark then @+if k2 then - begin hex_to_cur_chr; buffer[k-1]:=cur_chr; - end - else if c<@'100 then buffer[k-1]:=c+@'100 - else buffer[k-1]:=c-@'100; - limit:=limit-d; first:=first-d; - while k<=limit do - begin buffer[k]:=buffer[k+d]; incr(k); - end; - goto start_cs; - end; - end; -end -@y -begin if buffer[k]=cur_chr then @+if cat=sup_mark then @+if k2 then - begin hex_to_cur_chr; buffer[k-1]:=cur_chr; - end - else if c<@'100 then buffer[k-1]:=c+@'100 - else buffer[k-1]:=c-@'100; - limit:=limit-d; first:=first-d; - while k<=limit do - begin buffer[k]:=buffer[k+d]; incr(k); - end; - goto start_cs; - end - end - end -end -@z - -@x - else begin cur_cmd:=t div @'400; cur_chr:=t mod @'400; -@y - else begin cur_cmd:=t div max_char_val; cur_chr:=t mod max_char_val; -@z - -@x -@d no_expand_flag=257 {this characterizes a special variant of |relax|} -@y -@d no_expand_flag=special_char {this characterizes a special variant of |relax|} -@z - -@x - k := start; - while k < limit do begin print_buffer(k) end; -@y - if startmatch_token+255)or(info(r)=end_match_token)or(info(r) - if (cur_cs=0)and@| - ((cur_chr=s)or(cur_chr=s-"a"+"A")) then - begin store_new_token(cur_tok); - flush_list(link(backup_head)); scan_keyword:=true; return; - end - else if (cur_cmd<>spacer)or(p<>backup_head) then - begin back_input; - if p<>backup_head then back_list(link(backup_head)); - scan_keyword:=false; return; - end; - end; - end; -k:=str_start_macro(s); -while k; -@y -def_code: @; -XeTeX_def_code: - begin - scan_char_num; - if m=math_code_base then begin - scanned_result(ho(math_code(cur_val)))(int_val) - end - else if m=math_code_base+1 then begin - print_err("Can't use \XeTeXmathcode as a number"); - help2("\XeTeXmathcode is for setting a mathcode from separate values;")@/ - ("use \XeTeXmathcodenum to access them as single values."); error; - scanned_result(0)(int_val) - end - else if m=del_code_base then begin - scanned_result(ho(del_code(cur_val)))(int_val) - end else begin - print_err("Can't use \XeTeXdelcode as a number"); - help2("\XeTeXdelcode is for setting a delcode from separate values;")@/ - ("use \XeTeXdelcodenum to access them as single values."); error; - scanned_result(0)(int_val); - end; - end; -@z - -@x -if m=xord_code_base then scanned_result(xord[cur_val])(int_val) -else if m=xchr_code_base then scanned_result(xchr[cur_val])(int_val) -else if m=xprn_code_base then scanned_result(xprn[cur_val])(int_val) -else if m=math_code_base then scanned_result(ho(math_code(cur_val)))(int_val) -@y -if m=math_code_base then begin - cur_val1:=ho(math_code(cur_val)); - if is_active_math_char(cur_val1) then - cur_val1:=@"8000 - else if (math_class_field(cur_val1)>7) or - (math_fam_field(cur_val1)>15) or - (math_char_field(cur_val1)>255) then - begin print_err("Extended mathchar used as mathchar"); -@.Bad mathchar@> - help2("A mathchar number must be between 0 and ""7FFF.")@/ - ("I changed this one to zero."); int_error(cur_val1); cur_val1:=0; - end; - cur_val1:=(math_class_field(cur_val1)*@"1000) + - (math_fam_field(cur_val1)*@"100) + - math_char_field(cur_val1); - scanned_result(cur_val1)(int_val) - end -else if m=del_code_base then begin - cur_val1:=del_code(cur_val); - if cur_val1>=@"40000000 then begin - print_err("Extended delcode used as delcode"); -@.Bad delcode@> - help2("A delimiter code must be between 0 and ""7FFFFFF.")@/ - ("I changed this one to zero."); error; - scanned_result(0)(int_val); - end else begin - scanned_result(cur_val1)(int_val); - end -end -@z - -@x -@d eTeX_dim=eTeX_int+8 {first of \eTeX\ codes for dimensions} -@y -@# -@d XeTeX_int=eTeX_int+8 {first of \XeTeX\ codes for integers} -@# -@d eTeX_dim=XeTeX_int+29 {first of \eTeX\ codes for dimensions} - {changed for \XeTeX\ to make room for \XeTeX\ integers} -@z - -@x -procedure scan_eight_bit_int; -begin scan_int; -if (cur_val<0)or(cur_val>255) then - begin print_err("Bad register code"); -@.Bad register code@> - help2("A register number must be between 0 and 255.")@/ -@y -procedure scan_eight_bit_int; {only used for insertion numbers now} -begin scan_int; -if (cur_val<0)or(cur_val>255) then - begin print_err("Bad register code"); -@.Bad register code@> - help2("An insertion number must be between 0 and 255.")@/ -@z - -@x -procedure scan_char_num; -begin scan_int; -if (cur_val<0)or(cur_val>255) then -@y -procedure scan_usv_num; -begin scan_int; -if (cur_val<0)or(cur_val>@"10FFFF) then - begin print_err("Bad USV code"); -@.Bad character code@> - help2("A Unicode Scalar Value must be between 0 and ""10FFFF.")@/ - ("I changed this one to zero."); int_error(cur_val); cur_val:=0; - end; -end; - -procedure scan_char_num; -begin scan_int; -if (cur_val<0)or(cur_val>biggest_char) then -@z - -@x - help2("A character number must be between 0 and 255.")@/ -@y - help2("A character number must be between 0 and 65535.")@/ -@z - -@x -procedure scan_four_bit_int; -@y -procedure scan_xetex_math_char_int; -begin scan_int; - if is_active_math_char(cur_val) then begin - if cur_val <> active_math_char then begin - print_err("Bad active XeTeX math code"); - help2("Since I ignore class and family for active math chars,")@/ - ("I changed this one to ""1FFFFF."); int_error(cur_val); - cur_val := active_math_char; - end - end else if math_char_field(cur_val) > @"10FFFF then begin - print_err("Bad XeTeX math character code"); - help2("Since I expected a character number between 0 and ""10FFFF,")@/ - ("I changed this one to zero."); int_error(cur_val); cur_val:=0; - end; -end; - -procedure scan_math_class_int; -begin scan_int; -if (cur_val<0)or(cur_val>7) then - begin print_err("Bad math class"); -@.Bad number@> - help2("Since I expected to read a number between 0 and 7,")@/ - ("I changed this one to zero."); int_error(cur_val); cur_val:=0; - end; -end; - -procedure scan_math_fam_int; -begin scan_int; -if (cur_val<0)or(cur_val>number_math_families-1) then - begin print_err("Bad math family"); -@.Bad number@> - help2("Since I expected to read a number between 0 and 255,")@/ - ("I changed this one to zero."); int_error(cur_val); cur_val:=0; - end; -end; - -procedure scan_four_bit_int; -@z - -@x -procedure scan_twenty_seven_bit_int; -begin scan_int; -if (cur_val<0)or(cur_val>@'777777777) then - begin print_err("Bad delimiter code"); -@.Bad delimiter code@> - help2("A numeric delimiter code must be between 0 and 2^{27}-1.")@/ - ("I changed this one to zero."); int_error(cur_val); cur_val:=0; - end; -end; -@y -procedure scan_delimiter_int; -begin scan_int; -if (cur_val<0)or(cur_val>@'777777777) then - begin print_err("Bad delimiter code"); -@.Bad delimiter code@> - help2("A numeric delimiter code must be between 0 and 2^{27}-1.")@/ - ("I changed this one to zero."); int_error(cur_val); cur_val:=0; - end; -end; -@z - -@x -if cur_val>255 then -@y -if cur_val>biggest_char then -@z - -@x -@p procedure scan_dimen(@!mu,@!inf,@!shortcut:boolean); -@y -@p procedure xetex_scan_dimen(@!mu,@!inf,@!shortcut,@!requires_units:boolean); -@z - -@x -@; -@; -@y -if requires_units then begin -@; -@; -end else begin - if cur_val>=@'40000 then arith_error:=true - else cur_val:=cur_val*unity+f; -end; -@z - -@x -@ @= -@y -procedure scan_dimen(@!mu,@!inf,@!shortcut:boolean); -begin - xetex_scan_dimen(mu,inf,shortcut,true); -end; - -@ For XeTeX, we have an additional version |scan_decimal|, like |scan_dimen| -but without any scanning of units. - -@p procedure scan_decimal; - {sets |cur_val| to a quantity expressed as a decimal fraction} -begin - xetex_scan_dimen(false, false, false, false); -end; - -@ @= -@z - -@x -@d etex_convert_base=5 {base for \eTeX's command codes} -@d eTeX_revision_code=etex_convert_base {command code for \.{\\eTeXrevision}} -@d etex_convert_codes=etex_convert_base+1 {end of \eTeX's command codes} -@y -@d etex_convert_base=5 {base for \eTeX's command codes} -@d eTeX_revision_code=etex_convert_base {command code for \.{\\eTeXrevision}} - -@d XeTeX_revision_code=6 -@d XeTeX_variation_name_code=7 { must match codes in xetexmac.c } -@d XeTeX_feature_name_code=8 -@d XeTeX_selector_name_code=9 -@d XeTeX_glyph_name_code=10 - -@d etex_convert_codes=XeTeX_glyph_name_code+1 {end of \eTeX's command codes} -@z - -@x - eTeX_revision_code: print_esc("eTeXrevision"); -@y - @/@@/ -@z - -@x -@!c:number_code..job_name_code; {desired type of conversion} -@y -@!c:small_number; {desired type of conversion} -@z - -@x -@!b:pool_pointer; {base of temporary string} -@y -@!b:pool_pointer; {base of temporary string} -@!fnt,@!arg1,@!arg2:integer; {args for \XeTeX\ extensions} -@!font_name_str:str_number; {local vars for \.{\\fontname} quoting extension} -@!i:small_number; -@!quote_char:UTF16_code; -@z - -@x -eTeX_revision_code: do_nothing; -@y -@/@@/ -@z - -@x -font_name_code: begin print(font_name[cur_val]); -@y -font_name_code: begin - font_name_str:=font_name[cur_val]; - if is_native_font(cur_val) then begin - quote_char:=""""; - for i:=0 to length(font_name_str) - 1 do - if str_pool[str_start_macro(font_name_str) + i] = """" then quote_char:="'"; - print_char(quote_char); - print(font_name_str); - print_char(quote_char); - end else - print(font_name_str); -@z - -@x -eTeX_revision_code: print(eTeX_revision); -@y -@/@@/ -@z - -@x -job_name_code: print(job_name); -@y -job_name_code: print_file_name(job_name, 0, 0); -@z - -@x -@!read_file:array[0..15] of alpha_file; {used for \.{\\read}} -@y -@!read_file:array[0..15] of unicode_file; {used for \.{\\read}} -@z - -@x -else begin a_close(read_file[m]); read_open[m]:=closed; -@y -else begin u_close(read_file[m]); read_open[m]:=closed; -@z - -@x - begin a_close(read_file[m]); read_open[m]:=closed; -@y - begin u_close(read_file[m]); read_open[m]:=closed; -@z - -@x -if (cur_cmd>active_char)or(cur_chr>255) then {not a character} - begin m:=relax; n:=256; -@y -if (cur_cmd>active_char)or(cur_chr>biggest_char) then {not a character} - begin m:=relax; n:=too_big_char; -@z - -@x -if (cur_cmd>active_char)or(cur_chr>255) then - begin cur_cmd:=relax; cur_chr:=256; -@y -if (cur_cmd>active_char)or(cur_chr>biggest_char) then - begin cur_cmd:=relax; cur_chr:=too_big_char; -@z - -@x -@* \[29] File names. -@y -@* \[29] File names. -@z - -@x -The following procedures don't allow spaces to be part of -file names; but some users seem to like names that are spaced-out. -System-dependent changes to allow such things should probably -be made with reluctance, and only when an entire file name that -includes spaces is ``quoted'' somehow. - -@y -@z - -@x -@!ext_delimiter:pool_pointer; {the most recent `\..', if any} -@y -@!ext_delimiter:pool_pointer; {the most recent `\..', if any} -@!file_name_quote_char:UTF16_code; -@z - -@x -begin area_delimiter:=0; ext_delimiter:=0; quoted_filename:=false; -@y -begin area_delimiter:=0; ext_delimiter:=0; quoted_filename:=false; -file_name_quote_char:=0; -@z - -@x -@p function more_name(@!c:ASCII_code):boolean; -begin if (c=" ") and stop_at_space and (not quoted_filename) then - more_name:=false -else if c="""" then begin - quoted_filename:=not quoted_filename; - more_name:=true; - end -@y -@p function more_name(@!c:ASCII_code):boolean; -begin if stop_at_space and (c=" ") and (file_name_quote_char=0) then - more_name:=false -else if stop_at_space and (file_name_quote_char<>0) and (c=file_name_quote_char) then begin - file_name_quote_char:=0; - more_name:=true; - end -else if stop_at_space and (file_name_quote_char=0) and ((c="""") or (c="'") or (c="(")) then begin - if c="(" then file_name_quote_char:=")" - else file_name_quote_char:=c; - quoted_filename:=true; - more_name:=true; - end -@z - -@x -@p procedure end_name; -var temp_str: str_number; {result of file name cache lookups} -@!j,@!s,@!t: pool_pointer; {running indices} -@!must_quote:boolean; {whether we need to quote a string} -begin if str_ptr+3>max_strings then - overflow("number of strings",max_strings-init_str_ptr); -@:TeX capacity exceeded number of strings}{\quad number of strings@> -str_room(6); {Room for quotes, if needed.} -{add quotes if needed} -if area_delimiter<>0 then begin - {maybe quote |cur_area|} - must_quote:=false; - s:=str_start[str_ptr]; - t:=str_start[str_ptr]+area_delimiter; - j:=s; - while (not must_quote) and (j0 then ext_delimiter:=ext_delimiter+2; - area_delimiter:=area_delimiter+2; - pool_ptr:=pool_ptr+2; - end; - end; -{maybe quote |cur_name|} -s:=str_start[str_ptr]+area_delimiter; -if ext_delimiter=0 then t:=pool_ptr else t:=str_start[str_ptr]+ext_delimiter-1; -must_quote:=false; -j:=s; -while (not must_quote) and (j0 then ext_delimiter:=ext_delimiter+2; - pool_ptr:=pool_ptr+2; - end; -if ext_delimiter<>0 then begin - {maybe quote |cur_ext|} - s:=str_start[str_ptr]+ext_delimiter-1; - t:=pool_ptr; - must_quote:=false; - j:=s; - while (not must_quote) and (jmax_strings then - overflow("number of strings",max_strings-init_str_ptr); -@:TeX capacity exceeded number of strings}{\quad number of strings@> -@z - -@x - str_start[str_ptr+1]:=str_start[str_ptr]+area_delimiter; incr(str_ptr); -@y - str_start_macro(str_ptr+1):=str_start_macro(str_ptr)+area_delimiter; incr(str_ptr); -@z - -@x - for j:=str_start[str_ptr+1] to pool_ptr-1 do -@y - for j:=str_start_macro(str_ptr+1) to pool_ptr-1 do -@z - -@x - str_start[str_ptr+1]:=str_start[str_ptr]+ext_delimiter-area_delimiter-1; -@y - str_start_macro(str_ptr+1):=str_start_macro(str_ptr)+ext_delimiter-area_delimiter-1; -@z - -@x - for j:=str_start[str_ptr+1] to pool_ptr-1 do -@y - for j:=str_start_macro(str_ptr+1) to pool_ptr-1 do -@z - -@x -procedure print_file_name(@!n,@!a,@!e:integer); -var must_quote: boolean; {whether to quote the filename} -@!j:pool_pointer; {index into |str_pool|} -begin -must_quote:=false; -if a<>0 then begin - j:=str_start[a]; - while (not must_quote) and (j0 then begin - j:=str_start[n]; - while (not must_quote) and (j0 then begin - j:=str_start[e]; - while (not must_quote) and (j0)and(|str_pool|[|str_start|[|a|]]=""""))or - ((|n|<>0)and(|str_pool|[|str_start|[|n|]]=""""))or - ((|e|<>0)and(|str_pool|[|str_start|[|e|]]=""""));} -if must_quote then print_char(""""); -if a<>0 then - for j:=str_start[a] to str_start[a+1]-1 do - if so(str_pool[j])<>"""" then - print(so(str_pool[j])); -if n<>0 then - for j:=str_start[n] to str_start[n+1]-1 do - if so(str_pool[j])<>"""" then - print(so(str_pool[j])); -if e<>0 then - for j:=str_start[e] to str_start[e+1]-1 do - if so(str_pool[j])<>"""" then - print(so(str_pool[j])); -if must_quote then print_char(""""); -end; -@y -procedure print_file_name(@!n,@!a,@!e:integer); -var @!must_quote: boolean; {whether to quote the filename} -@!quote_char: integer; {current quote char (single or double)} -@!j:pool_pointer; {index into |str_pool|} -begin -must_quote:=false; -quote_char:=0; -if a<>0 then begin - j:=str_start_macro(a); - while ((not must_quote) or (quote_char=0)) and (j<>str_start_macro(a+1)) do begin - if (str_pool[j]=" ") then must_quote:=true - else if (str_pool[j]="""") or (str_pool[j]="'") then begin - must_quote:=true; - quote_char:="""" + "'" - str_pool[j]; - end; - incr(j); - end; -end; -if n<>0 then begin - j:=str_start_macro(n); - while ((not must_quote) or (quote_char=0)) and (j<>str_start_macro(n+1)) do begin - if (str_pool[j]=" ") then must_quote:=true - else if (str_pool[j]="""") or (str_pool[j]="'") then begin - must_quote:=true; - quote_char:="""" + "'" - str_pool[j]; - end; - incr(j); - end; -end; -if e<>0 then begin - j:=str_start_macro(e); - while ((not must_quote) or (quote_char=0)) and (j<>str_start_macro(e+1)) do begin - if (str_pool[j]=" ") then must_quote:=true - else if (str_pool[j]="""") or (str_pool[j]="'") then begin - must_quote:=true; - quote_char:="""" + "'" - str_pool[j]; - end; - incr(j); - end; -end; -if must_quote then begin - if quote_char=0 then quote_char:=""""; - print_char(quote_char); -end; -if a<>0 then - for j:=str_start_macro(a) to str_start_macro(a+1)-1 do begin - if str_pool[j]=quote_char then begin - print(quote_char); - quote_char:="""" + "'" - quote_char; - print(quote_char); - end; - print(str_pool[j]); - end; -if n<>0 then - for j:=str_start_macro(n) to str_start_macro(n+1)-1 do begin - if str_pool[j]=quote_char then begin - print(quote_char); - quote_char:="""" + "'" - quote_char; - print(quote_char); - end; - print(str_pool[j]); - end; -if e<>0 then - for j:=str_start_macro(e) to str_start_macro(e+1)-1 do begin - if str_pool[j]=quote_char then begin - print(quote_char); - quote_char:="""" + "'" - quote_char; - print(quote_char); - end; - print(str_pool[j]); - end; -if quote_char<>0 then print_char(quote_char); -end; -@z - -@x -@d append_to_name(#)==begin c:=#; if not (c="""") then begin incr(k); - if k<=file_name_size then name_of_file[k]:=xchr[c]; - end end -@y -@d append_to_name(#)==begin c:=#; incr(k); - if k<=file_name_size then begin - if (c < 128) then name_of_file[k]:=c - else if (c < @"800) then begin - name_of_file[k]:=@"C0 + c div @"40; incr(k); - name_of_file[k]:=@"80 + c mod @"40; - end else begin - name_of_file[k]:=@"E0 + c div @"1000; incr(k); - name_of_file[k]:=@"80 + (c mod @"1000) div @"40; incr(k); - name_of_file[k]:=@"80 + (c mod @"1000) mod @"40; - end - end - end -@z - -@x -name_of_file:= xmalloc_array (ASCII_code, length(a)+length(n)+length(e)+1); -for j:=str_start[a] to str_start[a+1]-1 do append_to_name(so(str_pool[j])); -for j:=str_start[n] to str_start[n+1]-1 do append_to_name(so(str_pool[j])); -for j:=str_start[e] to str_start[e+1]-1 do append_to_name(so(str_pool[j])); -@y -name_of_file:= xmalloc_array (UTF8_code, (length(a)+length(n)+length(e))*3+1); -for j:=str_start_macro(a) to str_start_macro(a+1)-1 do append_to_name(so(str_pool[j])); -for j:=str_start_macro(n) to str_start_macro(n+1)-1 do append_to_name(so(str_pool[j])); -for j:=str_start_macro(e) to str_start_macro(e+1)-1 do append_to_name(so(str_pool[j])); -@z - -@x -name_of_file := xmalloc_array (ASCII_code, n+(b-a+1)+format_ext_length+1); -for j:=1 to n do append_to_name(xord[TEX_format_default[j]]); -@y -name_of_file := xmalloc_array (UTF8_code, n+(b-a+1)+format_ext_length+1); -for j:=1 to n do append_to_name(TEX_format_default[j]); -@z - -@x - append_to_name(xord[TEX_format_default[j]]); -@y - append_to_name(TEX_format_default[j]); -@z - -@x -@p function make_name_string:str_number; -var k:1..file_name_size; {index into |name_of_file|} -begin if (pool_ptr+name_length>pool_size)or(str_ptr=max_strings)or - (cur_length>0) then - make_name_string:="?" -else begin for k:=1 to name_length do append_char(xord[name_of_file[k]]); - make_name_string:=make_string; - end; - {At this point we also set |cur_name|, |cur_ext|, and |cur_area| to - match the contents of |name_of_file|.} - k:=1; - name_in_progress:=true; - begin_name; - stop_at_space:=false; - while (k<=name_length)and(more_name(name_of_file[k])) do - incr(k); - stop_at_space:=true; - end_name; - name_in_progress:=false; -end; -@y -@p function make_name_string:str_number; -var k:1..file_name_size; {index into |name_of_file|} -begin if (pool_ptr+name_length>pool_size)or(str_ptr=max_strings)or - (cur_length>0) then - make_name_string:="?" -else begin - make_utf16_name; - for k:=0 to name_length16-1 do append_char(name_of_file16[k]); - make_name_string:=make_string; - end; -end; -function u_make_name_string(var f:unicode_file):str_number; -begin u_make_name_string:=make_name_string; -end; -@z - -@x -loop@+begin if (cur_cmd>other_char)or(cur_chr>255) then {not a character} -@y -loop@+begin if (cur_cmd>other_char)or(cur_chr>biggest_char) then - {not a character} -@z - -@x - {If |cur_chr| is a space and we're not scanning a token list, check - whether we're at the end of the buffer. Otherwise we end up adding - spurious spaces to file names in some cases.} - if (cur_chr=" ") and (state<>token_list) and (loc>limit) then goto done; -@y -@z - -@x - pack_job_name(".dvi"); - while not b_open_out(dvi_file) do - prompt_file_name("file name for output",".dvi"); -@y - pack_job_name(output_file_extension); - while not dvi_open_out(dvi_file) do - prompt_file_name("file name for output",output_file_extension); -@z - -@x -@!dvi_file: byte_file; {the device-independent output goes here} -@y -@!output_file_extension: str_number; -@!no_pdf_output: boolean; -@!dvi_file: byte_file; {the device-independent output goes here} -@z - -@x -@ @=output_file_name:=0; -@y -@ @= - output_file_name:=0; - if no_pdf_output then output_file_extension:=".xdv" - else output_file_extension:=".pdf"; -@z - -@x - if open_in_name_ok(stringcast(name_of_file+1)) - and a_open_in(cur_file, kpse_tex_format) then - goto done; -@y - if open_in_name_ok(stringcast(name_of_file+1)) - and u_open_in(cur_file, kpse_tex_format, XeTeX_default_input_mode, XeTeX_default_input_encoding) then - {At this point |name_of_file| contains the actual name found, as a UTF8 string. - We convert to UTF16, then extract the |cur_area|, |cur_name|, and |cur_ext| from it.} - begin - make_utf16_name; - name_in_progress:=true; - begin_name; - stop_at_space:=false; - k:=0; - while (k; -@y -if g<>null_font then goto done; -if file_name_quote_char=0 then begin - { we failed to find a TFM file, so try for a native font } - g:=load_native_font(u,nom,aire,s); - if g<>null_font then goto done -end; -bad_tfm: -if (not file_opened) and (file_name_quote_char<>0) then begin - @; -end; -@; -@z - -@x -@d start_font_error_message==print_err("Font "); sprint_cs(u); - print_char("="); print_file_name(nom,aire,""); -@y -@d start_font_error_message==print_err("Font "); sprint_cs(u); - print_char("="); - if file_name_quote_char=")" then print_char("(") - else if file_name_quote_char<>0 then print_char(file_name_quote_char); - print_file_name(nom,aire,cur_ext); - if file_name_quote_char<>0 then print_char(file_name_quote_char); -@z - -@x -else print(" not loadable: Metric (TFM) file not found"); -@y -else print(" not loadable: Metric (TFM) file or installed font not found"); -@z - -@x -@ @= -@; -@y -@ @= -start_font_error_message; -@.Font x=xx not loadable...@> -print(" not loadable: installed font not found"); -help4("I wasn't able to find this font in the Mac OS,")@/ -("so I will ignore the font specification.")@/ -("You might try inserting a different font spec;")@/ -("e.g., type `I\font='."); -error; -goto done - -@ @= -@; -@z - -@x -@ -@y -@; -end -@z - -@x -@ @= -file_opened:=false; -@y -@ @= -@z - -@x -if not b_open_in(tfm_file) then abort; -file_opened:=true -@y -if b_open_in(tfm_file) then begin - file_opened:=true -@z - -@x we have to move this before new_native_character -@ When \TeX\ wants to typeset a character that doesn't exist, the -character node is not created; thus the output routine can assume -that characters exist when it sees them. The following procedure -prints a warning message unless the user has suppressed it. - -@p procedure char_warning(@!f:internal_font_number;@!c:eight_bits); -var old_setting: integer; {saved value of |tracing_online|} -begin if tracing_lost_chars>0 then - begin old_setting:=tracing_online; - if eTeX_ex and(tracing_lost_chars>1) then tracing_online:=1; - begin begin_diagnostic; - print_nl("Missing character: There is no "); -@.Missing character@> - print_ASCII(c); print(" in font "); - slow_print(font_name[f]); print_char("!"); end_diagnostic(false); - end; - tracing_online:=old_setting; - end; -end; -@y -@ Procedure |char_warning| has been moved in the source. -@z - -@x -@p function new_character(@!f:internal_font_number;@!c:eight_bits):pointer; -@y -@p function new_character(@!f:internal_font_number;@!c:ASCII_code):pointer; -@z - -@x -begin ec:=effective_char(false,f,qi(c)); -@y -begin -if is_native_font(f) then - begin new_character:=new_native_character(f,c); return; - end; -ec:=effective_char(false,f,qi(c)); -@z - -@x -@* \[31] Device-independent file format. -@y -@* \[31] Device-independent file format. -@z - -@x -\yskip\noindent Commands 250--255 are undefined at the present time. -@y -\yskip\hang|set_glyph_string| 254 w[4] k[2] x[4k] g[2k]. - -\yskip\hang|set_glyph_array| 253 w[4] k[2] xy[8k] g[2k] - -\yskip\hang|define_native_font| 252 k[4] s[4] flags[2] - lenps[1] lenfam[1] lensty[1] ps[lenps] fam[lenfam] sty[lensty] - if (flags & COLORED): - rgba[4] - if (flags & VARIATIONS): - numvars[2] - axes[4nv] - values[4nv] - if (flags & MATRIX): - ta[4] tb[4] tc[4] td[4] tx[4] ty[4] - -\yskip\hang|pic_file| 251 flags[1] t[4][6] p[2] len[2] path[l] - flags = 0 for raster image, 1 for PDF - t is transform matrix - p is page # from the graphic file (0-based) - len is length of pathname - path is pathname of graphic file - -\yskip\noindent Commands 250 and 255 are undefined at the present time (but 255 is used by pTeX). -@z - -@x -@d post_post=249 {postamble ending} -@y -@d post_post=249 {postamble ending} - -@d set_glyph_string=254 {sequence of glyphs, all at the current y-position} -@d set_glyph_array=253 {sequence of glyphs with individual x-y coordinates} -@d define_native_font=252 {define native font} -@d pic_file=251 {embed picture or PDF} -@z - -@x -@d id_byte=2 {identifies the kind of \.{DVI} files described here} -@y -XeTeX changes the DVI version to 5, -as we have new DVI opcodes like |set_glyph_array| for native font text; -I used version 3 in an earlier extension of TeX, -and 4 in pre-1.0 XeTeX releases using Mac OS-specific data types. - -@d id_byte=5 {identifies the kind of \.{DVI} files described here} -@z - -@x -@* \[32] Shipping pages out. -@y -@* \[32] Shipping pages out. -@z - -@x -@ A mild optimization of the output is performed by the |dvi_pop| -@y -procedure dvi_two(s: UTF16_code); -begin - dvi_out(s div @'400); - dvi_out(s mod @'400); -end; - -@ A mild optimization of the output is performed by the |dvi_pop| -@z - -@x -@p procedure dvi_font_def(@!f:internal_font_number); -@y -@p procedure dvi_native_font_def(@!f:internal_font_number); -var - font_def_length, i: integer; -begin - dvi_out(define_native_font); - dvi_four(f-font_base-1); - font_def_length := make_font_def(f); - for i := 0 to font_def_length - 1 do dvi_out(xdv_buffer[i]); -end; - -procedure dvi_font_def(@!f:internal_font_number); -@z - -@x -begin if f<=256+font_base then -@y -begin if is_native_font(f) then dvi_native_font_def(f) else -begin if f<=256+font_base then -@z - -@x -@; -@y -@; -end; -@z - -@x -@ @= -for k:=str_start[font_area[f]] to str_start[font_area[f]+1]-1 do - dvi_out(so(str_pool[k])); -for k:=str_start[font_name[f]] to str_start[font_name[f]+1]-1 do - dvi_out(so(str_pool[k])) -@y -@ @= -for k:=str_start_macro(font_area[f]) to str_start_macro(font_area[f]+1)-1 do - dvi_out(so(str_pool[k])); -for k:=str_start_macro(font_name[f]) to str_start_macro(font_name[f]+1)-1 do - dvi_out(so(str_pool[k])) -@z - -@x -@ @= -dvi_h:=0; dvi_v:=0; cur_h:=h_offset; dvi_f:=null_font; -@y -@ @= -dvi_h:=0; dvi_v:=0; cur_h:=h_offset; dvi_f:=null_font; -@; -@z - -@x - print(" TeX output "); print_int(year); print_char("."); -@y - print(" XeTeX output "); print_int(year); print_char("."); -@z - -@x - for s:=str_start[str_ptr] to pool_ptr-1 do dvi_out(so(str_pool[s])); - pool_ptr:=str_start[str_ptr]; {flush the current string} -@y - for s:=str_start_macro(str_ptr) to pool_ptr-1 do dvi_out(so(str_pool[s])); - pool_ptr:=str_start_macro(str_ptr); {flush the current string} -@z - -@x -@d next_p=15 {go to this label when finished with node |p|} -@y -@d next_p=15 {go to this label when finished with node |p|} - -@d check_next=1236 -@d end_node_run=1237 -@z - -@x -label reswitch, move_past, fin_rule, next_p, continue, found; -@y -label reswitch, move_past, fin_rule, next_p, continue, found, check_next, end_node_run; -@z - -@x -@!prev_p:pointer; {one step behind |p|} -@y -@!prev_p:pointer; {one step behind |p|} -@!len: integer; { length of scratch string for native word output } -@!q,@!r: pointer; -@!k,@!j: integer; -@z - -@x -g_sign:=glue_sign(this_box); p:=list_ptr(this_box); -@y -g_sign:=glue_sign(this_box); -@; -p:=list_ptr(this_box); -@z - -@x -@ We ought to give special care to the efficiency of one part of |hlist_out|, -@y -@ Extra stuff for justifiable AAT text; need to merge runs of words and normal spaces. - -@d is_native_word_node(#) == (not is_char_node(#)) and (type(#) = whatsit_node) and (subtype(#) = native_word_node) - -@= -p := list_ptr(this_box); -prev_p := this_box+list_offset; -while p<>null do begin - if link(p) <> null then begin {not worth looking ahead at the end} - if is_native_word_node(p) and (font_area[native_font(p)] = aat_font_flag) - and (font_letter_space[native_font(p)] = 0) then begin - {got a word in an AAT font, might be the start of a run} - r := p; {|r| is start of possible run} - k := native_length(r); - q := link(p); -check_next: - @; - if (q <> null) and not is_char_node(q) then begin - if (type(q) = glue_node) and (subtype(q) = normal) and (glue_ptr(q) = font_glue[native_font(r)]) then begin - {found a normal space; if the next node is another word in the same font, we'll merge} - q := link(q); - @; - if (q <> null) and is_native_word_node(q) and (native_font(q) = native_font(r)) then begin - p := q; {record new tail of run in |p|} - k := k + 1 + native_length(q); - q := link(q); - goto check_next; - end; - goto end_node_run; - end; - {@;} - if (q <> null) and is_native_word_node(q) and (native_font(q) = native_font(r)) then begin - p := q; {record new tail of run in |p|} - q := link(q); - goto check_next; - end - end; -end_node_run: {now |r| points to first |native_word_node| of the run, and |p| to the last} - if p <> r then begin {merge nodes from |r| to |p| inclusive; total text length is |k|} - str_room(k); - k := 0; {now we'll use this as accumulator for total width} - q := r; - loop begin - if type(q) = whatsit_node then begin - if subtype(q) = native_word_node then begin - for j := 0 to native_length(q)-1 do - append_char(get_native_char(q, j)); - k := k + width(q); - end - end else if type(q) = glue_node then begin - append_char(" "); - g := glue_ptr(q); - k := k + width(g); - if g_sign <> normal then begin - if g_sign = stretching then begin - if stretch_order(g) = g_order then begin - k := k + round(float(glue_set(this_box)) * stretch(g)) - end - end else begin - if shrink_order(g) = g_order then begin - k := k - round(float(glue_set(this_box)) * shrink(g)) - end - end - end - end; - {discretionary and deleted nodes can be discarded here} - if q = p then break - else q := link(q); - end; -done: - q := new_native_word_node(native_font(r), cur_length); - link(prev_p) := q; - for j := 0 to cur_length - 1 do - set_native_char(q, j, str_pool[str_start_macro(str_ptr) + j]); - link(q) := link(p); - link(p) := null; - flush_node_list(r); - width(q) := k; - set_justified_native_glyphs(q); - p := q; - pool_ptr := str_start_macro(str_ptr); {flush the temporary string data} - end - end; - prev_p := p; - end; - p := link(p); -end - -@ @= -while (q <> null) and (not is_char_node(q)) and (type(q) = disc_node) do - q := link(q) - -@ We ought to give special care to the efficiency of one part of |hlist_out|, -@z - -@x -dvi_four(last_bop); last_bop:=page_loc; -@y -dvi_four(last_bop); last_bop:=page_loc; -if (pdf_page_width > 0) and (pdf_page_height > 0) then begin - { generate a papersize \special at start of page } - old_setting:=selector; selector:=new_string; - print("papersize "); - if mag=1000 then print_scaled(pdf_page_width) - else print_scaled(xn_over_d(pdf_page_width,mag,1000)); - print("pt"); print(","); - if mag=1000 then print_scaled(pdf_page_height) - else print_scaled(xn_over_d(pdf_page_height,mag,1000)); - print("pt"); - selector:=old_setting; - dvi_out(xxx1); dvi_out(cur_length); - for s:=str_start_macro(str_ptr) to pool_ptr-1 do dvi_out(so(str_pool[s])); - pool_ptr:=str_start_macro(str_ptr); {erase the string} -end; -@z - -@x -dvi_out(eop); incr(total_pages); cur_s:=-1; -@y -dvi_out(eop); incr(total_pages); cur_s:=-1; -if not no_pdf_output then fflush(dvi_file); -@z - -@x - print_nl("Output written on "); print_file_name(0, output_file_name, 0); -@y - print_nl("Output written on "); print(output_file_name); -@z - -@x - print(", "); print_int(dvi_offset+dvi_ptr); print(" bytes)."); - b_close(dvi_file); -@y - if no_pdf_output then begin - print(", "); print_int(dvi_offset+dvi_ptr); print(" bytes)."); - end else print(")."); - dvi_close(dvi_file); -@z - -@x -@* \[33] Packaging. -@y -@* \[33] Packaging. -@z - -@x -@p function hpack(@!p:pointer;@!w:scaled;@!m:small_number):pointer; -label reswitch, common_ending, exit; -@y -@p function hpack(@!p:pointer;@!w:scaled;@!m:small_number):pointer; -label reswitch, common_ending, exit, restart; -@z - -@x -@!hd:eight_bits; {height and depth indices for a character} -@y -@!hd:eight_bits; {height and depth indices for a character} -@!pp,@!ppp: pointer; -@!total_chars, @!k: integer; -@z - -@x -@* \[34] Data structures for math mode. -@y -@* \[34] Data structures for math mode. -@z - -@x -@d fam==font {a |quarterword| in |mem|} -@y -@d plane_and_fam_field==font {a |quarterword| in |mem|} -@d fam(#) == (plane_and_fam_field(#) mod @"100) -@z - -@x -@d small_fam(#)==mem[#].qqqq.b0 {|fam| for ``small'' delimiter} -@d small_char(#)==mem[#].qqqq.b1 {|character| for ``small'' delimiter} -@d large_fam(#)==mem[#].qqqq.b2 {|fam| for ``large'' delimiter} -@d large_char(#)==mem[#].qqqq.b3 {|character| for ``large'' delimiter} -@y -@d small_fam(#)==(mem[#].qqqq.b0 mod @"100) {|fam| for ``small'' delimiter} -@d small_char(#)==(mem[#].qqqq.b1 + (mem[#].qqqq.b0 div @"100) * @"10000) {|character| for ``small'' delimiter} -@d large_fam(#)==(mem[#].qqqq.b2 mod @"100) {|fam| for ``large'' delimiter} -@d large_char(#)==(mem[#].qqqq.b3 + (mem[#].qqqq.b2 div @"100) * @"10000) {|character| for ``large'' delimiter} -@d small_plane_and_fam_field(#)==mem[#].qqqq.b0 -@d small_char_field(#)==mem[#].qqqq.b1 -@d large_plane_and_fam_field(#)==mem[#].qqqq.b2 -@d large_char_field(#)==mem[#].qqqq.b3 -@z - -@x -procedure print_fam_and_char(@!p:pointer); {prints family and character} -begin print_esc("fam"); print_int(fam(p)); print_char(" "); -print_ASCII(qo(character(p))); -@y -procedure print_fam_and_char(@!p:pointer); {prints family and character} -begin print_esc("fam"); print_int(fam(p) mod @"100); print_char(" "); -print_ASCII(qo(character(p)) + (fam(p) div @"100) * @"10000); -@z - -@x -@* \[35] Subroutines for math mode. -@y -@* \[35] Subroutines for math mode. -@z - -@x -@d text_size=0 {size code for the largest size in a family} -@d script_size=16 {size code for the medium size in a family} -@d script_script_size=32 {size code for the smallest size in a family} -@y -@z - -@x -else cur_size:=16*((cur_style-text_style) div 2); -@y -else cur_size:=script_size*((cur_style-text_style) div 2); -@z - -@x -function var_delimiter(@!d:pointer;@!s:small_number;@!v:scaled):pointer; -@y -function var_delimiter(@!d:pointer;@!s:integer;@!v:scaled):pointer; -@z - -@x -@!z: small_number; {runs through font family members} -@y -@!z: integer; {runs through font family members} -@z - -@x - begin z:=z+s+16; - repeat z:=z-16; g:=fam_fnt(z); -@y - begin z:=z+s+script_size; - repeat z:=z-script_size; g:=fam_fnt(z); -@z - -@x - until z<16; -@y - until z -else begin if (qo(cur_c)>=font_bc[cur_f])and(qo(cur_c)<=font_ec[cur_f]) then - cur_i:=orig_char_info(cur_f)(cur_c) -@y -@p procedure fetch(@!a:pointer); {unpack the |math_char| field |a|} -begin cur_c:=cast_to_ushort(character(a)); cur_f:=fam_fnt(fam(a)+cur_size); -cur_c:=cur_c + (plane_and_fam_field(a) div @"100) * @"10000; -if cur_f=null_font then - @ -else if is_native_font(cur_f) then begin - cur_i:=null_character; -end else begin if (qo(cur_c)>=font_bc[cur_f])and(qo(cur_c)<=font_ec[cur_f]) then - cur_i:=orig_char_info(cur_f)(cur_c) -@z - -@x -@!cur_c:quarterword; {the |character| field of a |math_char|} -@y -@!cur_c:integer; {the |character| field of a |math_char|} -@z - -@x -procedure make_math_accent(@!q:pointer); -label done,done1; -var p,@!x,@!y:pointer; {temporary registers for box construction} -@!a:integer; {address of lig/kern instruction} -@!c:quarterword; {accent character} -@!f:internal_font_number; {its font} -@!i:four_quarters; {its |char_info|} -@!s:scaled; {amount to skew the accent to the right} -@!h:scaled; {height of character being accented} -@!delta:scaled; {space to remove between accent and accentee} -@!w:scaled; {width of the accentee, not including sub/superscripts} -begin fetch(accent_chr(q)); -if char_exists(cur_i) then - begin i:=cur_i; c:=cur_c; f:=cur_f;@/ - @; - x:=clean_box(nucleus(q),cramped_style(cur_style)); w:=width(x); h:=height(x); - @; -@y -procedure make_math_accent(@!q:pointer); -label done,done1; -var p,@!x,@!y:pointer; {temporary registers for box construction} -@!a:integer; {address of lig/kern instruction} -@!c:integer; {accent character} -@!f:internal_font_number; {its font} -@!i:four_quarters; {its |char_info|} -@!s:scaled; {amount to skew the accent to the right} -@!h:scaled; {height of character being accented} -@!delta:scaled; {space to remove between accent and accentee} -@!w:scaled; {width of the accentee, not including sub/superscripts} -begin fetch(accent_chr(q)); -x:=null; -if is_native_font(cur_f) then - begin c:=cur_c; f:=cur_f; - s:=0; {@;} - x:=clean_box(nucleus(q),cramped_style(cur_style)); w:=width(x); h:=height(x); - end -else if char_exists(cur_i) then - begin i:=cur_i; c:=cur_c; f:=cur_f;@/ - @; - x:=clean_box(nucleus(q),cramped_style(cur_style)); w:=width(x); h:=height(x); - @; - end; -if x<>null then begin -@z - -@x - character(nucleus(r)):=rem_byte(cur_i); - fam(nucleus(r)):=fam(nucleus(q));@/ -@y - character(nucleus(r)):=rem_byte(cur_i); - plane_and_fam_field(nucleus(r)):=fam(nucleus(q));@/ -@z - -@x -@ @= -begin fetch(nucleus(q)); -if char_exists(cur_i) then -@y -@ @= -begin fetch(nucleus(q)); -if is_native_font(cur_f) then begin - delta:=0; p:=new_native_character(cur_f, qo(cur_c)); -end else if char_exists(cur_i) then -@z - -@x -procedure make_scripts(@!q:pointer;@!delta:scaled); -var p,@!x,@!y,@!z:pointer; {temporary registers for box construction} -@!shift_up,@!shift_down,@!clr:scaled; {dimensions in the calculation} -@!t:small_number; {subsidiary size code} -@y -procedure make_scripts(@!q:pointer;@!delta:scaled); -var p,@!x,@!y,@!z:pointer; {temporary registers for box construction} -@!shift_up,@!shift_down,@!clr:scaled; {dimensions in the calculation} -@!t:integer; {subsidiary size code} -@z - -@x -magic_offset:=str_start[math_spacing]-9*ord_noad -@y -magic_offset:=str_start_macro(math_spacing)-9*ord_noad -@z - -@x -@* \[37] Alignment. -@y -@* \[37] Alignment. -@z - -@x -@d span_code=256 {distinct from any character} -@d cr_code=257 {distinct from |span_code| and from any character} -@y -@d span_code=special_char {distinct from any character} -@d cr_code=span_code+1 {distinct from |span_code| and from any character} -@z - -@x -if n>max_quarterword then confusion("256 spans"); {this can happen, but won't} -@^system dependencies@> -@:this can't happen 256 spans}{\quad 256 spans@> -@y -if n>max_quarterword then confusion("too many spans"); - {this can happen, but won't} -@^system dependencies@> -@:this can't happen too many spans}{\quad too many spans@> -@z - -@x -@* \[38] Breaking paragraphs into lines. -@y -@* \[38] Breaking paragraphs into lines. -@z - -@x -label done,done1,done2,done3,done4,done5,continue; -@y -label done,done1,done2,done3,done4,done5,done6,continue, restart; -@z - -@x - othercases confusion("disc1") -@y - whatsit_node: - if (subtype(v)=native_word_node) - or (subtype(v)=glyph_node) - or (subtype(v)=pic_node) - or (subtype(v)=pdf_node) - then break_width[1]:=break_width[1]-width(v) - else confusion("disc1a"); - othercases confusion("disc1") -@z - -@x - othercases confusion("disc2") -@y - whatsit_node: - if (subtype(s)=native_word_node) - or (subtype(s)=glyph_node) - or (subtype(s)=pic_node) - or (subtype(s)=pdf_node) - then break_width[1]:=break_width[1]+width(s) - else confusion("disc2a"); - othercases confusion("disc2") -@z - -@x -@* \[39] Breaking paragraphs into lines, continued. -@y -@* \[39] Breaking paragraphs into lines, continued. -@z - -@x - othercases confusion("disc3") -@y - whatsit_node: - if (subtype(s)=native_word_node) - or (subtype(s)=glyph_node) - or (subtype(s)=pic_node) - or (subtype(s)=pdf_node) - then disc_width:=disc_width+width(s) - else confusion("disc3a"); - othercases confusion("disc3") -@z - -@x - othercases confusion("disc4") -@y - whatsit_node: - if (subtype(s)=native_word_node) - or (subtype(s)=glyph_node) - or (subtype(s)=pic_node) - or (subtype(s)=pdf_node) - then act_width:=act_width+width(s) - else confusion("disc4a"); - othercases confusion("disc4") -@z - -@x -@* \[40] Pre-hyphenation. -@y -@* \[40] Pre-hyphenation. -@z - -@x -@!hc:array[0..65] of 0..256; {word to be hyphenated} -@y -@!hc:array[0..65] of 0..too_big_char; {word to be hyphenated} -@z - -@x -@!hu:array[0..63] of 0..256; {like |hc|, before conversion to lowercase} -@y -@!hu:array[0..63] of 0..too_big_char; - {like |hc|, before conversion to lowercase} -@z - -@x -@!cur_lang,@!init_cur_lang:ASCII_code; {current hyphenation table of interest} -@y -@!cur_lang,@!init_cur_lang:0..biggest_lang; - {current hyphenation table of interest} -@z - -@x -@!hyf_bchar:halfword; {boundary character after $c_n$} -@y -@!hyf_bchar:halfword; {boundary character after $c_n$} -@!max_hyph_char:integer; - -@ @= -max_hyph_char:=too_big_lang; -@z - -@x -@!c:0..255; {character being considered for hyphenation} -@y -@!c:ASCII_code; {character being considered for hyphenation} -@z - -@x - @; -@y -if (not is_char_node(ha)) and (type(ha) = whatsit_node) and (subtype(ha) = native_word_node) then begin - @; - @; -end else begin - @; -end; -@z - -@x -@ The first thing we need to do is find the node |ha| just before the -first letter. -@y -@ @= -s := link(ha); -loop@+ begin if not(is_char_node(s)) then - case type(s) of - ligature_node: do_nothing; - kern_node: if subtype(s)<>normal then goto done6; - whatsit_node,glue_node,penalty_node,ins_node,adjust_node,mark_node: - goto done6; - othercases goto done1 - endcases; - s:=link(s); - end; -done6: - -@ @= -{ note that if there are chars with |lccode = 0|, we split them out into separate |native_word| nodes } -hn := 0; -restart: -for l := 0 to native_length(ha)-1 do begin - c := get_native_char(ha, l); - set_lc_code(c); - if (hc[0] = 0) {or (hc[0] > max_hyph_char) -- no, there can be letters > max_hyph_char in the word} - then begin - if (hn > 0) then begin - { we've got some letters, and now found a non-letter, so break off the tail of the |native_word| - and link it after this node, and goto done3 } - @; - goto done3; - end - end else if (hn = 0) and (l > 0) then begin - { we've found the first letter after some non-letters, so break off the head of the |native_word| and restart } - @; - ha := link(ha); - goto restart; - end else if (hn = 63) then - { reached max hyphenatable length } - goto done3 - else begin - { found a letter that is part of a potentially hyphenatable sequence } - incr(hn); hu[hn] := c; hc[hn] := hc[0]; hyf_bchar := non_char; - end -end; - -@ @= - q := new_native_word_node(hf, native_length(ha) - l); - for i := l to native_length(ha) - 1 do - set_native_char(q, i - l, get_native_char(ha, i)); - set_native_metrics(q, XeTeX_use_glyph_metrics); - link(q) := link(ha); - link(ha) := q; - { truncate text in node |ha| } - native_length(ha) := l; - set_native_metrics(ha, XeTeX_use_glyph_metrics); - -@ @= -l: integer; -i: integer; - -@ The first thing we need to do is find the node |ha| just before the -first letter. -@z - -@x - begin @; - goto continue; -@y - begin - if subtype(s) = native_word_node then begin - { we only consider the node if it contains at least one letter, otherwise we'll skip it } - for l:=0 to native_length(s) - 1 do begin - c := get_native_char(s, l); - if lc_code(c) <> 0 then begin - hf := native_font(s); - prev_s := s; - goto done2; - end - end - end; - @; - goto continue -@z - -@x -if hyf_char>255 then goto done1; -@y -if hyf_char>biggest_char then goto done1; -@z - -@x - if hc[0]=0 then goto done3; -@y - if hc[0]=0 then goto done3; - if hc[0]>max_hyph_char then goto done3; -@z - -@x - if hc[0]=0 then goto done3; -@y - if hc[0]=0 then goto done3; - if hc[0]>max_hyph_char then goto done3; -@z - -@x -@* \[41] Post-hyphenation. -@y -@* \[41] Post-hyphenation. -@z - -@x -@= -@y -@= -if (not is_char_node(ha)) and (type(ha) = whatsit_node) and (subtype(ha) = native_word_node) then begin - @; -end else begin -@z - -@x - begin hu[0]:=256; init_lig:=false; -@y - begin hu[0]:=max_hyph_char; init_lig:=false; -@z - -@x -found2: s:=ha; j:=0; hu[0]:=256; init_lig:=false; init_list:=null; -@y -found2: s:=ha; j:=0; hu[0]:=max_hyph_char; init_lig:=false; init_list:=null; -@z - -@x -flush_list(init_list) -@y -flush_list(init_list); -end - -@ @= -{ find the node immediately before the word to be hyphenated } -s := cur_p; {we have |cur_p<>ha| because |type(cur_p)=glue_node|} -while link(s) <> ha do s := link(s); - -{ for each hyphen position, - create a |native_word_node| fragment for the text before this point, - and a |disc_node| for the break, with the |hyf_char| in the |pre_break| text -} - -hyphen_passed := 0; { location of last hyphen we saw } - -for j := l_hyf to hn - r_hyf do begin - { if this is a valid break.... } - if odd(hyf[j]) then begin - - { make a |native_word_node| for the fragment before the hyphen } - q := new_native_word_node(hf, j - hyphen_passed); - for i := 0 to j - hyphen_passed - 1 do - set_native_char(q, i, get_native_char(ha, i + hyphen_passed)); - set_native_metrics(q, XeTeX_use_glyph_metrics); - link(s) := q; { append the new node } - s := q; - - { make the |disc_node| for the hyphenation point } - q := new_disc; - pre_break(q) := new_native_character(hf, hyf_char); - link(s) := q; - s := q; - - hyphen_passed := j; - end -end; - -{ make a |native_word_node| for the last fragment of the word } -hn := native_length(ha); { ensure trailing punctuation is not lost! } -q := new_native_word_node(hf, hn - hyphen_passed); -for i := 0 to hn - hyphen_passed - 1 do - set_native_char(q, i, get_native_char(ha, i + hyphen_passed)); -set_native_metrics(q, XeTeX_use_glyph_metrics); -link(s) := q; { append the new node } -s := q; - -q := link(ha); -link(s) := q; -link(ha) := null; -flush_node_list(ha); -@z - -@x - begin decr(l); c:=hu[l]; c_loc:=l; hu[l]:=256; -@y - begin decr(l); c:=hu[l]; c_loc:=l; hu[l]:=max_hyph_char; -@z - -@x -@* \[42] Hyphenation. -@y -@* \[42] Hyphenation. -@z - -@x -@!op_start:array[ASCII_code] of 0..trie_op_size; {offset for current language} -@y -@!op_start:array[0..biggest_lang] of 0..trie_op_size; {offset for current language} -@z - -@x -hc[0]:=0; hc[hn+1]:=0; hc[hn+2]:=256; {insert delimiters} -@y -hc[0]:=0; hc[hn+1]:=0; hc[hn+2]:=max_hyph_char; {insert delimiters} -@z - -@x - begin j:=1; u:=str_start[k]; -@y - begin j:=1; u:=str_start_macro(k); -@z - -@x - else if language>255 then cur_lang:=0 -@y - else if language>biggest_lang then cur_lang:=0 -@z - -@x -u:=str_start[k]; v:=str_start[s]; -@y -u:=str_start_macro(k); v:=str_start_macro(s); -@z - -@x -until u=str_start[k+1]; -@y -until u=str_start_macro(k+1); -@z - -@x -@* \[43] Initializing the hyphenation tables. -@y -@* \[43] Initializing the hyphenation tables. -@z - -@x -@!trie_used:array[ASCII_code] of trie_opcode; -@y -@!trie_used:array[0..biggest_lang] of trie_opcode; -@z - -@x -@!trie_op_lang:array[1..trie_op_size] of ASCII_code; -@y -@!trie_op_lang:array[1..trie_op_size] of 0..biggest_lang; -@z - -@x -for j:=1 to 255 do op_start[j]:=op_start[j-1]+qo(trie_used[j-1]); -@y -for j:=1 to biggest_lang do op_start[j]:=op_start[j-1]+qo(trie_used[j-1]); -@z - -@x -for k:=0 to 255 do trie_used[k]:=min_trie_op; -@y -for k:=0 to biggest_lang do trie_used[k]:=min_trie_op; -@z - -@x -for p:=0 to 255 do trie_min[p]:=p+1; -@y -for p:=0 to biggest_char do trie_min[p]:=p+1; -@z - -@x -@!ll:1..256; {upper limit of |trie_min| updating} -@y -@!ll:1..too_big_char; {upper limit of |trie_min| updating} -@z - -@x - @=h+256|@>; -@y - @=h+max_hyph_char|@>; -@z - -@x -@ By making sure that |trie_max| is at least |h+256|, we can be sure that -@y -@ By making sure that |trie_max| is at least |h+max_hyph_char|, -we can be sure that -@z - -@x -@=h+256|@>= -if trie_max=h+max_hyph_char|@>= -if trie_maxmax_hyph_char then max_hyph_char:=cur_chr; - if k<63 then -@z - -@x -begin @; -@y -begin -incr(max_hyph_char); -@; -@z - -@x -@* \[44] Breaking vertical lists into pages. -@y -@* \[44] Breaking vertical lists into pages. -@z - -@x -@* \[45] The page builder. -@y -@* \[45] The page builder. -@z - -@x -@!n:min_quarterword..255; {insertion box number} -@y -@!n:min_quarterword..biggest_reg; {insertion box number} -@z - -@x -@!n:min_quarterword..255; {insertion box number} -@y -@!n:min_quarterword..biggest_reg; {insertion box number} -@z - -@x -@* \[46] The chief executive. -@y -@* \[46] The chief executive. -@z - -@x -@d main_loop=70 {go here to typeset a string of consecutive characters} -@y -@d main_loop=70 {go here to typeset a string of consecutive characters} -@d collect_native=71 {go here to collect characters in a "native" font string} -@z - -@x -hmode+char_num: begin scan_char_num; cur_chr:=cur_val; goto main_loop;@+end; -@y -hmode+char_num: begin scan_usv_num; cur_chr:=cur_val; goto main_loop;@+end; -@z - -@x -@!main_p:pointer; {temporary register for list manipulation} -@y -@!main_p:pointer; {temporary register for list manipulation} -@!main_pp,@!main_ppp:pointer; {more temporary registers for list manipulation} -@!main_h:pointer; {temp for hyphen offset in native-font text} -@!is_hyph:boolean; {whether the last char seen is the font's hyphenchar} -@z - -@x -adjust_space_factor;@/ -@y - -{ added code for native font support } -if is_native_font(cur_font) then begin - if mode>0 then if language<>clang then fix_language; - - main_h := 0; - main_f := cur_font; - -collect_native: - adjust_space_factor; - if (cur_chr > @"FFFF) then begin - str_room(2); - append_char((cur_chr - @"10000) div 1024 + @"D800); - append_char((cur_chr - @"10000) mod 1024 + @"DC00); - end else begin - str_room(1); - append_char(cur_chr); - end; - is_hyph := (cur_chr = hyphen_char[main_f]) - or (XeTeX_dash_break_en and (cur_chr = @"2014) or (cur_chr = @"2013)); - if (main_h = 0) and is_hyph then main_h := cur_length; - - {try to collect as many chars as possible in the same font} - get_next; - if (cur_cmd=letter) or (cur_cmd=other_char) or (cur_cmd=char_given) then goto collect_native; - x_token; - if (cur_cmd=letter) or (cur_cmd=other_char) or (cur_cmd=char_given) then goto collect_native; - if cur_cmd=char_num then begin - scan_usv_num; - cur_chr:=cur_val; - goto collect_native; - end; - - if (font_mapping[main_f] <> 0) then begin - main_k := apply_mapping(font_mapping[main_f], address_of(str_pool[str_start_macro(str_ptr)]), cur_length); - pool_ptr := str_start_macro(str_ptr); { flush the string, as we'll be using the mapped text instead } - str_room(main_k); - main_h := 0; - for main_p := 0 to main_k - 1 do begin - append_char(mapped_text[main_p]); - if (main_h = 0) and ((mapped_text[main_p] = hyphen_char[main_f]) - or (XeTeX_dash_break_en and ((mapped_text[main_p] = @"2014) or (mapped_text[main_p] = @"2013)) ) ) - then main_h := cur_length; - end - end; - - if tracing_lost_chars > 0 then begin - temp_ptr := str_start_macro(str_ptr); - main_p := temp_ptr + cur_length; - while (temp_ptr < main_p) do begin - main_k := str_pool[temp_ptr]; - incr(temp_ptr); - if (main_k >= @"D800) and (main_k < @"DC00) then begin - main_k := @"10000 + (main_k - @"D800) * 1024; - main_k := main_k + str_pool[temp_ptr] - @"DC00; - incr(temp_ptr); - end; - if map_char_to_glyph(main_f, main_k) = 0 then - char_warning(main_f, main_k); - end - end; - - main_k := cur_length; - main_pp := tail; - - if mode=hmode then begin - - main_ppp := head; - if main_ppp<>main_pp then - while (link(main_ppp)<>main_pp) do - main_ppp:=link(main_ppp); { find node preceding tail } - - temp_ptr := str_start_macro(str_ptr); - repeat - if main_h = 0 then main_h := main_k; - - if (not is_char_node(main_pp)) - and (type(main_pp)=whatsit_node) - and (subtype(main_pp)=native_word_node) - and (native_font(main_pp)=main_f) - and (main_ppp<>main_pp) - and type(main_ppp)<>disc_node - then begin - - { make a new temp string that contains the concatenated text of |tail| + the current word/fragment } - main_k := main_h + native_length(main_pp); - str_room(main_k); - - temp_ptr := pool_ptr; - for main_p := 0 to native_length(main_pp) - 1 do - append_char(get_native_char(main_pp, main_p)); - for main_p := str_start_macro(str_ptr) to temp_ptr - 1 do - append_char(str_pool[main_p]); - - do_locale_linebreaks(temp_ptr, main_k); - - pool_ptr := temp_ptr; { discard the temp string } - main_k := cur_length - main_h; { and set main_k to remaining length of new word } - temp_ptr := str_start_macro(str_ptr) + main_h; { pointer to remaining fragment } - - main_h := 0; - while (main_h < main_k) and (str_pool[temp_ptr + main_h] <> hyphen_char[main_f]) - and ( (not XeTeX_dash_break_en) - or ((str_pool[temp_ptr + main_h] <> @"2014) and (str_pool[temp_ptr + main_h] <> @"2013)) ) - do incr(main_h); { look for next hyphen or end of text } - if (main_h < main_k) then incr(main_h); - - { remove the preceding node from the list } - link(main_ppp) := link(main_pp); - link(main_pp) := null; - flush_node_list(main_pp); - main_pp := tail; - while (link(main_ppp)<>main_pp) do - main_ppp:=link(main_ppp); - - end else begin - - do_locale_linebreaks(temp_ptr, main_h); { append fragment of current word } - - temp_ptr := temp_ptr + main_h; { advance ptr to remaining fragment } - main_k := main_k - main_h; { decrement remaining length } - - main_h := 0; - while (main_h < main_k) and (str_pool[temp_ptr + main_h] <> hyphen_char[main_f]) - and ( (not XeTeX_dash_break_en) - or ((str_pool[temp_ptr + main_h] <> @"2014) and (str_pool[temp_ptr + main_h] <> @"2013)) ) - do incr(main_h); { look for next hyphen or end of text } - if (main_h < main_k) then incr(main_h); - - end; - - if (main_k > 0) or is_hyph then begin - tail_append(new_disc); { add a break if we aren't at end of text (must be a hyphen), - or if last char in original text was a hyphen } - end; - until main_k = 0; - - end else begin - { must be restricted hmode, so no need for line-breaking or discretionaries } - if (not is_char_node(main_pp)) and (type(main_pp)=whatsit_node) and (subtype(main_pp)=native_word_node) and (native_font(main_pp)=main_f) then begin - { total string length for the new merged whatsit } - link(main_pp) := new_native_word_node(main_f, main_k + native_length(main_pp)); - tail := link(main_pp); - - { copy text from the old one into the new } - for main_p := 0 to native_length(main_pp) - 1 do - set_native_char(tail, main_p, get_native_char(main_pp, main_p)); - { append the new text } - for main_p := 0 to main_k - 1 do - set_native_char(tail, main_p + native_length(main_pp), str_pool[str_start_macro(str_ptr) + main_p]); - set_native_metrics(tail, XeTeX_use_glyph_metrics); - - { remove the preceding node from the list } - main_p := head; - if main_p<>main_pp then - while link(main_p)<>main_pp do - main_p := link(main_p); - link(main_p) := link(main_pp); - link(main_pp) := null; - flush_node_list(main_pp); - end else begin - { package the current string into a |native_word| whatsit } - link(main_pp) := new_native_word_node(main_f, main_k); - tail := link(main_pp); - for main_p := 0 to main_k - 1 do - set_native_char(tail, main_p, str_pool[str_start_macro(str_ptr) + main_p]); - set_native_metrics(tail, XeTeX_use_glyph_metrics); - end - end; - - pool_ptr := str_start_macro(str_ptr); - goto reswitch; -end; -{ End of added code for native fonts } - -adjust_space_factor;@/ -@z - -@x -non_math(math_given), non_math(math_comp), non_math(delim_num), -@y -non_math(math_given), non_math(XeTeX_math_given), non_math(math_comp), non_math(delim_num), -@z - -@x -procedure append_italic_correction; -label exit; -var p:pointer; {|char_node| at the tail of the current list} -@!f:internal_font_number; {the font in the |char_node|} -begin if tail<>head then - begin if is_char_node(tail) then p:=tail - else if type(tail)=ligature_node then p:=lig_char(tail) - else return; -@y -procedure append_italic_correction; -label exit; -var p:pointer; {|char_node| at the tail of the current list} -@!f:internal_font_number; {the font in the |char_node|} -begin if tail<>head then - begin if is_char_node(tail) then p:=tail - else if type(tail)=ligature_node then p:=lig_char(tail) - else if (type(tail)=whatsit_node) then begin - if (subtype(tail)=native_word_node) then begin - tail_append(new_kern(get_native_italic_correction(tail))); subtype(tail):=explicit; - end - else if (subtype(tail)=glyph_node) then begin - tail_append(new_kern(get_native_glyph_italic_correction(tail))); subtype(tail):=explicit; - end; - return; - end - else return; -@z - -@x - if c>=0 then if c<256 then pre_break(tail):=new_character(cur_font,c); -@y - if c>=0 then if c<=biggest_char then pre_break(tail):=new_character(cur_font,c); -@z - -@x - if type(p)<>kern_node then if type(p)<>ligature_node then - begin print_err("Improper discretionary list"); -@y - if type(p)<>kern_node then if type(p)<>ligature_node then - if (type(p)<>whatsit_node) or ((subtype(p)<>native_word_node) - and (subtype(p)<>glyph_node)) then - begin print_err("Improper discretionary list"); -@z - -@x -@!a,@!h,@!x,@!w,@!delta:scaled; {heights and widths, as explained above} -@y -@!a,@!h,@!x,@!w,@!delta,@!lsb,@!rsb:scaled; {heights and widths, as explained above} -@z - -@x - a:=char_width(f)(char_info(f)(character(p)));@/ -@y - if is_native_font(f) then - begin a:=width(p); - if a=0 then get_native_char_sidebearings(f, cur_val, address_of(lsb), address_of(rsb)) - end - else a:=char_width(f)(char_info(f)(character(p)));@/ -@z - -@x -if (cur_cmd=letter)or(cur_cmd=other_char)or(cur_cmd=char_given) then - q:=new_character(f,cur_chr) -@y -if (cur_cmd=letter)or(cur_cmd=other_char)or(cur_cmd=char_given) then - begin q:=new_character(f,cur_chr); cur_val:=cur_chr - end -@z - -@x -i:=char_info(f)(character(q)); -w:=char_width(f)(i); h:=char_height(f)(height_depth(i)); -@y -if is_native_font(f) then begin - w:=width(q); - get_native_char_height_depth(f, cur_val, address_of(h), address_of(delta)) - {using delta as scratch space for the unneeded depth value} -end else begin - i:=char_info(f)(character(q)); - w:=char_width(f)(i); h:=char_height(f)(height_depth(i)) -end; -@z - -@x -delta:=round((w-a)/float_constant(2)+h*t-x*s); -@y -if is_native_font(f) and (a=0) then { special case for non-spacing marks } - delta:=round((w-lsb+rsb)/float_constant(2)+h*t-x*s) -else delta:=round((w-a)/float_constant(2)+h*t-x*s); -@z - -@x -whatsit_node: @; -@y -whatsit_node: @; -@z - -@x -letter,other_char,char_given: begin c:=ho(math_code(cur_chr)); - if c=@'100000 then -@y -letter,other_char,char_given: begin c:=ho(math_code(cur_chr)); - if is_active_math_char(c) then -@z - -@x -math_char_num: begin scan_fifteen_bit_int; c:=cur_val; - end; -@y -math_char_num: - if cur_chr = 2 then begin { \XeTeXmathchar } - scan_math_class_int; c := set_class_field(cur_val); - scan_math_fam_int; c := c + set_family_field(cur_val); - scan_usv_num; c := c + cur_val; - end else if cur_chr = 1 then begin { \XeTeXmathcharnum } - scan_xetex_math_char_int; c := cur_val; - end else begin scan_fifteen_bit_int; - c := set_class_field(cur_val div @"1000) + - set_family_field((cur_val mod @"1000) div @"100) + - (cur_val mod @"100); - end; -@z - -@x -math_given: c:=cur_chr; -delim_num: begin scan_twenty_seven_bit_int; c:=cur_val div @'10000; -@y -math_given: begin - c := set_class_field(cur_chr div @"1000) + - set_family_field((cur_chr mod @"1000) div @"100) + - (cur_chr mod @"100); - end; -XeTeX_math_given: c:=cur_chr; -delim_num: begin - if cur_chr=1 then begin {\XeTeXdelimiter } - scan_math_class_int; c := set_class_field(cur_val); - scan_math_fam_int; c := c + set_family_field(cur_val); - scan_usv_num; c := c + cur_val; - end else begin {\delimiter <27-bit delcode>} - scan_delimiter_int; - c := cur_val div @'10000; {get the 'small' delimiter field} - c := set_class_field(c div @"1000) + - set_family_field((c mod @"1000) div @"100) + - (c mod @"100); {and convert it to a xetex mathchar code} - end; -@z - -@x -math_type(p):=math_char; character(p):=qi(c mod 256); -if (c>=var_code)and fam_in_range then fam(p):=cur_fam -else fam(p):=(c div 256) mod 16; -@y -math_type(p):=math_char; character(p):=qi(c mod @"10000); -if (is_var_family(c)) and fam_in_range then plane_and_fam_field(p):=cur_fam -else plane_and_fam_field(p):=(math_fam_field(c)); -plane_and_fam_field(p) := plane_and_fam_field(p) + (math_char_field(c) div @"10000) * @"100; -@z - -@x -mmode+math_char_num: begin scan_fifteen_bit_int; set_math_char(cur_val); - end; -@y -mmode+math_char_num: if cur_chr = 2 then begin { \XeTeXmathchar } - scan_math_class_int; t := set_class_field(cur_val); - scan_math_fam_int; t := t + set_family_field(cur_val); - scan_usv_num; t := t + cur_val; - set_math_char(t); - end else if cur_chr = 1 then begin { \XeTeXmathcharnum } - scan_xetex_math_char_int; set_math_char(cur_val); - end else begin scan_fifteen_bit_int; - set_math_char(set_class_field(cur_val div @"1000) + - set_family_field((cur_val mod @"1000) div @"100) + - (cur_val mod @"100)); - end; -@z - -@x -mmode+math_given: set_math_char(cur_chr); -mmode+delim_num: begin scan_twenty_seven_bit_int; - set_math_char(cur_val div @'10000); -@y -mmode+math_given: begin - set_math_char(set_class_field(cur_chr div @"1000) + - set_family_field((cur_chr mod @"1000) div @"100) + - (cur_chr mod @"100)); - end; -mmode+XeTeX_math_given: set_math_char(cur_chr); -mmode+delim_num: begin - if cur_chr=1 then begin {\XeTeXdelimiter} - scan_math_class_int; t := set_class_field(cur_val); - scan_math_fam_int; t := t + set_family_field(cur_val); - scan_usv_num; t := t + cur_val; - set_math_char(t); - end else begin - scan_delimiter_int; - cur_val:=cur_val div @'10000; {discard the large delimiter code} - set_math_char(set_class_field(cur_val div @"1000) + - set_family_field((cur_val mod @"1000) div @"100) + - (cur_val mod @"100)); - end; -@z - -@x -procedure set_math_char(@!c:integer); -var p:pointer; {the new noad} -begin if c>=@'100000 then - @ -else begin p:=new_noad; math_type(nucleus(p)):=math_char; - character(nucleus(p)):=qi(c mod 256); - fam(nucleus(p)):=(c div 256) mod 16; - if c>=var_code then - begin if fam_in_range then fam(nucleus(p)):=cur_fam; - type(p):=ord_noad; - end - else type(p):=ord_noad+(c div @'10000); -@y -procedure set_math_char(@!c:integer); -var p,q,r:pointer; {the new noad} - ch: UnicodeScalar; -begin if is_active_math_char(c) then - @ -else begin p:=new_noad; math_type(nucleus(p)):=math_char; - ch:=math_char_field(c); - character(nucleus(p)):=qi(ch mod @"10000); - plane_and_fam_field(nucleus(p)):=math_fam_field(c); - if is_var_family(c) then - begin if fam_in_range then plane_and_fam_field(nucleus(p)):=cur_fam; - type(p):=ord_noad; - end - else type(p):=ord_noad+math_class_field(c); - plane_and_fam_field(nucleus(p)) := plane_and_fam_field(nucleus(p)) + (ch div @"10000) * @"100; -@z - -@x -procedure scan_delimiter(@!p:pointer;@!r:boolean); -begin if r then scan_twenty_seven_bit_int -@y -procedure scan_delimiter(@!p:pointer;@!r:boolean); -begin - if r then begin - if cur_chr=1 then begin {\XeTeXradical} - cur_val1 := @"40000000; {extended delcode flag} - scan_math_fam_int; cur_val1 := cur_val1 + cur_val * @"200000; - scan_usv_num; cur_val := cur_val1 + cur_val; - end else {\radical} - scan_delimiter_int; - end -@z - -@x - letter,other_char: cur_val:=del_code(cur_chr); - delim_num: scan_twenty_seven_bit_int; - othercases cur_val:=-1 -@y - letter,other_char: begin - cur_val:=del_code(cur_chr); - end; - delim_num: if cur_chr=1 then begin {\XeTeXdelimiter} - cur_val1 := @"40000000; {extended delcode flag} - scan_math_class_int; {discarded} - scan_math_fam_int; cur_val1 := cur_val1 + cur_val * @"200000; - scan_usv_num; cur_val := cur_val1 + cur_val; - end else scan_delimiter_int; {normal \delimiter} - othercases begin cur_val:=-1; end; -@z - -@x -if cur_val<0 then @; -small_fam(p):=(cur_val div @'4000000) mod 16; -small_char(p):=qi((cur_val div @'10000) mod 256); -large_fam(p):=(cur_val div 256) mod 16; -large_char(p):=qi(cur_val mod 256); -@y -if cur_val<0 then begin @; - end; -if cur_val>=@"40000000 then begin {extended delcode, only one size} - small_plane_and_fam_field(p) := ((cur_val mod @"200000) div @"10000) * @"100 {plane} - + (cur_val div @"200000) mod @"100; {family} - small_char_field(p) := qi(cur_val mod @"10000); - large_plane_and_fam_field(p) := 0; - large_char_field(p) := 0; -end else begin {standard delcode, 4-bit families and 8-bit char codes} - small_plane_and_fam_field(p) := (cur_val div @'4000000) mod 16; - small_char_field(p) := qi((cur_val div @'10000) mod 256); - large_plane_and_fam_field(p) := (cur_val div 256) mod 16; - large_char_field(p) := qi(cur_val mod 256); -end; -@z - -@x -procedure math_ac; -@y -procedure math_ac; -var c: integer; -@z - -@x -scan_fifteen_bit_int; -character(accent_chr(tail)):=qi(cur_val mod 256); -if (cur_val>=var_code)and fam_in_range then fam(accent_chr(tail)):=cur_fam -else fam(accent_chr(tail)):=(cur_val div 256) mod 16; -@y -if cur_chr=1 then begin - scan_math_class_int; c := set_class_field(cur_val); - scan_math_fam_int; c := c + set_family_field(cur_val); - scan_usv_num; cur_val := cur_val + c; -end -else begin - scan_fifteen_bit_int; - cur_val := set_class_field(cur_val div @"1000) + - set_family_field((cur_val mod @"1000) div @"100) + - (cur_val mod @"100); -end; -character(accent_chr(tail)):=qi(cur_val mod @"10000); -if (is_var_family(cur_val))and fam_in_range then plane_and_fam_field(accent_chr(tail)):=cur_fam -else plane_and_fam_field(accent_chr(tail)):=math_fam_field(cur_val); -plane_and_fam_field(accent_chr(tail)) - := plane_and_fam_field(accent_chr(tail)) + (math_char_field(cur_val) div @"10000) * @"100; -@z - -@x -@* \[49] Mode-independent processing. -@y -@* \[49] Mode-independent processing. -@z - -@x -any_mode(def_code), -@y -any_mode(def_code), -any_mode(XeTeX_def_code), -@z - -@x -@d word_define(#)==if global then geq_word_define(#)@+else eq_word_define(#) -@y -@d word_define(#)==if global then geq_word_define(#)@+else eq_word_define(#) -@d word_define1(#)==if global then geq_word_define1(#)@+else eq_word_define1(#) -@z - -@x -@d char_def_code=0 {|shorthand_def| for \.{\\chardef}} -@d math_char_def_code=1 {|shorthand_def| for \.{\\mathchardef}} -@d count_def_code=2 {|shorthand_def| for \.{\\countdef}} -@d dimen_def_code=3 {|shorthand_def| for \.{\\dimendef}} -@d skip_def_code=4 {|shorthand_def| for \.{\\skipdef}} -@d mu_skip_def_code=5 {|shorthand_def| for \.{\\muskipdef}} -@d toks_def_code=6 {|shorthand_def| for \.{\\toksdef}} -@d char_sub_def_code=7 {|shorthand_def| for \.{\\charsubdef}} -@y -@d char_def_code=0 {|shorthand_def| for \.{\\chardef}} -@d math_char_def_code=1 {|shorthand_def| for \.{\\mathchardef}} -@d count_def_code=2 {|shorthand_def| for \.{\\countdef}} -@d dimen_def_code=3 {|shorthand_def| for \.{\\dimendef}} -@d skip_def_code=4 {|shorthand_def| for \.{\\skipdef}} -@d mu_skip_def_code=5 {|shorthand_def| for \.{\\muskipdef}} -@d toks_def_code=6 {|shorthand_def| for \.{\\toksdef}} -@d char_sub_def_code=7 {|shorthand_def| for \.{\\charsubdef}} -@d XeTeX_math_char_num_def_code=8 -@d XeTeX_math_char_def_code=9 -@z - -@x -primitive("mathchardef",shorthand_def,math_char_def_code);@/ -@!@:math_char_def_}{\.{\\mathchardef} primitive@> -@y -primitive("mathchardef",shorthand_def,math_char_def_code);@/ -primitive("XeTeXmathcharnumdef",shorthand_def,XeTeX_math_char_num_def_code);@/ -primitive("XeTeXmathchardef",shorthand_def,XeTeX_math_char_def_code);@/ -@!@:math_char_def_}{\.{\\mathchardef} primitive@> -@z - -@x - math_char_def_code: print_esc("mathchardef"); -@y - math_char_def_code: print_esc("mathchardef"); - XeTeX_math_char_def_code: print_esc("XeTeXmathchardef"); - XeTeX_math_char_num_def_code: print_esc("XeTeXmathcharnumdef"); -@z - -@x -math_given: begin print_esc("mathchar"); print_hex(chr_code); - end; -@y -math_given: begin print_esc("mathchar"); print_hex(chr_code); - end; -XeTeX_math_given: begin print_esc("XeTeXmathchar"); print_hex(chr_code); - end; -@z - -@x -else begin n:=cur_chr; get_r_token; p:=cur_cs; define(p,relax,256); -@y -else begin n:=cur_chr; get_r_token; p:=cur_cs; define(p,relax,too_big_char); -@z - -@x - char_def_code: begin scan_char_num; define(p,char_given,cur_val); -@y - char_def_code: begin scan_usv_num; define(p,char_given,cur_val); -@z - -@x - math_char_def_code: begin scan_fifteen_bit_int; define(p,math_given,cur_val); - end; -@y - math_char_def_code: begin scan_fifteen_bit_int; define(p,math_given,cur_val); - end; - XeTeX_math_char_num_def_code: begin scan_xetex_math_char_int; - define(p, XeTeX_math_given, cur_val); - end; - XeTeX_math_char_def_code: begin - scan_math_class_int; n := set_class_field(cur_val); - scan_math_fam_int; n := n + set_family_field(cur_val); - scan_usv_num; n := n + cur_val; - define(p, XeTeX_math_given, n); - end; -@z - -@x -primitive("mathcode",def_code,math_code_base); -@y -primitive("mathcode",def_code,math_code_base); -primitive("XeTeXmathcodenum",XeTeX_def_code,math_code_base); -primitive("XeTeXmathcode",XeTeX_def_code,math_code_base+1); -@z - -@x -primitive("delcode",def_code,del_code_base); -@y -primitive("delcode",def_code,del_code_base); -primitive("XeTeXdelcodenum",XeTeX_def_code,del_code_base); -primitive("XeTeXdelcode",XeTeX_def_code,del_code_base+1); -@z - -@x -def_family: print_size(chr_code-math_font_base); -@y -XeTeX_def_code: if chr_code=math_code_base then print_esc("XeTeXmathcodenum") - else if chr_code=math_code_base+1 then print_esc("XeTeXmathcode") - else if chr_code=del_code_base then print_esc("XeTeXdelcodenum") - else print_esc("XeTeXdelcode"); -def_family: print_size(chr_code-math_font_base); -@z - -@x -def_code: begin @; -@y -XeTeX_def_code: begin - if cur_chr = math_code_base then begin - p:=cur_chr; scan_char_num; - p:=p+cur_val; - scan_optional_equals; - scan_xetex_math_char_int; - define(p,data,hi(cur_val)); - end - else if cur_chr = math_code_base+1 then begin - p:=cur_chr-1; scan_char_num; - p:=p+cur_val; - scan_optional_equals; - scan_math_class_int; n := set_class_field(cur_val); - scan_math_fam_int; n := n + set_family_field(cur_val); - scan_usv_num; n := n + cur_val; - define(p,data,hi(n)); - end - else if cur_chr = del_code_base then begin - p:=cur_chr; scan_char_num; - p:=p+cur_val; - scan_optional_equals; - scan_int; {scan_xetex_del_code_int; !!FIXME!!} - word_define(p,hi(cur_val)); - end else begin -{ -bit usage in delcode values: -original layout: @"00cffCFF small/LARGE family & char -extended: @"40000000 FLAG - + ff << 21 (mult by @"200000) FAMILY - + 1ccccc (21 bits) USV -} - p:=cur_chr-1; scan_char_num; - p:=p+cur_val; - scan_optional_equals; - n := @"40000000; {extended delcode flag} - scan_math_fam_int; n := n + cur_val * @"200000; - scan_usv_num; n := n + cur_val; - word_define(p,hi(n)); - end; - end; -def_code: begin @; -@z - -@x - if p<256 then xord[p]:=cur_val - else if p<512 then xchr[p-256]:=cur_val - else if p<768 then xprn[p-512]:=cur_val - else if pmin_quarterword then -@y -for k:=biggest_lang downto 0 do if trie_used[k]>min_quarterword then -@z - -@x -undump_size(0)(trie_op_size)('trie op size')(j); @+init trie_op_ptr:=j;@+tini -@y -undump_int(max_hyph_char); -undump_size(0)(trie_op_size)('trie op size')(j); @+init trie_op_ptr:=j;@+tini -@z - -@x -init for k:=0 to 255 do trie_used[k]:=min_quarterword;@+tini@;@/ -k:=256; -@y -init for k:=0 to biggest_lang do trie_used[k]:=min_quarterword;@+tini@;@/ -k:=biggest_lang+1; -@z - -@x - setup_bound_var (15000)('max_strings')(max_strings); -@y - setup_bound_var (15000)('max_strings')(max_strings); - max_strings:=max_strings+too_big_char; {the max_strings value doesn't include the 64K synthetic strings} -@z - -@x - input_file:=xmalloc_array (alpha_file, max_in_open); -@y - input_file:=xmalloc_array (unicode_file, max_in_open); -@z - -@x - print_file_name(0, log_name, 0); print_char("."); -@y - print(log_name); print_char("."); -@z - -@x - {Allocate and initialize font arrays} -@y - {Allocate and initialize font arrays} - font_mapping:=xmalloc_array(void_pointer, font_max); - font_layout_engine:=xmalloc_array(void_pointer, font_max); - font_flags:=xmalloc_array(char, font_max); - font_letter_space:=xmalloc_array(scaled, font_max); -@z - -@x - font_bc:=xmalloc_array(eight_bits, font_max); - font_ec:=xmalloc_array(eight_bits, font_max); -@y - font_bc:=xmalloc_array(UTF16_code, font_max); - font_ec:=xmalloc_array(UTF16_code, font_max); -@z - -@x -@* \[53] Extensions. -@y -@* \[53] Extensions. -@z - -@x -@d write_stream(#) == type(#+1) {stream number (0 to 17)} -@d mubyte_zero == 64 -@d write_mubyte(#) == subtype(#+1) {mubyte value + |mubyte_zero|} -@y -@d write_stream(#) == info(#+1) {stream number (0 to 17)} -@z - -@x -@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_save_pos_node == pdftex_first_extension_code + 0 - -@d pic_file_code=41 { command modifier for \.{\\XeTeXpicfile}, skipping codes pdfTeX might use } -@d pdf_file_code=42 { command modifier for \.{\\XeTeXpdffile} } -@d glyph_code=43 { command modifier for \.{\\XeTeXglyph} } - -@d XeTeX_input_encoding_extension_code=44 -@d XeTeX_default_encoding_extension_code=45 -@d XeTeX_linebreak_locale_extension_code=46 -@z - -@x -@!@:set_language_}{\.{\\setlanguage} primitive@> -@y -@!@:set_language_}{\.{\\setlanguage} primitive@> - -@ The \.{\\XeTeXpicfile} and \.{\\XeTeXpdffile} primitives are only defined in extended mode. - -@= -primitive("XeTeXpicfile",extension,pic_file_code);@/ -primitive("XeTeXpdffile",extension,pdf_file_code);@/ -primitive("XeTeXglyph",extension,glyph_code);@/ -primitive("XeTeXlinebreaklocale", extension, XeTeX_linebreak_locale_extension_code);@/ - -primitive("pdfsavepos",extension,pdf_save_pos_node);@/ -@z - -@x - set_language_code:print_esc("setlanguage"); -@y - set_language_code:print_esc("setlanguage"); - pic_file_code:print_esc("XeTeXpicfile"); - pdf_file_code:print_esc("XeTeXpdffile"); - glyph_code:print_esc("XeTeXglyph"); - XeTeX_linebreak_locale_extension_code:print_esc("XeTeXlinebreaklocale"); - - pdf_save_pos_node: print_esc("pdfsavepos"); -@z - -@x -set_language_code:@; -@y -set_language_code:@; -pic_file_code:@; -pdf_file_code:@; -glyph_code:@; -XeTeX_input_encoding_extension_code:@; -XeTeX_default_encoding_extension_code:@; -XeTeX_linebreak_locale_extension_code:@; - -pdf_save_pos_node: @; -@z - -@x -@ @= -@y -procedure print_native_word(@!p:pointer); -var i:integer; -begin - for i:=0 to native_length(p) - 1 do print_char(get_native_char(p,i)); -end; - -@ @= -@z - -@x -if write_stream(p) <> mubyte_zero then -begin - print_char ("<"); print_int (write_stream(p)-mubyte_zero); - if (write_stream(p)-mubyte_zero = 2) or - (write_stream(p)-mubyte_zero = 3) then - begin - print_char (":"); print_int (write_mubyte(p)-mubyte_zero); - end; - print_char (">"); -end; -@y -@z - -@x -othercases print("whatsit?") -@y -native_word_node:begin - print_esc(font_id_text(native_font(p))); - print_char(" "); - print_native_word(p); - end; -@{ -deleted_native_node: - print("[DELETED]"); -@} -glyph_node:begin - print_esc(font_id_text(native_font(p))); - print(" glyph#"); - print_int(native_glyph(p)); - end; -pic_node,pdf_node: begin - if subtype(p) = pic_node then print_esc("XeTeXpicfile") - else print_esc("XeTeXpdffile"); - print(" """); - for i:=0 to pic_path_length(p)-1 do - print_visible_char(pic_path_byte(p, i)); - print(""""); - end; -pdf_save_pos_node: print_esc("pdfsavepos"); -othercases print("whatsit?") -@z - -@x -@ @= -@y -@ Picture nodes are tricky in that they are variable size. -@d total_pic_node_size(#) == (pic_node_size + (pic_path_length(#) + sizeof(memory_word) - 1) div sizeof(memory_word)) - -@= -@z - -@x -othercases confusion("ext2") -@y -native_word_node: begin words:=native_size(p); - r:=get_node(words); - while words > 0 do - begin decr(words); mem[r+words]:=mem[p+words]; end; - native_glyph_info_ptr(r):=null_ptr; native_glyph_count(r):=0; - copy_native_glyph_info(p, r); - end; -glyph_node: begin r:=get_node(glyph_node_size); - words:=glyph_node_size; - end; -pic_node,pdf_node: begin words:=total_pic_node_size(p); - r:=get_node(words); - end; -pdf_save_pos_node: - r := get_node(small_node_size); -othercases confusion("ext2") -@z - -@x -othercases confusion("ext3") -@y -native_word_node: begin free_native_glyph_info(p); free_node(p,native_size(p)); end; -glyph_node: free_node(p,glyph_node_size); -pic_node,pdf_node: free_node(p,total_pic_node_size(p)); -pdf_save_pos_node: - free_node(p, small_node_size); -othercases confusion("ext3") -@z - -@x -@ @=do_nothing -@y -@ @= -begin - if (subtype(p)=pic_node) - or (subtype(p)=pdf_node) - then begin - x := x + d + height(p); - d := depth(p); - if width(p) > w then w := width(p); - end; -end -@z - -@x -@ @=do_nothing -@y -@ @= -begin - case subtype(p) of - - native_word_node: - begin - { merge with any following word fragments in same font, discarding discretionary breaks } - while (link(q) <> p) do q := link(q); { bring q up in preparation for deletion of nodes starting at p } - pp := link(p); - restart: - if (pp <> null) and (not is_char_node(pp)) then begin - if (type(pp) = whatsit_node) - and (subtype(pp) = native_word_node) - and (native_font(pp) = native_font(p)) then begin - pp := link(pp); - goto restart; - end - else if (type(pp) = disc_node) then begin - ppp := link(pp); - if (ppp <> null) and (not is_char_node(ppp)) - and (type(ppp) = whatsit_node) - and (subtype(ppp) = native_word_node) - and (native_font(ppp) = native_font(p)) then begin - pp := link(ppp); - goto restart; - end - end - end; - - { now pp points to the non-native_word node that ended the chain, or null } - - { we can just check type(p)=whatsit_node below, as we know that the chain - contains only discretionaries and native_word nodes, no other whatsits or char_nodes } - - if (pp <> link(p)) then begin - { found a chain of at least two pieces starting at p } - total_chars := 0; - p := link(q); { the first fragment } - while (p <> pp) do begin - if (type(p) = whatsit_node) then - total_chars := total_chars + native_length(p); { accumulate char count } - ppp := p; { remember last node seen } - p := link(p); { point to next fragment or discretionary or terminator } - end; - - p := link(q); { the first fragment again } - pp := new_native_word_node(native_font(p), total_chars); { make new node for merged word } - link(q) := pp; { link to preceding material } - link(pp) := link(ppp); { attach remainder of hlist to it } - link(ppp) := null; { and detach from the old fragments } - - { copy the chars into new node } - total_chars := 0; - ppp := p; - repeat - if (type(ppp) = whatsit_node) then - for k := 0 to native_length(ppp)-1 do begin - set_native_char(pp, total_chars, get_native_char(ppp, k)); - incr(total_chars); - end; - ppp := link(ppp); - until (ppp = null); - - flush_node_list(p); { delete the fragments } - p := link(q); { update p to point to the new node } - set_native_metrics(p, XeTeX_use_glyph_metrics); { and measure it (i.e., re-do the OT layout) } - end; - - { now incorporate the native_word node measurements into the box we're packing } - if height(p) > h then - h := height(p); - if depth(p) > d then - d := depth(p); - x := x + width(p); - end; - - glyph_node, pic_node, pdf_node: - begin - if height(p) > h then - h := height(p); - if depth(p) > d then - d := depth(p); - x := x + width(p); - end; - - othercases - do_nothing - - endcases -end -@z - -@x -@ @=d:=0 -@y -@ @= -if (subtype(p)=native_word_node) -or (subtype(p)=glyph_node) -or (subtype(p)=pic_node) -or (subtype(p)=pdf_node) -then begin - d:=width(p); - goto found; -end else - d := 0 -@z - -@x -@ @d adv_past(#)==@+if subtype(#)=language_node then - begin cur_lang:=what_lang(#); l_hyf:=what_lhm(#); r_hyf:=what_rhm(#);@+end -@y -@ @d adv_past(#)==@+if subtype(#)=language_node then - begin cur_lang:=what_lang(#); l_hyf:=what_lhm(#); r_hyf:=what_rhm(#);@+end - else if (subtype(#)=native_word_node) - or (subtype(#)=glyph_node) - or (subtype(#)=pic_node) - or (subtype(#)=pdf_node) - then - begin act_width:=act_width+width(#); end -@z - -@x -@ @= -goto contribute -@y -@ @= -begin - if (subtype(p)=pic_node) - or (subtype(p)=pdf_node) - then begin - page_total := page_total + page_depth + height(p); - page_depth := depth(p); - end; - goto contribute; -end -@z - -@x -@ @= -goto not_found -@y -@ @= -begin - if (subtype(p)=pic_node) - or (subtype(p)=pdf_node) - then begin - cur_height := cur_height + prev_dp + height(p); prev_dp := depth(p); - end; - goto not_found; -end -@z - -@x -@ @= -out_what(p) -@y -@ @= -begin - case subtype(p) of - pic_node, pdf_node: begin - save_h:=dvi_h; save_v:=dvi_v; - cur_v:=cur_v+height(p); - pic_out(p, subtype(p) = pdf_node); - dvi_h:=save_h; dvi_v:=save_v; - cur_v:=save_v+depth(p); cur_h:=left_edge; - end; - - pdf_save_pos_node: - @; - - othercases - out_what(p) - - endcases -end -@z - -@x -@ @= -out_what(p) -@y -@ @= -begin - pdf_last_x_pos := cur_h + cur_h_offset; - pdf_last_y_pos := cur_page_height - cur_v - cur_v_offset -end - -@ @= -cur_h_offset := h_offset + (unity * 7227) / 100; -cur_v_offset := v_offset + (unity * 7227) / 100; -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 - -@ @= -@!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} - -@ @= -begin - case subtype(p) of - native_word_node, glyph_node: begin - { synch DVI state to TeX state } - synch_h; synch_v; - f := native_font(p); - if f<>dvi_f then @; - - if subtype(p) = glyph_node then begin - dvi_out(set_glyph_string); - dvi_four(width(p)); - dvi_two(1); { glyph count } - dvi_four(0); { x-offset as fixed point } - dvi_two(native_glyph(p)); - cur_h := cur_h + width(p); - end else begin - if native_glyph_info_ptr(p) <> null_ptr then begin - len := make_xdv_glyph_array_data(p); - for k := 0 to len-1 do - dvi_out(xdv_buffer_byte(k)); - end; - cur_h := cur_h + width(p); - end; - - dvi_h := cur_h; - end; - - pic_node, pdf_node: begin - save_h:=dvi_h; save_v:=dvi_v; - cur_v:=base_line; - edge:=cur_h+width(p); - if cur_dir=right_to_left then cur_h:=edge; - pic_out(p, subtype(p) = pdf_node); - dvi_h:=save_h; dvi_v:=save_v; - cur_h:=edge; cur_v:=base_line; - end; - - pdf_save_pos_node: - @; - - othercases - out_what(p) - - endcases -end -@z - -@x -procedure special_out(@!p:pointer); -var old_setting:0..max_selector; {holds print |selector|} -@!k:pool_pointer; {index into |str_pool|} -begin synch_h; synch_v;@/ -@y -procedure special_out(@!p:pointer); -var old_setting:0..max_selector; {holds print |selector|} -@!k:pool_pointer; {index into |str_pool|} -begin synch_h; synch_v;@/ -doing_special := true; -@z - -@x -for k:=str_start[str_ptr] to pool_ptr-1 do dvi_out(so(str_pool[k])); -spec_out := spec_sout; mubyte_out := mubyte_sout; mubyte_log := mubyte_slog; -special_printing := false; cs_converting := false; -active_noconvert := false; -pool_ptr:=str_start[str_ptr]; {erase the string} -@y -for k:=str_start_macro(str_ptr) to pool_ptr-1 do dvi_out(so(str_pool[k])); -pool_ptr:=str_start_macro(str_ptr); {erase the string} -doing_special := false; -@z - -@x -@!j:small_number; {write stream number} -@y -@!j:small_number; {write stream number} -@!k:integer; -@z - -@x - print(so(str_pool[str_start[str_ptr]+d])); {N.B.: not |print_char|} -@y - print(so(str_pool[str_start_macro(str_ptr)+d])); {N.B.: not |print_char|} -@z - -@x - begin str_pool[str_start[str_ptr]+d]:=xchr[str_pool[str_start[str_ptr]+d]]; - if (str_pool[str_start[str_ptr]+d]=null_code) -@y - begin - if (str_pool[str_start_macro(str_ptr)+d]=null_code) -@z - -@x - system(stringcast(address_of(str_pool[str_start[str_ptr]]))); -@y - if name_of_file then libc_free(name_of_file); - name_of_file := xmalloc(cur_length * 3 + 2); - k := 0; - for d:=0 to cur_length-1 do append_to_name(str_pool[str_start_macro(str_ptr)+d]); - name_of_file[k+1] := 0; - system(name_of_file + 1); -@z - -@x - pool_ptr:=str_start[str_ptr]; {erase the string} -@y - pool_ptr:=str_start_macro(str_ptr); {erase the string} -@z - -@x -@= -@y -@= -procedure pic_out(@!p:pointer; @!is_pdf:boolean); -var - i:integer; -begin -synch_h; synch_v; -dvi_out(pic_file); -if is_pdf then - dvi_out(pic_box_type(p)) -else - dvi_out(0); -dvi_four(pic_transform1(p)); -dvi_four(pic_transform2(p)); -dvi_four(pic_transform3(p)); -dvi_four(pic_transform4(p)); -dvi_four(pic_transform5(p)); -dvi_four(pic_transform6(p)); -dvi_two(pic_page(p)); -dvi_two(pic_path_length(p)); -for i:=0 to pic_path_length(p)-1 do - dvi_out(pic_path_byte(p, i)); -end; - -@z - -@x -language_node:do_nothing; -@y -language_node:do_nothing; -@z - -@x -@ @= -for k:=0 to 15 do if write_open[k] then a_close(write_file[k]) -@y -@ @= -terminate_font_manager; -for k:=0 to 15 do if write_open[k] then a_close(write_file[k]) - -@ @= -if abs(mode)=mmode then report_illegal_case -else load_picture(false) - -@ @= -if abs(mode)=mmode then report_illegal_case -else load_picture(true) - -@ @= -begin - if abs(mode)=vmode then begin - back_input; - new_graf(true); - end else if abs(mode)=mmode then report_illegal_case - else begin - if is_native_font(cur_font) then begin - new_whatsit(glyph_node,glyph_node_size); - scan_int; - if (cur_val<0)or(cur_val>65535) then - begin print_err("Bad glyph number"); - help2("A glyph number must be between 0 and 65535.")@/ - ("I changed this one to zero."); int_error(cur_val); cur_val:=0; - end; - native_font(tail):=cur_font; - native_glyph(tail):=cur_val; - set_native_glyph_metrics(tail, XeTeX_use_glyph_metrics); - end else not_native_font_error(extension, glyph_code, cur_font); - end -end - -@ Load a picture file and handle following keywords. - -@d calc_min_and_max== - begin - xmin := 1000000.0; - xmax := -xmin; - ymin := xmin; - ymax := xmax; - for i := 0 to 3 do begin - if xCoord(corners[i]) < xmin then xmin := xCoord(corners[i]); - if xCoord(corners[i]) > xmax then xmax := xCoord(corners[i]); - if yCoord(corners[i]) < ymin then ymin := yCoord(corners[i]); - if yCoord(corners[i]) > ymax then ymax := yCoord(corners[i]); - end; - end - -@d update_corners== - for i := 0 to 3 do - transform_point(address_of(corners[i]), address_of(t2)) - -@d do_size_requests==begin - { calculate current width and height } - calc_min_and_max; - if x_size_req = 0.0 then begin - make_scale(address_of(t2), y_size_req / (ymax - ymin), y_size_req / (ymax - ymin)); - end else if y_size_req = 0.0 then begin - make_scale(address_of(t2), x_size_req / (xmax - xmin), x_size_req / (xmax - xmin)); - end else begin - make_scale(address_of(t2), x_size_req / (xmax - xmin), y_size_req / (ymax - ymin)); - end; - update_corners; - x_size_req := 0.0; - y_size_req := 0.0; - transform_concat(address_of(t), address_of(t2)); -end - -@= -procedure load_picture(@!is_pdf:boolean); -var - pic_path: ^char; - bounds: real_rect; - t, t2: transform; - corners: array[0..3] of real_point; - x_size_req,y_size_req: real; - check_keywords: boolean; - x_size, y_size: real; - xmin,xmax,ymin,ymax: real; - i: small_number; - page: integer; - pdf_box_type: integer; - result: integer; -begin - { scan the filename and pack into name_of_file } - scan_file_name; - pack_cur_name; - - pdf_box_type := 0; - page := 0; - if is_pdf then begin - if scan_keyword("page") then begin - scan_int; - page := cur_val; - end; - pdf_box_type := pdfbox_crop; - if scan_keyword("crop") then do_nothing - else if scan_keyword("media") then pdf_box_type := pdfbox_media - else if scan_keyword("bleed") then pdf_box_type := pdfbox_bleed - else if scan_keyword("trim") then pdf_box_type := pdfbox_trim - else if scan_keyword("art") then pdf_box_type := pdfbox_art; - end; - - { access the picture file and check its size } - result := find_pic_file(address_of(pic_path), address_of(bounds), pdf_box_type, page); - - setPoint(corners[0], xField(bounds) * 72.27 / 72.0, yField(bounds) * 72.27 / 72.0); - setPoint(corners[1], xField(corners[0]), (yField(bounds) + htField(bounds)) * 72.27 / 72.0); - setPoint(corners[2], (xField(bounds) + wdField(bounds)) * 72.27 / 72.0, yField(corners[1])); - setPoint(corners[3], xField(corners[2]), yField(corners[0])); - - x_size_req := 0.0; - y_size_req := 0.0; - - { look for any scaling requests for this picture } - make_identity(address_of(t)); - - check_keywords := true; - while check_keywords do begin - if scan_keyword("scaled") then begin - scan_int; - if (x_size_req = 0.0) and (y_size_req = 0.0) then begin - make_scale(address_of(t2), float(cur_val) / 1000.0, float(cur_val) / 1000.0); - update_corners; - transform_concat(address_of(t), address_of(t2)); - end - end else if scan_keyword("xscaled") then begin - scan_int; - if (x_size_req = 0.0) and (y_size_req = 0.0) then begin - make_scale(address_of(t2), float(cur_val) / 1000.0, 1.0); - update_corners; - transform_concat(address_of(t), address_of(t2)); - end - end else if scan_keyword("yscaled") then begin - scan_int; - if (x_size_req = 0.0) and (y_size_req = 0.0) then begin - make_scale(address_of(t2), 1.0, float(cur_val) / 1000.0); - update_corners; - transform_concat(address_of(t), address_of(t2)); - end - end else if scan_keyword("width") then begin - scan_normal_dimen; - if cur_val <= 0 then begin - print_err("Improper image "); - print("size ("); - print_scaled(cur_val); - print("pt) will be ignored"); - help2("I can't scale images to zero or negative sizes, ") - ("so I'm ignoring this."); - error; - end else - x_size_req := Fix2X(cur_val); - end else if scan_keyword("height") then begin - scan_normal_dimen; - if cur_val <= 0 then begin - print_err("Improper image "); - print("size ("); - print_scaled(cur_val); - print("pt) will be ignored"); - help2("I can't scale images to zero or negative sizes, ") - ("so I'm ignoring this."); - error; - end else - y_size_req := Fix2X(cur_val); - end else if scan_keyword("rotated") then begin - scan_decimal; - if (x_size_req <> 0.0) or (y_size_req <> 0.0) then do_size_requests; - make_rotation(address_of(t2), Fix2X(cur_val) * 3.141592653589793 / 180.0); - update_corners; - calc_min_and_max; - setPoint(corners[0], xmin, ymin); - setPoint(corners[1], xmin, ymax); - setPoint(corners[2], xmax, ymax); - setPoint(corners[3], xmax, ymin); - transform_concat(address_of(t), address_of(t2)); - end else - check_keywords := false; - end; - - if (x_size_req <> 0.0) or (y_size_req <> 0.0) then do_size_requests; - - calc_min_and_max; - make_translation(address_of(t2), -xmin, -ymin); - transform_concat(address_of(t), address_of(t2)); - - if result = 0 then begin - - new_whatsit(pic_node, pic_node_size + (strlen(pic_path) + sizeof(memory_word) - 1) div sizeof(memory_word)); - if is_pdf then begin - subtype(tail) := pdf_node; - pic_box_type(tail) := pdf_box_type; - end; - pic_path_length(tail) := strlen(pic_path); - pic_page(tail) := page; - - width(tail) := X2Fix(xmax - xmin); - height(tail) := X2Fix(ymax - ymin); - depth(tail) := 0; - - pic_transform1(tail) := X2Fix(aField(t)); - pic_transform2(tail) := X2Fix(bField(t)); - pic_transform3(tail) := X2Fix(cField(t)); - pic_transform4(tail) := X2Fix(dField(t)); - pic_transform5(tail) := X2Fix(txField(t)); - pic_transform6(tail) := X2Fix(tyField(t)); - - memcpy(address_of(mem[tail + pic_node_size]), pic_path, strlen(pic_path)); - libc_free(pic_path); - - end else begin - - print_err("Unable to load picture or PDF file '"); - print_file_name(cur_name,cur_area,cur_ext); print("'"); - if result = -43 then begin { Mac OS file not found error } - help2("The requested image couldn't be read because ") - ("the file was not found."); - end - else begin { otherwise assume GraphicImport failed } - help2("The requested image couldn't be read because ") - ("it was not a recognized image format."); - end; - error; - - end; - -end; - -@ @= -begin - { scan a filename-like arg for the input encoding } - scan_and_pack_name; - - { convert it to "mode" and "encoding" values, and apply to the current input file } - i := get_encoding_mode_and_info(address_of(j)); - if i = XeTeX_input_mode_auto then begin - print_err("Encoding mode `auto' is not valid for \XeTeXinputencoding."); - help2("You can't use `auto' encoding here, only for \XeTeXdefaultencoding. ") - ("I'll ignore this and leave the current encoding unchanged."); - error; - end else set_input_file_encoding(input_file[in_open], i, j); -end - -@ @= -begin - { scan a filename-like arg for the input encoding } - scan_and_pack_name; - - { convert it to "mode" and "encoding" values, and store them as defaults for new input files } - XeTeX_default_input_mode := get_encoding_mode_and_info(address_of(j)); - XeTeX_default_input_encoding := j; -end - -@ @= -begin - { scan a filename-like arg for the locale name } - scan_file_name; - if length(cur_name) = 0 then XeTeX_linebreak_locale := 0 - else XeTeX_linebreak_locale := cur_name; { we ignore the area and extension! } -end - -@ @= -@!pdf_last_x_pos: integer; -@!pdf_last_y_pos: integer; - -@ @= -begin - new_whatsit(pdf_save_pos_node, small_node_size); -end - -@z - -@x -@d eTeX_version_code=eTeX_int {code for \.{\\eTeXversion}} -@y -@d eTeX_version_code=eTeX_int {code for \.{\\eTeXversion}} - -@d XeTeX_version_code=XeTeX_int {code for \.{\\XeTeXversion}} - -{ these are also in xetexmac.c and must correspond! } -@d XeTeX_count_glyphs_code=XeTeX_int+1 - -@d XeTeX_count_variations_code=XeTeX_int+2 -@d XeTeX_variation_code=XeTeX_int+3 -@d XeTeX_find_variation_by_name_code=XeTeX_int+4 -@d XeTeX_variation_min_code=XeTeX_int+5 -@d XeTeX_variation_max_code=XeTeX_int+6 -@d XeTeX_variation_default_code=XeTeX_int+7 - -@d XeTeX_count_features_code=XeTeX_int+8 -@d XeTeX_feature_code_code=XeTeX_int+9 -@d XeTeX_find_feature_by_name_code=XeTeX_int+10 -@d XeTeX_is_exclusive_feature_code=XeTeX_int+11 -@d XeTeX_count_selectors_code=XeTeX_int+12 -@d XeTeX_selector_code_code=XeTeX_int+13 -@d XeTeX_find_selector_by_name_code=XeTeX_int+14 -@d XeTeX_is_default_selector_code=XeTeX_int+15 - -@d XeTeX_OT_count_scripts_code=XeTeX_int+16 -@d XeTeX_OT_count_languages_code=XeTeX_int+17 -@d XeTeX_OT_count_features_code=XeTeX_int+18 -@d XeTeX_OT_script_code=XeTeX_int+19 -@d XeTeX_OT_language_code=XeTeX_int+20 -@d XeTeX_OT_feature_code=XeTeX_int+21 - -@d XeTeX_map_char_to_glyph_code=XeTeX_int+22 -@d XeTeX_glyph_index_code=XeTeX_int+23 -@d XeTeX_font_type_code=XeTeX_int+24 - -@d XeTeX_first_char_code=XeTeX_int+25 -@d XeTeX_last_char_code=XeTeX_int+26 - -@d pdf_last_x_pos_code = XeTeX_int+27 -@d pdf_last_y_pos_code = XeTeX_int+28 - -{ NB: must update eTeX_dim when items are added here! } -@z - -@x -@!@:eTeX_revision_}{\.{\\eTeXrevision} primitive@> -@y -@!@:eTeX_revision_}{\.{\\eTeXrevision} primitive@> - -primitive("XeTeXversion",last_item,XeTeX_version_code); -@!@:XeTeX_version_}{\.{\\XeTeXversion} primitive@> -primitive("XeTeXrevision",convert,XeTeX_revision_code);@/ -@!@:XeTeXrevision_}{\.{\\XeTeXrevision} primitive@> - -primitive("XeTeXcountglyphs",last_item,XeTeX_count_glyphs_code); - -primitive("XeTeXcountvariations",last_item,XeTeX_count_variations_code); -primitive("XeTeXvariation",last_item,XeTeX_variation_code); -primitive("XeTeXfindvariationbyname",last_item,XeTeX_find_variation_by_name_code); -primitive("XeTeXvariationmin",last_item,XeTeX_variation_min_code); -primitive("XeTeXvariationmax",last_item,XeTeX_variation_max_code); -primitive("XeTeXvariationdefault",last_item,XeTeX_variation_default_code); - -primitive("XeTeXcountfeatures",last_item,XeTeX_count_features_code); -primitive("XeTeXfeaturecode",last_item,XeTeX_feature_code_code); -primitive("XeTeXfindfeaturebyname",last_item,XeTeX_find_feature_by_name_code); -primitive("XeTeXisexclusivefeature",last_item,XeTeX_is_exclusive_feature_code); -primitive("XeTeXcountselectors",last_item,XeTeX_count_selectors_code); -primitive("XeTeXselectorcode",last_item,XeTeX_selector_code_code); -primitive("XeTeXfindselectorbyname",last_item,XeTeX_find_selector_by_name_code); -primitive("XeTeXisdefaultselector",last_item,XeTeX_is_default_selector_code); - -primitive("XeTeXvariationname",convert,XeTeX_variation_name_code); -primitive("XeTeXfeaturename",convert,XeTeX_feature_name_code); -primitive("XeTeXselectorname",convert,XeTeX_selector_name_code); - -primitive("XeTeXOTcountscripts",last_item,XeTeX_OT_count_scripts_code); -primitive("XeTeXOTcountlanguages",last_item,XeTeX_OT_count_languages_code); -primitive("XeTeXOTcountfeatures",last_item,XeTeX_OT_count_features_code); -primitive("XeTeXOTscripttag",last_item,XeTeX_OT_script_code); -primitive("XeTeXOTlanguagetag",last_item,XeTeX_OT_language_code); -primitive("XeTeXOTfeaturetag",last_item,XeTeX_OT_feature_code); - -primitive("XeTeXcharglyph", last_item, XeTeX_map_char_to_glyph_code); -primitive("XeTeXglyphindex", last_item, XeTeX_glyph_index_code); - -primitive("XeTeXglyphname",convert,XeTeX_glyph_name_code); - -primitive("XeTeXfonttype", last_item, XeTeX_font_type_code); - -primitive("XeTeXfirstfontchar", last_item, XeTeX_first_char_code); -primitive("XeTeXlastfontchar", last_item, XeTeX_last_char_code); - -primitive("pdflastxpos",last_item,pdf_last_x_pos_code); -primitive("pdflastypos",last_item,pdf_last_y_pos_code); -@z - -@x -eTeX_version_code: print_esc("eTeXversion"); -@y -eTeX_version_code: print_esc("eTeXversion"); -XeTeX_version_code: print_esc("XeTeXversion"); - -XeTeX_count_glyphs_code: print_esc("XeTeXcountglyphs"); - -XeTeX_count_variations_code: print_esc("XeTeXcountvariations"); -XeTeX_variation_code: print_esc("XeTeXvariation"); -XeTeX_find_variation_by_name_code: print_esc("XeTeXfindvariationbyname"); -XeTeX_variation_min_code: print_esc("XeTeXvariationmin"); -XeTeX_variation_max_code: print_esc("XeTeXvariationmax"); -XeTeX_variation_default_code: print_esc("XeTeXvariationdefault"); - -XeTeX_count_features_code: print_esc("XeTeXcountfeatures"); -XeTeX_feature_code_code: print_esc("XeTeXfeaturecode"); -XeTeX_find_feature_by_name_code: print_esc("XeTeXfindfeaturebyname"); -XeTeX_is_exclusive_feature_code: print_esc("XeTeXisexclusivefeature"); -XeTeX_count_selectors_code: print_esc("XeTeXcountselectors"); -XeTeX_selector_code_code: print_esc("XeTeXselectorcode"); -XeTeX_find_selector_by_name_code: print_esc("XeTeXfindselectorbyname"); -XeTeX_is_default_selector_code: print_esc("XeTeXisdefaultselector"); - -XeTeX_OT_count_scripts_code: print_esc("XeTeXOTcountscripts"); -XeTeX_OT_count_languages_code: print_esc("XeTeXOTcountlanguages"); -XeTeX_OT_count_features_code: print_esc("XeTeXOTcountfeatures"); -XeTeX_OT_script_code: print_esc("XeTeXOTscripttag"); -XeTeX_OT_language_code: print_esc("XeTeXOTlanguagetag"); -XeTeX_OT_feature_code: print_esc("XeTeXOTfeaturetag"); - -XeTeX_map_char_to_glyph_code: print_esc("XeTeXcharglyph"); -XeTeX_glyph_index_code: print_esc("XeTeXglyphindex"); - -XeTeX_font_type_code: print_esc("XeTeXfonttype"); - -XeTeX_first_char_code: print_esc("XeTeXfirstfontchar"); -XeTeX_last_char_code: print_esc("XeTeXlastfontchar"); - - pdf_last_x_pos_code: print_esc("pdflastxpos"); - pdf_last_y_pos_code: print_esc("pdflastypos"); -@z - -@x -eTeX_version_code: cur_val:=eTeX_version; -@y -eTeX_version_code: cur_val:=eTeX_version; -XeTeX_version_code: cur_val:=XeTeX_version; - -XeTeX_count_glyphs_code: - begin - scan_font_ident; n:=cur_val; - if is_atsu_font(n) then - cur_val:=atsu_font_get(m - XeTeX_int, font_layout_engine[n]) - else if is_ot_font(n) then - cur_val:=ot_font_get(m - XeTeX_int, font_layout_engine[n]) - else - cur_val:=0; - end; - -XeTeX_count_variations_code, -XeTeX_count_features_code: - begin - scan_font_ident; n:=cur_val; - if is_atsu_font(n) then - cur_val:=atsu_font_get(m - XeTeX_int, font_layout_engine[n]) - else begin - cur_val:=0; - end; - end; - -XeTeX_variation_code, -XeTeX_variation_min_code, -XeTeX_variation_max_code, -XeTeX_variation_default_code, -XeTeX_feature_code_code, -XeTeX_is_exclusive_feature_code, -XeTeX_count_selectors_code: - begin - scan_font_ident; n:=cur_val; - if is_atsu_font(n) then begin - scan_int; k:=cur_val; - cur_val:=atsu_font_get_1(m - XeTeX_int, font_layout_engine[n], k); - end else begin - not_atsu_font_error(last_item, m, n); cur_val:=-1; - end; - end; - -XeTeX_selector_code_code, -XeTeX_is_default_selector_code: - begin - scan_font_ident; n:=cur_val; - if is_atsu_font(n) then begin - scan_int; k:=cur_val; scan_int; - cur_val:=atsu_font_get_2(m - XeTeX_int, font_layout_engine[n], k, cur_val); - end else begin - not_atsu_font_error(last_item, m, n); cur_val:=-1; - end; - end; - -XeTeX_find_variation_by_name_code, -XeTeX_find_feature_by_name_code: - begin - scan_font_ident; n:=cur_val; - if is_atsu_font(n) then begin - scan_and_pack_name; - cur_val:=atsu_font_get_named(m - XeTeX_int, font_layout_engine[n]); - end else begin - not_atsu_font_error(last_item, m, n); cur_val:=-1; - end; - end; - -XeTeX_find_selector_by_name_code: - begin - scan_font_ident; n:=cur_val; - if is_atsu_font(n) then begin - scan_int; k:=cur_val; scan_and_pack_name; - cur_val:=atsu_font_get_named_1(m - XeTeX_int, font_layout_engine[n], k); - end else begin - not_atsu_font_error(last_item, m, n); cur_val:=-1; - end; - end; - -XeTeX_OT_count_scripts_code: - begin - scan_font_ident; n:=cur_val; - if is_ot_font(n) then - cur_val:=ot_font_get(m - XeTeX_int, font_layout_engine[n]) - else begin -{ - not_ot_font_error(last_item, m, n); cur_val:=-1; -} - cur_val:=0; - end; - end; - -XeTeX_OT_count_languages_code, -XeTeX_OT_script_code: - begin - scan_font_ident; n:=cur_val; - if is_ot_font(n) then begin - scan_int; k:=cur_val; - cur_val:=ot_font_get_1(m - XeTeX_int, font_layout_engine[n], k); - end else begin - not_ot_font_error(last_item, m, n); cur_val:=-1; - end; - end; - -XeTeX_OT_count_features_code, -XeTeX_OT_language_code: - begin - scan_font_ident; n:=cur_val; - if is_ot_font(n) then begin - scan_int; k:=cur_val; scan_int; - cur_val:=ot_font_get_2(m - XeTeX_int, font_layout_engine[n], k, cur_val); - end else begin - not_ot_font_error(last_item, m, n); cur_val:=-1; - end; - end; - -XeTeX_OT_feature_code: - begin - scan_font_ident; n:=cur_val; - if is_ot_font(n) then begin - scan_int; k:=cur_val; scan_int; kk:=cur_val; scan_int; - cur_val:=ot_font_get_3(m - XeTeX_int, font_layout_engine[n], k, kk, cur_val); - end else begin - not_ot_font_error(last_item, m, n); cur_val:=-1; - end; - end; - -XeTeX_map_char_to_glyph_code: - begin - if is_native_font(cur_font) then begin - scan_int; n:=cur_val; cur_val:=map_char_to_glyph(cur_font, n) - end else begin - not_native_font_error(last_item, m, cur_font); cur_val:=0 - end - end; - -XeTeX_glyph_index_code: - begin - if is_native_font(cur_font) then begin - scan_and_pack_name; - cur_val:=map_glyph_to_index(cur_font) - end else begin - not_native_font_error(last_item, m, cur_font); cur_val:=0 - end - end; - -XeTeX_font_type_code: - begin - scan_font_ident; n:=cur_val; - if is_atsu_font(n) then cur_val:=1 - else begin - if is_ot_font(n) then cur_val:=2 - else cur_val:=0 - end - end; - -XeTeX_first_char_code,XeTeX_last_char_code: - begin - scan_font_ident; n:=cur_val; - if is_native_font(n) then - cur_val:=get_font_char_range(n, m = XeTeX_first_char_code) - else begin - if m = XeTeX_first_char_code then cur_val:=font_bc[n] - else cur_val:=font_ec[n]; - end - end; - - pdf_last_x_pos_code: cur_val := pdf_last_x_pos; - pdf_last_y_pos_code: cur_val := pdf_last_y_pos; - -@ Slip in an extra procedure here and there.... - -@= -procedure scan_and_pack_name; forward; - -@ @= -procedure scan_and_pack_name; -begin - scan_file_name; pack_cur_name; -end; - -@ @= -procedure not_atsu_font_error(cmd, c: integer; f: integer); -begin - print_err("Cannot use "); print_cmd_chr(cmd, c); - print(" with "); print(font_name[f]); - print("; not an AAT font"); - error; -end; - -procedure not_ot_font_error(cmd, c: integer; f: integer); -begin - print_err("Cannot use "); print_cmd_chr(cmd, c); - print(" with "); print(font_name[f]); - print("; not an OpenType Layout font"); - error; -end; - -procedure not_native_font_error(cmd, c: integer; f: integer); -begin - print_err("Cannot use "); print_cmd_chr(cmd, c); - print(" with "); print(font_name[f]); - print("; not a native platform font"); - error; -end; - -@ @= -eTeX_revision_code: print_esc("eTeXrevision"); -XeTeX_revision_code: print_esc("XeTeXrevision"); - -XeTeX_variation_name_code: print_esc("XeTeXvariationname"); -XeTeX_feature_name_code: print_esc("XeTeXfeaturename"); -XeTeX_selector_name_code: print_esc("XeTeXselectorname"); -XeTeX_glyph_name_code: print_esc("XeTeXglyphname"); - -@ @= -eTeX_revision_code: do_nothing; -XeTeX_revision_code: do_nothing; - -XeTeX_variation_name_code, -XeTeX_feature_name_code: - begin - scan_font_ident; fnt:=cur_val; - if is_atsu_font(fnt) then begin - scan_int; arg1:=cur_val; arg2:=0; - end else - not_atsu_font_error(convert, c, fnt); - end; - -XeTeX_selector_name_code: - begin - scan_font_ident; fnt:=cur_val; - if is_atsu_font(fnt) then begin - scan_int; arg1:=cur_val; scan_int; arg2:=cur_val; - end else - not_atsu_font_error(convert, c, fnt); - end; - -XeTeX_glyph_name_code: - begin - scan_font_ident; fnt:=cur_val; - if is_native_font(fnt) then begin - scan_int; arg1:=cur_val; - end else - not_native_font_error(convert, c, fnt); - end; - -@ @= -eTeX_revision_code: print(eTeX_revision); -XeTeX_revision_code: print(XeTeX_revision); - -XeTeX_variation_name_code, -XeTeX_feature_name_code, -XeTeX_selector_name_code: - if is_atsu_font(fnt) then - atsu_print_font_name(c, font_layout_engine[fnt], arg1, arg2); - -XeTeX_glyph_name_code: - if is_native_font(fnt) then print_glyph_name(fnt, arg1); -@z - -@x -font_char_wd_code, -font_char_ht_code, -font_char_dp_code, -font_char_ic_code: begin scan_font_ident; q:=cur_val; scan_char_num; - if (font_bc[q]<=cur_val)and(font_ec[q]>=cur_val) then - begin i:=char_info(q)(qi(cur_val)); - case m of - font_char_wd_code: cur_val:=char_width(q)(i); - font_char_ht_code: cur_val:=char_height(q)(height_depth(i)); - font_char_dp_code: cur_val:=char_depth(q)(height_depth(i)); - font_char_ic_code: cur_val:=char_italic(q)(i); - end; {there are no other cases} - end - else cur_val:=0; - end; -@y -font_char_wd_code, -font_char_ht_code, -font_char_dp_code, -font_char_ic_code: begin scan_font_ident; q:=cur_val; scan_usv_num; - if is_native_font(q) then begin - case m of - font_char_wd_code: cur_val := getnativecharwd(q, cur_val); - font_char_ht_code: cur_val := getnativecharht(q, cur_val); - font_char_dp_code: cur_val := getnativechardp(q, cur_val); - font_char_ic_code: cur_val := getnativecharic(q, cur_val); - end; {there are no other cases} - end else begin - if (font_bc[q]<=cur_val)and(font_ec[q]>=cur_val) then - begin i:=char_info(q)(qi(cur_val)); - case m of - font_char_wd_code: cur_val:=char_width(q)(i); - font_char_ht_code: cur_val:=char_height(q)(height_depth(i)); - font_char_dp_code: cur_val:=char_depth(q)(height_depth(i)); - font_char_ic_code: cur_val:=char_italic(q)(i); - end; {there are no other cases} - end - else cur_val:=0; - end - end; -@z - -@x -@d TeXXeT_en==(TeXXeT_state>0) {is \TeXXeT\ enabled?} -@y -@d TeXXeT_en==(TeXXeT_state>0) {is \TeXXeT\ enabled?} - -@d XeTeX_dash_break_state == eTeX_state(XeTeX_dash_break_code) -@d XeTeX_dash_break_en == (XeTeX_dash_break_state>0) - -@d XeTeX_default_input_mode == eTeX_state(XeTeX_default_input_mode_code) -@d XeTeX_default_input_encoding == eTeX_state(XeTeX_default_input_encoding_code) -@z - -@x -eTeX_state_code+TeXXeT_code:print_esc("TeXXeTstate"); -@y -eTeX_state_code+TeXXeT_code:print_esc("TeXXeTstate"); -eTeX_state_code+XeTeX_dash_break_code:print_esc("XeTeXdashbreakstate"); -@z - -@x -primitive("TeXXeTstate",assign_int,eTeX_state_base+TeXXeT_code); -@!@:TeXXeT_state_}{\.{\\TeXXeT_state} primitive@> -@y -primitive("TeXXeTstate",assign_int,eTeX_state_base+TeXXeT_code); -@!@:TeXXeT_state_}{\.{\\TeXXeT_state} primitive@> - -primitive("XeTeXdashbreakstate",assign_int,eTeX_state_base+XeTeX_dash_break_code); -@!@:XeTeX_dash_break_state_}{\.{\\XeTeX_dash_break_state} primitive@> - -primitive("XeTeXinputencoding",extension,XeTeX_input_encoding_extension_code); -primitive("XeTeXdefaultencoding",extension,XeTeX_default_encoding_extension_code); -@z - -@x -@ Here we compute the effective width of a glue node as in |hlist_out|. - -@= -glue_node: begin round_glue; - @; - end; -@y -@ Need to measure native_word and picture nodes when reversing! -@= -whatsit_node: - if (subtype(p)=native_word_node) - or (subtype(p)=glyph_node) - or (subtype(p)=pic_node) - or (subtype(p)=pdf_node) - then - rule_wd:=width(p) - else - goto next_p; - -@ Here we compute the effective width of a glue node as in |hlist_out|. - -@= -glue_node: begin round_glue; - @; - end; -@z - -@x -str_pool[pool_ptr]:=si(" "); l:=str_start[s]; -@y -str_pool[pool_ptr]:=si(" "); l:=str_start_macro(s); -@z - -@x -if_font_char_code:begin scan_font_ident; n:=cur_val; scan_char_num; - if (font_bc[n]<=cur_val)and(font_ec[n]>=cur_val) then - b:=char_exists(char_info(n)(qi(cur_val))) - else b:=false; - end; -@y -if_font_char_code:begin scan_font_ident; n:=cur_val; scan_usv_num; - if is_native_font(n) then - b := (map_char_to_glyph(n, cur_val) > 0) - else begin - if (font_bc[n]<=cur_val)and(font_ec[n]>=cur_val) then - b:=char_exists(char_info(n)(qi(cur_val))) - else b:=false; - end; - end; -@z - -@x - for c := str_start[text(h)] to str_start[text(h) + 1] - 1 -@y - for c := str_start_macro(text(h)) to str_start_macro(text(h) + 1) - 1 -@z - -@x - while s>255 do {first 256 strings depend on implementation!!} -@y - while s>65535 do {first 64K strings don't really exist in the pool!} -@z - -@x -@!mltex_enabled_p:boolean; {enable character substitution} -@y -@!mltex_enabled_p:boolean; {enable character substitution} -@!native_font_type_flag:integer; {used by XeTeX font loading code to record which font technology was used} -@z - -@x -effective_char_info:=null_character; -exit:end; -@y -effective_char_info:=null_character; -exit:end; - -{ the following procedure has been moved so that new_native_character can call it } - -procedure char_warning(@!f:internal_font_number;@!c:integer); -var old_setting: integer; {saved value of |tracing_online|} -begin if tracing_lost_chars>0 then - begin old_setting:=tracing_online; - if eTeX_ex and(tracing_lost_chars>1) then tracing_online:=1; - begin begin_diagnostic; - print_nl("Missing character: There is no "); -@.Missing character@> - if c < @"10000 then print_ASCII(c) - else begin { non-Plane 0 Unicodes can't be sent through print_ASCII } - print("character number "); - print_hex(c); - end; - print(" in font "); - slow_print(font_name[f]); print_char("!"); end_diagnostic(false); - end; - tracing_online:=old_setting; - end; -end; - -{ additional functions for native font support } - -function new_native_word_node(@!f:internal_font_number;@!n:integer):pointer; - { note that this function creates the node, but does not actually set its metrics; - call set_native_metrics(node) if that is required! } -var - l: integer; - q: pointer; -begin - l := native_node_size + (n * sizeof(UTF16_code) + sizeof(memory_word) - 1) div sizeof(memory_word); - - q := get_node(l); - type(q) := whatsit_node; - subtype(q) := native_word_node; - - native_size(q) := l; - native_font(q) := f; - native_length(q) := n; - - native_glyph_count(q) := 0; - native_glyph_info_ptr(q) := null_ptr; - - new_native_word_node := q; -end; - -function new_native_character(@!f:internal_font_number;@!c:UnicodeScalar):pointer; -var - p: pointer; - i, len: integer; -begin - if font_mapping[f] <> 0 then begin - if c > @"FFFF then begin - str_room(2); - append_char((c - @"10000) div 1024 + @"D800); - append_char((c - @"10000) mod 1024 + @"DC00); - end - else begin - str_room(1); - append_char(c); - end; - len := apply_mapping(font_mapping[f], address_of(str_pool[str_start_macro(str_ptr)]), cur_length); - pool_ptr := str_start_macro(str_ptr); { flush the string, as we'll be using the mapped text instead } - - i := 0; - while i < len do begin - if (mapped_text[i] >= @"D800) and (mapped_text[i] < @"DC00) then begin - c := (mapped_text[i] - @"D800) * 1024 + mapped_text[i+1] - @"DC00 + @"10000; - if map_char_to_glyph(f, c) = 0 then begin - char_warning(f, c); - end; - i := i + 2; - end - else begin - if map_char_to_glyph(f, mapped_text[i]) = 0 then begin - char_warning(f, mapped_text[i]); - end; - i := i + 1; - end; - end; - - p := new_native_word_node(f, len); - for i := 0 to len-1 do begin - set_native_char(p, i, mapped_text[i]); - end - end - else begin - if tracing_lost_chars > 0 then - if map_char_to_glyph(f, c) = 0 then begin - char_warning(f, c); - end; - - p := get_node(native_node_size + 1); - type(p) := whatsit_node; - subtype(p) := native_word_node; - - native_size(p) := native_node_size + 1; - native_glyph_count(p) := 0; - native_glyph_info_ptr(p) := null_ptr; - native_font(p) := f; - - if c > @"FFFF then begin - native_length(p) := 2; - set_native_char(p, 0, (c - @"10000) div 1024 + @"D800); - set_native_char(p, 1, (c - @"10000) mod 1024 + @"DC00); - end - else begin - native_length(p) := 1; - set_native_char(p, 0, c); - end; - end; - - set_native_metrics(p, XeTeX_use_glyph_metrics); - - new_native_character := p; -end; - -procedure font_feature_warning(featureNameP:void_pointer; featLen:integer; - settingNameP:void_pointer; setLen:integer); -var - i: integer; -begin - begin_diagnostic; - print_nl("Unknown "); - if setLen > 0 then begin - print("selector `"); - print_utf8_str(settingNameP, setLen); - print("' for "); - end; - print("feature `"); - print_utf8_str(featureNameP, featLen); - print("' in font `"); - i := 1; - while ord(name_of_file[i]) <> 0 do begin - print_visible_char(name_of_file[i]); { this is already UTF-8 } - incr(i); - end; - print("'."); - end_diagnostic(false); -end; - -procedure font_mapping_warning(mappingNameP:void_pointer; mappingNameLen:integer); -var - i: integer; -begin - begin_diagnostic; - print_nl("Font mapping `"); - print_utf8_str(mappingNameP, mappingNameLen); - print("' for font `"); - i := 1; - while ord(name_of_file[i]) <> 0 do begin - print_visible_char(name_of_file[i]); { this is already UTF-8 } - incr(i); - end; - print("' not found."); - end_diagnostic(false); -end; - -function load_native_font(u: pointer; nom, aire:str_number; s: scaled): internal_font_number; -label - done; -var - k: integer; - font_engine: void_pointer; {really an ATSUStyle or XeTeXLayoutEngine} - actual_size: scaled; {|s| converted to real size, if it was negative} - p: pointer; {for temporary |native_char| node we'll create} - ascent, descent, font_slant, x_ht, cap_ht: scaled; - f: internal_font_number; - full_name: str_number; -begin - { on entry here, the full name is packed into name_of_file in UTF8 form } - - load_native_font := null_font; - - if (s < 0) then actual_size := -s * unity div 100 else actual_size := s; - font_engine := find_native_font(name_of_file + 1, actual_size); - if font_engine = 0 then goto done; - - { look again to see if the font is already loaded, now that we know its canonical name } - str_room(name_length); - for k := 1 to name_length do - append_char(name_of_file[k]); - full_name := make_string; { not slow_make_string because we'll flush it if the font was already loaded } - - for f:=font_base+1 to font_ptr do - if (font_area[f] = native_font_type_flag) and str_eq_str(font_name[f], full_name) and (font_size[f] = actual_size) then begin - release_font_engine(font_engine, native_font_type_flag); - flush_string; - load_native_font := f; - goto done; - end; - - if (font_ptr = font_max) or (fmem_ptr + 8 > font_mem_size) then begin - @; - end; - - { we've found a valid installed font, and have room } - incr(font_ptr); - font_area[font_ptr] := native_font_type_flag; { set by find_native_font to either aat_font_flag or ot_font_flag } - - { store the canonical name } - font_name[font_ptr] := full_name; - - font_check[font_ptr].b0 := 0; - font_check[font_ptr].b1 := 0; - font_check[font_ptr].b2 := 0; - font_check[font_ptr].b3 := 0; - font_glue[font_ptr] := null; - font_dsize[font_ptr] := 10 * unity; - font_size[font_ptr] := actual_size; - - if (native_font_type_flag = aat_font_flag) then begin - atsu_get_font_metrics(font_engine, address_of(ascent), address_of(descent), - address_of(x_ht), address_of(cap_ht), address_of(font_slant)) - end else begin - ot_get_font_metrics(font_engine, address_of(ascent), address_of(descent), - address_of(x_ht), address_of(cap_ht), address_of(font_slant)); - end; - - height_base[font_ptr] := ascent; - depth_base[font_ptr] := -descent; - - font_params[font_ptr] := 8; { we add an extra \fontdimen: #8 -> cap_height } - font_bc[font_ptr] := 0; - font_ec[font_ptr] := 65535; - font_used[font_ptr] := false; - hyphen_char[font_ptr] := default_hyphen_char; - skew_char[font_ptr] := default_skew_char; - param_base[font_ptr] := fmem_ptr-1; - - font_layout_engine[font_ptr] := font_engine; - font_mapping[font_ptr] := 0; { don't use the mapping, if any, when measuring space here } - font_letter_space[font_ptr] := loaded_font_letter_space; - - {measure the width of the space character and set up font parameters} - p := new_native_character(font_ptr, " "); - s := width(p) + loaded_font_letter_space; - free_node(p, native_size(p)); - - font_info[fmem_ptr].sc := font_slant; {slant} - incr(fmem_ptr); - font_info[fmem_ptr].sc := s; {space = width of space character} - incr(fmem_ptr); - font_info[fmem_ptr].sc := s div 2; {space_stretch = 1/2 * space} - incr(fmem_ptr); - font_info[fmem_ptr].sc := s div 3; {space_shrink = 1/3 * space} - incr(fmem_ptr); - font_info[fmem_ptr].sc := x_ht; {x_height} - incr(fmem_ptr); - font_info[fmem_ptr].sc := font_size[font_ptr]; {quad = font size} - incr(fmem_ptr); - font_info[fmem_ptr].sc := s div 3; {extra_space = 1/3 * space} - incr(fmem_ptr); - font_info[fmem_ptr].sc := cap_ht; {cap_height} - incr(fmem_ptr); - - font_mapping[font_ptr] := loaded_font_mapping; - font_flags[font_ptr] := loaded_font_flags; - - load_native_font := font_ptr; -done: -end; - -procedure do_locale_linebreaks(s: pointer; len: integer); -var - offs, prevOffs, i: integer; - use_penalty, use_skip: boolean; -begin - if XeTeX_linebreak_locale = 0 then begin - link(tail) := new_native_word_node(main_f, len); - tail := link(tail); - for i := 0 to len - 1 do - set_native_char(tail, i, str_pool[s + i]); - set_native_metrics(tail, XeTeX_use_glyph_metrics); - end else begin - use_skip := XeTeX_linebreak_skip <> zero_glue; - use_penalty := XeTeX_linebreak_penalty <> 0 or not use_skip; - linebreak_start(XeTeX_linebreak_locale, address_of(str_pool[s]), len); - offs := 0; - repeat - prevOffs := offs; - offs := linebreak_next; - if offs > 0 then begin - if prevOffs <> 0 then begin - if use_penalty then - tail_append(new_penalty(XeTeX_linebreak_penalty)); - if use_skip then - tail_append(new_param_glue(XeTeX_linebreak_skip_code)); - end; - link(tail) := new_native_word_node(main_f, offs - prevOffs); - tail := link(tail); - for i := prevOffs to offs - 1 do - set_native_char(tail, i - prevOffs, str_pool[s + i]); - set_native_metrics(tail, XeTeX_use_glyph_metrics); - end; - until offs < 0; - end -end; - -@z diff --git a/Build/source/texk/web2c/xetexdir/xetex-noenc.ch b/Build/source/texk/web2c/xetexdir/xetex-noenc.ch deleted file mode 100644 index 71591ca8350..00000000000 --- a/Build/source/texk/web2c/xetexdir/xetex-noenc.ch +++ /dev/null @@ -1,1144 +0,0 @@ -% /****************************************************************************\ -% Part of the XeTeX typesetting system -% copyright (c) 1994-2006 by SIL International -% written by Jonathan Kew -% -% Permission is hereby granted, free of charge, to any person obtaining -% a copy of this software and associated documentation files (the -% "Software"), to deal in the Software without restriction, including -% without limitation the rights to use, copy, modify, merge, publish, -% distribute, sublicense, and/or sell copies of the Software, and to -% permit persons to whom the Software is furnished to do so, subject to -% the following conditions: -% -% The above copyright notice and this permission notice shall be -% included in all copies or substantial portions of the Software. -% -% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -% EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -% MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -% NONINFRINGEMENT. IN NO EVENT SHALL SIL INTERNATIONAL BE LIABLE FOR -% ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF -% CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -% WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -% -% Except as contained in this notice, the name of SIL International -% shall not be used in advertising or otherwise to promote the sale, -% use or other dealings in this Software without prior written -% authorization from SIL International. -% \****************************************************************************/ - -% Extra changes to remove the encTeX features from XeTeX -% (and print a warning if --translate-file is used) -% ====================================================== - - -@x -@!xord: array [text_char] of ASCII_code; - {specifies conversion of input characters} -xchr: array [ASCII_code] of text_char; - { specifies conversion of output characters } -xprn: array [ASCII_code] of ASCII_code; - { non zero iff character is printable } -mubyte_read: array [ASCII_code] of pointer; - { non zero iff character begins the multi byte code } -mubyte_write: array [ASCII_code] of str_number; - { non zero iff character expands to multi bytes in log and write files } -mubyte_cswrite: array [0..127] of pointer; - { non null iff cs mod 128 expands to multi bytes in log and write files } -mubyte_skip: integer; { the number of bytes to skip in |buffer| } -mubyte_keep: integer; { the number of chars we need to keep unchanged } -mubyte_skeep: integer; { saved |mubyte_keep| } -mubyte_prefix: integer; { the type of mubyte prefix } -mubyte_tablein: boolean; { the input side of table will be updated } -mubyte_tableout: boolean; { the output side of table will be updated } -mubyte_relax: boolean; { the relax prefix is used } -mubyte_start: boolean; { we are making the token at the start of the line } -mubyte_sstart: boolean; { saved |mubyte_start| } -mubyte_token: pointer; { the token returned by |read_buffer| } -mubyte_stoken: pointer; { saved first token in mubyte primitive } -mubyte_sout: integer; { saved value of |mubyte_out| } -mubyte_slog: integer; { saved value of |mubyte_log| } -spec_sout: integer; { saved value of |spec_out| } -no_convert: boolean; { conversion supressed by noconvert primitive } -active_noconvert: boolean; { true if noconvert primitive is active } -write_noexpanding: boolean; { true only if we need not write expansion } -cs_converting: boolean; { true only if we need csname converting } -special_printing: boolean; { true only if we need converting in special } -message_printing: boolean; { true if message or errmessage prints to string } -@y -@!xchr: ^text_char; - {dummy variable so tangle doesn't complain; not actually used} -@z - -@x -xchr[@'40]:=' '; -xchr[@'41]:='!'; -xchr[@'42]:='"'; -xchr[@'43]:='#'; -xchr[@'44]:='$'; -xchr[@'45]:='%'; -xchr[@'46]:='&'; -xchr[@'47]:='''';@/ -xchr[@'50]:='('; -xchr[@'51]:=')'; -xchr[@'52]:='*'; -xchr[@'53]:='+'; -xchr[@'54]:=','; -xchr[@'55]:='-'; -xchr[@'56]:='.'; -xchr[@'57]:='/';@/ -xchr[@'60]:='0'; -xchr[@'61]:='1'; -xchr[@'62]:='2'; -xchr[@'63]:='3'; -xchr[@'64]:='4'; -xchr[@'65]:='5'; -xchr[@'66]:='6'; -xchr[@'67]:='7';@/ -xchr[@'70]:='8'; -xchr[@'71]:='9'; -xchr[@'72]:=':'; -xchr[@'73]:=';'; -xchr[@'74]:='<'; -xchr[@'75]:='='; -xchr[@'76]:='>'; -xchr[@'77]:='?';@/ -xchr[@'100]:='@@'; -xchr[@'101]:='A'; -xchr[@'102]:='B'; -xchr[@'103]:='C'; -xchr[@'104]:='D'; -xchr[@'105]:='E'; -xchr[@'106]:='F'; -xchr[@'107]:='G';@/ -xchr[@'110]:='H'; -xchr[@'111]:='I'; -xchr[@'112]:='J'; -xchr[@'113]:='K'; -xchr[@'114]:='L'; -xchr[@'115]:='M'; -xchr[@'116]:='N'; -xchr[@'117]:='O';@/ -xchr[@'120]:='P'; -xchr[@'121]:='Q'; -xchr[@'122]:='R'; -xchr[@'123]:='S'; -xchr[@'124]:='T'; -xchr[@'125]:='U'; -xchr[@'126]:='V'; -xchr[@'127]:='W';@/ -xchr[@'130]:='X'; -xchr[@'131]:='Y'; -xchr[@'132]:='Z'; -xchr[@'133]:='['; -xchr[@'134]:='\'; -xchr[@'135]:=']'; -xchr[@'136]:='^'; -xchr[@'137]:='_';@/ -xchr[@'140]:='`'; -xchr[@'141]:='a'; -xchr[@'142]:='b'; -xchr[@'143]:='c'; -xchr[@'144]:='d'; -xchr[@'145]:='e'; -xchr[@'146]:='f'; -xchr[@'147]:='g';@/ -xchr[@'150]:='h'; -xchr[@'151]:='i'; -xchr[@'152]:='j'; -xchr[@'153]:='k'; -xchr[@'154]:='l'; -xchr[@'155]:='m'; -xchr[@'156]:='n'; -xchr[@'157]:='o';@/ -xchr[@'160]:='p'; -xchr[@'161]:='q'; -xchr[@'162]:='r'; -xchr[@'163]:='s'; -xchr[@'164]:='t'; -xchr[@'165]:='u'; -xchr[@'166]:='v'; -xchr[@'167]:='w';@/ -xchr[@'170]:='x'; -xchr[@'171]:='y'; -xchr[@'172]:='z'; -xchr[@'173]:='{'; -xchr[@'174]:='|'; -xchr[@'175]:='}'; -xchr[@'176]:='~';@/ -@y -{ don't need to set up xchr here } -@z - -@x -{Initialize |xchr| to the identity mapping.} -for i:=0 to @'37 do xchr[i]:=i; -for i:=@'177 to @'377 do xchr[i]:=i; -{Initialize enc\TeX\ data.} -for i:=0 to 255 do mubyte_read[i]:=null; -for i:=0 to 255 do mubyte_write[i]:=0; -for i:=0 to 128 do mubyte_cswrite[i]:=null; -mubyte_keep := 0; mubyte_start := false; -write_noexpanding := false; cs_converting := false; -special_printing := false; message_printing := false; -no_convert := false; active_noconvert := false; -@y -@z - -@x -for i:=first_text_char to last_text_char do xord[chr(i)]:=invalid_code; -for i:=@'200 to @'377 do xord[xchr[i]]:=i; -for i:=0 to @'176 do xord[xchr[i]]:=i; -{Set |xprn| for printable ASCII, unless |eight_bit_p| is set.} -for i:=0 to 255 do xprn[i]:=(eight_bit_p or ((i>=" ")and(i<="~"))); - -{The idea for this dynamic translation comes from the patch by - Libor Skarvada \.{} - and Petr Sojka \.{}. I didn't use any of the - actual code, though, preferring a more general approach.} - -{This updates the |xchr|, |xord|, and |xprn| arrays from the provided - |translate_filename|. See the function definition in \.{texmfmp.c} for - more comments.} -if translate_filename then read_tcx_file; -@y -@z - -@x -if translate_filename then begin - wterm(' ('); - fputs(translate_filename, stdout); - wterm_ln(')'); -end; -@y -if translate_filename then begin - wterm(' (WARNING: translate-file "'); - fputs(translate_filename, stdout); - wterm_ln('" ignored)'); -end; -@z - -@x -@d xord_code_base=cur_font_loc+1 -@d xchr_code_base=xord_code_base+1 -@d xprn_code_base=xchr_code_base+1 -@d math_font_base=xprn_code_base+1 -@y -@d math_font_base=cur_font_loc+1 -@z - -@x -@d mubyte_in_code=web2c_int_base+3 {if positive then reading mubytes is active} -@d mubyte_out_code=web2c_int_base+4 {if positive then printing mubytes is active} -@d mubyte_log_code=web2c_int_base+5 {if positive then print mubytes to log and terminal} -@d spec_out_code=web2c_int_base+6 {if positive then print specials by mubytes} -@d web2c_int_pars=web2c_int_base+7 {total number of web2c's integer parameters} -@y -@d web2c_int_pars=web2c_int_base+3 {total number of web2c's integer parameters} -@z - -@x -@d mubyte_in==int_par(mubyte_in_code) -@d mubyte_out==int_par(mubyte_out_code) -@d mubyte_log==int_par(mubyte_log_code) -@d spec_out==int_par(spec_out_code) -@y -@z - -@x -mubyte_in_code:print_esc("mubytein"); -mubyte_out_code:print_esc("mubyteout"); -mubyte_log_code:print_esc("mubytelog"); -spec_out_code:print_esc("specialout"); -@y -@z - -@x -if enctex_p then - begin enctex_enabled_p:=true; - primitive("mubytein",assign_int,int_base+mubyte_in_code);@/ -@!@:mubyte_in_}{\.{\\mubytein} primitive@> - primitive("mubyteout",assign_int,int_base+mubyte_out_code);@/ -@!@:mubyte_out_}{\.{\\mubyteout} primitive@> - primitive("mubytelog",assign_int,int_base+mubyte_log_code);@/ -@!@:mubyte_log_}{\.{\\mubytelog} primitive@> - primitive("specialout",assign_int,int_base+spec_out_code);@/ -@!@:spec_out_}{\.{\\specialout} primitive@> -end; -@y -@z - -@x -procedure print_cs(@!p:integer); {prints a purported control sequence} -var q: pointer; - s: str_number; -begin - if active_noconvert and (not no_convert) and - (eq_type(p) = let) and (equiv(p) = normal+11) then { noconvert } - begin - no_convert := true; - return; - end; - s := 0; - if cs_converting and (not no_convert) then - begin - q := mubyte_cswrite [p mod 128] ; - while q <> null do - if info (q) = p then - begin - s := info (link(q)); q := null; - end else q := link (link (q)); - end; - no_convert := false; - if s > 0 then print (s) - else if p -end; -@y -@z - -@x -i := start; mubyte_skeep := mubyte_keep; -mubyte_sstart := mubyte_start; mubyte_start := false; -if j>0 then while i < j do -begin - if i=loc then set_trick_count; - print_buffer(i); -end; -mubyte_keep := mubyte_skeep; mubyte_start := mubyte_sstart -@y -if j>0 then for i:=start to j-1 do - begin if i=loc then set_trick_count; - print(buffer[i]); - end -@z - -@x -Some additional routines used by the enc\TeX extension have to be -declared at this point. - -@p @t\4@>@@/ - -@y -@z - -@x -@!i,@!j: 0..buf_size; {more indexes for encTeX} -@!mubyte_incs: boolean; {control sequence is converted by mubyte} -@!p:pointer; {for encTeX test if noexpanding} -@y -@z - -@x - begin - { Use |k| instead of |loc| for type correctness. } - k := loc; - cur_chr := read_buffer (k); - loc := k; incr (loc); - if (mubyte_token > 0) then - begin - state := mid_line; - cur_cs := mubyte_token - cs_token_flag; - goto found; - end; -@y - begin cur_chr:=buffer[loc]; incr(loc); -@z - -@x -else begin start_cs: - mubyte_incs := false; k := loc; mubyte_skeep := mubyte_keep; - cur_chr := read_buffer (k); cat := cat_code (cur_chr); - if (mubyte_in>0) and (not mubyte_incs) and - ((mubyte_skip>0) or (cur_chr<>buffer[k])) then mubyte_incs := true; - incr (k); - if mubyte_token > 0 then - begin - state := mid_line; - cur_cs := mubyte_token - cs_token_flag; - goto found; - end; -@y -else begin start_cs: k:=loc; cur_chr:=buffer[k]; cat:=cat_code(cur_chr); - incr(k); -@z - -@x - mubyte_keep := mubyte_skeep; - cur_cs:=single_base + read_buffer(loc); incr(loc); -@y - cur_cs:=single_base+buffer[loc]; incr(loc); -@z - -@x -if write_noexpanding then -begin - p := mubyte_cswrite [cur_cs mod 128]; - while p <> null do - if info (p) = cur_cs then - begin - cur_cmd := relax; cur_chr := 256; p := null; - end else p := link (link (p)); -end; -@y -@z - -@x -@ @= -begin - repeat cur_chr := read_buffer (k); cat := cat_code (cur_chr); - if mubyte_token>0 then cat := escape; - if (mubyte_in>0) and (not mubyte_incs) and (cat=letter) and - ((mubyte_skip>0) or (cur_chr<>buffer[k])) then mubyte_incs := true; - incr (k); - until (cat <> letter) or (k > limit); - @; - if cat <> letter then - begin - decr (k); k := k - mubyte_skip; - end; - if k > loc + 1 then { multiletter control sequence has been scanned } - begin - if mubyte_incs then { multibyte in csname occurrs } - begin - i := loc; j := first; mubyte_keep := mubyte_skeep; - if j - loc + k > max_buf_stack then - begin - max_buf_stack := j - loc + k; - if max_buf_stack >= buf_size then - begin - max_buf_stack := buf_size; - overflow ("buffer size", buf_size); - end; - end; - while i < k do - begin - buffer [j] := read_buffer (i); - incr (i); incr (j); - end; - if j = first+1 then - cur_cs := single_base + buffer [first] - else - cur_cs := id_lookup (first, j-first); - end else cur_cs := id_lookup (loc, k-loc) ; - loc := k; - goto found; - end; -end -@y -@ @= -begin repeat cur_chr:=buffer[k]; cat:=cat_code(cur_chr); incr(k); -until (cat<>letter)or(k>limit); -@; -if cat<>letter then decr(k); - {now |k| points to first nonletter} -if k>loc+1 then {multiletter control sequence has been scanned} - begin cur_cs:=id_lookup(loc,k-loc); loc:=k; goto found; - end; -end -@z - -@x - if write_noexpanding then - begin - p := mubyte_cswrite [cur_cs mod 128]; - while p <> null do - if info (p) = cur_cs then - begin - cur_cmd := relax; cur_chr := 256; p := null; - end else p := link (link (p)); - end; -@y -@z - -@x -if enctex_enabled_p then - begin wlog_cr; wlog(encTeX_banner); wlog(', reencoding enabled'); - if translate_filename then - begin wlog_cr; - wlog(' (\xordcode, \xchrcode, \xprncode overridden by TCX)'); - end; - end; -@y -@z - -@x -if translate_filename then begin - wlog_cr; - wlog(' ('); - fputs(translate_filename, log_file); - wlog(')'); - end; -@y -if translate_filename then begin - wlog_cr; - wlog(' (WARNING: translate-file "'); - fputs(translate_filename, log_file); - wlog('" ignored)'); - end; -@z - -@x -procedure cs_error; -begin -if cur_chr = 10 then -begin - print_err("Extra "); print_esc("endmubyte"); -@.Extra \\endmubyte@> - help1("I'm ignoring this, since I wasn't doing a \mubyte."); -end else begin - print_err("Extra "); print_esc("endcsname"); -@.Extra \\endcsname@> - help1("I'm ignoring this, since I wasn't doing a \csname."); -end; -error; -end; -@y -procedure cs_error; -begin print_err("Extra "); print_esc("endcsname"); -@.Extra \\endcsname@> -help1("I'm ignoring this, since I wasn't doing a \csname."); -error; -end; -@z - -@x -if enctex_p then -begin - primitive("mubyte",let,normal+10);@/ -@!@:mubyte_}{\.{\\mubyte} primitive@> - primitive("noconvert",let,normal+11);@/ -@!@:noconvert_}{\.{\\noconvert} primitive@> -end; -@y -@z - -@x -let: if chr_code<>normal then - if chr_code = normal+10 then print_esc("mubyte") - else if chr_code = normal+11 then print_esc("noconvert") - else print_esc("futurelet") - else print_esc("let"); -@y -let: if chr_code<>normal then print_esc("futurelet")@+else print_esc("let"); -@z - -@x -let: if cur_chr = normal+11 then do_nothing { noconvert primitive } - else if cur_chr = normal+10 then { mubyte primitive } - begin - selector:=term_and_log; - get_token; - mubyte_stoken := cur_tok; - if cur_tok <= cs_token_flag then mubyte_stoken := cur_tok mod 256; - mubyte_prefix := 60; mubyte_relax := false; - mubyte_tablein := true; mubyte_tableout := true; - get_x_token; - if cur_cmd = spacer then get_x_token; - if cur_cmd = sub_mark then - begin - mubyte_tableout := false; get_x_token; - if cur_cmd = sub_mark then - begin - mubyte_tableout := true; mubyte_tablein := false; - get_x_token; - end; - end else if (mubyte_stoken > cs_token_flag) and - (cur_cmd = mac_param) then - begin - mubyte_tableout := false; - scan_int; mubyte_prefix := cur_val; get_x_token; - if mubyte_prefix > 50 then mubyte_prefix := 52; - if mubyte_prefix <= 0 then mubyte_prefix := 51; - end - else if (mubyte_stoken > cs_token_flag) and (cur_cmd = relax) then - begin - mubyte_tableout := true; mubyte_tablein := false; - mubyte_relax := true; get_x_token; - end; - r := get_avail; p := r; - while cur_cs = 0 do begin store_new_token (cur_tok); get_x_token; end; - if (cur_cmd <> end_cs_name) or (cur_chr <> 10) then - begin - print_err("Missing "); print_esc("endmubyte"); print(" inserted"); - help2("The control sequence marked should")@/ -("not appear in between \mubyte and \endmubyte."); - back_error; - end; - p := link(r); - if (p = null) and mubyte_tablein then - begin - print_err("The empty , "); - print_esc("mubyte"); print(" ignored"); - help2("The in")@/ -("\mubyte \endmubyte should not be empty."); - error; - end else begin - while p <> null do - begin - append_char (info(p) mod 256); - p := link (p); - end; - flush_list (r); - if (str_start [str_ptr] + 1 = pool_ptr) and - (str_pool [pool_ptr-1] = mubyte_stoken) then - begin - if mubyte_read [mubyte_stoken] <> null - and mubyte_tablein then { clearing data } - dispose_munode (mubyte_read [mubyte_stoken]); - if mubyte_tablein then mubyte_read [mubyte_stoken] := null; - if mubyte_tableout then mubyte_write [mubyte_stoken] := 0; - pool_ptr := str_start [str_ptr]; - end else begin - if mubyte_tablein then mubyte_update; { updating input side } - if mubyte_tableout then { updating output side } - begin - if mubyte_stoken > cs_token_flag then { control sequence } - begin - dispose_mutableout (mubyte_stoken-cs_token_flag); - if (str_start [str_ptr] < pool_ptr) or mubyte_relax then - begin { store data } - r := mubyte_cswrite[(mubyte_stoken-cs_token_flag) mod 128]; - p := get_avail; - mubyte_cswrite[(mubyte_stoken-cs_token_flag) mod 128] := p; - info (p) := mubyte_stoken-cs_token_flag; - link (p) := get_avail; - p := link (p); - if mubyte_relax then begin - info (p) := 0; pool_ptr := str_start [str_ptr]; - end else info (p) := slow_make_string; - link (p) := r; - end; - end else begin { single character } - if str_start [str_ptr] = pool_ptr then - mubyte_write [mubyte_stoken] := 0 - else - mubyte_write [mubyte_stoken] := slow_make_string; - end; - end else pool_ptr := str_start [str_ptr]; - end; - end; - end else begin { let primitive } - n:=cur_chr; -@y -let: begin n:=cur_chr; -@z - -@x -if enctex_p then -begin - primitive("xordcode",def_code,xord_code_base); -@!@:xord_code_}{\.{\\xordcode} primitive@> - primitive("xchrcode",def_code,xchr_code_base); -@!@:xchr_code_}{\.{\\xchrcode} primitive@> - primitive("xprncode",def_code,xprn_code_base); -@!@:xprn_code_}{\.{\\xprncode} primitive@> -end; -@y -@z - -@x -def_code: if chr_code=xord_code_base then print_esc("xordcode") - else if chr_code=xchr_code_base then print_esc("xchrcode") - else if chr_code=xprn_code_base then print_esc("xprncode") - else if chr_code=cat_code_base then print_esc("catcode") -@y -def_code: if chr_code=cat_code_base then print_esc("catcode") -@z - -@x - if p=xord_code_base then p:=cur_val - else if p=xchr_code_base then p:=cur_val+256 - else if p=xprn_code_base then p:=cur_val+512 - else p:=p+cur_val; -@y - p:=p+cur_val; -@z - -@x -message_printing := true; active_noconvert := true; -token_show(def_ref); -message_printing := false; active_noconvert := false; -@y -token_show(def_ref); -@z - -@x -@; -@y -@z - -@x -@!dummy_xord: ASCII_code; -@!dummy_xchr: text_char; -@!dummy_xprn: ASCII_code; -@y -@z - -@x -@; -@y -@z - -@x -@; -@y -@z - -@x -@; -@y -@z - -@x -if enctex_enabled_p then - begin wterm(encTeX_banner); wterm_ln(', reencoding enabled.'); - if translate_filename then begin - wterm_ln(' (\xordcode, \xchrcode, \xprncode overridden by TCX)'); - end; - end; -@y -@z - -@x -if mubyte_out + mubyte_zero < 0 then write_mubyte(tail) := 0 -else if mubyte_out + mubyte_zero >= 2*mubyte_zero then - write_mubyte(tail) := 2*mubyte_zero - 1 - else write_mubyte(tail) := mubyte_out + mubyte_zero; -@y -@z - -@x -@= -begin new_whatsit(special_node,write_node_size); -if spec_out + mubyte_zero < 0 then write_stream(tail) := 0 -else if spec_out + mubyte_zero >= 2*mubyte_zero then - write_stream(tail) := 2*mubyte_zero - 1 - else write_stream(tail) := spec_out + mubyte_zero; -if mubyte_out + mubyte_zero < 0 then write_mubyte(tail) := 0 -else if mubyte_out + mubyte_zero >= 2*mubyte_zero then - write_mubyte(tail) := 2*mubyte_zero - 1 - else write_mubyte(tail) := mubyte_out + mubyte_zero; -if (spec_out = 2) or (spec_out = 3) then - if (mubyte_out > 2) or (mubyte_out = -1) or (mubyte_out = -2) then - write_noexpanding := true; -p:=scan_toks(false,true); write_tokens(tail):=def_ref; -write_noexpanding := false; -end -@y -@= -begin new_whatsit(special_node,write_node_size); write_stream(tail):=0; -p:=scan_toks(false,true); write_tokens(tail):=def_ref; -end -@z - -@x -if (s = "write") and (write_mubyte (p) <> mubyte_zero) then -begin - print_char ("<"); print_int (write_mubyte(p)-mubyte_zero); print_char (">"); -end; -@y -@z - -@x -spec_sout := spec_out; spec_out := write_stream(p) - mubyte_zero; -mubyte_sout := mubyte_out; mubyte_out := write_mubyte(p) - mubyte_zero; -active_noconvert := true; -mubyte_slog := mubyte_log; -mubyte_log := 0; -if (mubyte_out > 0) or (mubyte_out = -1) then mubyte_log := 1; -if (spec_out = 2) or (spec_out = 3) then -begin - if (mubyte_out > 0) or (mubyte_out = -1) then - begin - special_printing := true; mubyte_log := 1; - end; - if mubyte_out > 1 then cs_converting := true; -end; -@y -@z - -@x -if (spec_out = 1) or (spec_out = 3) then - for k:=str_start[str_ptr] to pool_ptr-1 do - str_pool[k] := si(xchr[so(str_pool[k])]); -@y -@z - -@x -begin -mubyte_sout := mubyte_out; mubyte_out := write_mubyte(p) - mubyte_zero; -if (mubyte_out > 2) or (mubyte_out = -1) or (mubyte_out = -2) then - write_noexpanding := true; -@ 1 then cs_converting := true; -mubyte_slog := mubyte_log; -if (mubyte_out > 0) or (mubyte_out = -1) then mubyte_log := 1 -else mubyte_log := 0; -token_show(def_ref); print_ln; -cs_converting := false; write_noexpanding := false; -active_noconvert := false; -mubyte_out := mubyte_sout; mubyte_log := mubyte_slog; -@y -token_show(def_ref); print_ln; -@z - -@x -@ Dumping the |xord|, |xchr|, and |xprn| arrays. We dump these always -in the format, so a TCX file loaded during format creation can set a -default for users of the format. - -@= -dump_things(xord[0], 256); -dump_things(xchr[0], 256); -dump_things(xprn[0], 256); - -@ Undumping the |xord|, |xchr|, and |xprn| arrays. This code is more -complicated, because we want to ensure that a TCX file specified on -the command line will override whatever is in the format. Since the -tcx file has already been loaded, that implies throwing away the data -in the format. Also, if no |translate_filename| is given, but -|eight_bit_p| is set we have to make all characters printable. - -@= -if translate_filename then begin - for k:=0 to 255 do undump_things(dummy_xord, 1); - for k:=0 to 255 do undump_things(dummy_xchr, 1); - for k:=0 to 255 do undump_things(dummy_xprn, 1); - end -else begin - undump_things(xord[0], 256); - undump_things(xchr[0], 256); - undump_things(xprn[0], 256); - if eight_bit_p then - for k:=0 to 255 do - xprn[k]:=1; -end; - - -@y -@z - -@x -@* \[54/enc\TeX] System-dependent changes for enc\TeX. - -@d encTeX_banner == ' encTeX v. Jun. 2004' - -@ The boolean variable |enctex_p| is set by web2c according to the given -command line option (or an entry in the configuration file) before any -\TeX{} function is called. - -@ = -@!enctex_p: boolean; - - -@ The boolean variable |enctex_enabled_p| is used to enable enc\TeX's -primitives. It is initialised to |false|. When loading a \.{FMT} it -is set to the value of the boolean |enctex_p| saved in the \.{FMT} file. -Additionally it is set to the value of |enctex_p| in Ini\TeX. - -@= -@!enctex_enabled_p:boolean; {enable encTeX} - - -@ @= -enctex_enabled_p:=false; - - -@ Auxiliary functions/procedures for enc\TeX{} (by Petr Olsak) follow. -These functions implement the \.{\\mubyte} code to convert -the multibytes in |buffer| to one byte or to one control -sequence. These functions manipulate a mubyte tree: each node of -this tree is token list with n+1 tokens (first token consist the byte -from the byte sequence itself and the other tokens point to the -branches). If you travel from root of the tree to a leaf then you -find exactly one byte sequence which we have to convert to one byte or -control sequence. There are two variants of the leaf: the ``definitive -end'' or the ``middle leaf'' if a longer byte sequence exists and the mubyte -tree continues under this leaf. First variant is implemented as one -memory word where the link part includes the token to -which we have to convert and type part includes the number 60 (normal -conversion) or 1..52 (insert the control sequence). -The second variant of ``middle leaf'' is implemented as two memory words: -first one has a type advanced by 64 and link points to the second -word where info part includes the token to which we have to convert -and link points to the next token list with the branches of -the subtree. - -The inverse: one byte to multi byte (for log printing and \.{\\write} -printing) is implemented via a pool. Each multibyte sequence is stored -in a pool as a string and |mubyte_write|[{\it printed char\/}] points -to this string. - -@d new_mubyte_node == - link (p) := get_avail; p := link (p); info (p) := get_avail; p := info (p) -@d subinfo (#) == subtype (#) - -@= -{ read |buffer|[|i|] and convert multibyte. |i| should have been - of type 0..|buf_size|, but web2c doesn't like that construct in - argument lists. } -function read_buffer(var i:integer):ASCII_code; -var p: pointer; - last_found: integer; - last_type: integer; -begin - mubyte_skip := 0; mubyte_token := 0; - read_buffer := buffer[i]; - if mubyte_in = 0 then - begin - if mubyte_keep > 0 then mubyte_keep := 0; - return ; - end; - last_found := -2; - if (i = start) and (not mubyte_start) then - begin - mubyte_keep := 0; - if (end_line_char >= 0) and (end_line_char < 256) then - if mubyte_read [end_line_char] <> null then - begin - mubyte_start := true; mubyte_skip := -1; - p := mubyte_read [end_line_char]; - goto continue; - end; - end; -restart: - mubyte_start := false; - if (mubyte_read [buffer[i]] = null) or (mubyte_keep > 0) then - begin - if mubyte_keep > 0 then decr (mubyte_keep); - return ; - end; - p := mubyte_read [buffer[i]]; -continue: - if type (p) >= 64 then - begin - last_type := type (p) - 64; - p := link (p); - mubyte_token := info (p); last_found := mubyte_skip; - end else if type (p) > 0 then - begin - last_type := type (p); - mubyte_token := link (p); - goto found; - end; - incr (mubyte_skip); - if i + mubyte_skip > limit then - begin - mubyte_skip := 0; - if mubyte_start then goto restart; - return; - end; - repeat - p := link (p); - if subinfo (info(p)) = buffer [i+mubyte_skip] then - begin - p := info (p); goto continue; - end; - until link (p) = null; - mubyte_skip := 0; - if mubyte_start then goto restart; - if last_found = -2 then return; { no found } - mubyte_skip := last_found; -found: - if mubyte_token < 256 then { multibyte to one byte } - begin - read_buffer := mubyte_token; mubyte_token := 0; - i := i + mubyte_skip; - if mubyte_start and (i >= start) then mubyte_start := false; - return; - end else begin { multibyte to control sequence } - read_buffer := 0; - if last_type = 60 then { normal conversion } - i := i + mubyte_skip - else begin { insert control sequence } - decr (i); mubyte_keep := last_type; - if i < start then mubyte_start := true; - if last_type = 52 then mubyte_keep := 10000; - if last_type = 51 then mubyte_keep := mubyte_skip + 1; - mubyte_skip := -1; - end; - if mubyte_start and (i >= start) then mubyte_start := false; - return; - end; -exit: end; - -@ @= -procedure mubyte_update; { saves new string to mubyte tree } -var j: pool_pointer; - p: pointer; - q: pointer; - in_mutree: integer; -begin - j := str_start [str_ptr]; - if mubyte_read [so(str_pool[j])] = null then - begin - in_mutree := 0; - p := get_avail; - mubyte_read [so(str_pool[j])] := p; - subinfo (p) := so(str_pool[j]); type (p) := 0; - end else begin - in_mutree := 1; - p := mubyte_read [so(str_pool[j])]; - end; - incr (j); - while j < pool_ptr do - begin - if in_mutree = 0 then - begin - new_mubyte_node; subinfo (p) := so(str_pool[j]); type (p) := 0; - end else { |in_mutree| = 1 } - if (type (p) > 0) and (type (p) < 64) then - begin - type (p) := type (p) + 64; - q := link (p); link (p) := get_avail; p := link (p); - info (p) := q; - new_mubyte_node; subinfo (p) := so(str_pool[j]); type (p) := 0; - in_mutree := 0; - end else begin - if type (p) >= 64 then p := link (p); - repeat - p := link (p); - if subinfo (info(p)) = so(str_pool[j]) then - begin - p := info (p); - goto continue; - end; - until link (p) = null; - new_mubyte_node; subinfo (p) := so(str_pool[j]); type (p) := 0; - in_mutree := 0; - end; -continue: - incr (j); - end; - if in_mutree = 1 then - begin - if type (p) = 0 then - begin - type (p) := mubyte_prefix + 64; - q := link (p); link (p) := get_avail; p := link (p); - link (p) := q; info (p) := mubyte_stoken; - return; - end; - if type (p) >= 64 then - begin - type (p) := mubyte_prefix + 64; - p := link (p); info (p) := mubyte_stoken; - return; - end; - end; - type (p) := mubyte_prefix; - link (p) := mubyte_stoken; -exit: end; -@# -procedure dispose_munode (p: pointer); { frees a mu subtree recursivelly } -var q: pointer; -begin - if (type (p) > 0) and (type (p) < 64) then free_avail (p) - else begin - if type (p) >= 64 then - begin - q := link (p); free_avail (p); p := q; - end; - q := link (p); free_avail (p); p := q; - while p <> null do - begin - dispose_munode (info (p)); - q := link (p); - free_avail (p); - p := q; - end; - end; -end; -@# -procedure dispose_mutableout (cs: pointer); { frees record from out table } -var p, q, r: pointer; -begin - p := mubyte_cswrite [cs mod 128]; - r := null; - while p <> null do - if info (p) = cs then - begin - if r <> null then link (r) := link (link (p)) - else mubyte_cswrite[cs mod 128] := link (link (p)); - q := link (link(p)); - free_avail (link(p)); free_avail (p); - p := q; - end else begin - r := link (p); p := link (r); - end; -end; - -@ The |print_buffer| procedure prints one character from |buffer|[|i|]. -It also increases |i| to the next character in the buffer. - -@= -{ print one char from |buffer|[|i|]. |i| should have been of type - 0..|buf_size|, but web2c doesn't like that construct in argument lists. } -procedure print_buffer(var i:integer); -var c: ASCII_code; -begin - if mubyte_in = 0 then print (buffer[i]) { normal TeX } - else if mubyte_log > 0 then print_char (buffer[i]) - else begin - c := read_buffer (i); - if mubyte_token > 0 then print_cs (mubyte_token-cs_token_flag) - else print (c); - end; - incr (i); -end; - -@ Additional material to dump for enc\TeX. This includes whether -enc\TeX is enabled, and if it is we also have to dump the \.{\\mubyte} -arrays. - -@= -dump_int(@"45435458); {enc\TeX's magic constant: "ECTX"} -if not enctex_p then dump_int(0) -else begin - dump_int(1); - dump_things(mubyte_read[0], 256); - dump_things(mubyte_write[0], 256); - dump_things(mubyte_cswrite[0], 128); -end; - -@ Undumping the additional material we dumped for enc\TeX. This includes -conditionally undumping the \.{\\mubyte} arrays. - -@= -undump_int(x); {check magic constant of enc\TeX} -if x<>@"45435458 then goto bad_fmt; -undump_int(x); {undump |enctex_p| flag into |enctex_enabled_p|} -if x=0 then enctex_enabled_p:=false -else if x<>1 then goto bad_fmt -else begin - enctex_enabled_p:=true; - undump_things(mubyte_read[0], 256); - undump_things(mubyte_write[0], 256); - undump_things(mubyte_cswrite[0], 128); -end; - -@y -@z diff --git a/Build/source/texk/web2c/xetexdir/xetex-otmath.ch b/Build/source/texk/web2c/xetexdir/xetex-otmath.ch deleted file mode 100644 index e7ea126d21c..00000000000 --- a/Build/source/texk/web2c/xetexdir/xetex-otmath.ch +++ /dev/null @@ -1,667 +0,0 @@ -% /****************************************************************************\ -% Part of the XeTeX typesetting system -% copyright (c) 1994-2006 by SIL International -% written by Jonathan Kew -% -% Permission is hereby granted, free of charge, to any person obtaining -% a copy of this software and associated documentation files (the -% "Software"), to deal in the Software without restriction, including -% without limitation the rights to use, copy, modify, merge, publish, -% distribute, sublicense, and/or sell copies of the Software, and to -% permit persons to whom the Software is furnished to do so, subject to -% the following conditions: -% -% The above copyright notice and this permission notice shall be -% included in all copies or substantial portions of the Software. -% -% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -% EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -% MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -% NONINFRINGEMENT. IN NO EVENT SHALL SIL INTERNATIONAL BE LIABLE FOR -% ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF -% CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -% WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -% -% Except as contained in this notice, the name of SIL International -% shall not be used in advertising or otherwise to promote the sale, -% use or other dealings in this Software without prior written -% authorization from SIL International. -% \****************************************************************************/ - --- redefine mathsy() and mathex() to go to the MATH table for OT fonts -@x -@d mathsy_end(#)==fam_fnt(2+#)]].sc -@d mathsy(#)==font_info[#+param_base[mathsy_end -@d math_x_height==mathsy(5) {height of `\.x'} -@d math_quad==mathsy(6) {\.{18mu}} -@d num1==mathsy(8) {numerator shift-up in display styles} -@d num2==mathsy(9) {numerator shift-up in non-display, non-\.{\\atop}} -@d num3==mathsy(10) {numerator shift-up in non-display \.{\\atop}} -@d denom1==mathsy(11) {denominator shift-down in display styles} -@d denom2==mathsy(12) {denominator shift-down in non-display styles} -@d sup1==mathsy(13) {superscript shift-up in uncramped display style} -@d sup2==mathsy(14) {superscript shift-up in uncramped non-display} -@d sup3==mathsy(15) {superscript shift-up in cramped styles} -@d sub1==mathsy(16) {subscript shift-down if superscript is absent} -@d sub2==mathsy(17) {subscript shift-down if superscript is present} -@d sup_drop==mathsy(18) {superscript baseline below top of large box} -@d sub_drop==mathsy(19) {subscript baseline below bottom of large box} -@d delim1==mathsy(20) {size of \.{\\atopwithdelims} delimiters - in display styles} -@d delim2==mathsy(21) {size of \.{\\atopwithdelims} delimiters in non-displays} -@d axis_height==mathsy(22) {height of fraction lines above the baseline} -@d total_mathsy_params=22 -@y -NB: the access functions here must all put the font # into /f/ for mathsy(). - -The accessors are defined with -define_mathsy_accessor(NAME)(fontdimen-number)(NAME) -because I can't see how to only give the name once, with WEB's limited -macro capabilities. This seems a bit ugly, but it works. - -@d total_mathsy_params=22 - -{the following are OpenType MATH constant indices for use with OT math fonts} -@d scriptPercentScaleDown = 0 -@d scriptScriptPercentScaleDown = 1 -@d delimitedSubFormulaMinHeight = 2 -@d displayOperatorMinHeight = 3 -@d mathLeading = 4 -@d firstMathValueRecord = mathLeading -@d axisHeight = 5 -@d accentBaseHeight = 6 -@d flattenedAccentBaseHeight = 7 -@d subscriptShiftDown = 8 -@d subscriptTopMax = 9 -@d subscriptBaselineDropMin = 10 -@d superscriptShiftUp = 11 -@d superscriptShiftUpCramped = 12 -@d superscriptBottomMin = 13 -@d superscriptBaselineDropMax = 14 -@d subSuperscriptGapMin = 15 -@d superscriptBottomMaxWithSubscript = 16 -@d spaceAfterScript = 17 -@d upperLimitGapMin = 18 -@d upperLimitBaselineRiseMin = 19 -@d lowerLimitGapMin = 20 -@d lowerLimitBaselineDropMin = 21 -@d stackTopShiftUp = 22 -@d stackTopDisplayStyleShiftUp = 23 -@d stackBottomShiftDown = 24 -@d stackBottomDisplayStyleShiftDown = 25 -@d stackGapMin = 26 -@d stackDisplayStyleGapMin = 27 -@d stretchStackTopShiftUp = 28 -@d stretchStackBottomShiftDown = 29 -@d stretchStackGapAboveMin = 30 -@d stretchStackGapBelowMin = 31 -@d fractionNumeratorShiftUp = 32 -@d fractionNumeratorDisplayStyleShiftUp = 33 -@d fractionDenominatorShiftDown = 34 -@d fractionDenominatorDisplayStyleShiftDown = 35 -@d fractionNumeratorGapMin = 36 -@d fractionNumDisplayStyleGapMin = 37 -@d fractionRuleThickness = 38 -@d fractionDenominatorGapMin = 39 -@d fractionDenomDisplayStyleGapMin = 40 -@d skewedFractionHorizontalGap = 41 -@d skewedFractionVerticalGap = 42 -@d overbarVerticalGap = 43 -@d overbarRuleThickness = 44 -@d overbarExtraAscender = 45 -@d underbarVerticalGap = 46 -@d underbarRuleThickness = 47 -@d underbarExtraDescender = 48 -@d radicalVerticalGap = 49 -@d radicalDisplayStyleVerticalGap = 50 -@d radicalRuleThickness = 51 -@d radicalExtraAscender = 52 -@d radicalKernBeforeDegree = 53 -@d radicalKernAfterDegree = 54 -@d lastMathValueRecord = radicalKernAfterDegree -@d radicalDegreeBottomRaisePercent = 55 -@d lastMathConstant = radicalDegreeBottomRaisePercent - - -@d mathsy(#)==font_info[#+param_base[f]].sc - -@d define_mathsy_end(#)== - # := rval; - end -@d define_mathsy_body(#)== - var - f: integer; - rval: scaled; - begin - f := fam_fnt(2 + size_code); - if is_ot_font(f) then - rval := get_native_mathsy_param(f, #) - else - rval := mathsy(#); - define_mathsy_end -@d define_mathsy_accessor(#)==function #(size_code: integer): scaled; define_mathsy_body - -@p define_mathsy_accessor(math_x_height)(5)(math_x_height); -define_mathsy_accessor(math_quad)(6)(math_quad); -define_mathsy_accessor(num1)(8)(num1); -define_mathsy_accessor(num2)(9)(num2); -define_mathsy_accessor(num3)(10)(num3); -define_mathsy_accessor(denom1)(11)(denom1); -define_mathsy_accessor(denom2)(12)(denom2); -define_mathsy_accessor(sup1)(13)(sup1); -define_mathsy_accessor(sup2)(14)(sup2); -define_mathsy_accessor(sup3)(15)(sup3); -define_mathsy_accessor(sub1)(16)(sub1); -define_mathsy_accessor(sub2)(17)(sub2); -define_mathsy_accessor(sup_drop)(18)(sup_drop); -define_mathsy_accessor(sub_drop)(19)(sub_drop); -define_mathsy_accessor(delim1)(20)(delim1); -define_mathsy_accessor(delim2)(21)(delim2); -define_mathsy_accessor(axis_height)(22)(axis_height); -@z - -@x -@d mathex(#)==font_info[#+param_base[fam_fnt(3+cur_size)]].sc -@d default_rule_thickness==mathex(8) {thickness of \.{\\over} bars} -@d big_op_spacing1==mathex(9) {minimum clearance above a displayed op} -@d big_op_spacing2==mathex(10) {minimum clearance below a displayed op} -@d big_op_spacing3==mathex(11) {minimum baselineskip above displayed op} -@d big_op_spacing4==mathex(12) {minimum baselineskip below displayed op} -@d big_op_spacing5==mathex(13) {padding above and below displayed limits} -@d total_mathex_params=13 -@y -@d total_mathex_params=13 - -@d mathex(#)==font_info[#+param_base[f]].sc - -@d define_mathex_end(#)== - # := rval; - end -@d define_mathex_body(#)== - var - f: integer; - rval: scaled; - begin - f := fam_fnt(3 + cur_size); - if is_ot_font(f) then - rval := get_native_mathex_param(f, #) - else - rval := mathex(#); - define_mathex_end -@d define_mathex_accessor(#)==function #:scaled; define_mathex_body - -@p define_mathex_accessor(default_rule_thickness)(8)(default_rule_thickness); -define_mathex_accessor(big_op_spacing1)(9)(big_op_spacing1); -define_mathex_accessor(big_op_spacing2)(10)(big_op_spacing2); -define_mathex_accessor(big_op_spacing3)(11)(big_op_spacing3); -define_mathex_accessor(big_op_spacing4)(12)(big_op_spacing4); -define_mathex_accessor(big_op_spacing5)(13)(big_op_spacing5); -@z - --- var_delimiter needs to use MathVariants -@x -function var_delimiter(@!d:pointer;@!s:integer;@!v:scaled):pointer; -label found,continue; -var b:pointer; {the box that will be constructed} -@y -procedure stack_glyph_into_box(@!b:pointer;@!f:internal_font_number;@!g:integer); -var p,q:pointer; -begin - p:=get_node(glyph_node_size); - type(p):=whatsit_node; subtype(p):=glyph_node; - native_font(p):=f; native_glyph(p):=g; - set_native_glyph_metrics(p, 1); - link(p):=list_ptr(b); list_ptr(b):=p; - height(b):=height(p); width(b):=width(p); -end; - -procedure stack_glue_into_box(@!b:pointer;@!min,max:scaled); -var p,q:pointer; -begin - q:=new_spec(zero_glue); - width(q):=min; - stretch(q):=max-min; - p:=new_glue(q); - link(p):=list_ptr(b); list_ptr(b):=p; - height(b):=height(p); width(b):=width(p); -end; - -function build_opentype_assembly(@!f:internal_font_number;@!a:void_pointer;@!h:scaled):pointer; - {return a box with height at least |h|, using font |f|, with glyph assembly info from |a|} -var - b:pointer; {the box we're constructing} - n:integer; {the number of repetitions of each extender} - i,j:integer; {indexes} - g:integer; {glyph code} - p:pointer; {temp pointer} - h_max,o,oo,prev_o,min_o:scaled; - no_extenders: boolean; - nat,str:scaled; {natural height, stretch} -begin - b:=new_null_box; - type(b):=vlist_node; - - {figure out how many repeats of each extender to use} - n:=-1; - no_extenders:=true; - min_o:=ot_min_connector_overlap(f); - repeat - n:=n+1; - {calc max possible height with this number of extenders} - h_max:=0; - prev_o:=0; - for i:=0 to ot_part_count(a)-1 do begin - if ot_part_is_extender(a, i) then begin - no_extenders:=false; - for j:=1 to n do begin - o:=ot_part_start_connector(f, a, i); - if min_o=h) or no_extenders; - - {assemble box using |n| copies of each extender, - with appropriate glue wherever an overlap occurs} - prev_o:=0; - for i:=0 to ot_part_count(a)-1 do begin - if ot_part_is_extender(a, i) then begin - for j:=1 to n do begin - o:=ot_part_start_connector(f, a, i); - if prev_o0 then stack_glue_into_box(b, -oo, -o); - g:=ot_part_glyph(a, i); - stack_glyph_into_box(b, f, g); - prev_o:=ot_part_end_connector(f, a, i); - end - end else begin - o:=ot_part_start_connector(f, a, i); - if prev_o0 then stack_glue_into_box(b, -oo, -o); - g:=ot_part_glyph(a, i); - stack_glyph_into_box(b, f, g); - prev_o:=ot_part_end_connector(f, a, i); - end; - end; - - {find natural height and total stretch of the box} - p:=list_ptr(b); nat:=0; str:=0; - while p<>null do begin - if type(p)=whatsit_node then nat:=nat+height(p)+depth(p) - else if type(p)=glue_node then begin - nat:=nat+width(glue_ptr(p)); - str:=str+stretch(glue_ptr(p)); - end; - p:=link(p); - end; - - {set glue so as to stretch the connections if needed} - depth(b):=0; - if (h>nat) and (str>0) then begin - glue_order(b):=normal; glue_sign(b):=stretching; - glue_set(b):=unfloat((h-nat)/str); - height(b):=nat+round(str*float(glue_set(b))); - end else height(b):=nat; - - build_opentype_assembly:=b; -end; - -function var_delimiter(@!d:pointer;@!s:integer;@!v:scaled):pointer; -label found,continue; -var b:pointer; {the box that will be constructed} -ot_assembly_ptr:void_pointer; -@z - -@x -loop@+ begin @; - if large_attempt then goto found; {there were none large enough} - large_attempt:=true; z:=large_fam(d); x:=large_char(d); - end; -found: if f<>null_font then - @ -else begin b:=new_null_box; - width(b):=null_delimiter_space; {use this width if no delimiter was found} - end; -@y -ot_assembly_ptr:=nil; -loop@+ begin @; - if large_attempt then goto found; {there were none large enough} - large_attempt:=true; z:=large_fam(d); x:=large_char(d); - end; -found: if f<>null_font then begin - if not is_ot_font(f) then - @ - else begin - {for OT fonts, c is the glyph ID to use} - if ot_assembly_ptr<>nil then - b:=build_opentype_assembly(f, ot_assembly_ptr, v) - else begin - b:=new_null_box; type(b):=vlist_node; list_ptr(b):=get_node(glyph_node_size); - type(list_ptr(b)):=whatsit_node; subtype(list_ptr(b)):=glyph_node; - native_font(list_ptr(b)):=f; native_glyph(list_ptr(b)):=c; - set_native_glyph_metrics(list_ptr(b), 1); - width(b):=width(list_ptr(b)); - height(b):=height(list_ptr(b)); - depth(b):=depth(list_ptr(b)); - end - end -end else begin b:=new_null_box; - width(b):=null_delimiter_space; {use this width if no delimiter was found} - end; -@z - -@x -@ @= -@y -@ @= -if is_ot_font(g) then begin - b:=new_native_character(g, x); - x:=get_native_glyph(b, 0); - free_node(b, native_size(b)); - f:=g; c:=x; w:=0; n:=0; - repeat - y:=get_ot_math_variant(g, x, n, address_of(u)); - if u>w then begin - c:=y; w:=u; - if u>=v then goto found; - end; - n:=n+1; - until u<0; - {if we get here, then we didn't find a big enough glyph; check if the char is extensible} - ot_assembly_ptr:=get_ot_assembly_ptr(g, x); - if ot_assembly_ptr<>nil then goto found; -end else -@z - --- get radical rule thickness etc from OT -@x -procedure make_radical(@!q:pointer); -var x,@!y:pointer; {temporary registers for box construction} -@!delta,@!clr:scaled; {dimensions involved in the calculation} -begin x:=clean_box(nucleus(q),cramped_style(cur_style)); -if cur_style= -begin if cur_style= -begin if is_ot_font(fam_fnt(3+cur_size)) then begin - if cur_style= -begin if cur_style= -begin if is_ot_font(fam_fnt(3+cur_size)) then begin - delta:=half(thickness(q)); - if cur_styleempty)and(subtype(q)<>limits) then - width(x):=width(x)-delta; {remove italic correction} - shift_amount(x):=half(height(x)-depth(x)) - axis_height(cur_size); - {center vertically} - math_type(nucleus(q)):=sub_box; info(nucleus(q)):=x; - end -else delta:=0; -if subtype(q)=limits then - @; -make_op:=delta; -end; -@y -function make_op(@!q:pointer):scaled; -var delta:scaled; {offset between subscript and superscript} -@!p,@!v,@!x,@!y,@!z:pointer; {temporary registers for box construction} -@!c:quarterword;@+@!i:four_quarters; {registers for character examination} -@!shift_up,@!shift_down:scaled; {dimensions for box calculation} -@!h1,@!h2:scaled; {height of original text-style symbol and possible replacement} -@!n,@!g:integer; {potential variant index and glyph code} -begin if (subtype(q)=normal)and(cur_style0 then native_glyph(p):=g; - incr(n); - until (h2<0) or (h2>(h1*5)/4); - set_native_glyph_metrics(p, 1); - end; - width(x):=width(p); height(x):=height(p); depth(x):=depth(p); - delta:=get_ot_math_ital_corr(cur_f, native_glyph(p)); - end - end; - if (math_type(subscr(q))<>empty)and(subtype(q)<>limits) then - width(x):=width(x)-delta; {remove italic correction} - shift_amount(x):=half(height(x)-depth(x)) - axis_height(cur_size); - {center vertically} - math_type(nucleus(q)):=sub_box; info(nucleus(q)):=x; - end; -if subtype(q)=limits then - @; -make_op:=delta; -end; -@z - --- make glyph nodes rather than native_word_nodes here -@x -@ @= -begin fetch(nucleus(q)); -if is_native_font(cur_f) then begin - delta:=0; p:=new_native_character(cur_f, qo(cur_c)); -@y -@ @= -begin fetch(nucleus(q)); -if is_native_font(cur_f) then begin - z:=new_native_character(cur_f, qo(cur_c)); - p:=get_node(glyph_node_size); - type(p):=whatsit_node; subtype(p):=glyph_node; - native_font(p):=cur_f; native_glyph(p):=get_native_glyph(z, 0); - set_native_glyph_metrics(p, 1); - free_node(z, native_size(z)); - delta:=0; {FIXME} -@z - --- make_scripts needs to treat native_text like char_node, not box -@x -@ The purpose of |make_scripts(q,delta)| is to attach the subscript and/or -superscript of noad |q| to the list that starts at |new_hlist(q)|, -given that subscript and superscript aren't both empty. The superscript -will appear to the right of the subscript by a given distance |delta|. - -We set |shift_down| and |shift_up| to the minimum amounts to shift the -baseline of subscripts and superscripts based on the given nucleus. - -@= -procedure make_scripts(@!q:pointer;@!delta:scaled); -var p,@!x,@!y,@!z:pointer; {temporary registers for box construction} -@!shift_up,@!shift_down,@!clr:scaled; {dimensions in the calculation} -@!t:integer; {subsidiary size code} -begin p:=new_hlist(q); -if is_char_node(p) then -@y -@ The purpose of |make_scripts(q,delta)| is to attach the subscript and/or -superscript of noad |q| to the list that starts at |new_hlist(q)|, -given that subscript and superscript aren't both empty. The superscript -will appear to the right of the subscript by a given distance |delta|. - -We set |shift_down| and |shift_up| to the minimum amounts to shift the -baseline of subscripts and superscripts based on the given nucleus. - -@= -procedure make_scripts(@!q:pointer;@!delta:scaled); -var p,@!x,@!y,@!z:pointer; {temporary registers for box construction} -@!shift_up,@!shift_down,@!clr:scaled; {dimensions in the calculation} -@!t:integer; {subsidiary size code} -begin p:=new_hlist(q); -if is_char_node(p) or (p<>null and is_native_word_node(p)) then -@z - --- we allow either TFMs with lots of fontdimens or OpenType fonts -@x -@ @= -if (font_params[fam_fnt(2+text_size)]= -if ((font_params[fam_fnt(2+text_size)]= -begin - case subtype(p) of -@y -@ @= -begin - case subtype(p) of - glyph_node: begin - cur_v:=cur_v+height(p); - cur_h:=left_edge; - - { synch DVI state to TeX state } - synch_h; synch_v; - f := native_font(p); - if f<>dvi_f then @; - - dvi_out(set_glyph_string); - dvi_four(0); { width } - dvi_two(1); { glyph count } - dvi_four(0); { x-offset as fixed point } - dvi_two(native_glyph(p)); - - cur_v:=cur_v+depth(p); - cur_h:=left_edge; - end; -@z diff --git a/Build/source/texk/web2c/xetexdir/xetex-upwards.ch b/Build/source/texk/web2c/xetexdir/xetex-upwards.ch deleted file mode 100644 index 64a423f1bb8..00000000000 --- a/Build/source/texk/web2c/xetexdir/xetex-upwards.ch +++ /dev/null @@ -1,244 +0,0 @@ -% /****************************************************************************\ -% Part of the XeTeX typesetting system -% copyright (c) 1994-2006 by SIL International -% written by Jonathan Kew -% -% Permission is hereby granted, free of charge, to any person obtaining -% a copy of this software and associated documentation files (the -% "Software"), to deal in the Software without restriction, including -% without limitation the rights to use, copy, modify, merge, publish, -% distribute, sublicense, and/or sell copies of the Software, and to -% permit persons to whom the Software is furnished to do so, subject to -% the following conditions: -% -% The above copyright notice and this permission notice shall be -% included in all copies or substantial portions of the Software. -% -% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -% EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -% MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -% NONINFRINGEMENT. IN NO EVENT SHALL SIL INTERNATIONAL BE LIABLE FOR -% ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF -% CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -% WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -% -% Except as contained in this notice, the name of SIL International -% shall not be used in advertising or otherwise to promote the sale, -% use or other dealings in this Software without prior written -% authorization from SIL International. -% \****************************************************************************/ - -{ This file implements the experimental feature \XeTeXupwardsmode. - It also adds the state variable \XeTeXuseglyphmetrics, for use - from xetex-new.ch } - -@x -@d XeTeX_default_input_mode_code = 2 {input mode for newly opened files} -@y -@d XeTeX_upwards_code = 2 {non-zero if the main vertical list is being built upwards} -@d XeTeX_use_glyph_metrics_code = 3 {non-zero to use exact glyph height/depth} -@# -@d XeTeX_default_input_mode_code = 4 {input mode for newly opened files} -@z - -@x -@d XeTeX_default_input_encoding_code = 3 {str_number of encoding name if mode = ICU} -@# -@d eTeX_states=4 {number of \eTeX\ state variables in |eqtb|} -@y -@d XeTeX_default_input_encoding_code = 5 {str_number of encoding name if mode = ICU} -@# -@d eTeX_states=6 {number of \eTeX\ state variables in |eqtb|} -@z - -@x { to ensure following change doesn't get applied to hlist_out() } -@p procedure vlist_out; {output a |vlist_node| box} -@y -@p procedure vlist_out; {output a |vlist_node| box} -@z - -@x -@!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); -if cur_s>0 then dvi_out(push); -if cur_s>max_push then max_push:=cur_s; -save_loc:=dvi_offset+dvi_ptr; left_edge:=cur_h; cur_v:=cur_v-height(this_box); -@y -@!cur_g:scaled; {rounded equivalent of |cur_glue| times the glue ratio} -@!upwards:boolean; {whether we're stacking upwards} -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); -upwards:=(subtype(this_box)=min_quarterword+1); -incr(cur_s); -if cur_s>0 then dvi_out(push); -if cur_s>max_push then max_push:=cur_s; -save_loc:=dvi_offset+dvi_ptr; left_edge:=cur_h; -if upwards then cur_v:=cur_v+depth(this_box) else cur_v:=cur_v-height(this_box); -@z - -@x -kern_node:cur_v:=cur_v+width(p); -@y -kern_node:if upwards then cur_v:=cur_v-width(p) else cur_v:=cur_v+width(p); -@z - -@x -move_past: cur_v:=cur_v+rule_ht; -@y -move_past: if upwards then cur_v:=cur_v-rule_ht else cur_v:=cur_v+rule_ht; -@z - -@x -@= -if list_ptr(p)=null then cur_v:=cur_v+height(p)+depth(p) -else begin cur_v:=cur_v+height(p); synch_v; - save_h:=dvi_h; save_v:=dvi_v; - if cur_dir=right_to_left then cur_h:=left_edge-shift_amount(p) - else cur_h:=left_edge+shift_amount(p); {shift the box right} - temp_ptr:=p; - if type(p)=vlist_node then vlist_out@+else hlist_out; - dvi_h:=save_h; dvi_v:=save_v; - cur_v:=save_v+depth(p); cur_h:=left_edge; - end -@y -@= -if list_ptr(p)=null then - if upwards then cur_v:=cur_v-height(p)-depth(p) - else cur_v:=cur_v+height(p)+depth(p) -else begin if upwards then cur_v:=cur_v-depth(p) else cur_v:=cur_v+height(p); synch_v; - save_h:=dvi_h; save_v:=dvi_v; - if cur_dir=right_to_left then cur_h:=left_edge-shift_amount(p) - else cur_h:=left_edge+shift_amount(p); {shift the box right} - temp_ptr:=p; - if type(p)=vlist_node then vlist_out@+else hlist_out; - dvi_h:=save_h; dvi_v:=save_v; - if upwards then cur_v:=save_v-height(p) else cur_v:=save_v+depth(p); cur_h:=left_edge; - end -@z - -@x -cur_v:=cur_v+rule_ht; -@y -if upwards then cur_v:=cur_v-rule_ht else cur_v:=cur_v+rule_ht; -@z - -@x -cur_v:=height(p)+v_offset; temp_ptr:=p; -@y -cur_v:=height(p)+v_offset; { does this need changing for upwards mode ???? } -temp_ptr:=p; -@z - -@x { to ensure following change doesn't get applied to hpack() } -@d vpack(#)==vpackage(#,max_dimen) {special case of unconstrained depth} -@y -@d vpack(#)==vpackage(#,max_dimen) {special case of unconstrained depth} -@z - -@x -subtype(r):=min_quarterword; shift_amount(r):=0; -@y -if XeTeX_upwards then subtype(r):=min_quarterword+1 else subtype(r):=min_quarterword; -shift_amount(r):=0; -@z - -@x -@p procedure append_to_vlist(@!b:pointer); -var d:scaled; {deficiency of space between baselines} -@!p:pointer; {a new glue specification} -begin if prev_depth>ignore_depth then - begin d:=width(baseline_skip)-prev_depth-height(b); - if dignore_depth then - begin if upwards then d:=width(baseline_skip)-prev_depth-depth(b) - else d:=width(baseline_skip)-prev_depth-height(b); - if d; - end; -pop_nest; box_end(saved(0)); -@y -@!u,v:integer; {saved values for upwards mode flag} -begin d:=box_max_depth; u:=XeTeX_upwards_state; unsave; save_ptr:=save_ptr-3; -v:=XeTeX_upwards_state; XeTeX_upwards_state:=u; -if mode=-hmode then cur_box:=hpack(link(head),saved(2),saved(1)) -else begin cur_box:=vpackage(link(head),saved(2),saved(1),d); - if c=vtop_code then @; - end; -XeTeX_upwards_state:=v; -pop_nest; box_end(saved(0)); -@z - -@x -@ @= -dump_int(eTeX_mode); -for j:=0 to eTeX_states-1 do eTeX_state(j):=0; {disable all enhancements} -@y -@ @= -dump_int(eTeX_mode); -{ in a deliberate change from e-TeX, we allow non-zero state variables to be dumped } -@z - -@x -@d TeXXeT_en==(TeXXeT_state>0) {is \TeXXeT\ enabled?} -@y -@d TeXXeT_en==(TeXXeT_state>0) {is \TeXXeT\ enabled?} - -@d XeTeX_upwards_state==eTeX_state(XeTeX_upwards_code) -@d XeTeX_upwards==(XeTeX_upwards_state>0) - -@d XeTeX_use_glyph_metrics_state==eTeX_state(XeTeX_use_glyph_metrics_code) -@d XeTeX_use_glyph_metrics==(XeTeX_use_glyph_metrics_state>0) -@z - -@x -eTeX_state_code+TeXXeT_code:print_esc("TeXXeTstate"); -@y -eTeX_state_code+TeXXeT_code:print_esc("TeXXeTstate"); -eTeX_state_code+XeTeX_upwards_code:print_esc("XeTeXupwardsmode"); -eTeX_state_code+XeTeX_use_glyph_metrics_code:print_esc("XeTeXuseglyphmetrics"); -@z - -@x -primitive("TeXXeTstate",assign_int,eTeX_state_base+TeXXeT_code); -@!@:TeXXeT_state_}{\.{\\TeXXeT_state} primitive@> -@y -primitive("TeXXeTstate",assign_int,eTeX_state_base+TeXXeT_code); -@!@:TeXXeT_state_}{\.{\\TeXXeT_state} primitive@> -primitive("XeTeXupwardsmode",assign_int,eTeX_state_base+XeTeX_upwards_code); -@!@:XeTeX_upwards_mode_}{\.{\\XeTeX_upwards_mode} primitive@> -primitive("XeTeXuseglyphmetrics",assign_int,eTeX_state_base+XeTeX_use_glyph_metrics_code); -@!@:XeTeX_use_glyph_metrics_}{\.{\\XeTeX_use_glyph_metrics} primitive@> -@z - diff --git a/Build/source/texk/web2c/xetexdir/xetex.ch b/Build/source/texk/web2c/xetexdir/xetex.ch new file mode 100644 index 00000000000..607babd5987 --- /dev/null +++ b/Build/source/texk/web2c/xetexdir/xetex.ch @@ -0,0 +1,8938 @@ +@x +@* \[1] Introduction. +@y +@* \[1] Introduction. +@z + +@x +@d eTeX_version_string=='-2.2' {current \eTeX\ version} +@y +@d eTeX_version_string=='-2.2' {current \eTeX\ version} + +@d XeTeX_version=0 +@d XeTeX_revision==".997" +@d XeTeX_version_string=='-0.997' {current \XeTeX\ version} +@z + +@x +@d eTeX_banner_k=='This is e-TeXk, Version 3.141592',eTeX_version_string +@d eTeX_banner=='This is e-TeX, Version 3.141592',eTeX_version_string + {printed when \eTeX\ starts} +@# +@d TeX_banner_k=='This is TeXk, Version 3.141592' {printed when \TeX\ starts} +@d TeX_banner=='This is TeX, Version 3.141592' {printed when \TeX\ starts} +@# +@d banner==eTeX_banner +@d banner_k==eTeX_banner_k +@y +@d XeTeX_banner=='This is XeTeX, Version 3.141592',eTeX_version_string,XeTeX_version_string + {printed when \XeTeX\ starts} +@d XeTeX_banner_k=='This is XeTeXk, Version 3.141592',eTeX_version_string,XeTeX_version_string +@# +@d banner==XeTeX_banner +@d banner_k==XeTeX_banner_k +@z + +@x +@d TEX==ETEX {change program name into |ETEX|} +@y +@d TEX==XETEX {change program name into |XETEX|} +@z + +@x +@d TeXXeT_code=0 {the \TeXXeT\ feature is optional} +@# +@d eTeX_states=1 {number of \eTeX\ state variables in |eqtb|} +@y +@d TeXXeT_code=0 {the \TeXXeT\ feature is optional} +@# +@d XeTeX_dash_break_code = 1 {non-zero to enable breaks after en- and em-dashes} +@# +@d XeTeX_upwards_code = 2 {non-zero if the main vertical list is being built upwards} +@d XeTeX_use_glyph_metrics_code = 3 {non-zero to use exact glyph height/depth} +@d XeTeX_inter_char_tokens_code = 4 {non-zero to enable \\XeTeXinterchartokens insertion} +@# +@d XeTeX_default_input_mode_code = 5 {input mode for newly opened files} +@d XeTeX_input_mode_auto = 0 +@d XeTeX_input_mode_utf8 = 1 +@d XeTeX_input_mode_utf16be = 2 +@d XeTeX_input_mode_utf16le = 3 +@d XeTeX_input_mode_raw = 4 +@d XeTeX_input_mode_icu_mapping = 5 +@# +@d XeTeX_default_input_encoding_code = 6 {str_number of encoding name if mode = ICU} +@# +@d eTeX_states=7 {number of \eTeX\ state variables in |eqtb|} +@z + +@x +@d hyph_prime=607 {another prime for hashing \.{\\hyphenation} exceptions; + if you change this, you should also change |iinf_hyphen_size|.} +@y +@d hyph_prime=607 {another prime for hashing \.{\\hyphenation} exceptions; + if you change this, you should also change |iinf_hyphen_size|.} + +@d biggest_char=65535 {the largest allowed character number; + must be |<=max_quarterword|} +@d biggest_usv=@"10FFFF {the largest Unicode Scalar Value} +@d too_big_char=65536 {|biggest_char+1|} +@d special_char=65537 {|biggest_char+2|} +@d number_chars=65536 {|biggest_char+1|} +@d number_usvs=@"110000 +@d biggest_reg=255 {the largest allowed register number; + must be |<=max_quarterword|} +@d number_regs=256 {|biggest_reg+1|} +@d font_biggest=255 {the real biggest font} +@d number_fonts=font_biggest-font_base+2 +@d number_math_families=256 +@d number_math_fonts=number_math_families+number_math_families+number_math_families +@d math_font_biggest=number_math_fonts-1 +@d text_size=0 {size code for the largest size in a family} +@d script_size=number_math_families {size code for the medium size in a family} +@d script_script_size=number_math_families+number_math_families {size code for the smallest size in a family} +@d biggest_lang=255 +@d too_big_lang=256 +@z + +@x +@* \[2] The character set. +@y +@* \[2] The character set. +@z + +@x +@ Characters of text that have been converted to \TeX's internal form +are said to be of type |ASCII_code|, which is a subrange of the integers. + +@= +@!ASCII_code=0..255; {eight-bit numbers} +@y +@ Characters of text that have been converted to \TeX's internal form +are said to be of type |ASCII_code|, which is a subrange of the integers. +For xetex, we rename |ASCII_code| as |UTF16_code|. But we also have a +new type |UTF8_code|, used when we construct filenames to pass to the +system libraries. + +@d ASCII_code==UTF16_code +@d packed_ASCII_code==packed_UTF16_code + +@= +@!ASCII_code=0..biggest_char; {16-bit numbers} +@!UTF8_code=0..255; {8-bit numbers} +@!UnicodeScalar=0..@"10FFFF; {Unicode scalars} +@z + +@x +@d last_text_char=255 {ordinal number of the largest element of |text_char|} +@y +@d last_text_char=biggest_char {ordinal number of the largest element of |text_char|} +@z + +@x +@!xord: array [text_char] of ASCII_code; + {specifies conversion of input characters} +xchr: array [ASCII_code] of text_char; + { specifies conversion of output characters } +xprn: array [ASCII_code] of ASCII_code; + { non zero iff character is printable } +mubyte_read: array [ASCII_code] of pointer; + { non zero iff character begins the multi byte code } +mubyte_write: array [ASCII_code] of str_number; + { non zero iff character expands to multi bytes in log and write files } +mubyte_cswrite: array [0..127] of pointer; + { non null iff cs mod 128 expands to multi bytes in log and write files } +mubyte_skip: integer; { the number of bytes to skip in |buffer| } +mubyte_keep: integer; { the number of chars we need to keep unchanged } +mubyte_skeep: integer; { saved |mubyte_keep| } +mubyte_prefix: integer; { the type of mubyte prefix } +mubyte_tablein: boolean; { the input side of table will be updated } +mubyte_tableout: boolean; { the output side of table will be updated } +mubyte_relax: boolean; { the relax prefix is used } +mubyte_start: boolean; { we are making the token at the start of the line } +mubyte_sstart: boolean; { saved |mubyte_start| } +mubyte_token: pointer; { the token returned by |read_buffer| } +mubyte_stoken: pointer; { saved first token in mubyte primitive } +mubyte_sout: integer; { saved value of |mubyte_out| } +mubyte_slog: integer; { saved value of |mubyte_log| } +spec_sout: integer; { saved value of |spec_out| } +no_convert: boolean; { conversion supressed by noconvert primitive } +active_noconvert: boolean; { true if noconvert primitive is active } +write_noexpanding: boolean; { true only if we need not write expansion } +cs_converting: boolean; { true only if we need csname converting } +special_printing: boolean; { true only if we need converting in special } +message_printing: boolean; { true if message or errmessage prints to string } +@y +@!xchr: ^text_char; + {dummy variable so tangle doesn't complain; not actually used} +@z + +@x +xchr[@'40]:=' '; +xchr[@'41]:='!'; +xchr[@'42]:='"'; +xchr[@'43]:='#'; +xchr[@'44]:='$'; +xchr[@'45]:='%'; +xchr[@'46]:='&'; +xchr[@'47]:='''';@/ +xchr[@'50]:='('; +xchr[@'51]:=')'; +xchr[@'52]:='*'; +xchr[@'53]:='+'; +xchr[@'54]:=','; +xchr[@'55]:='-'; +xchr[@'56]:='.'; +xchr[@'57]:='/';@/ +xchr[@'60]:='0'; +xchr[@'61]:='1'; +xchr[@'62]:='2'; +xchr[@'63]:='3'; +xchr[@'64]:='4'; +xchr[@'65]:='5'; +xchr[@'66]:='6'; +xchr[@'67]:='7';@/ +xchr[@'70]:='8'; +xchr[@'71]:='9'; +xchr[@'72]:=':'; +xchr[@'73]:=';'; +xchr[@'74]:='<'; +xchr[@'75]:='='; +xchr[@'76]:='>'; +xchr[@'77]:='?';@/ +xchr[@'100]:='@@'; +xchr[@'101]:='A'; +xchr[@'102]:='B'; +xchr[@'103]:='C'; +xchr[@'104]:='D'; +xchr[@'105]:='E'; +xchr[@'106]:='F'; +xchr[@'107]:='G';@/ +xchr[@'110]:='H'; +xchr[@'111]:='I'; +xchr[@'112]:='J'; +xchr[@'113]:='K'; +xchr[@'114]:='L'; +xchr[@'115]:='M'; +xchr[@'116]:='N'; +xchr[@'117]:='O';@/ +xchr[@'120]:='P'; +xchr[@'121]:='Q'; +xchr[@'122]:='R'; +xchr[@'123]:='S'; +xchr[@'124]:='T'; +xchr[@'125]:='U'; +xchr[@'126]:='V'; +xchr[@'127]:='W';@/ +xchr[@'130]:='X'; +xchr[@'131]:='Y'; +xchr[@'132]:='Z'; +xchr[@'133]:='['; +xchr[@'134]:='\'; +xchr[@'135]:=']'; +xchr[@'136]:='^'; +xchr[@'137]:='_';@/ +xchr[@'140]:='`'; +xchr[@'141]:='a'; +xchr[@'142]:='b'; +xchr[@'143]:='c'; +xchr[@'144]:='d'; +xchr[@'145]:='e'; +xchr[@'146]:='f'; +xchr[@'147]:='g';@/ +xchr[@'150]:='h'; +xchr[@'151]:='i'; +xchr[@'152]:='j'; +xchr[@'153]:='k'; +xchr[@'154]:='l'; +xchr[@'155]:='m'; +xchr[@'156]:='n'; +xchr[@'157]:='o';@/ +xchr[@'160]:='p'; +xchr[@'161]:='q'; +xchr[@'162]:='r'; +xchr[@'163]:='s'; +xchr[@'164]:='t'; +xchr[@'165]:='u'; +xchr[@'166]:='v'; +xchr[@'167]:='w';@/ +xchr[@'170]:='x'; +xchr[@'171]:='y'; +xchr[@'172]:='z'; +xchr[@'173]:='{'; +xchr[@'174]:='|'; +xchr[@'175]:='}'; +xchr[@'176]:='~';@/ +@y +{ don't need to set up xchr here } +@z + +@x +{Initialize |xchr| to the identity mapping.} +for i:=0 to @'37 do xchr[i]:=i; +for i:=@'177 to @'377 do xchr[i]:=i; +{Initialize enc\TeX\ data.} +for i:=0 to 255 do mubyte_read[i]:=null; +for i:=0 to 255 do mubyte_write[i]:=0; +for i:=0 to 128 do mubyte_cswrite[i]:=null; +mubyte_keep := 0; mubyte_start := false; +write_noexpanding := false; cs_converting := false; +special_printing := false; message_printing := false; +no_convert := false; active_noconvert := false; +@y +@z + +@x +for i:=first_text_char to last_text_char do xord[chr(i)]:=invalid_code; +for i:=@'200 to @'377 do xord[xchr[i]]:=i; +for i:=0 to @'176 do xord[xchr[i]]:=i; +{Set |xprn| for printable ASCII, unless |eight_bit_p| is set.} +for i:=0 to 255 do xprn[i]:=(eight_bit_p or ((i>=" ")and(i<="~"))); + +{The idea for this dynamic translation comes from the patch by + Libor Skarvada \.{} + and Petr Sojka \.{}. I didn't use any of the + actual code, though, preferring a more general approach.} + +{This updates the |xchr|, |xord|, and |xprn| arrays from the provided + |translate_filename|. See the function definition in \.{texmfmp.c} for + more comments.} +if translate_filename then read_tcx_file; +@y +@z + +@x +@* \[3] Input and output. +@y +@* \[3] Input and output. +@z + +@x +@!name_of_file:^text_char; +@!name_length:0..file_name_size;@/{this many characters are actually + relevant in |name_of_file| (the rest are blank)} +@y +@!name_of_file:^UTF8_code; {we build filenames in utf8 to pass to the OS} +@!name_of_file16:^UTF16_code; {but sometimes we need a utf16 version of the name} +@!name_length:0..file_name_size;@/{this many characters are actually + relevant in |name_of_file| (the rest are blank)} +@!name_length16:0..file_name_size; +@z + +@x +@!buffer:^ASCII_code; {lines of characters being read} +@y +@!buffer:^UnicodeScalar; {lines of characters being read} +@z + +@x +@d term_in==stdin {the terminal as an input file} +@y +@z + +@x +@!bound_default:integer; {temporary for setup} +@y +@!term_in:unicode_file; +@# +@!bound_default:integer; {temporary for setup} +@z + +@x +@* \[4] String handling. +@y +@* \[4] String handling. +@z + +@x +|str_start[s]<=j=@"10000) then length:=str_start_macro(s+1)-str_start_macro(s) +else if (s>=@"20) and (s<@"7F) then length:=1 +else if (s<=@"7F) then length:=3 +else if (s<@"100) then length:=4 +else length:=8 +end; +@z + +@x +@d cur_length == (pool_ptr - str_start[str_ptr]) +@y +@d cur_length == (pool_ptr - str_start_macro(str_ptr)) +@z + +@x +incr(str_ptr); str_start[str_ptr]:=pool_ptr; +@y +incr(str_ptr); str_start_macro(str_ptr):=pool_ptr; +@z + +@x +@d flush_string==begin decr(str_ptr); pool_ptr:=str_start[str_ptr]; +@y +@d flush_string==begin decr(str_ptr); pool_ptr:=str_start_macro(str_ptr); +@z + +@x +begin j:=str_start[s]; +while jbuffer[k] then +@y +begin j:=str_start_macro(s); +while j=@"10000 then + if so(str_pool[j])<>@"D800+(buffer[k]-@"10000)div@"400 then + begin result:=false; goto not_found; + end + else if so(str_pool[j+1])<>@"DC00+(buffer[k]-@"10000)mod@"400 then + begin result:=false; goto not_found; + end + else incr(j) + else if so(str_pool[j])<>buffer[k] then +@z + +@x +j:=str_start[s]; k:=str_start[t]; +while jstr_pool[k] then goto not_found; + incr(j); incr(k); +@y +if (length(s)=1) then begin + if s<65536 then begin + if t<65536 then begin + if s<>t then goto not_found; + end + else begin + if s<>str_pool[str_start_macro(t)] then goto not_found; + end; + end + else begin + if t<65536 then begin + if str_pool[str_start_macro(s)]<>t then goto not_found; + end + else begin + if str_pool[str_start_macro(s)]<>str_pool[str_start_macro(t)] then + goto not_found; + end; + end; + end +else begin + j:=str_start_macro(s); k:=str_start_macro(t); + while jstr_pool[k] then goto not_found; + incr(j); incr(k); + end; +@z + +@x +begin pool_ptr:=0; str_ptr:=0; str_start[0]:=0; +@y +begin pool_ptr:=0; str_ptr:=0; +@z + +@x +@ @d app_lc_hex(#)==l:=#; + if l<10 then append_char(l+"0")@+else append_char(l-10+"a") +@y +@ The first 65536 strings will consist of a single character only. +But we don't actually make them; they're simulated on the fly. +@z + +@x +for k:=0 to 255 do + begin if (@) then + begin append_char("^"); append_char("^"); + if k<@'100 then append_char(k+@'100) + else if k<@'200 then append_char(k-@'100) + else begin app_lc_hex(k div 16); app_lc_hex(k mod 16); + end; + end + else append_char(k); + g:=make_string; + end +@y +begin +str_ptr:=too_big_char; +str_start_macro(str_ptr):=pool_ptr; +end +@z + +@x +@= + (k<" ")or(k>"~") +@y +@= +{ this module is not used } +@z + +@x +@ When the \.{WEB} system program called \.{TANGLE} processes the \.{TEX.WEB} +description that you are now reading, it outputs the \PASCAL\ program +\.{TEX.PAS} and also a string pool file called \.{TEX.POOL}. The \.{INITEX} +@.WEB@>@.INITEX@> +program reads the latter file, where each string appears as a two-digit decimal +length followed by the string itself, and the information is recorded in +\TeX's string memory. + +@= +@!init @!pool_file:alpha_file; {the string-pool file output by \.{TANGLE}} +tini + +@ @d bad_pool(#)==begin wake_up_terminal; write_ln(term_out,#); + a_close(pool_file); get_strings_started:=false; return; + end +@= +name_length := strlen (pool_name); +name_of_file := xmalloc_array (ASCII_code, name_length + 1); +strcpy (stringcast(name_of_file+1), pool_name); {copy the string} +if a_open_in (pool_file, kpse_texpool_format) then + begin c:=false; + repeat @; + until c; + a_close(pool_file); get_strings_started:=true; + end +else bad_pool('! I can''t read ', pool_name, '; bad path?') +@.I can't read TEX.POOL@> + +@ @= +begin if eof(pool_file) then bad_pool('! ', pool_name, ' has no check sum.'); +@.TEX.POOL has no check sum@> +read(pool_file,m); read(pool_file,n); {read two digits of string length} +if m='*' then @ +else begin if (xord[m]<"0")or(xord[m]>"9")or@| + (xord[n]<"0")or(xord[n]>"9") then + bad_pool('! ', pool_name, ' line doesn''t begin with two digits.'); +@.TEX.POOL line doesn't...@> + l:=xord[m]*10+xord[n]-"0"*11; {compute the length} + if pool_ptr+l+string_vacancies>pool_size then + bad_pool('! You have to increase POOLSIZE.'); +@.You have to increase POOLSIZE@> + for k:=1 to l do + begin if eoln(pool_file) then m:=' '@+else read(pool_file,m); + append_char(xord[m]); + end; + read_ln(pool_file); g:=make_string; + end; +end + +@ The \.{WEB} operation \.{@@\$} denotes the value that should be at the +end of this \.{TEX.POOL} file; any other value means that the wrong pool +file has been loaded. +@^check sum@> + +@= +begin a:=0; k:=1; +loop@+ begin if (xord[n]<"0")or(xord[n]>"9") then + bad_pool('! ', pool_name, ' check sum doesn''t have nine digits.'); +@.TEX.POOL check sum...@> + a:=10*a+xord[n]-"0"; + if k=9 then goto done; + incr(k); read(pool_file,n); + end; +done: if a<>@$ then + bad_pool('! ', pool_name, ' doesn''t match; tangle me again (or fix the path).'); +@.TEX.POOL doesn't match@> +c:=true; +end +@y +@ @= +if init_pool(pool_size-string_vacancies) = 0 then + get_strings_started:=false; +get_strings_started:=true; +@z + +@x +@* \[5] On-line and off-line printing. +@y +@* \[5] On-line and off-line printing. +@z + +@x +procedure print_char(@!s:ASCII_code); {prints a single character} +label exit; +begin if @ then + if selector= +procedure print_char(@!s:integer); {prints a single character} +label exit; +var l: small_number; +begin if (selector>pseudo) and (not doing_special) then + {"printing" to a new string, encode as UTF-16 rather than UTF-8} + begin if s>=@"10000 then begin + print_visible_char(@"D800 + (s - @"10000) div @"400); + print_visible_char(@"DC00 + (s - @"10000) mod @"400); + end else print_visible_char(s); + return; + end; +if @ then + if selector= 128: encode as UTF8 } + if s<@"800 then begin + print_visible_char(@"C0 + s div @"40); + print_visible_char(@"80 + s mod @"40); + end + else if s<@"10000 then begin + print_visible_char(@"E0 + (s div @"1000)); + print_visible_char(@"80 + (s mod @"1000) div @"40); + print_visible_char(@"80 + (s mod @"40)); + end else begin + print_visible_char(@"F0 + (s div @"40000)); + print_visible_char(@"80 + (s mod @"40000) div @"1000); + print_visible_char(@"80 + (s mod @"1000) div @"40); + print_visible_char(@"80 + (s mod @"40)); + end +end; +exit:end; + +@ @d native_room(#)==while native_text_size <= native_len+# do begin + native_text_size:=native_text_size+128; + native_text:=xrealloc(native_text, native_text_size * sizeof(UTF16_code)); + end +@d append_native(#)==begin native_text[native_len]:=#; incr(native_len); end + +@ @= +@!doing_special: boolean; +@!native_text: ^UTF16_code; { buffer for collecting native-font strings } +@!native_text_size: integer; { size of buffer } +@!native_len: integer; +@!save_native_len: integer; + +@ @= +doing_special:=false; +native_text_size:=128; +native_text:=xmalloc(native_text_size * sizeof(UTF16_code)); +@z + +@x +procedure print(@!s:integer); {prints string |s|} +label exit; +var j:pool_pointer; {current character code position} +@!nl:integer; {new-line character to restore} +begin if s>=str_ptr then s:="???" {this can't happen} +@.???@> +else if s<256 then + if s<0 then s:="???" {can't happen} + else begin if (selector>pseudo) and (not special_printing) + and (not message_printing) then + begin print_char(s); return; {internal strings are not expanded} + end; + if (@) then + if selector0) and (not no_convert) and (mubyte_write[s]>0) then + s := mubyte_write[s] + else if xprn[s] or special_printing then + begin print_char(s); no_convert := false; return; end; + no_convert := false; + nl:=new_line_char; new_line_char:=-1; + {temporarily disable new-line character} + j:=str_start[s]; + while j=str_ptr then s:="???" {this can't happen} +@.???@> +else if spseudo then + begin print_char(s); return; {internal strings are not expanded} + end; + if (@) then + if selector=@"D800) and (so(str_pool[j])<=@"DFFF) then + begin if (so(str_pool[j])<=@"DBFF) and (j+1=@"DC00) and (so(str_pool[j+1])<=@"DFFF) then + begin print_char(@"10000 + (so(str_pool[j])-@"D800) * @"400 + + so(str_pool[j+1])-@"DC00); j:=j+2; + end + end else begin print_char(so(str_pool[j])); incr(j); + end; +exit:end; +@z + +@x +@ Control sequence names, file names, and strings constructed with +\.{\\string} might contain |ASCII_code| values that can't +be printed using |print_char|. Therefore we use |slow_print| for them: + +@= +procedure slow_print(@!s:integer); {prints string |s|} +var j:pool_pointer; {current character code position} +begin if (s>=str_ptr) or (s<256) then print(s) +else begin j:=str_start[s]; + while j; +if c>=0 then if c<256 then print(c); +@y +begin @; +if c>=0 then if c<=biggest_usv then print_char(c); +@z + +@x +begin j:=str_start["m2d5c2l5x2v5i"]; v:=1000; +@y +begin j:=str_start_macro("m2d5c2l5x2v5i"); v:=1000; +@z + +@x +@p procedure print_current_string; {prints a yet-unmade string} +var j:pool_pointer; {points to current character code} +begin j:=str_start[str_ptr]; +@y +@p procedure print_current_string; {prints a yet-unmade string} +var j:pool_pointer; {points to current character code} +begin j:=str_start_macro(str_ptr); +@z + +@x +k:=first; while k < last do begin print_buffer(k) end; +@y +if last<>first then for k:=first to last-1 do print(buffer[k]); +@z + +@x +@* \[6] Reporting errors. +@y +@* \[6] Reporting errors. +@z + +@x + begin edit_name_start:=str_start[edit_file.name_field]; + edit_name_length:=str_start[edit_file.name_field+1] - + str_start[edit_file.name_field]; +@y + begin edit_name_start:=str_start_macro(edit_file.name_field); + edit_name_length:=str_start_macro(edit_file.name_field+1) - + str_start_macro(edit_file.name_field); +@z + +@x +@* \[7] Arithmetic with scaled dimensions. +@y +@* \[7] Arithmetic with scaled dimensions. +@z + +@x +@* \[8] Packed data. +@y +@* \[8] Packed data. +@z + +@x +@d min_quarterword=0 {smallest allowable value in a |quarterword|} +@d max_quarterword=255 {largest allowable value in a |quarterword|} +@d min_halfword==-@"FFFFFFF {smallest allowable value in a |halfword|} +@d max_halfword==@"FFFFFFF {largest allowable value in a |halfword|} +@y +@d min_quarterword=0 {smallest allowable value in a |quarterword|} +@d max_quarterword=@"FFFF {largest allowable value in a |quarterword|} +@d min_halfword==-@"FFFFFFF {smallest allowable value in a |halfword|} +@d max_halfword==@"3FFFFFFF {largest allowable value in a |halfword|} +@z + +@x +if (min_quarterword>0)or(max_quarterword<127) then bad:=11; +if (min_halfword>0)or(max_halfword<32767) then bad:=12; +@y +if (min_quarterword>0)or(max_quarterword<@"7FFF) then bad:=11; +if (min_halfword>0)or(max_halfword<@"3FFFFFFF) then bad:=12; +@z + +@x +if max_quarterword-min_quarterword<255 then bad:=19; +@y +if max_quarterword-min_quarterword<@"FFFF then bad:=19; +@z + +@x +@!word_file = file of memory_word; +@y +@!word_file = gzFile; +@z + +@x +@* \[9] Dynamic memory allocation. +@y +@* \[9] Dynamic memory allocation. +@z + +@x +@* \[10] Data structures for boxes and their friends. +@y +@* \[10] Data structures for boxes and their friends. +@z + +@x +@d whatsit_node=8 {|type| of special extension nodes} +@y +@d whatsit_node=8 {|type| of special extension nodes} + +{ added stuff here for native_word and picture nodes } +@d native_word_node=40 {|subtype| in whatsits that hold native_font words + (0-3 are used for open, write, close, special; 4 is language; pdfTeX uses up through 30-something) + +To support ``native'' fonts, we build |native_word_nodes|, which are variable size whatsits. +These have the same |width|, |depth|, and |height| fields as a |box_node|, at offsets 1-3, +and then a word containing a size field for the node, a font number, a length, and a glyph count. +Then there is a field containing a C pointer to a glyph info array; +this and the glyph count are set by |set_native_metrics|. +Copying and freeing of these nodes needs to take account of this! +This is followed by |2*length| bytes, for the actual characters of the string (in UTF-16). + +So |native_node_size|, which does not include any space for the actual text, is 6.} + +@d native_node_size=6 {size of a native_word node (plus the actual chars) -- see also xetex.h} +@d native_size(#)==mem[#+4].qqqq.b0 +@d native_font(#)==mem[#+4].qqqq.b1 +@d native_length(#)==mem[#+4].qqqq.b2 +@d native_glyph_count(#)==mem[#+4].qqqq.b3 +@d native_glyph_info_ptr(#)==mem[#+5].ptr +@d native_glyph_info_size=10 { number of bytes of info per glyph: 16-bit glyph ID, 32-bit x and y coords } + +@d free_native_glyph_info(#) == + begin + if native_glyph_info_ptr(#) <> null_ptr then begin + libc_free(native_glyph_info_ptr(#)); + native_glyph_info_ptr(#) := null_ptr; + native_glyph_count(#) := 0; + end + end + +@p procedure copy_native_glyph_info(src:pointer; dest:pointer); +var glyph_count:integer; +begin + if native_glyph_info_ptr(src) <> null_ptr then begin + glyph_count := native_glyph_count(src); + native_glyph_info_ptr(dest) := xmalloc_array(char, glyph_count * native_glyph_info_size); + memcpy(native_glyph_info_ptr(dest), native_glyph_info_ptr(src), glyph_count * native_glyph_info_size); + native_glyph_count(dest) := glyph_count; + end +end; + +@ There are also |glyph_nodes|; these are like |native_word_nodes| in having |width|, |depth|, and |height| fields, +but then they contain a glyph ID rather than size and length fields, and there's no subsidiary C pointer. + +@d glyph_node_size=5 +@d native_glyph==native_length {in |glyph_node|s, we store the glyph number here} + +@d pic_node=42 {|subtype| in whatsits that hold picture file references} +@d pdf_node=43 {|subtype| in whatsits that hold PDF page references} +@d glyph_node=44 {|subtype| in whatsits that hold glyph numbers} + +@d pdfbox_crop = 1 { |pic_box_type| values in PDF nodes } +@d pdfbox_media = 2 +@d pdfbox_bleed = 3 +@d pdfbox_trim = 4 +@d pdfbox_art = 5 + + +{Picture files are handled with nodes that include fields for the transform associated +with the picture, and a pathname for the picture file itself. +They also have +the |width|, |depth|, and |height| fields of a |box_node| at offsets 1-3. (|depth| will +always be zero, as it happens.) + +So |pic_node_size|, which does not include any space for the picture file pathname, is 7. + +pdf_nodes are just like pic_nodes, but generate a different xdv file code.} + +@d pic_node_size=8 { must sync with xetex.h } +@d pic_path_length(#)==mem[#+4].hh.b0 +@d pic_page(#)==mem[#+4].hh.b1 +@d pic_box_type(#)==mem[#+4].hh.rh { for PDF, unused in picfile } +@d pic_transform1(#)==mem[#+5].hh.lh +@d pic_transform2(#)==mem[#+5].hh.rh +@d pic_transform3(#)==mem[#+6].hh.lh +@d pic_transform4(#)==mem[#+6].hh.rh +@d pic_transform5(#)==mem[#+7].hh.lh +@d pic_transform6(#)==mem[#+7].hh.rh +@z + +@x +@* \[11] Memory layout. +@y +@* \[11] Memory layout. +@z + +@x +@* \[12] Displaying boxes. +@y +@* \[12] Displaying boxes. +@z + +@x +@ @= +case type(p) of +hlist_node,vlist_node,ins_node,whatsit_node,mark_node,adjust_node, + unset_node: print("[]"); +@y +@ @= +case type(p) of +hlist_node,vlist_node,ins_node,mark_node,adjust_node, + unset_node: print("[]"); +whatsit_node: + case subtype(p) of + native_word_node: begin + if native_font(p)<>font_in_short_display then begin + print_esc(font_id_text(native_font(p))); + print_char(" "); + font_in_short_display:=native_font(p); + end; + print_native_word(p); + end; + othercases print("[]") + endcases; +@z + +@x +@p procedure show_node_list(@!p:integer); {prints a node list symbolically} +label exit; +var n:integer; {the number of items already printed at this level} +@y +@p procedure show_node_list(@!p:integer); {prints a node list symbolically} +label exit; +var n:integer; {the number of items already printed at this level} +i:integer; {temp index for printing chars of picfile paths} +@z + +@x +@* \[15] The command codes. +@y +@* \[15] The command codes. +@z + +@x +@d math_given=69 {math code defined by \.{\\mathchardef}} +@d last_item=70 {most recent item ( \.{\\lastpenalty}, + \.{\\lastkern}, \.{\\lastskip} )} +@d max_non_prefixed_command=70 {largest command code that can't be \.{\\global}} + +@ The next codes are special; they all relate to mode-independent +assignment of values to \TeX's internal registers or tables. +Codes that are |max_internal| or less represent internal quantities +that might be expanded by `\.{\\the}'. + +@d toks_register=71 {token list register ( \.{\\toks} )} +@d assign_toks=72 {special token list ( \.{\\output}, \.{\\everypar}, etc.~)} +@d assign_int=73 {user-defined integer ( \.{\\tolerance}, \.{\\day}, etc.~)} +@d assign_dimen=74 {user-defined length ( \.{\\hsize}, etc.~)} +@d assign_glue=75 {user-defined glue ( \.{\\baselineskip}, etc.~)} +@d assign_mu_glue=76 {user-defined muglue ( \.{\\thinmuskip}, etc.~)} +@d assign_font_dimen=77 {user-defined font dimension ( \.{\\fontdimen} )} +@d assign_font_int=78 {user-defined font integer ( \.{\\hyphenchar}, + \.{\\skewchar} )} +@d set_aux=79 {specify state info ( \.{\\spacefactor}, \.{\\prevdepth} )} +@d set_prev_graf=80 {specify state info ( \.{\\prevgraf} )} +@d set_page_dimen=81 {specify state info ( \.{\\pagegoal}, etc.~)} +@d set_page_int=82 {specify state info ( \.{\\deadcycles}, + \.{\\insertpenalties} )} + {( or \.{\\interactionmode} )} +@d set_box_dimen=83 {change dimension of box ( \.{\\wd}, \.{\\ht}, \.{\\dp} )} +@d set_shape=84 {specify fancy paragraph shape ( \.{\\parshape} )} + {(or \.{\\interlinepenalties}, etc.~)} +@d def_code=85 {define a character code ( \.{\\catcode}, etc.~)} +@d def_family=86 {declare math fonts ( \.{\\textfont}, etc.~)} +@d set_font=87 {set current font ( font identifiers )} +@d def_font=88 {define a font file ( \.{\\font} )} +@d register=89 {internal register ( \.{\\count}, \.{\\dimen}, etc.~)} +@d max_internal=89 {the largest code that can follow \.{\\the}} +@d advance=90 {advance a register or parameter ( \.{\\advance} )} +@d multiply=91 {multiply a register or parameter ( \.{\\multiply} )} +@d divide=92 {divide a register or parameter ( \.{\\divide} )} +@d prefix=93 {qualify a definition ( \.{\\global}, \.{\\long}, \.{\\outer} )} + {( or \.{\\protected} )} +@d let=94 {assign a command code ( \.{\\let}, \.{\\futurelet} )} +@d shorthand_def=95 {code definition ( \.{\\chardef}, \.{\\countdef}, etc.~)} + {or \.{\\charsubdef}} +@d read_to_cs=96 {read into a control sequence ( \.{\\read} )} + {( or \.{\\readline} )} +@d def=97 {macro definition ( \.{\\def}, \.{\\gdef}, \.{\\xdef}, \.{\\edef} )} +@d set_box=98 {set a box ( \.{\\setbox} )} +@d hyph_data=99 {hyphenation data ( \.{\\hyphenation}, \.{\\patterns} )} +@d set_interaction=100 {define level of interaction ( \.{\\batchmode}, etc.~)} +@d max_command=100 {the largest command code seen at |big_switch|} +@y +@d math_given=69 {math code defined by \.{\\mathchardef}} +@d XeTeX_math_given=70 +@d last_item=71 {most recent item ( \.{\\lastpenalty}, + \.{\\lastkern}, \.{\\lastskip} )} +@d max_non_prefixed_command=71 {largest command code that can't be \.{\\global}} + +@ The next codes are special; they all relate to mode-independent +assignment of values to \TeX's internal registers or tables. +Codes that are |max_internal| or less represent internal quantities +that might be expanded by `\.{\\the}'. + +@d toks_register=72 {token list register ( \.{\\toks} )} +@d assign_toks=73 {special token list ( \.{\\output}, \.{\\everypar}, etc.~)} +@d assign_int=74 {user-defined integer ( \.{\\tolerance}, \.{\\day}, etc.~)} +@d assign_dimen=75 {user-defined length ( \.{\\hsize}, etc.~)} +@d assign_glue=76 {user-defined glue ( \.{\\baselineskip}, etc.~)} +@d assign_mu_glue=77 {user-defined muglue ( \.{\\thinmuskip}, etc.~)} +@d assign_font_dimen=78 {user-defined font dimension ( \.{\\fontdimen} )} +@d assign_font_int=79 {user-defined font integer ( \.{\\hyphenchar}, + \.{\\skewchar} )} +@d set_aux=80 {specify state info ( \.{\\spacefactor}, \.{\\prevdepth} )} +@d set_prev_graf=81 {specify state info ( \.{\\prevgraf} )} +@d set_page_dimen=82 {specify state info ( \.{\\pagegoal}, etc.~)} +@d set_page_int=83 {specify state info ( \.{\\deadcycles}, + \.{\\insertpenalties} )} + {( or \.{\\interactionmode} )} +@d set_box_dimen=84 {change dimension of box ( \.{\\wd}, \.{\\ht}, \.{\\dp} )} +@d set_shape=85 {specify fancy paragraph shape ( \.{\\parshape} )} + {(or \.{\\interlinepenalties}, etc.~)} +@d def_code=86 {define a character code ( \.{\\catcode}, etc.~)} +@d XeTeX_def_code=87 {\.{\\XeTeXmathcode}, \.{\\XeTeXdelcode}} +@d def_family=88 {declare math fonts ( \.{\\textfont}, etc.~)} +@d set_font=89 {set current font ( font identifiers )} +@d def_font=90 {define a font file ( \.{\\font} )} +@d register=91 {internal register ( \.{\\count}, \.{\\dimen}, etc.~)} +@d max_internal=91 {the largest code that can follow \.{\\the}} +@d advance=92 {advance a register or parameter ( \.{\\advance} )} +@d multiply=93 {multiply a register or parameter ( \.{\\multiply} )} +@d divide=94 {divide a register or parameter ( \.{\\divide} )} +@d prefix=95 {qualify a definition ( \.{\\global}, \.{\\long}, \.{\\outer} )} + {( or \.{\\protected} )} +@d let=96 {assign a command code ( \.{\\let}, \.{\\futurelet} )} +@d shorthand_def=97 {code definition ( \.{\\chardef}, \.{\\countdef}, etc.~)} + {or \.{\\charsubdef}} +@d read_to_cs=98 {read into a control sequence ( \.{\\read} )} + {( or \.{\\readline} )} +@d def=99 {macro definition ( \.{\\def}, \.{\\gdef}, \.{\\xdef}, \.{\\edef} )} +@d set_box=100 {set a box ( \.{\\setbox} )} +@d hyph_data=101 {hyphenation data ( \.{\\hyphenation}, \.{\\patterns} )} +@d set_interaction=102 {define level of interaction ( \.{\\batchmode}, etc.~)} +@d max_command=102 {the largest command code seen at |big_switch|} +@z + +@x +@* \[17] The table of equivalents. +@y +@* \[17] The table of equivalents. +@z + +@x +In the first region we have 256 equivalents for ``active characters'' that +act as control sequences, followed by 256 equivalents for single-character +control sequences. +@y +In the first region we have |number_chars| equivalents for ``active characters'' +that act as control sequences, followed by |number_chars| equivalents for +single-character control sequences. +@z + +@x +@d single_base=active_base+256 {equivalents of one-character control sequences} +@d null_cs=single_base+256 {equivalent of \.{\\csname\\endcsname}} +@y +@d single_base=active_base+number_usvs + {equivalents of one-character control sequences} +@d null_cs=single_base+number_usvs {equivalent of \.{\\csname\\endcsname}} +@z + +@x +@ Region 3 of |eqtb| contains the 256 \.{\\skip} registers, as well as the +glue parameters defined here. It is important that the ``muskip'' +parameters have larger numbers than the others. +@y +@ Region 3 of |eqtb| contains the |number_regs| \.{\\skip} registers, +as well as the glue parameters defined here. It is important that the +``muskip'' parameters have larger numbers than the others. +@z + +@x +@d par_fill_skip_code=14 {glue on last line of paragraph} +@d thin_mu_skip_code=15 {thin space in math formula} +@d med_mu_skip_code=16 {medium space in math formula} +@d thick_mu_skip_code=17 {thick space in math formula} +@d glue_pars=18 {total number of glue parameters} +@y +@d par_fill_skip_code=14 {glue on last line of paragraph} +@d XeTeX_linebreak_skip_code=15 {glue introduced at potential linebreak location} +@d thin_mu_skip_code=16 {thin space in math formula} +@d med_mu_skip_code=17 {medium space in math formula} +@d thick_mu_skip_code=18 {thick space in math formula} +@d glue_pars=19 {total number of glue parameters} +@z + +@x +@d skip_base=glue_base+glue_pars {table of 256 ``skip'' registers} +@d mu_skip_base=skip_base+256 {table of 256 ``muskip'' registers} +@d local_base=mu_skip_base+256 {beginning of region 4} +@y +@d skip_base=glue_base+glue_pars {table of |number_regs| ``skip'' registers} +@d mu_skip_base=skip_base+number_regs + {table of |number_regs| ``muskip'' registers} +@d local_base=mu_skip_base+number_regs {beginning of region 4} +@z + +@x +@d par_fill_skip==glue_par(par_fill_skip_code) +@y +@d par_fill_skip==glue_par(par_fill_skip_code) +@d XeTeX_linebreak_skip==glue_par(XeTeX_linebreak_skip_code) +@z + +@x +par_fill_skip_code: print_esc("parfillskip"); +@y +par_fill_skip_code: print_esc("parfillskip"); +XeTeX_linebreak_skip_code: print_esc("XeTeXlinebreakskip"); +@z + +@x +primitive("parfillskip",assign_glue,glue_base+par_fill_skip_code);@/ +@!@:par_fill_skip_}{\.{\\parfillskip} primitive@> +@y +primitive("parfillskip",assign_glue,glue_base+par_fill_skip_code);@/ +@!@:par_fill_skip_}{\.{\\parfillskip} primitive@> +primitive("XeTeXlinebreakskip",assign_glue,glue_base+XeTeX_linebreak_skip_code);@/ +@z + +@x +@d etex_toks=etex_toks_base+1 {end of \eTeX's token list parameters} +@y +@d XeTeX_inter_char_loc=every_eof_loc+1 {not really used, but serves as a flag} +@d etex_toks=XeTeX_inter_char_loc+1 {end of \eTeX's token list parameters} +@z + +@x +@d toks_base=etex_toks {table of 256 token list registers} +@# +@d etex_pen_base=toks_base+256 {start of table of \eTeX's penalties} +@d inter_line_penalties_loc=etex_pen_base {additional penalties between lines} +@d club_penalties_loc=etex_pen_base+1 {penalties for creating club lines} +@d widow_penalties_loc=etex_pen_base+2 {penalties for creating widow lines} +@d display_widow_penalties_loc=etex_pen_base+3 {ditto, just before a display} +@d etex_pens=etex_pen_base+4 {end of table of \eTeX's penalties} +@# +@d box_base=etex_pens {table of 256 box registers} +@d cur_font_loc=box_base+256 {internal font number outside math mode} +@d xord_code_base=cur_font_loc+1 +@d xchr_code_base=xord_code_base+1 +@d xprn_code_base=xchr_code_base+1 +@d math_font_base=xprn_code_base+1 +@d cat_code_base=math_font_base+48 + {table of 256 command codes (the ``catcodes'')} +@d lc_code_base=cat_code_base+256 {table of 256 lowercase mappings} +@d uc_code_base=lc_code_base+256 {table of 256 uppercase mappings} +@d sf_code_base=uc_code_base+256 {table of 256 spacefactor mappings} +@d math_code_base=sf_code_base+256 {table of 256 math mode mappings} +@d char_sub_code_base=math_code_base+256 {table of character substitutions} +@d int_base=char_sub_code_base+256 {beginning of region 5} +@y +@d toks_base=etex_toks {table of number_regs token list registers} +@# +@d etex_pen_base=toks_base+number_regs {start of table of \eTeX's penalties} +@d inter_line_penalties_loc=etex_pen_base {additional penalties between lines} +@d club_penalties_loc=etex_pen_base+1 {penalties for creating club lines} +@d widow_penalties_loc=etex_pen_base+2 {penalties for creating widow lines} +@d display_widow_penalties_loc=etex_pen_base+3 {ditto, just before a display} +@d etex_pens=etex_pen_base+4 {end of table of \eTeX's penalties} +@# +@d box_base=etex_pens {table of number_regs box registers} +@d cur_font_loc=box_base+number_regs {internal font number outside math mode} +@d math_font_base=cur_font_loc+1 +@d cat_code_base=math_font_base+number_math_fonts + {table of number_chars command codes (the ``catcodes'')} +@d lc_code_base=cat_code_base+number_usvs {table of number_chars lowercase mappings} +@d uc_code_base=lc_code_base+number_usvs {table of number_chars uppercase mappings} +@d sf_code_base=uc_code_base+number_usvs {table of number_chars spacefactor mappings} +@d math_code_base=sf_code_base+number_usvs {table of number_chars math mode mappings} +@d char_sub_code_base=math_code_base+number_usvs {table of character substitutions} +@d int_base=char_sub_code_base+number_usvs {beginning of region 5} +@z + +@x +@d var_code==@'70000 {math code meaning ``use the current family''} +@y +@d var_fam_class = 7 +@d active_math_char = @"1FFFFF +@d is_active_math_char(#) == math_char_field(#) = active_math_char +@d is_var_family(#) == math_class_field(#) = 7 +@z + +@x +for k:=output_routine_loc to toks_base+255 do +@y +for k:=output_routine_loc to toks_base+number_regs-1 do +@z + +@x +for k:=box_base+1 to box_base+255 do eqtb[k]:=eqtb[box_base]; +@y +for k:=box_base+1 to box_base+number_regs-1 do eqtb[k]:=eqtb[box_base]; +@z + +@x +for k:=math_font_base to math_font_base+47 do eqtb[k]:=eqtb[cur_font_loc]; +@y +for k:=math_font_base to math_font_base+number_math_fonts-1 do eqtb[k]:=eqtb[cur_font_loc]; +@z + +@x +for k:=0 to 255 do +@y +for k:=0 to number_usvs-1 do +@z + +@x +for k:="0" to "9" do math_code(k):=hi(k+var_code); +@y +for k:="0" to "9" do math_code(k):=hi(k + set_class_field(var_fam_class)); +@z + +@x + math_code(k):=hi(k+var_code+@"100); + math_code(k+"a"-"A"):=hi(k+"a"-"A"+var_code+@"100);@/ +@y + math_code(k) := hi(k + set_family_field(1) + set_class_field(var_fam_class)); + math_code(k+"a"-"A") := hi(k+"a"-"A" + set_family_field(1) + set_class_field(var_fam_class));@/ +@z + +@x +begin if n=cur_font_loc then print("current font") +else if n +@y +primitive("errorcontextlines",assign_int,int_base+error_context_lines_code);@/ +@!@:error_context_lines_}{\.{\\errorcontextlines} primitive@> +primitive("XeTeXlinebreakpenalty",assign_int,int_base+XeTeX_linebreak_penalty_code);@/ +@z + +@x +if enctex_p then + begin enctex_enabled_p:=true; + primitive("mubytein",assign_int,int_base+mubyte_in_code);@/ +@!@:mubyte_in_}{\.{\\mubytein} primitive@> + primitive("mubyteout",assign_int,int_base+mubyte_out_code);@/ +@!@:mubyte_out_}{\.{\\mubyteout} primitive@> + primitive("mubytelog",assign_int,int_base+mubyte_log_code);@/ +@!@:mubyte_log_}{\.{\\mubytelog} primitive@> + primitive("specialout",assign_int,int_base+spec_out_code);@/ +@!@:spec_out_}{\.{\\specialout} primitive@> +end; +@y +@z + +@x +for k:=0 to 255 do del_code(k):=-1; +del_code("."):=0; {this null delimiter is used in error recovery} +@y +for k:=0 to number_chars-1 do del_code(k):=-1; +del_code("."):=0; {this null delimiter is used in error recovery} +@z + +@x +@ The final region of |eqtb| contains the dimension parameters defined +here, and the 256 \.{\\dimen} registers. +@y +@ The final region of |eqtb| contains the dimension parameters defined +here, and the |number_regs| \.{\\dimen} registers. +@z + +@x +@d emergency_stretch_code=20 {reduces badnesses on final pass of line-breaking} +@d dimen_pars=21 {total number of dimension parameters} +@y +@d emergency_stretch_code=20 {reduces badnesses on final pass of line-breaking} +@d pdf_page_width_code=21 {page width of the PDF output} +@d pdf_page_height_code=22 {page height of the PDF output} +@d dimen_pars=23 {total number of dimension parameters} +@z + +@x +@d scaled_base=dimen_base+dimen_pars + {table of 256 user-defined \.{\\dimen} registers} +@d eqtb_size=scaled_base+255 {largest subscript of |eqtb|} +@y +@d scaled_base=dimen_base+dimen_pars + {table of |number_regs| user-defined \.{\\dimen} registers} +@d eqtb_size=scaled_base+biggest_reg {largest subscript of |eqtb|} +@z + +@x +@d emergency_stretch==dimen_par(emergency_stretch_code) +@y +@d emergency_stretch==dimen_par(emergency_stretch_code) +@d pdf_page_width == dimen_par(pdf_page_width_code) +@d pdf_page_height == dimen_par(pdf_page_height_code) +@z + +@x +emergency_stretch_code:print_esc("emergencystretch"); +@y +emergency_stretch_code:print_esc("emergencystretch"); +pdf_page_width_code: print_esc("pdfpagewidth"); +pdf_page_height_code: print_esc("pdfpageheight"); +@z + +@x +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("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@> +@z + +@x +for q:=active_base to box_base+255 do +@y +for q:=active_base to box_base+biggest_reg do +@z + +@x +@* \[18] The hash table. +@y +@* \[18] The hash table. +@z + +@x +begin @; +p:=h+hash_base; {we start searching here; note that |0<=h0 then if length(text(p))=l then +@y +@!ll:integer; {length in utf16 code units} +begin @; +p:=h+hash_base; {we start searching here; note that |0<=h=@"10000 then incr(ll); +loop@+begin if text(p)>0 then if length(text(p))=ll then +@z + +@x +str_room(l); d:=cur_length; +while pool_ptr>str_start[str_ptr] do +@y +str_room(ll); d:=cur_length; +while pool_ptr>str_start_macro(str_ptr) do +@z + +@x +for k:=j to j+l-1 do append_char(buffer[k]); +@y +for k:=j to j+l-1 do begin + if buffer[k]<@"10000 then append_char(buffer[k]) + else begin + append_char(@"D800+(buffer[k]-@"10000)div@"400); + append_char(@"DC00+(buffer[k]-@"10000)mod@"400); + end +end; +@z + +@x +The conversion from control sequence to byte sequence for enc\TeX is +implemented here. Of course, the simplest way is to implement an array +of string pointers with |hash_size| length, but we assume that only a +few control sequences will need to be converted. So |mubyte_cswrite|, +an array with only 128 items, is used. The items point to the token +lists. First token includes a csname number and the second points the +string to be output. The third token includes the number of another +csname and fourth token its pointer to the string etc. We need to do +the sequential searching in one of the 128 token lists. +@y +@z + +@x +procedure print_cs(@!p:integer); {prints a purported control sequence} +var q: pointer; + s: str_number; +begin + if active_noconvert and (not no_convert) and + (eq_type(p) = let) and (equiv(p) = normal+11) then { noconvert } + begin + no_convert := true; + return; + end; + s := 0; + if cs_converting and (not no_convert) then + begin + q := mubyte_cswrite [p mod 128] ; + while q <> null do + if info (q) = p then + begin + s := info (link(q)); q := null; + end else q := link (link (q)); + end; + no_convert := false; + if s > 0 then print (s) + else if p +end; +@y +@z + +@x +primitive("mathaccent",math_accent,0);@/ +@y +primitive("mathaccent",math_accent,0);@/ +primitive("XeTeXmathaccent",math_accent,1);@/ +@z + +@x +primitive("mathchar",math_char_num,0);@/ +@!@:math_char_}{\.{\\mathchar} primitive@> +@y +primitive("mathchar",math_char_num,0);@/ +primitive("XeTeXmathcharnum",math_char_num,1);@/ +primitive("XeTeXmathchar",math_char_num,2);@/ +@!@:math_char_}{\.{\\mathchar} primitive@> +@z + +@x +primitive("radical",radical,0);@/ +@y +primitive("radical",radical,0);@/ +primitive("XeTeXradical",radical,1);@/ +@z + +@x +primitive("relax",relax,256); {cf.\ |scan_file_name|} +@y +primitive("relax",relax,too_big_char); {cf.\ |scan_file_name|} +@z + +@x +delim_num: print_esc("delimiter"); +@y +delim_num: if chr_code=1 then print_esc("XeTeXdelimiter") + else print_esc("delimiter"); +@z + +@x +end_cs_name: if chr_code = 10 then print_esc("endmubyte") + else print_esc("endcsname"); +@y +end_cs_name: print_esc("endcsname"); +@z + +@x +math_accent: print_esc("mathaccent"); +@y +math_accent: if chr_code=1 then print_esc("XeTeXmathaccent") + else print_esc("mathaccent"); +@z + +@x +math_char_num: print_esc("mathchar"); +@y +math_char_num: if chr_code=2 then print_esc("XeTeXmathchar") + else if chr_code=1 then print_esc("XeTeXmathcharnum") + else print_esc("mathchar"); +@z + +@x +radical: print_esc("radical"); +@y +radical: if chr_code=1 then print_esc("XeTeXradical") else print_esc("radical"); +@z + +@x +@* \[19] Saving and restoring equivalents. +@y +@* \[19] Saving and restoring equivalents. +@z + +@x +@* \[20] Token lists. +@y +@* \[20] Token lists. +@z + +@x +A \TeX\ token is either a character or a control sequence, and it is +@^token@> +represented internally in one of two ways: (1)~A character whose ASCII +code number is |c| and whose command code is |m| is represented as the +number $2^8m+c$; the command code is in the range |1<=m<=14|. (2)~A control +sequence whose |eqtb| address is |p| is represented as the number +|cs_token_flag+p|. Here |cs_token_flag=@t$2^{12}-1$@>| is larger than +$2^8m+c$, yet it is small enough that |cs_token_flag+p< max_halfword|; +thus, a token fits comfortably in a halfword. +@y +A \TeX\ token is either a character or a control sequence, and it is +@^token@> +represented internally in one of two ways: (1)~A character whose ASCII +code number is |c| and whose command code is |m| is represented as the +number $2^16m+c$; the command code is in the range |1<=m<=14|. (2)~A control +sequence whose |eqtb| address is |p| is represented as the number +|cs_token_flag+p|. Here |cs_token_flag=@t$2^{20}-1$@>| is larger than +$2^8m+c$, yet it is small enough that |cs_token_flag+p< max_halfword|; +thus, a token fits comfortably in a halfword. +@z + +@x +@d cs_token_flag==@'7777 {amount added to the |eqtb| location in a + token that stands for a control sequence; is a multiple of~256, less~1} +@d left_brace_token=@'0400 {$2^8\cdot|left_brace|$} +@d left_brace_limit=@'1000 {$2^8\cdot(|left_brace|+1)$} +@d right_brace_token=@'1000 {$2^8\cdot|right_brace|$} +@d right_brace_limit=@'1400 {$2^8\cdot(|right_brace|+1)$} +@d math_shift_token=@'1400 {$2^8\cdot|math_shift|$} +@d tab_token=@'2000 {$2^8\cdot|tab_mark|$} +@d out_param_token=@'2400 {$2^8\cdot|out_param|$} +@d space_token=@'5040 {$2^8\cdot|spacer|+|" "|$} +@d letter_token=@'5400 {$2^8\cdot|letter|$} +@d other_token=@'6000 {$2^8\cdot|other_char|$} +@d match_token=@'6400 {$2^8\cdot|match|$} +@d end_match_token=@'7000 {$2^8\cdot|end_match|$} +@d protected_token=@'7001 {$2^8\cdot|end_match|+1$} +@y +@d cs_token_flag= @"1FFFFFF {@"FFFFF amount added to the |eqtb| location in a + token that stands for a control sequence; is a multiple of~65536, less~1} +@d max_char_val= @"200000 {@"10000 to separate char and command code} +@d left_brace_token= @"200000 {@"10000 $2^16\cdot|left_brace|$} +@d left_brace_limit= @"400000 {@"20000 $2^16\cdot(|left_brace|+1)$} +@d right_brace_token= @"400000 {@"20000 $2^16\cdot|right_brace|$} +@d right_brace_limit= @"600000 {@"30000 $2^16\cdot(|right_brace|+1)$} +@d math_shift_token= @"600000 {@"30000 $2^16\cdot|math_shift|$} +@d tab_token= @"800000 {@"40000 $2^16\cdot|tab_mark|$} +@d out_param_token= @"A00000 {@"50000 $2^16\cdot|out_param|$} +@d space_token= @"1400020 {@"A0020 $2^16\cdot|spacer|+|" "|$} +@d letter_token= @"1600000 {@"B0000 $2^16\cdot|letter|$} +@d other_token= @"1800000 {@"C0000 $2^16\cdot|other_char|$} +@d match_token= @"1A00000 {@"D0000 $2^16\cdot|match|$} +@d end_match_token= @"1C00000 {@"E0000 $2^16\cdot|end_match|$} + +@d protected_token=end_match_token+1 {$2^8\cdot|end_match|+1$} +@z + +@x +procedure show_token_list(@!p,@!q:integer;@!l:integer); +label exit; +var m,@!c:integer; {pieces of a token} +@!match_chr:ASCII_code; {character used in a `|match|'} +@y +procedure show_token_list(@!p,@!q:integer;@!l:integer); +label exit; +var m,@!c:integer; {pieces of a token} +@!match_chr:integer; {character used in a `|match|'} +@z + +@x +else begin m:=info(p) div @'400; c:=info(p) mod @'400; +@y +else begin m:=info(p) div max_char_val; c:=info(p) mod max_char_val; +@z + +@x +@= +case m of +left_brace,right_brace,math_shift,tab_mark,sup_mark,sub_mark,spacer, + letter,other_char: print(c); +mac_param: begin print(c); print(c); + end; +out_param: begin print(match_chr); + if c<=9 then print_char(c+"0") + else begin print_char("!"); return; + end; + end; +match: begin match_chr:=c; print(c); incr(n); print_char(n); +@y +@= +case m of +left_brace,right_brace,math_shift,tab_mark,sup_mark,sub_mark,spacer, + letter,other_char: print_char(c); +mac_param: begin print_char(c); print_char(c); + end; +out_param: begin print_char(match_chr); + if c<=9 then print_char(c+"0") + else begin print_char("!"); return; + end; + end; +match: begin match_chr:=c; print_char(c); incr(n); print_char(n); +@z + +@x +@* \[21] Introduction to the syntactic routines. +@y +@* \[21] Introduction to the syntactic routines. +@z + +@x +procedure print_cmd_chr(@!cmd:quarterword;@!chr_code:halfword); +var n:integer; {temp variable} +@y +procedure print_cmd_chr(@!cmd:quarterword;@!chr_code:halfword); +var n:integer; {temp variable} +@!font_name_str:str_number; {local vars for \.{\\fontname} quoting extension} +@!quote_char:UTF16_code; +@z + +@x +@* \[22] Input stacks and states. +@y +@* \[22] Input stacks and states. +@z + +@x +@!input_file : ^alpha_file; +@y +@!input_file : ^unicode_file; +@z + +@x +@d inserted=4 {|token_type| code for inserted texts} +@d macro=5 {|token_type| code for defined control sequences} +@d output_text=6 {|token_type| code for output routines} +@d every_par_text=7 {|token_type| code for \.{\\everypar}} +@d every_math_text=8 {|token_type| code for \.{\\everymath}} +@d every_display_text=9 {|token_type| code for \.{\\everydisplay}} +@d every_hbox_text=10 {|token_type| code for \.{\\everyhbox}} +@d every_vbox_text=11 {|token_type| code for \.{\\everyvbox}} +@d every_job_text=12 {|token_type| code for \.{\\everyjob}} +@d every_cr_text=13 {|token_type| code for \.{\\everycr}} +@d mark_text=14 {|token_type| code for \.{\\topmark}, etc.} +@# +@d eTeX_text_offset=output_routine_loc-output_text +@y +@d backed_up_char=4 {special code for backed-up char from \\XeTeXinterchartoks hook} +@d inserted=5 {|token_type| code for inserted texts} +@d macro=6 {|token_type| code for defined control sequences} +@d output_text=7 {|token_type| code for output routines} +@d every_par_text=8 {|token_type| code for \.{\\everypar}} +@d every_math_text=9 {|token_type| code for \.{\\everymath}} +@d every_display_text=10 {|token_type| code for \.{\\everydisplay}} +@d every_hbox_text=11 {|token_type| code for \.{\\everyhbox}} +@d every_vbox_text=12 {|token_type| code for \.{\\everyvbox}} +@d every_job_text=13 {|token_type| code for \.{\\everyjob}} +@d every_cr_text=14 {|token_type| code for \.{\\everycr}} +@d mark_text=15 {|token_type| code for \.{\\topmark}, etc.} +@d inter_char_text=16 {text from \\XeTeXinterchartoks} +@# +@d eTeX_text_offset=output_routine_loc-output_text-1 {1 more to make space for the inter_char_text} +@z + +@x +backed_up: if loc=null then print_nl(" ") +@y +backed_up_char,backed_up: if loc=null then print_nl(" ") +@z + +@x +every_eof_text: print_nl(" "); +@y +inter_char_text: print_nl(" "); +every_eof_text: print_nl(" "); +@z + +@x +for q:=p to first_count-1 do print_char(trick_buf[q mod error_line]); +print_ln; +for q:=1 to n do print_char(" "); {print |n| spaces to begin line~2} +if m+n<=error_line then p:=first_count+m else p:=first_count+(error_line-n-3); +for q:=first_count to p-1 do print_char(trick_buf[q mod error_line]); +@y +for q:=p to first_count-1 do print_visible_char(trick_buf[q mod error_line]); +print_ln; +for q:=1 to n do print_visible_char(" "); {print |n| spaces to begin line~2} +if m+n<=error_line then p:=first_count+m else p:=first_count+(error_line-n-3); +for q:=first_count to p-1 do print_visible_char(trick_buf[q mod error_line]); +@z + +@x +i := start; mubyte_skeep := mubyte_keep; +mubyte_sstart := mubyte_start; mubyte_start := false; +if j>0 then while i < j do +begin + if i=loc then set_trick_count; + print_buffer(i); +end; +mubyte_keep := mubyte_skeep; mubyte_start := mubyte_sstart +@y +if j>0 then for i:=start to j-1 do + begin if i=loc then set_trick_count; + print_char(buffer[i]); + end +@z + +@x +@* \[23] Maintaining the input stacks. +@y +@* \[23] Maintaining the input stacks. +@z + +@x + othercases print_cmd_chr(assign_toks,t-output_text+output_routine_loc) +@y + othercases print_cmd_chr(assign_toks,t-output_text+output_routine_loc+1) +@z + +@x +if name>17 then a_close(cur_file); {forget it} +@y +if name>17 then u_close(cur_file); {forget it} +@z + +@x +@* \[24] Getting the next token. +@y +@* \[24] Getting the next token. +@z + +@x +Some additional routines used by the enc\TeX extension have to be +declared at this point. + +@p @t\4@>@@/ + +@y +@z + +@x +primitive("par",par_end,256); {cf. |scan_file_name|} +@y +primitive("par",par_end,too_big_char); {cf. |scan_file_name|} +@z + +@x +@d start_cs=26 {another} +@y +@d start_cs=26 {another} +@d not_exp=27 +@z + +@x + exit; {go here when the next input token has been got} +@y + not_exp, {go here when ^^ turned out not to start an expanded code} + exit; {go here when the next input token has been got} +@z + +@x +@!i,@!j: 0..buf_size; {more indexes for encTeX} +@!mubyte_incs: boolean; {control sequence is converted by mubyte} +@!p:pointer; {for encTeX test if noexpanding} +@y +@z + +@x +@!c,@!cc:ASCII_code; {constituents of a possible expanded code} +@!d:2..3; {number of excess characters in an expanded code} +@y +@!c:UnicodeScalar; {constituent of a possible expanded code} +@!d:small_number; {number of excess characters in an expanded code} +@!sup_count:small_number; {number of identical sup_mark characters} +@z + +@x + begin + { Use |k| instead of |loc| for type correctness. } + k := loc; + cur_chr := read_buffer (k); + loc := k; incr (loc); + if (mubyte_token > 0) then + begin + state := mid_line; + cur_cs := mubyte_token - cs_token_flag; + goto found; + end; +@y + begin cur_chr:=buffer[loc]; incr(loc); +@z + +@x +@d hex_to_cur_chr== + if c<="9" then cur_chr:=c-"0" @+else cur_chr:=c-"a"+10; + if cc<="9" then cur_chr:=16*cur_chr+cc-"0" + else cur_chr:=16*cur_chr+cc-"a"+10 +@y +@d hex_to_cur_chr== + if c<="9" then cur_chr:=c-"0" @+else cur_chr:=c-"a"+10; + if cc<="9" then cur_chr:=16*cur_chr+cc-"0" + else cur_chr:=16*cur_chr+cc-"a"+10 +@d long_hex_to_cur_chr== + if c<="9" then cur_chr:=c-"0" @+else cur_chr:=c-"a"+10; + if cc<="9" then cur_chr:=16*cur_chr+cc-"0" + else cur_chr:=16*cur_chr+cc-"a"+10; + if ccc<="9" then cur_chr:=16*cur_chr+ccc-"0" + else cur_chr:=16*cur_chr+ccc-"a"+10; + if cccc<="9" then cur_chr:=16*cur_chr+cccc-"0" + else cur_chr:=16*cur_chr+cccc-"a"+10 +@z + +@x +@= +begin if cur_chr=buffer[loc] then if loc= +begin if cur_chr=buffer[loc] then if locbiggest_usv then + begin cur_chr:=buffer[loc]; + goto not_exp; + end; + loc:=loc+2*sup_count-1; + goto reswitch; + end; +not_exp: +state:=mid_line; +end +@z + +@x +else begin start_cs: + mubyte_incs := false; k := loc; mubyte_skeep := mubyte_keep; + cur_chr := read_buffer (k); cat := cat_code (cur_chr); + if (mubyte_in>0) and (not mubyte_incs) and + ((mubyte_skip>0) or (cur_chr<>buffer[k])) then mubyte_incs := true; + incr (k); + if mubyte_token > 0 then + begin + state := mid_line; + cur_cs := mubyte_token - cs_token_flag; + goto found; + end; +@y +else begin start_cs: k:=loc; cur_chr:=buffer[k]; cat:=cat_code(cur_chr); + incr(k); +@z + +@x + mubyte_keep := mubyte_skeep; + cur_cs:=single_base + read_buffer(loc); incr(loc); +@y + cur_cs:=single_base+buffer[loc]; incr(loc); +@z + +@x +if write_noexpanding then +begin + p := mubyte_cswrite [cur_cs mod 128]; + while p <> null do + if info (p) = cur_cs then + begin + cur_cmd := relax; cur_chr := 256; p := null; + end else p := link (link (p)); +end; +@y +@z + +@x +@= +begin if buffer[k]=cur_chr then @+if cat=sup_mark then @+if k2 then + begin hex_to_cur_chr; buffer[k-1]:=cur_chr; + end + else if c<@'100 then buffer[k-1]:=c+@'100 + else buffer[k-1]:=c-@'100; + limit:=limit-d; first:=first-d; + while k<=limit do + begin buffer[k]:=buffer[k+d]; incr(k); + end; + goto start_cs; + end; + end; +end +@y +@= +begin if (cat=sup_mark) and (buffer[k]=cur_chr) and (k0 then {there were the right number of hex chars, so convert them} + begin cur_chr:=0; + for d:=1 to sup_count do + begin c:=buffer[k+sup_count-2+d]; + if c<="9" then cur_chr:=16*cur_chr+c-"0" + else cur_chr:=16*cur_chr+c-"a"+10; + end; + {check the resulting value is within the valid range} + if cur_chr>biggest_usv then cur_chr:=buffer[k] + else begin buffer[k-1]:=cur_chr; + d:=2*sup_count-1; + {shift the rest of the buffer left by |d| chars} + limit:=limit-d; + while k<=limit do + begin buffer[k]:=buffer[k+d]; incr(k); + end; + goto start_cs; + end + end + end +end +@z + +@x +@ @= +begin + repeat cur_chr := read_buffer (k); cat := cat_code (cur_chr); + if mubyte_token>0 then cat := escape; + if (mubyte_in>0) and (not mubyte_incs) and (cat=letter) and + ((mubyte_skip>0) or (cur_chr<>buffer[k])) then mubyte_incs := true; + incr (k); + until (cat <> letter) or (k > limit); + @; + if cat <> letter then + begin + decr (k); k := k - mubyte_skip; + end; + if k > loc + 1 then { multiletter control sequence has been scanned } + begin + if mubyte_incs then { multibyte in csname occurrs } + begin + i := loc; j := first; mubyte_keep := mubyte_skeep; + if j - loc + k > max_buf_stack then + begin + max_buf_stack := j - loc + k; + if max_buf_stack >= buf_size then + begin + max_buf_stack := buf_size; + overflow ("buffer size", buf_size); + end; + end; + while i < k do + begin + buffer [j] := read_buffer (i); + incr (i); incr (j); + end; + if j = first+1 then + cur_cs := single_base + buffer [first] + else + cur_cs := id_lookup (first, j-first); + end else cur_cs := id_lookup (loc, k-loc) ; + loc := k; + goto found; + end; +end +@y +@ @= +begin repeat cur_chr:=buffer[k]; cat:=cat_code(cur_chr); incr(k); +until (cat<>letter)or(k>limit); +@; +if cat<>letter then decr(k); + {now |k| points to first nonletter} +if k>loc+1 then {multiletter control sequence has been scanned} + begin cur_cs:=id_lookup(loc,k-loc); loc:=k; goto found; + end; +end +@z + +@x + if write_noexpanding then + begin + p := mubyte_cswrite [cur_cs mod 128]; + while p <> null do + if info (p) = cur_cs then + begin + cur_cmd := relax; cur_chr := 256; p := null; + end else p := link (link (p)); + end; +@y +@z + +@x + else begin cur_cmd:=t div @'400; cur_chr:=t mod @'400; +@y + else begin cur_cmd:=t div max_char_val; cur_chr:=t mod max_char_val; +@z + +@x +@d no_expand_flag=257 {this characterizes a special variant of |relax|} +@y +@d no_expand_flag=special_char {this characterizes a special variant of |relax|} +@z + +@x + k := start; + while k < limit do begin print_buffer(k) end; +@y + if startmatch_token+255)or(info(r)=end_match_token)or(info(r) + if (cur_cs=0)and@| + ((cur_chr=s)or(cur_chr=s-"a"+"A")) then + begin store_new_token(cur_tok); + flush_list(link(backup_head)); scan_keyword:=true; return; + end + else if (cur_cmd<>spacer)or(p<>backup_head) then + begin back_input; + if p<>backup_head then back_list(link(backup_head)); + scan_keyword:=false; return; + end; + end; + end; +k:=str_start_macro(s); +while k; +@y +def_code: @; +XeTeX_def_code: + begin + scan_usv_num; + if m=sf_code_base then begin + scanned_result(ho(sf_code(cur_val) div @"10000))(int_val) + end + else if m=math_code_base then begin + scanned_result(ho(math_code(cur_val)))(int_val) + end + else if m=math_code_base+1 then begin + print_err("Can't use \XeTeXmathcode as a number (try \XeTeXmathcodenum)"); + help2("\XeTeXmathcode is for setting a mathcode from separate values;")@/ + ("use \XeTeXmathcodenum to access them as single values."); error; + scanned_result(0)(int_val) + end + else if m=del_code_base then begin + scanned_result(ho(del_code(cur_val)))(int_val) + end else begin + print_err("Can't use \XeTeXdelcode as a number (try \XeTeXdelcodenum)"); + help2("\XeTeXdelcode is for setting a delcode from separate values;")@/ + ("use \XeTeXdelcodenum to access them as single values."); error; + scanned_result(0)(int_val); + end; + end; +@z + +@x +@ @= +begin scan_char_num; +@y +@ @= +begin scan_usv_num; +@z + +@x +if m=xord_code_base then scanned_result(xord[cur_val])(int_val) +else if m=xchr_code_base then scanned_result(xchr[cur_val])(int_val) +else if m=xprn_code_base then scanned_result(xprn[cur_val])(int_val) +else if m=math_code_base then scanned_result(ho(math_code(cur_val)))(int_val) +@y +if m=math_code_base then begin + cur_val1:=ho(math_code(cur_val)); + if is_active_math_char(cur_val1) then + cur_val1:=@"8000 + else if (math_class_field(cur_val1)>7) or + (math_fam_field(cur_val1)>15) or + (math_char_field(cur_val1)>255) then + begin print_err("Extended mathchar used as mathchar"); +@.Bad mathchar@> + help2("A mathchar number must be between 0 and ""7FFF.")@/ + ("I changed this one to zero."); int_error(cur_val1); cur_val1:=0; + end; + cur_val1:=(math_class_field(cur_val1)*@"1000) + + (math_fam_field(cur_val1)*@"100) + + math_char_field(cur_val1); + scanned_result(cur_val1)(int_val) + end +else if m=del_code_base then begin + cur_val1:=del_code(cur_val); + if cur_val1>=@"40000000 then begin + print_err("Extended delcode used as delcode"); +@.Bad delcode@> + help2("A delimiter code must be between 0 and ""7FFFFFF.")@/ + ("I changed this one to zero."); error; + scanned_result(0)(int_val); + end else begin + scanned_result(cur_val1)(int_val); + end +end +@z + +@x +else if m255) then + begin print_err("Bad register code"); +@.Bad register code@> + help2("A register number must be between 0 and 255.")@/ +@y +procedure scan_char_class; +begin scan_int; +if (cur_val<0)or(cur_val>256) then + begin print_err("Bad character class"); +@.Bad character code@> + help2("A character class must be between 0 and 256.")@/ + ("I changed this one to zero."); int_error(cur_val); cur_val:=0; + end; +end; + +procedure scan_eight_bit_int; +begin scan_int; +if (cur_val<0)or(cur_val>255) then + begin print_err("Bad register code"); +@.Bad register code@> + help2("A register code or char class must be between 0 and 255.")@/ +@z + +@x +procedure scan_char_num; +begin scan_int; +if (cur_val<0)or(cur_val>255) then +@y +procedure scan_usv_num; +begin scan_int; +if (cur_val<0)or(cur_val>@"10FFFF) then + begin print_err("Bad USV code"); +@.Bad character code@> + help2("A Unicode Scalar Value must be between 0 and ""10FFFF.")@/ + ("I changed this one to zero."); int_error(cur_val); cur_val:=0; + end; +end; + +procedure scan_char_num; +begin scan_int; +if (cur_val<0)or(cur_val>biggest_char) then +@z + +@x + help2("A character number must be between 0 and 255.")@/ +@y + help2("A character number must be between 0 and 65535.")@/ +@z + +@x +procedure scan_four_bit_int; +@y +procedure scan_xetex_math_char_int; +begin scan_int; + if is_active_math_char(cur_val) then begin + if cur_val <> active_math_char then begin + print_err("Bad active XeTeX math code"); + help2("Since I ignore class and family for active math chars,")@/ + ("I changed this one to ""1FFFFF."); int_error(cur_val); + cur_val := active_math_char; + end + end else if math_char_field(cur_val) > @"10FFFF then begin + print_err("Bad XeTeX math character code"); + help2("Since I expected a character number between 0 and ""10FFFF,")@/ + ("I changed this one to zero."); int_error(cur_val); cur_val:=0; + end; +end; + +procedure scan_math_class_int; +begin scan_int; +if (cur_val<0)or(cur_val>7) then + begin print_err("Bad math class"); +@.Bad number@> + help2("Since I expected to read a number between 0 and 7,")@/ + ("I changed this one to zero."); int_error(cur_val); cur_val:=0; + end; +end; + +procedure scan_math_fam_int; +begin scan_int; +if (cur_val<0)or(cur_val>number_math_families-1) then + begin print_err("Bad math family"); +@.Bad number@> + help2("Since I expected to read a number between 0 and 255,")@/ + ("I changed this one to zero."); int_error(cur_val); cur_val:=0; + end; +end; + +procedure scan_four_bit_int; +@z + +@x +procedure scan_twenty_seven_bit_int; +begin scan_int; +if (cur_val<0)or(cur_val>@'777777777) then + begin print_err("Bad delimiter code"); +@.Bad delimiter code@> + help2("A numeric delimiter code must be between 0 and 2^{27}-1.")@/ + ("I changed this one to zero."); int_error(cur_val); cur_val:=0; + end; +end; +@y +procedure scan_delimiter_int; +begin scan_int; +if (cur_val<0)or(cur_val>@'777777777) then + begin print_err("Bad delimiter code"); +@.Bad delimiter code@> + help2("A numeric delimiter code must be between 0 and 2^{27}-1.")@/ + ("I changed this one to zero."); int_error(cur_val); cur_val:=0; + end; +end; +@z + +@x +if cur_val>255 then +@y +if cur_val>biggest_usv then +@z + +@x +@p procedure scan_dimen(@!mu,@!inf,@!shortcut:boolean); +@y +@p procedure xetex_scan_dimen(@!mu,@!inf,@!shortcut,@!requires_units:boolean); +@z + +@x +@; +@; +@y +if requires_units then begin +@; +@; +end else begin + if cur_val>=@'40000 then arith_error:=true + else cur_val:=cur_val*unity+f; +end; +@z + +@x +@ @= +@y +procedure scan_dimen(@!mu,@!inf,@!shortcut:boolean); +begin + xetex_scan_dimen(mu,inf,shortcut,true); +end; + +@ For XeTeX, we have an additional version |scan_decimal|, like |scan_dimen| +but without any scanning of units. + +@p procedure scan_decimal; + {sets |cur_val| to a quantity expressed as a decimal fraction} +begin + xetex_scan_dimen(false, false, false, false); +end; + +@ @= +@z + +@x +@d etex_convert_base=5 {base for \eTeX's command codes} +@d eTeX_revision_code=etex_convert_base {command code for \.{\\eTeXrevision}} +@d etex_convert_codes=etex_convert_base+1 {end of \eTeX's command codes} +@y +@d etex_convert_base=5 {base for \eTeX's command codes} +@d eTeX_revision_code=etex_convert_base {command code for \.{\\eTeXrevision}} + +@d XeTeX_revision_code=6 +@d XeTeX_variation_name_code=7 { must match codes in xetexmac.c } +@d XeTeX_feature_name_code=8 +@d XeTeX_selector_name_code=9 +@d XeTeX_glyph_name_code=10 + +@d etex_convert_codes=XeTeX_glyph_name_code+1 {end of \eTeX's command codes} +@z + +@x + eTeX_revision_code: print_esc("eTeXrevision"); +@y + @/@@/ +@z + +@x +@!c:number_code..job_name_code; {desired type of conversion} +@y +@!c:small_number; {desired type of conversion} +@z + +@x +@!b:pool_pointer; {base of temporary string} +@y +@!b:pool_pointer; {base of temporary string} +@!fnt,@!arg1,@!arg2:integer; {args for \XeTeX\ extensions} +@!font_name_str:str_number; {local vars for \.{\\fontname} quoting extension} +@!i:small_number; +@!quote_char:UTF16_code; +@z + +@x +eTeX_revision_code: do_nothing; +@y +@/@@/ +@z + +@x +font_name_code: begin print(font_name[cur_val]); +@y +font_name_code: begin + font_name_str:=font_name[cur_val]; + if is_native_font(cur_val) then begin + quote_char:=""""; + for i:=0 to length(font_name_str) - 1 do + if str_pool[str_start_macro(font_name_str) + i] = """" then quote_char:="'"; + print_char(quote_char); + print(font_name_str); + print_char(quote_char); + end else + print(font_name_str); +@z + +@x +eTeX_revision_code: print(eTeX_revision); +@y +@/@@/ +@z + +@x +job_name_code: print(job_name); +@y +job_name_code: print_file_name(job_name, 0, 0); +@z + +@x +@!read_file:array[0..15] of alpha_file; {used for \.{\\read}} +@y +@!read_file:array[0..15] of unicode_file; {used for \.{\\read}} +@z + +@x +else begin a_close(read_file[m]); read_open[m]:=closed; +@y +else begin u_close(read_file[m]); read_open[m]:=closed; +@z + +@x + begin a_close(read_file[m]); read_open[m]:=closed; +@y + begin u_close(read_file[m]); read_open[m]:=closed; +@z + +@x +if (cur_cmd>active_char)or(cur_chr>255) then {not a character} + begin m:=relax; n:=256; +@y +if (cur_cmd>active_char)or(cur_chr>biggest_usv) then {not a character} + begin m:=relax; n:=too_big_char; +@z + +@x +if (cur_cmd>active_char)or(cur_chr>255) then + begin cur_cmd:=relax; cur_chr:=256; +@y +if (cur_cmd>active_char)or(cur_chr>biggest_usv) then + begin cur_cmd:=relax; cur_chr:=too_big_char; +@z + +@x +@* \[29] File names. +@y +@* \[29] File names. +@z + +@x +The following procedures don't allow spaces to be part of +file names; but some users seem to like names that are spaced-out. +System-dependent changes to allow such things should probably +be made with reluctance, and only when an entire file name that +includes spaces is ``quoted'' somehow. + +@y +@z + +@x +@!ext_delimiter:pool_pointer; {the most recent `\..', if any} +@y +@!ext_delimiter:pool_pointer; {the most recent `\..', if any} +@!file_name_quote_char:UTF16_code; +@z + +@x +begin area_delimiter:=0; ext_delimiter:=0; quoted_filename:=false; +@y +begin area_delimiter:=0; ext_delimiter:=0; quoted_filename:=false; +file_name_quote_char:=0; +@z + +@x +@p function more_name(@!c:ASCII_code):boolean; +begin if (c=" ") and stop_at_space and (not quoted_filename) then + more_name:=false +else if c="""" then begin + quoted_filename:=not quoted_filename; + more_name:=true; + end +@y +@p function more_name(@!c:ASCII_code):boolean; +begin if stop_at_space and (c=" ") and (file_name_quote_char=0) then + more_name:=false +else if stop_at_space and (file_name_quote_char<>0) and (c=file_name_quote_char) then begin + file_name_quote_char:=0; + more_name:=true; + end +else if stop_at_space and (file_name_quote_char=0) and ((c="""") or (c="'") or (c="(")) then begin + if c="(" then file_name_quote_char:=")" + else file_name_quote_char:=c; + quoted_filename:=true; + more_name:=true; + end +@z + +@x +@p procedure end_name; +var temp_str: str_number; {result of file name cache lookups} +@!j,@!s,@!t: pool_pointer; {running indices} +@!must_quote:boolean; {whether we need to quote a string} +begin if str_ptr+3>max_strings then + overflow("number of strings",max_strings-init_str_ptr); +@:TeX capacity exceeded number of strings}{\quad number of strings@> +str_room(6); {Room for quotes, if needed.} +{add quotes if needed} +if area_delimiter<>0 then begin + {maybe quote |cur_area|} + must_quote:=false; + s:=str_start[str_ptr]; + t:=str_start[str_ptr]+area_delimiter; + j:=s; + while (not must_quote) and (j0 then ext_delimiter:=ext_delimiter+2; + area_delimiter:=area_delimiter+2; + pool_ptr:=pool_ptr+2; + end; + end; +{maybe quote |cur_name|} +s:=str_start[str_ptr]+area_delimiter; +if ext_delimiter=0 then t:=pool_ptr else t:=str_start[str_ptr]+ext_delimiter-1; +must_quote:=false; +j:=s; +while (not must_quote) and (j0 then ext_delimiter:=ext_delimiter+2; + pool_ptr:=pool_ptr+2; + end; +if ext_delimiter<>0 then begin + {maybe quote |cur_ext|} + s:=str_start[str_ptr]+ext_delimiter-1; + t:=pool_ptr; + must_quote:=false; + j:=s; + while (not must_quote) and (jmax_strings then + overflow("number of strings",max_strings-init_str_ptr); +@:TeX capacity exceeded number of strings}{\quad number of strings@> +@z + +@x + str_start[str_ptr+1]:=str_start[str_ptr]+area_delimiter; incr(str_ptr); +@y + str_start_macro(str_ptr+1):=str_start_macro(str_ptr)+area_delimiter; incr(str_ptr); +@z + +@x + for j:=str_start[str_ptr+1] to pool_ptr-1 do +@y + for j:=str_start_macro(str_ptr+1) to pool_ptr-1 do +@z + +@x + str_start[str_ptr+1]:=str_start[str_ptr]+ext_delimiter-area_delimiter-1; +@y + str_start_macro(str_ptr+1):=str_start_macro(str_ptr)+ext_delimiter-area_delimiter-1; +@z + +@x + for j:=str_start[str_ptr+1] to pool_ptr-1 do +@y + for j:=str_start_macro(str_ptr+1) to pool_ptr-1 do +@z + +@x +procedure print_file_name(@!n,@!a,@!e:integer); +var must_quote: boolean; {whether to quote the filename} +@!j:pool_pointer; {index into |str_pool|} +begin +must_quote:=false; +if a<>0 then begin + j:=str_start[a]; + while (not must_quote) and (j0 then begin + j:=str_start[n]; + while (not must_quote) and (j0 then begin + j:=str_start[e]; + while (not must_quote) and (j0)and(|str_pool|[|str_start|[|a|]]=""""))or + ((|n|<>0)and(|str_pool|[|str_start|[|n|]]=""""))or + ((|e|<>0)and(|str_pool|[|str_start|[|e|]]=""""));} +if must_quote then print_char(""""); +if a<>0 then + for j:=str_start[a] to str_start[a+1]-1 do + if so(str_pool[j])<>"""" then + print(so(str_pool[j])); +if n<>0 then + for j:=str_start[n] to str_start[n+1]-1 do + if so(str_pool[j])<>"""" then + print(so(str_pool[j])); +if e<>0 then + for j:=str_start[e] to str_start[e+1]-1 do + if so(str_pool[j])<>"""" then + print(so(str_pool[j])); +if must_quote then print_char(""""); +end; +@y +procedure print_file_name(@!n,@!a,@!e:integer); +var @!must_quote: boolean; {whether to quote the filename} +@!quote_char: integer; {current quote char (single or double)} +@!j:pool_pointer; {index into |str_pool|} +begin +must_quote:=false; +quote_char:=0; +if a<>0 then begin + j:=str_start_macro(a); + while ((not must_quote) or (quote_char=0)) and (j0 then begin + j:=str_start_macro(n); + while ((not must_quote) or (quote_char=0)) and (j0 then begin + j:=str_start_macro(e); + while ((not must_quote) or (quote_char=0)) and (j0 then + for j:=str_start_macro(a) to str_start_macro(a+1)-1 do begin + if str_pool[j]=quote_char then begin + print(quote_char); + quote_char:="""" + "'" - quote_char; + print(quote_char); + end; + print(str_pool[j]); + end; +if n<>0 then + for j:=str_start_macro(n) to str_start_macro(n+1)-1 do begin + if str_pool[j]=quote_char then begin + print(quote_char); + quote_char:="""" + "'" - quote_char; + print(quote_char); + end; + print(str_pool[j]); + end; +if e<>0 then + for j:=str_start_macro(e) to str_start_macro(e+1)-1 do begin + if str_pool[j]=quote_char then begin + print(quote_char); + quote_char:="""" + "'" - quote_char; + print(quote_char); + end; + print(str_pool[j]); + end; +if quote_char<>0 then print_char(quote_char); +end; +@z + +@x +@d append_to_name(#)==begin c:=#; if not (c="""") then begin incr(k); + if k<=file_name_size then name_of_file[k]:=xchr[c]; + end end +@y +@d append_to_name(#)==begin c:=#; incr(k); + if k<=file_name_size then begin + if (c < 128) then name_of_file[k]:=c + else if (c < @"800) then begin + name_of_file[k]:=@"C0 + c div @"40; incr(k); + name_of_file[k]:=@"80 + c mod @"40; + end else begin + name_of_file[k]:=@"E0 + c div @"1000; incr(k); + name_of_file[k]:=@"80 + (c mod @"1000) div @"40; incr(k); + name_of_file[k]:=@"80 + (c mod @"1000) mod @"40; + end + end + end +@z + +@x +name_of_file:= xmalloc_array (ASCII_code, length(a)+length(n)+length(e)+1); +for j:=str_start[a] to str_start[a+1]-1 do append_to_name(so(str_pool[j])); +for j:=str_start[n] to str_start[n+1]-1 do append_to_name(so(str_pool[j])); +for j:=str_start[e] to str_start[e+1]-1 do append_to_name(so(str_pool[j])); +@y +name_of_file:= xmalloc_array (UTF8_code, (length(a)+length(n)+length(e))*3+1); +for j:=str_start_macro(a) to str_start_macro(a+1)-1 do append_to_name(so(str_pool[j])); +for j:=str_start_macro(n) to str_start_macro(n+1)-1 do append_to_name(so(str_pool[j])); +for j:=str_start_macro(e) to str_start_macro(e+1)-1 do append_to_name(so(str_pool[j])); +@z + +@x +name_of_file := xmalloc_array (ASCII_code, n+(b-a+1)+format_ext_length+1); +for j:=1 to n do append_to_name(xord[TEX_format_default[j]]); +@y +name_of_file := xmalloc_array (UTF8_code, n+(b-a+1)+format_ext_length+1); +for j:=1 to n do append_to_name(TEX_format_default[j]); +@z + +@x + append_to_name(xord[TEX_format_default[j]]); +@y + append_to_name(TEX_format_default[j]); +@z + +@x +@p function make_name_string:str_number; +var k:1..file_name_size; {index into |name_of_file|} +begin if (pool_ptr+name_length>pool_size)or(str_ptr=max_strings)or + (cur_length>0) then + make_name_string:="?" +else begin for k:=1 to name_length do append_char(xord[name_of_file[k]]); + make_name_string:=make_string; + end; + {At this point we also set |cur_name|, |cur_ext|, and |cur_area| to + match the contents of |name_of_file|.} + k:=1; + name_in_progress:=true; + begin_name; + stop_at_space:=false; + while (k<=name_length)and(more_name(name_of_file[k])) do + incr(k); + stop_at_space:=true; + end_name; + name_in_progress:=false; +end; +@y +@p function make_name_string:str_number; +var k:1..file_name_size; {index into |name_of_file|} +begin if (pool_ptr+name_length>pool_size)or(str_ptr=max_strings)or + (cur_length>0) then + make_name_string:="?" +else begin + make_utf16_name; + for k:=0 to name_length16-1 do append_char(name_of_file16[k]); + make_name_string:=make_string; + end; +end; +function u_make_name_string(var f:unicode_file):str_number; +begin u_make_name_string:=make_name_string; +end; +@z + +@x +loop@+begin if (cur_cmd>other_char)or(cur_chr>255) then {not a character} +@y +loop@+begin if (cur_cmd>other_char)or(cur_chr>biggest_char) then + {not a character} +@z + +@x + {If |cur_chr| is a space and we're not scanning a token list, check + whether we're at the end of the buffer. Otherwise we end up adding + spurious spaces to file names in some cases.} + if (cur_chr=" ") and (state<>token_list) and (loc>limit) then goto done; +@y +@z + +@x + pack_job_name(".dvi"); + while not b_open_out(dvi_file) do + prompt_file_name("file name for output",".dvi"); +@y + pack_job_name(output_file_extension); + while not dvi_open_out(dvi_file) do + prompt_file_name("file name for output",output_file_extension); +@z + +@x +@!dvi_file: byte_file; {the device-independent output goes here} +@y +@!output_file_extension: str_number; +@!no_pdf_output: boolean; +@!dvi_file: byte_file; {the device-independent output goes here} +@z + +@x +@ @=output_file_name:=0; +@y +@ @= + output_file_name:=0; + if no_pdf_output then output_file_extension:=".xdv" + else output_file_extension:=".pdf"; +@z + +@x +if enctex_enabled_p then + begin wlog_cr; wlog(encTeX_banner); wlog(', reencoding enabled'); + if translate_filename then + begin wlog_cr; + wlog(' (\xordcode, \xchrcode, \xprncode overridden by TCX)'); + end; + end; +@y +@z + +@x +if translate_filename then begin + wlog_cr; + wlog(' ('); + fputs(translate_filename, log_file); + wlog(')'); + end; +@y +if translate_filename then begin + wlog_cr; + wlog(' (WARNING: translate-file "'); + fputs(translate_filename, log_file); + wlog('" ignored)'); + end; +@z + +@x + if open_in_name_ok(stringcast(name_of_file+1)) + and a_open_in(cur_file, kpse_tex_format) then + goto done; +@y + if open_in_name_ok(stringcast(name_of_file+1)) + and u_open_in(cur_file, kpse_tex_format, XeTeX_default_input_mode, XeTeX_default_input_encoding) then + {At this point |name_of_file| contains the actual name found, as a UTF8 string. + We convert to UTF16, then extract the |cur_area|, |cur_name|, and |cur_ext| from it.} + begin + make_utf16_name; + name_in_progress:=true; + begin_name; + stop_at_space:=false; + k:=0; + while (knull_font then goto done; +end; +{ it was an unquoted name, or not found as an installed font, so try for a TFM file } +@; +@y +if g<>null_font then goto done; +if not quoted_filename then begin + { we failed to find a TFM file, so try for a native font } + g:=load_native_font(u,nom,aire,s); + if g<>null_font then goto done +end; +bad_tfm: +if suppress_fontnotfound_error=0 then begin + @; + end; +@z + +@x +@d start_font_error_message==print_err("Font "); sprint_cs(u); + print_char("="); print_file_name(nom,aire,""); +@y +@d start_font_error_message==print_err("Font "); sprint_cs(u); + print_char("="); + if file_name_quote_char=")" then print_char("(") + else if file_name_quote_char<>0 then print_char(file_name_quote_char); + print_file_name(nom,aire,cur_ext); + if file_name_quote_char<>0 then print_char(file_name_quote_char); +@z + +@x +else print(" not loadable: Metric (TFM) file not found"); +@y +else print(" not loadable: Metric (TFM) file or installed font not found"); +@z + +@x +@ @= +@; +@y +@ @= +@; +@z + +@x +@ +@y +@; +end +@z + +@x +@ @= +file_opened:=false; +@y +@ @= +@z + +@x +if not b_open_in(tfm_file) then abort; +file_opened:=true +@y +if b_open_in(tfm_file) then begin + file_opened:=true +@z + +@x +@ When \TeX\ wants to typeset a character that doesn't exist, the +character node is not created; thus the output routine can assume +that characters exist when it sees them. The following procedure +prints a warning message unless the user has suppressed it. + +@p procedure char_warning(@!f:internal_font_number;@!c:eight_bits); +var old_setting: integer; {saved value of |tracing_online|} +begin if tracing_lost_chars>0 then + begin old_setting:=tracing_online; + if eTeX_ex and(tracing_lost_chars>1) then tracing_online:=1; + begin begin_diagnostic; + print_nl("Missing character: There is no "); +@.Missing character@> + print_ASCII(c); print(" in font "); + slow_print(font_name[f]); print_char("!"); end_diagnostic(false); + end; + tracing_online:=old_setting; + end; +end; +@y +@ Procedure |char_warning| has been moved in the source. +@z + +@x +@p function new_character(@!f:internal_font_number;@!c:eight_bits):pointer; +@y +@p function new_character(@!f:internal_font_number;@!c:ASCII_code):pointer; +@z + +@x +begin ec:=effective_char(false,f,qi(c)); +@y +begin +if is_native_font(f) then + begin new_character:=new_native_character(f,c); return; + end; +ec:=effective_char(false,f,qi(c)); +@z + +@x +@* \[31] Device-independent file format. +@y +@* \[31] Device-independent file format. +@z + +@x +\yskip\noindent Commands 250--255 are undefined at the present time. +@y +\yskip\hang|set_glyph_string| 254 w[4] k[2] x[4k] g[2k]. + +\yskip\hang|set_glyph_array| 253 w[4] k[2] xy[8k] g[2k] + +\yskip\hang|define_native_font| 252 k[4] s[4] flags[2] + lenps[1] lenfam[1] lensty[1] ps[lenps] fam[lenfam] sty[lensty] + if (flags & COLORED): + rgba[4] + if (flags & VARIATIONS): + numvars[2] + axes[4nv] + values[4nv] + if (flags & MATRIX): + ta[4] tb[4] tc[4] td[4] tx[4] ty[4] + +\yskip\hang|pic_file| 251 flags[1] t[4][6] p[2] len[2] path[l] + flags = 0 for raster image, 1 for PDF + t is transform matrix + p is page # from the graphic file (0-based) + len is length of pathname + path is pathname of graphic file + +\yskip\noindent Commands 250 and 255 are undefined at the present time (but 255 is used by pTeX). +@z + +@x +@d post_post=249 {postamble ending} +@y +@d post_post=249 {postamble ending} + +@d set_glyph_string=254 {sequence of glyphs, all at the current y-position} +@d set_glyph_array=253 {sequence of glyphs with individual x-y coordinates} +@d define_native_font=252 {define native font} +@d pic_file=251 {embed picture or PDF} +@z + +@x +@d id_byte=2 {identifies the kind of \.{DVI} files described here} +@y +XeTeX changes the DVI version to 5, +as we have new DVI opcodes like |set_glyph_array| for native font text; +I used version 3 in an earlier extension of TeX, +and 4 in pre-1.0 XeTeX releases using Mac OS-specific data types. + +@d id_byte=5 {identifies the kind of \.{DVI} files described here} +@z + +@x +@* \[32] Shipping pages out. +@y +@* \[32] Shipping pages out. +@z + +@x +@ A mild optimization of the output is performed by the |dvi_pop| +@y +procedure dvi_two(s: UTF16_code); +begin + dvi_out(s div @'400); + dvi_out(s mod @'400); +end; + +@ A mild optimization of the output is performed by the |dvi_pop| +@z + +@x +@p procedure dvi_font_def(@!f:internal_font_number); +@y +@p procedure dvi_native_font_def(@!f:internal_font_number); +var + font_def_length, i: integer; +begin + dvi_out(define_native_font); + dvi_four(f-font_base-1); + font_def_length := make_font_def(f); + for i := 0 to font_def_length - 1 do dvi_out(xdv_buffer[i]); +end; + +procedure dvi_font_def(@!f:internal_font_number); +@z + +@x +begin if f<=256+font_base then +@y +begin if is_native_font(f) then dvi_native_font_def(f) else +begin if f<=256+font_base then +@z + +@x +@; +@y +@; +end; +@z + +@x +@ @= +for k:=str_start[font_area[f]] to str_start[font_area[f]+1]-1 do + dvi_out(so(str_pool[k])); +for k:=str_start[font_name[f]] to str_start[font_name[f]+1]-1 do + dvi_out(so(str_pool[k])) +@y +@ @= +for k:=str_start_macro(font_area[f]) to str_start_macro(font_area[f]+1)-1 do + dvi_out(so(str_pool[k])); +for k:=str_start_macro(font_name[f]) to str_start_macro(font_name[f]+1)-1 do + dvi_out(so(str_pool[k])) +@z + +@x +@ @= +dvi_h:=0; dvi_v:=0; cur_h:=h_offset; dvi_f:=null_font; +@y +@ @= +dvi_h:=0; dvi_v:=0; cur_h:=h_offset; dvi_f:=null_font; +@; +@z + +@x + print(" TeX output "); print_int(year); print_char("."); +@y + print(" XeTeX output "); print_int(year); print_char("."); +@z + +@x + for s:=str_start[str_ptr] to pool_ptr-1 do dvi_out(so(str_pool[s])); + pool_ptr:=str_start[str_ptr]; {flush the current string} +@y + for s:=str_start_macro(str_ptr) to pool_ptr-1 do dvi_out(so(str_pool[s])); + pool_ptr:=str_start_macro(str_ptr); {flush the current string} +@z + +@x +@d next_p=15 {go to this label when finished with node |p|} +@y +@d next_p=15 {go to this label when finished with node |p|} + +@d check_next=1236 +@d end_node_run=1237 +@z + +@x +label reswitch, move_past, fin_rule, next_p, continue, found; +@y +label reswitch, move_past, fin_rule, next_p, continue, found, check_next, end_node_run; +@z + +@x +@!prev_p:pointer; {one step behind |p|} +@y +@!prev_p:pointer; {one step behind |p|} +@!len: integer; { length of scratch string for native word output } +@!q,@!r: pointer; +@!k,@!j: integer; +@z + +@x +g_sign:=glue_sign(this_box); p:=list_ptr(this_box); +@y +g_sign:=glue_sign(this_box); +@; +p:=list_ptr(this_box); +@z + +@x +@ We ought to give special care to the efficiency of one part of |hlist_out|, +@y +@ Extra stuff for justifiable AAT text; need to merge runs of words and normal spaces. + +@d is_native_word_node(#) == ((not is_char_node(#)) and (type(#) = whatsit_node) and (subtype(#) = native_word_node)) + +@= +p := list_ptr(this_box); +prev_p := this_box+list_offset; +while p<>null do begin + if link(p) <> null then begin {not worth looking ahead at the end} + if is_native_word_node(p) and (font_area[native_font(p)] = aat_font_flag) + and (font_letter_space[native_font(p)] = 0) then begin + {got a word in an AAT font, might be the start of a run} + r := p; {|r| is start of possible run} + k := native_length(r); + q := link(p); +check_next: + @; + if (q <> null) and not is_char_node(q) then begin + if (type(q) = glue_node) and (subtype(q) = normal) and (glue_ptr(q) = font_glue[native_font(r)]) then begin + {found a normal space; if the next node is another word in the same font, we'll merge} + q := link(q); + @; + if (q <> null) and is_native_word_node(q) and (native_font(q) = native_font(r)) then begin + p := q; {record new tail of run in |p|} + k := k + 1 + native_length(q); + q := link(q); + goto check_next; + end; + goto end_node_run; + end; + {@;} + if (q <> null) and is_native_word_node(q) and (native_font(q) = native_font(r)) then begin + p := q; {record new tail of run in |p|} + q := link(q); + goto check_next; + end + end; +end_node_run: {now |r| points to first |native_word_node| of the run, and |p| to the last} + if p <> r then begin {merge nodes from |r| to |p| inclusive; total text length is |k|} + str_room(k); + k := 0; {now we'll use this as accumulator for total width} + q := r; + loop begin + if type(q) = whatsit_node then begin + if subtype(q) = native_word_node then begin + for j := 0 to native_length(q)-1 do + append_char(get_native_char(q, j)); + k := k + width(q); + end + end else if type(q) = glue_node then begin + append_char(" "); + g := glue_ptr(q); + k := k + width(g); + if g_sign <> normal then begin + if g_sign = stretching then begin + if stretch_order(g) = g_order then begin + k := k + round(float(glue_set(this_box)) * stretch(g)) + end + end else begin + if shrink_order(g) = g_order then begin + k := k - round(float(glue_set(this_box)) * shrink(g)) + end + end + end + end; + {discretionary and deleted nodes can be discarded here} + if q = p then break + else q := link(q); + end; +done: + q := new_native_word_node(native_font(r), cur_length); + link(prev_p) := q; + for j := 0 to cur_length - 1 do + set_native_char(q, j, str_pool[str_start_macro(str_ptr) + j]); + link(q) := link(p); + link(p) := null; + flush_node_list(r); + width(q) := k; + set_justified_native_glyphs(q); + p := q; + pool_ptr := str_start_macro(str_ptr); {flush the temporary string data} + end + end; + prev_p := p; + end; + p := link(p); +end + +@ @= +while (q <> null) and (not is_char_node(q)) and (type(q) = disc_node) do + q := link(q) + +@ We ought to give special care to the efficiency of one part of |hlist_out|, +@z + +@x +@p procedure vlist_out; {output a |vlist_node| box} +@y +@p procedure vlist_out; {output a |vlist_node| box} +@z + +@x +@!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); +if cur_s>0 then dvi_out(push); +if cur_s>max_push then max_push:=cur_s; +save_loc:=dvi_offset+dvi_ptr; left_edge:=cur_h; cur_v:=cur_v-height(this_box); +@y +@!cur_g:scaled; {rounded equivalent of |cur_glue| times the glue ratio} +@!upwards:boolean; {whether we're stacking upwards} +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); +upwards:=(subtype(this_box)=min_quarterword+1); +incr(cur_s); +if cur_s>0 then dvi_out(push); +if cur_s>max_push then max_push:=cur_s; +save_loc:=dvi_offset+dvi_ptr; left_edge:=cur_h; +if upwards then cur_v:=cur_v+depth(this_box) else cur_v:=cur_v-height(this_box); +@z + +@x +kern_node:cur_v:=cur_v+width(p); +@y +kern_node:if upwards then cur_v:=cur_v-width(p) else cur_v:=cur_v+width(p); +@z + +@x +move_past: cur_v:=cur_v+rule_ht; +@y +move_past: if upwards then cur_v:=cur_v-rule_ht else cur_v:=cur_v+rule_ht; +@z + +@x +@= +if list_ptr(p)=null then cur_v:=cur_v+height(p)+depth(p) +else begin cur_v:=cur_v+height(p); synch_v; + save_h:=dvi_h; save_v:=dvi_v; + if cur_dir=right_to_left then cur_h:=left_edge-shift_amount(p) + else cur_h:=left_edge+shift_amount(p); {shift the box right} + temp_ptr:=p; + if type(p)=vlist_node then vlist_out@+else hlist_out; + dvi_h:=save_h; dvi_v:=save_v; + cur_v:=save_v+depth(p); cur_h:=left_edge; + end +@y +@= +if list_ptr(p)=null then + if upwards then cur_v:=cur_v-height(p)-depth(p) + else cur_v:=cur_v+height(p)+depth(p) +else begin if upwards then cur_v:=cur_v-depth(p) else cur_v:=cur_v+height(p); synch_v; + save_h:=dvi_h; save_v:=dvi_v; + if cur_dir=right_to_left then cur_h:=left_edge-shift_amount(p) + else cur_h:=left_edge+shift_amount(p); {shift the box right} + temp_ptr:=p; + if type(p)=vlist_node then vlist_out@+else hlist_out; + dvi_h:=save_h; dvi_v:=save_v; + if upwards then cur_v:=save_v-height(p) else cur_v:=save_v+depth(p); cur_h:=left_edge; + end +@z + +@x +cur_v:=cur_v+rule_ht; +@y +if upwards then cur_v:=cur_v-rule_ht else cur_v:=cur_v+rule_ht; +@z + +@x +begin if tracing_output>0 then +@y +begin if job_name=0 then open_log_file; +if tracing_output>0 then +@z + +@x +dvi_four(last_bop); last_bop:=page_loc; +@y +dvi_four(last_bop); last_bop:=page_loc; +{ generate a pagesize \special at start of page } +old_setting:=selector; selector:=new_string; +print("pdf:pagesize "); +if (pdf_page_width > 0) and (pdf_page_height > 0) then begin + print("width"); print(" "); + if mag=1000 then print_scaled(pdf_page_width) + else print_scaled(xn_over_d(pdf_page_width,mag,1000)); + print("pt"); print(" "); + print("height"); print(" "); + if mag=1000 then print_scaled(pdf_page_height) + else print_scaled(xn_over_d(pdf_page_height,mag,1000)); + print("pt"); +end else + print("default"); +selector:=old_setting; +dvi_out(xxx1); dvi_out(cur_length); +for s:=str_start_macro(str_ptr) to pool_ptr-1 do dvi_out(so(str_pool[s])); +pool_ptr:=str_start_macro(str_ptr); {erase the string} +@z + +@x +cur_v:=height(p)+v_offset; temp_ptr:=p; +@y +cur_v:=height(p)+v_offset; { does this need changing for upwards mode ???? } +temp_ptr:=p; +@z + +@x +dvi_out(eop); incr(total_pages); cur_s:=-1; +@y +dvi_out(eop); incr(total_pages); cur_s:=-1; +if not no_pdf_output then fflush(dvi_file); +@z + +@x + print_nl("Output written on "); print_file_name(0, output_file_name, 0); +@.Output written on x@> + print(" ("); print_int(total_pages); + if total_pages<>1 then print(" pages") + else print(" page"); + print(", "); print_int(dvi_offset+dvi_ptr); print(" bytes)."); + b_close(dvi_file); +@y + k:=dvi_close(dvi_file); + if k=0 then begin + print_nl("Output written on "); print(output_file_name); +@.Output written on x@> + print(" ("); print_int(total_pages); + if total_pages<>1 then print(" pages") + else print(" page"); + if no_pdf_output then begin + print(", "); print_int(dvi_offset+dvi_ptr); print(" bytes)."); + end else print(")."); + end else begin + print_nl("Error "); print_int(k); print(" ("); + if no_pdf_output then printcstring(strerror(k)) + else print("driver return code"); + print(") generating output;"); + print_nl("file "); print(output_file_name); print(" may not be valid."); + end; +@z + +@x +@* \[33] Packaging. +@y +@* \[33] Packaging. +@z + +@x +@p function hpack(@!p:pointer;@!w:scaled;@!m:small_number):pointer; +label reswitch, common_ending, exit; +@y +@p function hpack(@!p:pointer;@!w:scaled;@!m:small_number):pointer; +label reswitch, common_ending, exit, restart; +@z + +@x +@!hd:eight_bits; {height and depth indices for a character} +@y +@!hd:eight_bits; {height and depth indices for a character} +@!pp,@!ppp: pointer; +@!total_chars, @!k: integer; +@z + +@x +@d vpack(#)==vpackage(#,max_dimen) {special case of unconstrained depth} +@y +@d vpack(#)==vpackage(#,max_dimen) {special case of unconstrained depth} +@z + +@x +subtype(r):=min_quarterword; shift_amount(r):=0; +@y +if XeTeX_upwards then subtype(r):=min_quarterword+1 else subtype(r):=min_quarterword; +shift_amount(r):=0; +@z + +@x +@p procedure append_to_vlist(@!b:pointer); +var d:scaled; {deficiency of space between baselines} +@!p:pointer; {a new glue specification} +begin if prev_depth>ignore_depth then + begin d:=width(baseline_skip)-prev_depth-height(b); + if dignore_depth then + begin if upwards then d:=width(baseline_skip)-prev_depth-depth(b) + else d:=width(baseline_skip)-prev_depth-height(b); + if d=h) or no_extenders; + + {assemble box using |n| copies of each extender, + with appropriate glue wherever an overlap occurs} + prev_o:=0; + for i:=0 to ot_part_count(a)-1 do begin + if ot_part_is_extender(a, i) then begin + for j:=1 to n do begin + o:=ot_part_start_connector(f, a, i); + if prev_o0 then stack_glue_into_box(b, -oo, -o); + g:=ot_part_glyph(a, i); + stack_glyph_into_box(b, f, g); + prev_o:=ot_part_end_connector(f, a, i); + end + end else begin + o:=ot_part_start_connector(f, a, i); + if prev_o0 then stack_glue_into_box(b, -oo, -o); + g:=ot_part_glyph(a, i); + stack_glyph_into_box(b, f, g); + prev_o:=ot_part_end_connector(f, a, i); + end; + end; + + {find natural height and total stretch of the box} + p:=list_ptr(b); nat:=0; str:=0; + while p<>null do begin + if type(p)=whatsit_node then nat:=nat+height(p)+depth(p) + else if type(p)=glue_node then begin + nat:=nat+width(glue_ptr(p)); + str:=str+stretch(glue_ptr(p)); + end; + p:=link(p); + end; + + {set glue so as to stretch the connections if needed} + depth(b):=0; + if (h>nat) and (str>0) then begin + glue_order(b):=normal; glue_sign(b):=stretching; + glue_set(b):=unfloat((h-nat)/str); + height(b):=nat+round(str*float(glue_set(b))); + end else height(b):=nat; + + build_opentype_assembly:=b; +end; + +function var_delimiter(@!d:pointer;@!s:integer;@!v:scaled):pointer; +label found,continue; +var b:pointer; {the box that will be constructed} +ot_assembly_ptr:void_pointer; +@z + +@x +@!z: small_number; {runs through font family members} +@y +@!z: integer; {runs through font family members} +@z + +@x +loop@+ begin @; + if large_attempt then goto found; {there were none large enough} + large_attempt:=true; z:=large_fam(d); x:=large_char(d); + end; +found: if f<>null_font then + @ +else begin b:=new_null_box; + width(b):=null_delimiter_space; {use this width if no delimiter was found} + end; +@y +ot_assembly_ptr:=nil; +loop@+ begin @; + if large_attempt then goto found; {there were none large enough} + large_attempt:=true; z:=large_fam(d); x:=large_char(d); + end; +found: if f<>null_font then begin + if not is_ot_font(f) then + @ + else begin + {for OT fonts, c is the glyph ID to use} + if ot_assembly_ptr<>nil then + b:=build_opentype_assembly(f, ot_assembly_ptr, v) + else begin + b:=new_null_box; type(b):=vlist_node; list_ptr(b):=get_node(glyph_node_size); + type(list_ptr(b)):=whatsit_node; subtype(list_ptr(b)):=glyph_node; + native_font(list_ptr(b)):=f; native_glyph(list_ptr(b)):=c; + set_native_glyph_metrics(list_ptr(b), 1); + width(b):=width(list_ptr(b)); + height(b):=height(list_ptr(b)); + depth(b):=depth(list_ptr(b)); + end + end +end else begin b:=new_null_box; + width(b):=null_delimiter_space; {use this width if no delimiter was found} + end; +@z + +@x + begin z:=z+s+16; + repeat z:=z-16; g:=fam_fnt(z); +@y + begin z:=z+s+script_size; + repeat z:=z-script_size; g:=fam_fnt(z); +@z + +@x + until z<16; +@y + until z= +@y +@ @= +if is_ot_font(g) then begin + b:=new_native_character(g, x); + x:=get_native_glyph(b, 0); + free_node(b, native_size(b)); + f:=g; c:=x; w:=0; n:=0; + repeat + y:=get_ot_math_variant(g, x, n, address_of(u), 0); + if u>w then begin + c:=y; w:=u; + if u>=v then goto found; + end; + n:=n+1; + until u<0; + {if we get here, then we didn't find a big enough glyph; check if the char is extensible} + ot_assembly_ptr:=get_ot_assembly_ptr(g, x, 0); + if ot_assembly_ptr<>nil then goto found; +end else +@z + +@x +function char_box(@!f:internal_font_number;@!c:quarterword):pointer; +var q:four_quarters; +@!hd:eight_bits; {|height_depth| byte} +@!b,@!p:pointer; {the new box and its character node} +begin q:=char_info(f)(c); hd:=height_depth(q); +b:=new_null_box; width(b):=char_width(f)(q)+char_italic(f)(q); +height(b):=char_height(f)(hd); depth(b):=char_depth(f)(hd); +p:=get_avail; character(p):=c; font(p):=f; list_ptr(b):=p; char_box:=b; +end; +@y +function char_box(@!f:internal_font_number;@!c:integer):pointer; +var q:four_quarters; +@!hd:eight_bits; {|height_depth| byte} +@!b,@!p:pointer; {the new box and its character node} +begin +if is_native_font(f) then begin + b:=new_null_box; + p:=new_native_character(f, c); + list_ptr(b):=p; + height(b):=height(p); width(b):=width(p); + if depth(p)<0 then depth(b):=0 else depth(b):=depth(p); + end +else begin + q:=char_info(f)(c); hd:=height_depth(q); + b:=new_null_box; width(b):=char_width(f)(q)+char_italic(f)(q); + height(b):=char_height(f)(hd); depth(b):=char_depth(f)(hd); + p:=get_avail; character(p):=c; font(p):=f; + end; +list_ptr(b):=p; char_box:=b; +end; +@z + +@x +@* \[36] Typesetting math formulas. +@y +@* \[36] Typesetting math formulas. +@z + +@x +@!cur_size:small_number; {size code corresponding to |cur_style|} +@y +@!cur_size:integer; {size code corresponding to |cur_style|} +@z + +@x +@p procedure fetch(@!a:pointer); {unpack the |math_char| field |a|} +begin cur_c:=character(a); cur_f:=fam_fnt(fam(a)+cur_size); +if cur_f=null_font then + @ +else begin if (qo(cur_c)>=font_bc[cur_f])and(qo(cur_c)<=font_ec[cur_f]) then + cur_i:=orig_char_info(cur_f)(cur_c) +@y +@p procedure fetch(@!a:pointer); {unpack the |math_char| field |a|} +begin cur_c:=cast_to_ushort(character(a)); cur_f:=fam_fnt(fam(a)+cur_size); +cur_c:=cur_c + (plane_and_fam_field(a) div @"100) * @"10000; +if cur_f=null_font then + @ +else if is_native_font(cur_f) then begin + cur_i:=null_character; +end else begin if (qo(cur_c)>=font_bc[cur_f])and(qo(cur_c)<=font_ec[cur_f]) then + cur_i:=orig_char_info(cur_f)(cur_c) +@z + +@x +@!cur_c:quarterword; {the |character| field of a |math_char|} +@y +@!cur_c:integer; {the |character| field of a |math_char|} +@z + +@x +procedure make_radical(@!q:pointer); +var x,@!y:pointer; {temporary registers for box construction} +@!delta,@!clr:scaled; {dimensions involved in the calculation} +begin x:=clean_box(nucleus(q),cramped_style(cur_style)); +if cur_style; + x:=clean_box(nucleus(q),cramped_style(cur_style)); w:=width(x); h:=height(x); + @; +@y +procedure make_math_accent(@!q:pointer); +label done,done1; +var p,@!x,@!y:pointer; {temporary registers for box construction} +@!a:integer; {address of lig/kern instruction} +@!c,@!g:integer; {accent character} +@!f:internal_font_number; {its font} +@!i:four_quarters; {its |char_info|} +@!s:scaled; {amount to skew the accent to the right} +@!h:scaled; {height of character being accented} +@!delta:scaled; {space to remove between accent and accentee} +@!w,@!wa,@!w2:scaled; {width of the accentee, not including sub/superscripts} +begin fetch(accent_chr(q)); +x:=null; +if is_native_font(cur_f) then + begin c:=cur_c; f:=cur_f; + s:=0; {@;} + x:=clean_box(nucleus(q),cramped_style(cur_style)); w:=width(x); h:=height(x); + end +else if char_exists(cur_i) then + begin i:=cur_i; c:=cur_c; f:=cur_f;@/ + @; + x:=clean_box(nucleus(q),cramped_style(cur_style)); w:=width(x); h:=height(x); + @; + end; +if x<>null then begin +@z + +@x + y:=char_box(f,c); + shift_amount(y):=s+half(w-width(y)); +@y + y:=char_box(f,c); + if is_native_font(f) then begin + {turn the native_word node into a native_glyph one} + p:=get_node(glyph_node_size); + type(p):=whatsit_node; subtype(p):=glyph_node; + native_font(p):=f; native_glyph(p):=get_native_glyph(list_ptr(y), 0); + set_native_glyph_metrics(p, 1); + free_node(list_ptr(y), native_size(list_ptr(y))); + list_ptr(y):=p; + + @; + + {determine horiz positioning} + wa:=get_ot_math_accent_pos(f,native_glyph(p)); + if wa=@"7FFFFFFF then wa:=half(width(y)); + p:=list_ptr(x); + if (type(p)=whatsit_node) and (subtype(p)=glyph_node) and (link(p)=null) then begin + w:=get_ot_math_accent_pos(native_font(p), native_glyph(p)); + if w=@"7FFFFFFF then w:=half(width(x)); + end else + w:=half(width(x)); + shift_amount(y):=s+w-wa; + end else + shift_amount(y):=s+half(w-width(y)); +@z + +@x +@ @= +@y +@ @= + wa:=width(x); + c:=native_glyph(p); + a:=0; + repeat + g:=get_ot_math_variant(f, c, a, address_of(w2), 1); + if (w2>0) and (w2<=wa) then begin + native_glyph(p):=g; + set_native_glyph_metrics(p, 1); + incr(a); + end; + until (w2<0) or (w2>=wa); +{ + if (w2<0) then begin + ot_assembly_ptr:=get_ot_assembly_ptr(f, c, 1); + if ot_assembly_ptr<>nil then begin + free_node(p,glyph_node_size); + p:=build_opentype_assembly(cur_f, ot_assembly_ptr, w1); + list_ptr(y):=p; + goto found; + end; + end else +} + set_native_glyph_metrics(p, 1); +{found:} + width(y):=width(p); height(y):=height(p); depth(y):=depth(p); + if depth(y)<0 then depth(y):=0; + +@ @= +@z + +@x +@= +begin if cur_style= +begin if is_ot_font(fam_fnt(3+cur_size)) then begin + if cur_style= +begin if cur_style= +begin if is_ot_font(fam_fnt(3+cur_size)) then begin + delta:=half(thickness(q)); + if cur_styleempty)and(subtype(q)<>limits) then + width(x):=width(x)-delta; {remove italic correction} + shift_amount(x):=half(height(x)-depth(x)) - axis_height(cur_size); + {center vertically} + math_type(nucleus(q)):=sub_box; info(nucleus(q)):=x; + end +else delta:=0; +if subtype(q)=limits then + @; +make_op:=delta; +end; +@y +function make_op(@!q:pointer):scaled; +label found; +var delta:scaled; {offset between subscript and superscript} +@!p,@!v,@!x,@!y,@!z:pointer; {temporary registers for box construction} +@!c:quarterword;@+@!i:four_quarters; {registers for character examination} +@!shift_up,@!shift_down:scaled; {dimensions for box calculation} +@!h1,@!h2:scaled; {height of original text-style symbol and possible replacement} +@!n,@!g:integer; {potential variant index and glyph code} +@!ot_assembly_ptr:void_pointer; +begin if (subtype(q)=normal)and(cur_style0 then native_glyph(p):=g; + incr(n); + until (h2<0) or (h2>=h1); + if (h2<0) then begin + {if we get here, then we didn't find a big enough glyph; check if the char is extensible} + ot_assembly_ptr:=get_ot_assembly_ptr(cur_f, c, 0); + if ot_assembly_ptr<>nil then begin + free_node(p,glyph_node_size); + p:=build_opentype_assembly(cur_f, ot_assembly_ptr, h1); + list_ptr(x):=p; + delta:=0; + goto found; + end; + end else + set_native_glyph_metrics(p, 1); + end; + delta:=get_ot_math_ital_corr(cur_f, native_glyph(p)); +found: + width(x):=width(p); height(x):=height(p); depth(x):=depth(p); + end + end; + if (math_type(subscr(q))<>empty)and(subtype(q)<>limits) then + width(x):=width(x)-delta; {remove italic correction} + shift_amount(x):=half(height(x)-depth(x)) - axis_height(cur_size); + {center vertically} + math_type(nucleus(q)):=sub_box; info(nucleus(q)):=x; + end; +if subtype(q)=limits then + @; +make_op:=delta; +end; +@z + +@x + character(nucleus(r)):=rem_byte(cur_i); + fam(nucleus(r)):=fam(nucleus(q));@/ +@y + character(nucleus(r)):=rem_byte(cur_i); + plane_and_fam_field(nucleus(r)):=fam(nucleus(q));@/ +@z + +@x +@ @= +begin fetch(nucleus(q)); +if char_exists(cur_i) then +@y +@ @= +begin fetch(nucleus(q)); +if is_native_font(cur_f) then begin + z:=new_native_character(cur_f, qo(cur_c)); + p:=get_node(glyph_node_size); + type(p):=whatsit_node; subtype(p):=glyph_node; + native_font(p):=cur_f; native_glyph(p):=get_native_glyph(z, 0); + set_native_glyph_metrics(p, 1); + free_node(z, native_size(z)); + delta:=get_ot_math_ital_corr(cur_f, native_glyph(p)); + if (math_type(nucleus(q))=math_text_char)and(space(cur_f)<>0) then + delta:=0; {no italic correction in mid-word of text font} + if (math_type(subscr(q))=empty)and(delta<>0) then + begin link(p):=new_kern(delta); delta:=0; + end; +end else if char_exists(cur_i) then +@z + +@x +@ The purpose of |make_scripts(q,delta)| is to attach the subscript and/or +superscript of noad |q| to the list that starts at |new_hlist(q)|, +given that subscript and superscript aren't both empty. The superscript +will appear to the right of the subscript by a given distance |delta|. + +We set |shift_down| and |shift_up| to the minimum amounts to shift the +baseline of subscripts and superscripts based on the given nucleus. + +@= +procedure make_scripts(@!q:pointer;@!delta:scaled); +var p,@!x,@!y,@!z:pointer; {temporary registers for box construction} +@!shift_up,@!shift_down,@!clr:scaled; {dimensions in the calculation} +@!t:small_number; {subsidiary size code} +begin p:=new_hlist(q); +if is_char_node(p) then +@y +@ The purpose of |make_scripts(q,delta)| is to attach the subscript and/or +superscript of noad |q| to the list that starts at |new_hlist(q)|, +given that subscript and superscript aren't both empty. The superscript +will appear to the right of the subscript by a given distance |delta|. + +We set |shift_down| and |shift_up| to the minimum amounts to shift the +baseline of subscripts and superscripts based on the given nucleus. + +@= +procedure make_scripts(@!q:pointer;@!delta:scaled); +var p,@!x,@!y,@!z:pointer; {temporary registers for box construction} +@!shift_up,@!shift_down,@!clr:scaled; {dimensions in the calculation} +@!t:integer; {subsidiary size code} +begin p:=new_hlist(q); +if is_char_node(p) or (p<>null and is_native_word_node(p)) then +@z + +@x +magic_offset:=str_start[math_spacing]-9*ord_noad +@y +magic_offset:=str_start_macro(math_spacing)-9*ord_noad +@z + +@x +@* \[37] Alignment. +@y +@* \[37] Alignment. +@z + +@x +@d span_code=256 {distinct from any character} +@d cr_code=257 {distinct from |span_code| and from any character} +@y +@d span_code=special_char {distinct from any character} +@d cr_code=span_code+1 {distinct from |span_code| and from any character} +@z + +@x +if n>max_quarterword then confusion("256 spans"); {this can happen, but won't} +@^system dependencies@> +@:this can't happen 256 spans}{\quad 256 spans@> +@y +if n>max_quarterword then confusion("too many spans"); + {this can happen, but won't} +@^system dependencies@> +@:this can't happen too many spans}{\quad too many spans@> +@z + +@x +@* \[38] Breaking paragraphs into lines. +@y +@* \[38] Breaking paragraphs into lines. +@z + +@x +label done,done1,done2,done3,done4,done5,continue; +@y +label done,done1,done2,done3,done4,done5,done6,continue, restart; +@z + +@x + othercases confusion("disc1") +@y + whatsit_node: + if (subtype(v)=native_word_node) + or (subtype(v)=glyph_node) + or (subtype(v)=pic_node) + or (subtype(v)=pdf_node) + then break_width[1]:=break_width[1]-width(v) + else confusion("disc1a"); + othercases confusion("disc1") +@z + +@x + othercases confusion("disc2") +@y + whatsit_node: + if (subtype(s)=native_word_node) + or (subtype(s)=glyph_node) + or (subtype(s)=pic_node) + or (subtype(s)=pdf_node) + then break_width[1]:=break_width[1]+width(s) + else confusion("disc2a"); + othercases confusion("disc2") +@z + +@x +@* \[39] Breaking paragraphs into lines, continued. +@y +@* \[39] Breaking paragraphs into lines, continued. +@z + +@x + othercases confusion("disc3") +@y + whatsit_node: + if (subtype(s)=native_word_node) + or (subtype(s)=glyph_node) + or (subtype(s)=pic_node) + or (subtype(s)=pdf_node) + then disc_width:=disc_width+width(s) + else confusion("disc3a"); + othercases confusion("disc3") +@z + +@x + othercases confusion("disc4") +@y + whatsit_node: + if (subtype(s)=native_word_node) + or (subtype(s)=glyph_node) + or (subtype(s)=pic_node) + or (subtype(s)=pdf_node) + then act_width:=act_width+width(s) + else confusion("disc4a"); + othercases confusion("disc4") +@z + +@x +@* \[40] Pre-hyphenation. +@y +@* \[40] Pre-hyphenation. +@z + +@x +@!hc:array[0..65] of 0..256; {word to be hyphenated} +@y +@!hc:array[0..65] of 0..too_big_char; {word to be hyphenated} +@z + +@x +@!hu:array[0..63] of 0..256; {like |hc|, before conversion to lowercase} +@y +@!hu:array[0..63] of 0..too_big_char; + {like |hc|, before conversion to lowercase} +@z + +@x +@!cur_lang,@!init_cur_lang:ASCII_code; {current hyphenation table of interest} +@y +@!cur_lang,@!init_cur_lang:0..biggest_lang; + {current hyphenation table of interest} +@z + +@x +@!hyf_bchar:halfword; {boundary character after $c_n$} +@y +@!hyf_bchar:halfword; {boundary character after $c_n$} +@!max_hyph_char:integer; + +@ @= +max_hyph_char:=too_big_lang; +@z + +@x +@!c:0..255; {character being considered for hyphenation} +@y +@!c:ASCII_code; {character being considered for hyphenation} +@z + +@x + @; +@y +if (not is_char_node(ha)) and (type(ha) = whatsit_node) and (subtype(ha) = native_word_node) then begin + @; + @; +end else begin + @; +end; +@z + +@x +@ The first thing we need to do is find the node |ha| just before the +first letter. +@y +@ @= +s := link(ha); +loop@+ begin if not(is_char_node(s)) then + case type(s) of + ligature_node: do_nothing; + kern_node: if subtype(s)<>normal then goto done6; + whatsit_node,glue_node,penalty_node,ins_node,adjust_node,mark_node: + goto done6; + othercases goto done1 + endcases; + s:=link(s); + end; +done6: + +@ @= +{ note that if there are chars with |lccode = 0|, we split them out into separate |native_word| nodes } +hn := 0; +restart: +for l := 0 to native_length(ha)-1 do begin + c := get_native_char(ha, l); + set_lc_code(c); + if (hc[0] = 0) {or (hc[0] > max_hyph_char) -- no, there can be letters > max_hyph_char in the word} + then begin + if (hn > 0) then begin + { we've got some letters, and now found a non-letter, so break off the tail of the |native_word| + and link it after this node, and goto done3 } + @; + goto done3; + end + end else if (hn = 0) and (l > 0) then begin + { we've found the first letter after some non-letters, so break off the head of the |native_word| and restart } + @; + ha := link(ha); + goto restart; + end else if (hn = 63) then + { reached max hyphenatable length } + goto done3 + else begin + { found a letter that is part of a potentially hyphenatable sequence } + incr(hn); hu[hn] := c; hc[hn] := hc[0]; hyf_bchar := non_char; + end +end; + +@ @= + q := new_native_word_node(hf, native_length(ha) - l); + for i := l to native_length(ha) - 1 do + set_native_char(q, i - l, get_native_char(ha, i)); + set_native_metrics(q, XeTeX_use_glyph_metrics); + link(q) := link(ha); + link(ha) := q; + { truncate text in node |ha| } + native_length(ha) := l; + set_native_metrics(ha, XeTeX_use_glyph_metrics); + +@ @= +l: integer; +i: integer; + +@ The first thing we need to do is find the node |ha| just before the +first letter. +@z + +@x + begin @; + goto continue; +@y + begin + if subtype(s) = native_word_node then begin + { we only consider the node if it contains at least one letter, otherwise we'll skip it } + for l:=0 to native_length(s) - 1 do begin + c := get_native_char(s, l); + if lc_code(c) <> 0 then begin + hf := native_font(s); + prev_s := s; + goto done2; + end + end + end; + @; + goto continue +@z + +@x +if hyf_char>255 then goto done1; +@y +if hyf_char>biggest_char then goto done1; +@z + +@x + if hc[0]=0 then goto done3; +@y + if hc[0]=0 then goto done3; + if hc[0]>max_hyph_char then goto done3; +@z + +@x + if hc[0]=0 then goto done3; +@y + if hc[0]=0 then goto done3; + if hc[0]>max_hyph_char then goto done3; +@z + +@x +@* \[41] Post-hyphenation. +@y +@* \[41] Post-hyphenation. +@z + +@x +@= +@y +@= +if (not is_char_node(ha)) and (type(ha) = whatsit_node) and (subtype(ha) = native_word_node) then begin + @; +end else begin +@z + +@x + begin hu[0]:=256; init_lig:=false; +@y + begin hu[0]:=max_hyph_char; init_lig:=false; +@z + +@x +found2: s:=ha; j:=0; hu[0]:=256; init_lig:=false; init_list:=null; +@y +found2: s:=ha; j:=0; hu[0]:=max_hyph_char; init_lig:=false; init_list:=null; +@z + +@x +flush_list(init_list) +@y +flush_list(init_list); +end + +@ @= +{ find the node immediately before the word to be hyphenated } +s := cur_p; {we have |cur_p<>ha| because |type(cur_p)=glue_node|} +while link(s) <> ha do s := link(s); + +{ for each hyphen position, + create a |native_word_node| fragment for the text before this point, + and a |disc_node| for the break, with the |hyf_char| in the |pre_break| text +} + +hyphen_passed := 0; { location of last hyphen we saw } + +for j := l_hyf to hn - r_hyf do begin + { if this is a valid break.... } + if odd(hyf[j]) then begin + + { make a |native_word_node| for the fragment before the hyphen } + q := new_native_word_node(hf, j - hyphen_passed); + for i := 0 to j - hyphen_passed - 1 do + set_native_char(q, i, get_native_char(ha, i + hyphen_passed)); + set_native_metrics(q, XeTeX_use_glyph_metrics); + link(s) := q; { append the new node } + s := q; + + { make the |disc_node| for the hyphenation point } + q := new_disc; + pre_break(q) := new_native_character(hf, hyf_char); + link(s) := q; + s := q; + + hyphen_passed := j; + end +end; + +{ make a |native_word_node| for the last fragment of the word } +hn := native_length(ha); { ensure trailing punctuation is not lost! } +q := new_native_word_node(hf, hn - hyphen_passed); +for i := 0 to hn - hyphen_passed - 1 do + set_native_char(q, i, get_native_char(ha, i + hyphen_passed)); +set_native_metrics(q, XeTeX_use_glyph_metrics); +link(s) := q; { append the new node } +s := q; + +q := link(ha); +link(s) := q; +link(ha) := null; +flush_node_list(ha); +@z + +@x + begin decr(l); c:=hu[l]; c_loc:=l; hu[l]:=256; +@y + begin decr(l); c:=hu[l]; c_loc:=l; hu[l]:=max_hyph_char; +@z + +@x +@* \[42] Hyphenation. +@y +@* \[42] Hyphenation. +@z + +@x +@!op_start:array[ASCII_code] of 0..trie_op_size; {offset for current language} +@y +@!op_start:array[0..biggest_lang] of 0..trie_op_size; {offset for current language} +@z + +@x +hc[0]:=0; hc[hn+1]:=0; hc[hn+2]:=256; {insert delimiters} +@y +hc[0]:=0; hc[hn+1]:=0; hc[hn+2]:=max_hyph_char; {insert delimiters} +@z + +@x + begin j:=1; u:=str_start[k]; +@y + begin j:=1; u:=str_start_macro(k); +@z + +@x + else if language>255 then cur_lang:=0 +@y + else if language>biggest_lang then cur_lang:=0 +@z + +@x +u:=str_start[k]; v:=str_start[s]; +@y +u:=str_start_macro(k); v:=str_start_macro(s); +@z + +@x +until u=str_start[k+1]; +@y +until u=str_start_macro(k+1); +@z + +@x +@* \[43] Initializing the hyphenation tables. +@y +@* \[43] Initializing the hyphenation tables. +@z + +@x +@!trie_used:array[ASCII_code] of trie_opcode; +@y +@!trie_used:array[0..biggest_lang] of trie_opcode; +@z + +@x +@!trie_op_lang:array[1..trie_op_size] of ASCII_code; +@y +@!trie_op_lang:array[1..trie_op_size] of 0..biggest_lang; +@z + +@x +for j:=1 to 255 do op_start[j]:=op_start[j-1]+qo(trie_used[j-1]); +@y +for j:=1 to biggest_lang do op_start[j]:=op_start[j-1]+qo(trie_used[j-1]); +@z + +@x +for k:=0 to 255 do trie_used[k]:=min_trie_op; +@y +for k:=0 to biggest_lang do trie_used[k]:=min_trie_op; +@z + +@x +for p:=0 to 255 do trie_min[p]:=p+1; +@y +for p:=0 to biggest_char do trie_min[p]:=p+1; +@z + +@x +@!ll:1..256; {upper limit of |trie_min| updating} +@y +@!ll:1..too_big_char; {upper limit of |trie_min| updating} +@z + +@x + @=h+256|@>; +@y + @=h+max_hyph_char|@>; +@z + +@x +@ By making sure that |trie_max| is at least |h+256|, we can be sure that +@y +@ By making sure that |trie_max| is at least |h+max_hyph_char|, +we can be sure that +@z + +@x +@=h+256|@>= +if trie_max=h+max_hyph_char|@>= +if trie_maxmax_hyph_char then max_hyph_char:=cur_chr; + if k<63 then +@z + +@x +begin @; +@y +begin +incr(max_hyph_char); +@; +@z + +@x +@* \[44] Breaking vertical lists into pages. +@y +@* \[44] Breaking vertical lists into pages. +@z + +@x +@* \[45] The page builder. +@y +@* \[45] The page builder. +@z + +@x +@!n:min_quarterword..255; {insertion box number} +@y +@!n:min_quarterword..biggest_reg; {insertion box number} +@z + +@x +@!n:min_quarterword..255; {insertion box number} +@y +@!n:min_quarterword..biggest_reg; {insertion box number} +@z + +@x +@* \[46] The chief executive. +@y +@* \[46] The chief executive. +@z + +@x +@d main_loop=70 {go here to typeset a string of consecutive characters} +@y +@d main_loop=70 {go here to typeset a string of consecutive characters} +@d collect_native=71 {go here to collect characters in a "native" font string} +@d collected=72 +@z + +@x + append_normal_space,exit; +@y + collect_native,collected, + append_normal_space,exit; +@z + +@x +hmode+char_num: begin scan_char_num; cur_chr:=cur_val; goto main_loop;@+end; +@y +hmode+char_num: begin scan_usv_num; cur_chr:=cur_val; goto main_loop;@+end; +@z + +@x +hmode+spacer: if space_factor=1000 then goto append_normal_space + else app_space; +hmode+ex_space,mmode+ex_space: goto append_normal_space; +@t\4@>@@; +end; {of the big |case| statement} +@y +othercases begin + if abs(mode)=hmode then check_for_post_char_toks(big_switch); + case abs(mode)+cur_cmd of + hmode+spacer: if space_factor=1000 then goto append_normal_space + else app_space; + hmode+ex_space,mmode+ex_space: goto append_normal_space; + @t\4@>@ + end + end +endcases; {of the big |case| statement} +@z + +@x +append_normal_space:@@;@/ + main_s:=sf_code(cur_chr); +@y +@d adjust_space_factor==@t@>@;@/ + main_s:=sf_code(cur_chr) mod @"10000; +@z + +@x +@= +if ((head=tail) and (mode>0)) then begin + if (insert_src_special_auto) then append_src_special; +end; +adjust_space_factor;@/ +@y +@d check_for_inter_char_toks(#)=={check for a spacing token list, goto # if found, + or big_switch in case of the initial letter of a run} + cur_ptr:=null; + space_class:=sf_code(cur_chr) div @"10000; + + if XeTeX_inter_char_tokens_en and space_class <> 256 then begin {class 256 = ignored (for combining marks etc)} + if prev_class = 255 then begin {boundary} + if (state<>token_list) or (token_type<>backed_up_char) then begin + find_sa_element(inter_char_val, 255*@"100 + space_class, false); + if cur_ptr<>null then begin + if cur_cs=0 then begin + if cur_cmd=char_num then cur_cmd:=char_given; + cur_tok:=(cur_cmd*max_char_val)+cur_chr; + end else cur_tok:=cs_token_flag+cur_cs; {can't happen?} + back_input; token_type:=backed_up_char; + begin_token_list(sa_ptr(cur_ptr), inter_char_text); + goto big_switch; + end + end + end else begin + find_sa_element(inter_char_val, prev_class*@"100 + space_class, false); + if cur_ptr<>null then begin + if cur_cs=0 then begin + if cur_cmd=char_num then cur_cmd:=char_given; + cur_tok:=(cur_cmd*max_char_val)+cur_chr; + end else cur_tok:=cs_token_flag+cur_cs; {can't happen?} + back_input; token_type:=backed_up_char; + begin_token_list(sa_ptr(cur_ptr), inter_char_text); + prev_class:=255; + goto #; + end; + end; + prev_class:=space_class; + end + +@d check_for_post_char_toks(#)== + if XeTeX_inter_char_tokens_en and (space_class<>256) and (prev_class<>255) then begin + prev_class:=255; + find_sa_element(inter_char_val, space_class*@"100 + 255, false); {boundary} + if cur_ptr<>null then begin + if cur_cs=0 then begin + if cur_cmd=char_num then cur_cmd:=char_given; + cur_tok:=(cur_cmd*max_char_val)+cur_chr; + end else cur_tok:=cs_token_flag+cur_cs; + back_input; + begin_token_list(sa_ptr(cur_ptr), inter_char_text); + goto #; + end; + end + +@= +if ((head=tail) and (mode>0)) then begin + if (insert_src_special_auto) then append_src_special; +end; + +prev_class := 255; {boundary} + +{ added code for native font support } +if is_native_font(cur_font) then begin + if mode>0 then if language<>clang then fix_language; + + main_h := 0; + main_f := cur_font; + native_len := 0; + +collect_native: + adjust_space_factor; + + check_for_inter_char_toks(collected); + + if (cur_chr > @"FFFF) then begin + native_room(2); + append_native((cur_chr - @"10000) div 1024 + @"D800); + append_native((cur_chr - @"10000) mod 1024 + @"DC00); + end else begin + native_room(1); + append_native(cur_chr); + end; + is_hyph := (cur_chr = hyphen_char[main_f]) + or (XeTeX_dash_break_en and ((cur_chr = @"2014) or (cur_chr = @"2013))); + if (main_h = 0) and is_hyph then main_h := native_len; + + {try to collect as many chars as possible in the same font} + get_next; + if (cur_cmd=letter) or (cur_cmd=other_char) or (cur_cmd=char_given) then goto collect_native; + x_token; + if (cur_cmd=letter) or (cur_cmd=other_char) or (cur_cmd=char_given) then goto collect_native; + if cur_cmd=char_num then begin + scan_usv_num; + cur_chr:=cur_val; + goto collect_native; + end; + + check_for_post_char_toks(collected); + +collected: + if (font_mapping[main_f] <> 0) then begin + main_k := apply_mapping(font_mapping[main_f], native_text, native_len); + native_len := 0; + native_room(main_k); + main_h := 0; + for main_p := 0 to main_k - 1 do begin + append_native(mapped_text[main_p]); + if (main_h = 0) and ((mapped_text[main_p] = hyphen_char[main_f]) + or (XeTeX_dash_break_en and ((mapped_text[main_p] = @"2014) or (mapped_text[main_p] = @"2013)) ) ) + then main_h := native_len; + end + end; + + if tracing_lost_chars > 0 then begin + temp_ptr := 0; + while (temp_ptr < native_len) do begin + main_k := native_text[temp_ptr]; + incr(temp_ptr); + if (main_k >= @"D800) and (main_k < @"DC00) then begin + main_k := @"10000 + (main_k - @"D800) * 1024; + main_k := main_k + native_text[temp_ptr] - @"DC00; + incr(temp_ptr); + end; + if map_char_to_glyph(main_f, main_k) = 0 then + char_warning(main_f, main_k); + end + end; + + main_k := native_len; + main_pp := tail; + + if mode=hmode then begin + + main_ppp := head; + if main_ppp<>main_pp then { find node preceding tail, skipping discretionaries } + while (link(main_ppp)<>main_pp) do begin + if (not is_char_node(main_ppp)) and (type(main_ppp=disc_node)) then begin + temp_ptr:=main_ppp; + for main_p:=1 to replace_count(temp_ptr) do main_ppp:=link(main_ppp); + end; + if main_ppp<>main_pp then main_ppp:=link(main_ppp); + end; + + temp_ptr := 0; + repeat + if main_h = 0 then main_h := main_k; + + if (not is_char_node(main_pp)) + and (type(main_pp)=whatsit_node) + and (subtype(main_pp)=native_word_node) + and (native_font(main_pp)=main_f) + and (main_ppp<>main_pp) + and (not is_char_node(main_ppp)) + and (type(main_ppp)<>disc_node) + then begin + + { make a new temp string that contains the concatenated text of |tail| + the current word/fragment } + main_k := main_h + native_length(main_pp); + native_room(main_k); + + save_native_len := native_len; + for main_p := 0 to native_length(main_pp) - 1 do + append_native(get_native_char(main_pp, main_p)); + for main_p := 0 to main_h - 1 do + append_native(native_text[temp_ptr + main_p]); + + do_locale_linebreaks(save_native_len, main_k); + + native_len := save_native_len; { discard the temp string } + main_k := native_len - main_h - temp_ptr; { and set main_k to remaining length of new word } + temp_ptr := main_h; { pointer to remaining fragment } + + main_h := 0; + while (main_h < main_k) and (native_text[temp_ptr + main_h] <> hyphen_char[main_f]) + and ( (not XeTeX_dash_break_en) + or ((native_text[temp_ptr + main_h] <> @"2014) and (native_text[temp_ptr + main_h] <> @"2013)) ) + do incr(main_h); { look for next hyphen or end of text } + if (main_h < main_k) then incr(main_h); + + { remove the preceding node from the list } + link(main_ppp) := link(main_pp); + link(main_pp) := null; + flush_node_list(main_pp); + main_pp := tail; + while (link(main_ppp)<>main_pp) do + main_ppp:=link(main_ppp); + + end else begin + + do_locale_linebreaks(temp_ptr, main_h); { append fragment of current word } + + temp_ptr := temp_ptr + main_h; { advance ptr to remaining fragment } + main_k := main_k - main_h; { decrement remaining length } + + main_h := 0; + while (main_h < main_k) and (native_text[temp_ptr + main_h] <> hyphen_char[main_f]) + and ( (not XeTeX_dash_break_en) + or ((native_text[temp_ptr + main_h] <> @"2014) and (native_text[temp_ptr + main_h] <> @"2013)) ) + do incr(main_h); { look for next hyphen or end of text } + if (main_h < main_k) then incr(main_h); + + end; + + if (main_k > 0) or is_hyph then begin + tail_append(new_disc); { add a break if we aren't at end of text (must be a hyphen), + or if last char in original text was a hyphen } + main_pp:=tail; + end; + until main_k = 0; + + end else begin + { must be restricted hmode, so no need for line-breaking or discretionaries } + if (not is_char_node(main_pp)) and (type(main_pp)=whatsit_node) and (subtype(main_pp)=native_word_node) and (native_font(main_pp)=main_f) then begin + { total string length for the new merged whatsit } + link(main_pp) := new_native_word_node(main_f, main_k + native_length(main_pp)); + tail := link(main_pp); + + { copy text from the old one into the new } + for main_p := 0 to native_length(main_pp) - 1 do + set_native_char(tail, main_p, get_native_char(main_pp, main_p)); + { append the new text } + for main_p := 0 to main_k - 1 do + set_native_char(tail, main_p + native_length(main_pp), native_text[main_p]); + set_native_metrics(tail, XeTeX_use_glyph_metrics); + + { remove the preceding node from the list } + main_p := head; + if main_p<>main_pp then + while link(main_p)<>main_pp do + main_p := link(main_p); + link(main_p) := link(main_pp); + link(main_pp) := null; + flush_node_list(main_pp); + end else begin + { package the current string into a |native_word| whatsit } + link(main_pp) := new_native_word_node(main_f, main_k); + tail := link(main_pp); + for main_p := 0 to main_k - 1 do + set_native_char(tail, main_p, native_text[main_p]); + set_native_metrics(tail, XeTeX_use_glyph_metrics); + end + end; + + if cur_ptr<>null then goto big_switch + else goto reswitch; +end; +{ End of added code for native fonts } + +adjust_space_factor;@/ +check_for_inter_char_toks(big_switch); +@z + +@x +main_loop_lookahead+1: adjust_space_factor; +@y +main_loop_lookahead+1: adjust_space_factor; +check_for_inter_char_toks(big_switch); +@z + +@x +non_math(math_given), non_math(math_comp), non_math(delim_num), +@y +non_math(math_given), non_math(XeTeX_math_given), non_math(math_comp), non_math(delim_num), +@z + +@x +begin d:=box_max_depth; unsave; save_ptr:=save_ptr-3; +if mode=-hmode then cur_box:=hpack(link(head),saved(2),saved(1)) +else begin cur_box:=vpackage(link(head),saved(2),saved(1),d); + if c=vtop_code then @; + end; +pop_nest; box_end(saved(0)); +@y +@!u,v:integer; {saved values for upwards mode flag} +begin d:=box_max_depth; u:=XeTeX_upwards_state; unsave; save_ptr:=save_ptr-3; +v:=XeTeX_upwards_state; XeTeX_upwards_state:=u; +if mode=-hmode then cur_box:=hpack(link(head),saved(2),saved(1)) +else begin cur_box:=vpackage(link(head),saved(2),saved(1),d); + if c=vtop_code then @; + end; +XeTeX_upwards_state:=v; +pop_nest; box_end(saved(0)); +@z + +@x +procedure append_italic_correction; +label exit; +var p:pointer; {|char_node| at the tail of the current list} +@!f:internal_font_number; {the font in the |char_node|} +begin if tail<>head then + begin if is_char_node(tail) then p:=tail + else if type(tail)=ligature_node then p:=lig_char(tail) + else return; +@y +procedure append_italic_correction; +label exit; +var p:pointer; {|char_node| at the tail of the current list} +@!f:internal_font_number; {the font in the |char_node|} +begin if tail<>head then + begin if is_char_node(tail) then p:=tail + else if type(tail)=ligature_node then p:=lig_char(tail) + else if (type(tail)=whatsit_node) then begin + if (subtype(tail)=native_word_node) then begin + tail_append(new_kern(get_native_italic_correction(tail))); subtype(tail):=explicit; + end + else if (subtype(tail)=glyph_node) then begin + tail_append(new_kern(get_native_glyph_italic_correction(tail))); subtype(tail):=explicit; + end; + return; + end + else return; +@z + +@x + if c>=0 then if c<256 then pre_break(tail):=new_character(cur_font,c); +@y + if c>=0 then if c<=biggest_char then pre_break(tail):=new_character(cur_font,c); +@z + +@x + if type(p)<>kern_node then if type(p)<>ligature_node then + begin print_err("Improper discretionary list"); +@y + if type(p)<>kern_node then if type(p)<>ligature_node then + if (type(p)<>whatsit_node) or ((subtype(p)<>native_word_node) + and (subtype(p)<>glyph_node)) then + begin print_err("Improper discretionary list"); +@z + +@x +@!a,@!h,@!x,@!w,@!delta:scaled; {heights and widths, as explained above} +@y +@!a,@!h,@!x,@!w,@!delta,@!lsb,@!rsb:scaled; {heights and widths, as explained above} +@z + +@x + a:=char_width(f)(char_info(f)(character(p)));@/ +@y + if is_native_font(f) then + begin a:=width(p); + if a=0 then get_native_char_sidebearings(f, cur_val, address_of(lsb), address_of(rsb)) + end + else a:=char_width(f)(char_info(f)(character(p)));@/ +@z + +@x +if (cur_cmd=letter)or(cur_cmd=other_char)or(cur_cmd=char_given) then + q:=new_character(f,cur_chr) +@y +if (cur_cmd=letter)or(cur_cmd=other_char)or(cur_cmd=char_given) then + begin q:=new_character(f,cur_chr); cur_val:=cur_chr + end +@z + +@x +i:=char_info(f)(character(q)); +w:=char_width(f)(i); h:=char_height(f)(height_depth(i)); +@y +if is_native_font(f) then begin + w:=width(q); + get_native_char_height_depth(f, cur_val, address_of(h), address_of(delta)) + {using delta as scratch space for the unneeded depth value} +end else begin + i:=char_info(f)(character(q)); + w:=char_width(f)(i); h:=char_height(f)(height_depth(i)) +end; +@z + +@x +delta:=round((w-a)/float_constant(2)+h*t-x*s); +@y +if is_native_font(f) and (a=0) then { special case for non-spacing marks } + delta:=round((w-lsb+rsb)/float_constant(2)+h*t-x*s) +else delta:=round((w-a)/float_constant(2)+h*t-x*s); +@z + +@x +procedure cs_error; +begin +if cur_chr = 10 then +begin + print_err("Extra "); print_esc("endmubyte"); +@.Extra \\endmubyte@> + help1("I'm ignoring this, since I wasn't doing a \mubyte."); +end else begin + print_err("Extra "); print_esc("endcsname"); +@.Extra \\endcsname@> + help1("I'm ignoring this, since I wasn't doing a \csname."); +end; +error; +end; +@y +procedure cs_error; +begin print_err("Extra "); print_esc("endcsname"); +@.Extra \\endcsname@> +help1("I'm ignoring this, since I wasn't doing a \csname."); +error; +end; +@z + +@x +whatsit_node: @; +@y +whatsit_node: @; +@z + +@x +letter,other_char,char_given: begin c:=ho(math_code(cur_chr)); + if c=@'100000 then +@y +letter,other_char,char_given: begin c:=ho(math_code(cur_chr)); + if is_active_math_char(c) then +@z + +@x +math_char_num: begin scan_fifteen_bit_int; c:=cur_val; + end; +@y +math_char_num: + if cur_chr = 2 then begin { \XeTeXmathchar } + scan_math_class_int; c := set_class_field(cur_val); + scan_math_fam_int; c := c + set_family_field(cur_val); + scan_usv_num; c := c + cur_val; + end else if cur_chr = 1 then begin { \XeTeXmathcharnum } + scan_xetex_math_char_int; c := cur_val; + end else begin scan_fifteen_bit_int; + c := set_class_field(cur_val div @"1000) + + set_family_field((cur_val mod @"1000) div @"100) + + (cur_val mod @"100); + end; +@z + +@x +math_given: c:=cur_chr; +delim_num: begin scan_twenty_seven_bit_int; c:=cur_val div @'10000; +@y +math_given: begin + c := set_class_field(cur_chr div @"1000) + + set_family_field((cur_chr mod @"1000) div @"100) + + (cur_chr mod @"100); + end; +XeTeX_math_given: c:=cur_chr; +delim_num: begin + if cur_chr=1 then begin {\XeTeXdelimiter } + scan_math_class_int; c := set_class_field(cur_val); + scan_math_fam_int; c := c + set_family_field(cur_val); + scan_usv_num; c := c + cur_val; + end else begin {\delimiter <27-bit delcode>} + scan_delimiter_int; + c := cur_val div @'10000; {get the 'small' delimiter field} + c := set_class_field(c div @"1000) + + set_family_field((c mod @"1000) div @"100) + + (c mod @"100); {and convert it to a xetex mathchar code} + end; +@z + +@x +math_type(p):=math_char; character(p):=qi(c mod 256); +if (c>=var_code)and fam_in_range then fam(p):=cur_fam +else fam(p):=(c div 256) mod 16; +@y +math_type(p):=math_char; character(p):=qi(c mod @"10000); +if (is_var_family(c)) and fam_in_range then plane_and_fam_field(p):=cur_fam +else plane_and_fam_field(p):=(math_fam_field(c)); +plane_and_fam_field(p) := plane_and_fam_field(p) + (math_char_field(c) div @"10000) * @"100; +@z + +@x +mmode+math_char_num: begin scan_fifteen_bit_int; set_math_char(cur_val); + end; +@y +mmode+math_char_num: if cur_chr = 2 then begin { \XeTeXmathchar } + scan_math_class_int; t := set_class_field(cur_val); + scan_math_fam_int; t := t + set_family_field(cur_val); + scan_usv_num; t := t + cur_val; + set_math_char(t); + end else if cur_chr = 1 then begin { \XeTeXmathcharnum } + scan_xetex_math_char_int; set_math_char(cur_val); + end else begin scan_fifteen_bit_int; + set_math_char(set_class_field(cur_val div @"1000) + + set_family_field((cur_val mod @"1000) div @"100) + + (cur_val mod @"100)); + end; +@z + +@x +mmode+math_given: set_math_char(cur_chr); +mmode+delim_num: begin scan_twenty_seven_bit_int; + set_math_char(cur_val div @'10000); +@y +mmode+math_given: begin + set_math_char(set_class_field(cur_chr div @"1000) + + set_family_field((cur_chr mod @"1000) div @"100) + + (cur_chr mod @"100)); + end; +mmode+XeTeX_math_given: set_math_char(cur_chr); +mmode+delim_num: begin + if cur_chr=1 then begin {\XeTeXdelimiter} + scan_math_class_int; t := set_class_field(cur_val); + scan_math_fam_int; t := t + set_family_field(cur_val); + scan_usv_num; t := t + cur_val; + set_math_char(t); + end else begin + scan_delimiter_int; + cur_val:=cur_val div @'10000; {discard the large delimiter code} + set_math_char(set_class_field(cur_val div @"1000) + + set_family_field((cur_val mod @"1000) div @"100) + + (cur_val mod @"100)); + end; +@z + +@x +procedure set_math_char(@!c:integer); +var p:pointer; {the new noad} +begin if c>=@'100000 then + @ +else begin p:=new_noad; math_type(nucleus(p)):=math_char; + character(nucleus(p)):=qi(c mod 256); + fam(nucleus(p)):=(c div 256) mod 16; + if c>=var_code then + begin if fam_in_range then fam(nucleus(p)):=cur_fam; + type(p):=ord_noad; + end + else type(p):=ord_noad+(c div @'10000); +@y +procedure set_math_char(@!c:integer); +var p,q,r:pointer; {the new noad} + ch: UnicodeScalar; +begin if is_active_math_char(c) then + @ +else begin p:=new_noad; math_type(nucleus(p)):=math_char; + ch:=math_char_field(c); + character(nucleus(p)):=qi(ch mod @"10000); + plane_and_fam_field(nucleus(p)):=math_fam_field(c); + if is_var_family(c) then + begin if fam_in_range then plane_and_fam_field(nucleus(p)):=cur_fam; + type(p):=ord_noad; + end + else type(p):=ord_noad+math_class_field(c); + plane_and_fam_field(nucleus(p)) := plane_and_fam_field(nucleus(p)) + (ch div @"10000) * @"100; +@z + +@x +procedure scan_delimiter(@!p:pointer;@!r:boolean); +begin if r then scan_twenty_seven_bit_int +@y +procedure scan_delimiter(@!p:pointer;@!r:boolean); +begin + if r then begin + if cur_chr=1 then begin {\XeTeXradical} + cur_val1 := @"40000000; {extended delcode flag} + scan_math_fam_int; cur_val1 := cur_val1 + cur_val * @"200000; + scan_usv_num; cur_val := cur_val1 + cur_val; + end else {\radical} + scan_delimiter_int; + end +@z + +@x + letter,other_char: cur_val:=del_code(cur_chr); + delim_num: scan_twenty_seven_bit_int; + othercases cur_val:=-1 +@y + letter,other_char: begin + cur_val:=del_code(cur_chr); + end; + delim_num: if cur_chr=1 then begin {\XeTeXdelimiter} + cur_val1 := @"40000000; {extended delcode flag} + scan_math_class_int; {discarded} + scan_math_fam_int; cur_val1 := cur_val1 + cur_val * @"200000; + scan_usv_num; cur_val := cur_val1 + cur_val; + end else scan_delimiter_int; {normal \delimiter} + othercases begin cur_val:=-1; end; +@z + +@x +if cur_val<0 then @; +small_fam(p):=(cur_val div @'4000000) mod 16; +small_char(p):=qi((cur_val div @'10000) mod 256); +large_fam(p):=(cur_val div 256) mod 16; +large_char(p):=qi(cur_val mod 256); +@y +if cur_val<0 then begin @; + end; +if cur_val>=@"40000000 then begin {extended delcode, only one size} + small_plane_and_fam_field(p) := ((cur_val mod @"200000) div @"10000) * @"100 {plane} + + (cur_val div @"200000) mod @"100; {family} + small_char_field(p) := qi(cur_val mod @"10000); + large_plane_and_fam_field(p) := 0; + large_char_field(p) := 0; +end else begin {standard delcode, 4-bit families and 8-bit char codes} + small_plane_and_fam_field(p) := (cur_val div @'4000000) mod 16; + small_char_field(p) := qi((cur_val div @'10000) mod 256); + large_plane_and_fam_field(p) := (cur_val div 256) mod 16; + large_char_field(p) := qi(cur_val mod 256); +end; +@z + +@x +procedure math_ac; +@y +procedure math_ac; +var c: integer; +@z + +@x +scan_fifteen_bit_int; +character(accent_chr(tail)):=qi(cur_val mod 256); +if (cur_val>=var_code)and fam_in_range then fam(accent_chr(tail)):=cur_fam +else fam(accent_chr(tail)):=(cur_val div 256) mod 16; +@y +if cur_chr=1 then begin + scan_math_class_int; c := set_class_field(cur_val); + scan_math_fam_int; c := c + set_family_field(cur_val); + scan_usv_num; cur_val := cur_val + c; +end +else begin + scan_fifteen_bit_int; + cur_val := set_class_field(cur_val div @"1000) + + set_family_field((cur_val mod @"1000) div @"100) + + (cur_val mod @"100); +end; +character(accent_chr(tail)):=qi(cur_val mod @"10000); +if (is_var_family(cur_val))and fam_in_range then plane_and_fam_field(accent_chr(tail)):=cur_fam +else plane_and_fam_field(accent_chr(tail)):=math_fam_field(cur_val); +plane_and_fam_field(accent_chr(tail)) + := plane_and_fam_field(accent_chr(tail)) + (math_char_field(cur_val) div @"10000) * @"100; +@z + +@x +@ @= +if (font_params[fam_fnt(2+text_size)]= +if ((font_params[fam_fnt(2+text_size)] + primitive("noconvert",let,normal+11);@/ +@!@:noconvert_}{\.{\\noconvert} primitive@> +end; +@y +@z + +@x +let: if chr_code<>normal then + if chr_code = normal+10 then print_esc("mubyte") + else if chr_code = normal+11 then print_esc("noconvert") + else print_esc("futurelet") + else print_esc("let"); +@y +let: if chr_code<>normal then print_esc("futurelet")@+else print_esc("let"); +@z + +@x +let: if cur_chr = normal+11 then do_nothing { noconvert primitive } + else if cur_chr = normal+10 then { mubyte primitive } + begin + selector:=term_and_log; + get_token; + mubyte_stoken := cur_tok; + if cur_tok <= cs_token_flag then mubyte_stoken := cur_tok mod 256; + mubyte_prefix := 60; mubyte_relax := false; + mubyte_tablein := true; mubyte_tableout := true; + get_x_token; + if cur_cmd = spacer then get_x_token; + if cur_cmd = sub_mark then + begin + mubyte_tableout := false; get_x_token; + if cur_cmd = sub_mark then + begin + mubyte_tableout := true; mubyte_tablein := false; + get_x_token; + end; + end else if (mubyte_stoken > cs_token_flag) and + (cur_cmd = mac_param) then + begin + mubyte_tableout := false; + scan_int; mubyte_prefix := cur_val; get_x_token; + if mubyte_prefix > 50 then mubyte_prefix := 52; + if mubyte_prefix <= 0 then mubyte_prefix := 51; + end + else if (mubyte_stoken > cs_token_flag) and (cur_cmd = relax) then + begin + mubyte_tableout := true; mubyte_tablein := false; + mubyte_relax := true; get_x_token; + end; + r := get_avail; p := r; + while cur_cs = 0 do begin store_new_token (cur_tok); get_x_token; end; + if (cur_cmd <> end_cs_name) or (cur_chr <> 10) then + begin + print_err("Missing "); print_esc("endmubyte"); print(" inserted"); + help2("The control sequence marked should")@/ +("not appear in between \mubyte and \endmubyte."); + back_error; + end; + p := link(r); + if (p = null) and mubyte_tablein then + begin + print_err("The empty , "); + print_esc("mubyte"); print(" ignored"); + help2("The in")@/ +("\mubyte \endmubyte should not be empty."); + error; + end else begin + while p <> null do + begin + append_char (info(p) mod 256); + p := link (p); + end; + flush_list (r); + if (str_start [str_ptr] + 1 = pool_ptr) and + (str_pool [pool_ptr-1] = mubyte_stoken) then + begin + if mubyte_read [mubyte_stoken] <> null + and mubyte_tablein then { clearing data } + dispose_munode (mubyte_read [mubyte_stoken]); + if mubyte_tablein then mubyte_read [mubyte_stoken] := null; + if mubyte_tableout then mubyte_write [mubyte_stoken] := 0; + pool_ptr := str_start [str_ptr]; + end else begin + if mubyte_tablein then mubyte_update; { updating input side } + if mubyte_tableout then { updating output side } + begin + if mubyte_stoken > cs_token_flag then { control sequence } + begin + dispose_mutableout (mubyte_stoken-cs_token_flag); + if (str_start [str_ptr] < pool_ptr) or mubyte_relax then + begin { store data } + r := mubyte_cswrite[(mubyte_stoken-cs_token_flag) mod 128]; + p := get_avail; + mubyte_cswrite[(mubyte_stoken-cs_token_flag) mod 128] := p; + info (p) := mubyte_stoken-cs_token_flag; + link (p) := get_avail; + p := link (p); + if mubyte_relax then begin + info (p) := 0; pool_ptr := str_start [str_ptr]; + end else info (p) := slow_make_string; + link (p) := r; + end; + end else begin { single character } + if str_start [str_ptr] = pool_ptr then + mubyte_write [mubyte_stoken] := 0 + else + mubyte_write [mubyte_stoken] := slow_make_string; + end; + end else pool_ptr := str_start [str_ptr]; + end; + end; + end else begin { let primitive } + n:=cur_chr; +@y +let: begin n:=cur_chr; +@z + +@x +@d char_def_code=0 {|shorthand_def| for \.{\\chardef}} +@d math_char_def_code=1 {|shorthand_def| for \.{\\mathchardef}} +@d count_def_code=2 {|shorthand_def| for \.{\\countdef}} +@d dimen_def_code=3 {|shorthand_def| for \.{\\dimendef}} +@d skip_def_code=4 {|shorthand_def| for \.{\\skipdef}} +@d mu_skip_def_code=5 {|shorthand_def| for \.{\\muskipdef}} +@d toks_def_code=6 {|shorthand_def| for \.{\\toksdef}} +@d char_sub_def_code=7 {|shorthand_def| for \.{\\charsubdef}} +@y +@d char_def_code=0 {|shorthand_def| for \.{\\chardef}} +@d math_char_def_code=1 {|shorthand_def| for \.{\\mathchardef}} +@d count_def_code=2 {|shorthand_def| for \.{\\countdef}} +@d dimen_def_code=3 {|shorthand_def| for \.{\\dimendef}} +@d skip_def_code=4 {|shorthand_def| for \.{\\skipdef}} +@d mu_skip_def_code=5 {|shorthand_def| for \.{\\muskipdef}} +@d toks_def_code=6 {|shorthand_def| for \.{\\toksdef}} +@d char_sub_def_code=7 {|shorthand_def| for \.{\\charsubdef}} +@d XeTeX_math_char_num_def_code=8 +@d XeTeX_math_char_def_code=9 +@z + +@x +primitive("mathchardef",shorthand_def,math_char_def_code);@/ +@!@:math_char_def_}{\.{\\mathchardef} primitive@> +@y +primitive("mathchardef",shorthand_def,math_char_def_code);@/ +primitive("XeTeXmathcharnumdef",shorthand_def,XeTeX_math_char_num_def_code);@/ +primitive("XeTeXmathchardef",shorthand_def,XeTeX_math_char_def_code);@/ +@!@:math_char_def_}{\.{\\mathchardef} primitive@> +@z + +@x + math_char_def_code: print_esc("mathchardef"); +@y + math_char_def_code: print_esc("mathchardef"); + XeTeX_math_char_def_code: print_esc("XeTeXmathchardef"); + XeTeX_math_char_num_def_code: print_esc("XeTeXmathcharnumdef"); +@z + +@x +math_given: begin print_esc("mathchar"); print_hex(chr_code); + end; +@y +math_given: begin print_esc("mathchar"); print_hex(chr_code); + end; +XeTeX_math_given: begin print_esc("XeTeXmathchar"); print_hex(chr_code); + end; +@z + +@x +else begin n:=cur_chr; get_r_token; p:=cur_cs; define(p,relax,256); +@y +else begin n:=cur_chr; get_r_token; p:=cur_cs; define(p,relax,too_big_char); +@z + +@x + char_def_code: begin scan_char_num; define(p,char_given,cur_val); +@y + char_def_code: begin scan_usv_num; define(p,char_given,cur_val); +@z + +@x + math_char_def_code: begin scan_fifteen_bit_int; define(p,math_given,cur_val); + end; +@y + math_char_def_code: begin scan_fifteen_bit_int; define(p,math_given,cur_val); + end; + XeTeX_math_char_num_def_code: begin scan_xetex_math_char_int; + define(p, XeTeX_math_given, cur_val); + end; + XeTeX_math_char_def_code: begin + scan_math_class_int; n := set_class_field(cur_val); + scan_math_fam_int; n := n + set_family_field(cur_val); + scan_usv_num; n := n + cur_val; + define(p, XeTeX_math_given, n); + end; +@z + +@x + else e:=true; +@y + else e:=true + else if cur_chr=XeTeX_inter_char_loc then begin + scan_eight_bit_int; cur_ptr:=cur_val; + scan_eight_bit_int; + find_sa_element(inter_char_val, cur_ptr*@"100 + cur_val, true); + cur_chr:=cur_ptr; e:=true; + end; +@z + +@x + else q:=equiv(cur_chr); +@y + else if cur_chr=XeTeX_inter_char_loc then begin + scan_eight_bit_int; cur_ptr:=cur_val; + scan_eight_bit_int; + find_sa_element(inter_char_val, cur_ptr*@"100 + cur_val, false); + if cur_ptr=null then q:=null + else q:=sa_ptr(cur_ptr); + end else q:=equiv(cur_chr); +@z + +@x +if enctex_p then +begin + primitive("xordcode",def_code,xord_code_base); +@!@:xord_code_}{\.{\\xordcode} primitive@> + primitive("xchrcode",def_code,xchr_code_base); +@!@:xchr_code_}{\.{\\xchrcode} primitive@> + primitive("xprncode",def_code,xprn_code_base); +@!@:xprn_code_}{\.{\\xprncode} primitive@> +end; +primitive("mathcode",def_code,math_code_base); +@y +primitive("mathcode",def_code,math_code_base); +primitive("XeTeXmathcodenum",XeTeX_def_code,math_code_base); +primitive("XeTeXmathcode",XeTeX_def_code,math_code_base+1); +@z + +@x +primitive("sfcode",def_code,sf_code_base); +@!@:sf_code_}{\.{\\sfcode} primitive@> +primitive("delcode",def_code,del_code_base); +@y +primitive("sfcode",def_code,sf_code_base); +@!@:sf_code_}{\.{\\sfcode} primitive@> +primitive("XeTeXcharclass",XeTeX_def_code,sf_code_base); +primitive("delcode",def_code,del_code_base); +primitive("XeTeXdelcodenum",XeTeX_def_code,del_code_base); +primitive("XeTeXdelcode",XeTeX_def_code,del_code_base+1); +@z + +@x +def_code: if chr_code=xord_code_base then print_esc("xordcode") + else if chr_code=xchr_code_base then print_esc("xchrcode") + else if chr_code=xprn_code_base then print_esc("xprncode") + else if chr_code=cat_code_base then print_esc("catcode") +@y +def_code: if chr_code=cat_code_base then print_esc("catcode") +@z + +@x +def_family: print_size(chr_code-math_font_base); +@y +XeTeX_def_code: + if chr_code=sf_code_base then print_esc("XeTeXcharclass") + else if chr_code=math_code_base then print_esc("XeTeXmathcodenum") + else if chr_code=math_code_base+1 then print_esc("XeTeXmathcode") + else if chr_code=del_code_base then print_esc("XeTeXdelcodenum") + else print_esc("XeTeXdelcode"); +def_family: print_size(chr_code-math_font_base); +@z + +@x +def_code: begin @; + p:=cur_chr; scan_char_num; +@y +XeTeX_def_code: begin + if cur_chr = sf_code_base then begin + p:=cur_chr; scan_usv_num; + p:=p+cur_val; + n:=sf_code(cur_val) mod @"10000; + scan_optional_equals; + scan_char_class; + define(p,data,cur_val*@"10000 + n); + end + else if cur_chr = math_code_base then begin + p:=cur_chr; scan_usv_num; + p:=p+cur_val; + scan_optional_equals; + scan_xetex_math_char_int; + define(p,data,hi(cur_val)); + end + else if cur_chr = math_code_base+1 then begin + p:=cur_chr-1; scan_usv_num; + p:=p+cur_val; + scan_optional_equals; + scan_math_class_int; n := set_class_field(cur_val); + scan_math_fam_int; n := n + set_family_field(cur_val); + scan_usv_num; n := n + cur_val; + define(p,data,hi(n)); + end + else if cur_chr = del_code_base then begin + p:=cur_chr; scan_usv_num; + p:=p+cur_val; + scan_optional_equals; + scan_int; {scan_xetex_del_code_int; !!FIXME!!} + word_define(p,hi(cur_val)); + end else begin +{ +bit usage in delcode values: +original layout: @"00cffCFF small/LARGE family & char +extended: @"40000000 FLAG + + ff << 21 (mult by @"200000) FAMILY + + 1ccccc (21 bits) USV +} + p:=cur_chr-1; scan_usv_num; + p:=p+cur_val; + scan_optional_equals; + n := @"40000000; {extended delcode flag} + scan_math_fam_int; n := n + cur_val * @"200000; + scan_usv_num; n := n + cur_val; + word_define(p,hi(n)); + end; + end; +def_code: begin @; + p:=cur_chr; scan_usv_num; +@z + +@x + if p=xord_code_base then p:=cur_val + else if p=xchr_code_base then p:=cur_val+256 + else if p=xprn_code_base then p:=cur_val+512 + else p:=p+cur_val; +@y + p:=p+cur_val; +@z + +@x + if p<256 then xord[p]:=cur_val + else if p<512 then xchr[p-256]:=cur_val + else if p<768 then xprn[p-512]:=cur_val + else if p=sf_code_base then begin + n:=equiv(p) div @"10000; + define(p,data,n*@"10000 + cur_val); + end else + define(p,data,cur_val) + end else if p; +@y +@z + +@x +@!format_engine: ^text_char; +@y +@!format_engine: ^char; +@z + +@x +@!dummy_xord: ASCII_code; +@!dummy_xchr: text_char; +@!dummy_xprn: ASCII_code; +@y +@z + +@x +@; +@y +@z + +@x +format_engine:=xmalloc_array(text_char,x+4); +@y +format_engine:=xmalloc_array(char,x+4); +@z + +@x +@; +@y +@z + +@x +format_engine:=xmalloc_array(text_char, x); +@y +format_engine:=xmalloc_array(char, x); +@z + +@x +@; +@y +@z + +@x +dump_things(str_start[0], str_ptr+1); +@y +dump_things(str_start_macro(too_big_char), str_ptr+1-too_big_char); +@z + +@x +undump_checked_things(0, pool_ptr, str_start[0], str_ptr+1);@/ +@y +undump_checked_things(0, pool_ptr, str_start_macro(too_big_char), str_ptr+1-too_big_char);@/ +@z + +@x +if eTeX_ex then for k:=int_val to tok_val do dump_int(sa_root[k]); +@y +if eTeX_ex then for k:=int_val to inter_char_val do dump_int(sa_root[k]); +@z + +@x +if eTeX_ex then for k:=int_val to tok_val do +@y +if eTeX_ex then for k:=int_val to inter_char_val do +@z + +@x + print_file_name(font_name[k],font_area[k],""); +@y + if is_native_font(k) then + begin print_file_name(font_name[k],"",""); + print_err("Can't \dump a format with preloaded native fonts"); + help2("You really, really don't want to do this.") + ("It won't work, and only confuses me."); + error; + end + else print_file_name(font_name[k],font_area[k],""); +@z + +@x +begin {Allocate the font arrays} +@y +begin {Allocate the font arrays} +font_mapping:=xmalloc_array(void_pointer, font_max); +font_layout_engine:=xmalloc_array(void_pointer, font_max); +font_flags:=xmalloc_array(char, font_max); +font_letter_space:=xmalloc_array(scaled, font_max); +@z + +@x +font_bc:=xmalloc_array(eight_bits, font_max); +font_ec:=xmalloc_array(eight_bits, font_max); +@y +font_bc:=xmalloc_array(UTF16_code, font_max); +font_ec:=xmalloc_array(UTF16_code, font_max); +@z + +@x +dump_int(trie_op_ptr); +@y +dump_int(max_hyph_char); +dump_int(trie_op_ptr); +@z + +@x +for k:=255 downto 0 do if trie_used[k]>min_quarterword then +@y +for k:=biggest_lang downto 0 do if trie_used[k]>min_quarterword then +@z + +@x +undump_size(0)(trie_op_size)('trie op size')(j); @+init trie_op_ptr:=j;@+tini +@y +undump_int(max_hyph_char); +undump_size(0)(trie_op_size)('trie op size')(j); @+init trie_op_ptr:=j;@+tini +@z + +@x +init for k:=0 to 255 do trie_used[k]:=min_quarterword;@+tini@;@/ +k:=256; +@y +init for k:=0 to biggest_lang do trie_used[k]:=min_quarterword;@+tini@;@/ +k:=biggest_lang+1; +@z + +@x +undump_int(x); +if (x<>69069)or feof(fmt_file) then goto bad_fmt +@y +undump_int(x); +if (x<>69069) then goto bad_fmt; +if not w_eof(fmt_file) then goto bad_fmt +@z + +@x +@* \[51] The main program. +@y +@* \[51] The main program. +@z + +@x + setup_bound_var (15000)('max_strings')(max_strings); +@y + setup_bound_var (15000)('max_strings')(max_strings); + max_strings:=max_strings+too_big_char; {the max_strings value doesn't include the 64K synthetic strings} +@z + +@x + buffer:=xmalloc_array (ASCII_code, buf_size); +@y + buffer:=xmalloc_array (UnicodeScalar, buf_size); +@z + +@x + input_file:=xmalloc_array (alpha_file, max_in_open); +@y + input_file:=xmalloc_array (unicode_file, max_in_open); +@z + +@x + print_file_name(0, log_name, 0); print_char("."); +@y + print(log_name); print_char("."); +@z + +@x +if enctex_enabled_p then + begin wterm(encTeX_banner); wterm_ln(', reencoding enabled.'); + if translate_filename then begin + wterm_ln(' (\xordcode, \xchrcode, \xprncode overridden by TCX)'); + end; + end; +@y +@z + +@x + {Allocate and initialize font arrays} +@y + {Allocate and initialize font arrays} + font_mapping:=xmalloc_array(void_pointer, font_max); + font_layout_engine:=xmalloc_array(void_pointer, font_max); + font_flags:=xmalloc_array(char, font_max); + font_letter_space:=xmalloc_array(scaled, font_max); +@z + +@x + font_bc:=xmalloc_array(eight_bits, font_max); + font_ec:=xmalloc_array(eight_bits, font_max); +@y + font_bc:=xmalloc_array(UTF16_code, font_max); + font_ec:=xmalloc_array(UTF16_code, font_max); +@z + +@x +@* \[53] Extensions. +@y +@* \[53] Extensions. +@z + +@x +@d write_stream(#) == type(#+1) {stream number (0 to 17)} +@d mubyte_zero == 64 +@d write_mubyte(#) == subtype(#+1) {mubyte value + |mubyte_zero|} +@y +@d write_stream(#) == info(#+1) {stream number (0 to 17)} +@z + +@x +@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_save_pos_node == pdftex_first_extension_code + 0 + +@d pic_file_code=41 { command modifier for \.{\\XeTeXpicfile}, skipping codes pdfTeX might use } +@d pdf_file_code=42 { command modifier for \.{\\XeTeXpdffile} } +@d glyph_code=43 { command modifier for \.{\\XeTeXglyph} } + +@d XeTeX_input_encoding_extension_code=44 +@d XeTeX_default_encoding_extension_code=45 +@d XeTeX_linebreak_locale_extension_code=46 +@z + +@x +@!@:set_language_}{\.{\\setlanguage} primitive@> +@y +@!@:set_language_}{\.{\\setlanguage} primitive@> + +@ The \.{\\XeTeXpicfile} and \.{\\XeTeXpdffile} primitives are only defined in extended mode. + +@= +primitive("XeTeXpicfile",extension,pic_file_code);@/ +primitive("XeTeXpdffile",extension,pdf_file_code);@/ +primitive("XeTeXglyph",extension,glyph_code);@/ +primitive("XeTeXlinebreaklocale", extension, XeTeX_linebreak_locale_extension_code);@/ +primitive("XeTeXinterchartoks",assign_toks,XeTeX_inter_char_loc); + +primitive("pdfsavepos",extension,pdf_save_pos_node);@/ +@z + +@x + set_language_code:print_esc("setlanguage"); +@y + set_language_code:print_esc("setlanguage"); + pic_file_code:print_esc("XeTeXpicfile"); + pdf_file_code:print_esc("XeTeXpdffile"); + glyph_code:print_esc("XeTeXglyph"); + XeTeX_linebreak_locale_extension_code:print_esc("XeTeXlinebreaklocale"); + XeTeX_input_encoding_extension_code:print_esc("XeTeXinputencoding"); + XeTeX_default_encoding_extension_code:print_esc("XeTeXdefaultencoding"); + pdf_save_pos_node: print_esc("pdfsavepos"); +@z + +@x +set_language_code:@; +@y +set_language_code:@; +pic_file_code:@; +pdf_file_code:@; +glyph_code:@; +XeTeX_input_encoding_extension_code:@; +XeTeX_default_encoding_extension_code:@; +XeTeX_linebreak_locale_extension_code:@; + +pdf_save_pos_node: @; +@z + +@x +if mubyte_out + mubyte_zero < 0 then write_mubyte(tail) := 0 +else if mubyte_out + mubyte_zero >= 2*mubyte_zero then + write_mubyte(tail) := 2*mubyte_zero - 1 + else write_mubyte(tail) := mubyte_out + mubyte_zero; +@y +@z + +@x +@= +begin new_whatsit(special_node,write_node_size); +if spec_out + mubyte_zero < 0 then write_stream(tail) := 0 +else if spec_out + mubyte_zero >= 2*mubyte_zero then + write_stream(tail) := 2*mubyte_zero - 1 + else write_stream(tail) := spec_out + mubyte_zero; +if mubyte_out + mubyte_zero < 0 then write_mubyte(tail) := 0 +else if mubyte_out + mubyte_zero >= 2*mubyte_zero then + write_mubyte(tail) := 2*mubyte_zero - 1 + else write_mubyte(tail) := mubyte_out + mubyte_zero; +if (spec_out = 2) or (spec_out = 3) then + if (mubyte_out > 2) or (mubyte_out = -1) or (mubyte_out = -2) then + write_noexpanding := true; +p:=scan_toks(false,true); write_tokens(tail):=def_ref; +write_noexpanding := false; +end +@y +@= +begin new_whatsit(special_node,write_node_size); write_stream(tail):=0; +p:=scan_toks(false,true); write_tokens(tail):=def_ref; +end +@z + +@x +if (s = "write") and (write_mubyte (p) <> mubyte_zero) then +begin + print_char ("<"); print_int (write_mubyte(p)-mubyte_zero); print_char (">"); +end; +@y +@z + +@x +@ @= +@y +procedure print_native_word(@!p:pointer); +var i,c,cc:integer; +begin + for i:=0 to native_length(p) - 1 do begin + c:=get_native_char(p,i); + if (c >= @"D800) and (c <= @"DBFF) then begin + if i < native_length(p) - 1 then begin + cc:=get_native_char(p, i+1); + if (cc >= @"DC00) and (cc <= @"DFFF) then begin + c := @"10000 + (c - @"D800) * @"400 + (cc - @"DC00); + print_char(c); + incr(i); + end else + print("."); + end else + print("."); + end else + print_char(c); + end +end; + +@ @= +@z + +@x +if write_stream(p) <> mubyte_zero then +begin + print_char ("<"); print_int (write_stream(p)-mubyte_zero); + if (write_stream(p)-mubyte_zero = 2) or + (write_stream(p)-mubyte_zero = 3) then + begin + print_char (":"); print_int (write_mubyte(p)-mubyte_zero); + end; + print_char (">"); +end; +@y +@z + +@x +othercases print("whatsit?") +@y +native_word_node:begin + print_esc(font_id_text(native_font(p))); + print_char(" "); + print_native_word(p); + end; +glyph_node:begin + print_esc(font_id_text(native_font(p))); + print(" glyph#"); + print_int(native_glyph(p)); + end; +pic_node,pdf_node: begin + if subtype(p) = pic_node then print_esc("XeTeXpicfile") + else print_esc("XeTeXpdffile"); + print(" """); + for i:=0 to pic_path_length(p)-1 do + print_visible_char(pic_path_byte(p, i)); + print(""""); + end; +pdf_save_pos_node: print_esc("pdfsavepos"); +othercases print("whatsit?") +@z + +@x +@ @= +@y +@ Picture nodes are tricky in that they are variable size. +@d total_pic_node_size(#) == (pic_node_size + (pic_path_length(#) + sizeof(memory_word) - 1) div sizeof(memory_word)) + +@= +@z + +@x +othercases confusion("ext2") +@y +native_word_node: begin words:=native_size(p); + r:=get_node(words); + while words > 0 do + begin decr(words); mem[r+words]:=mem[p+words]; end; + native_glyph_info_ptr(r):=null_ptr; native_glyph_count(r):=0; + copy_native_glyph_info(p, r); + end; +glyph_node: begin r:=get_node(glyph_node_size); + words:=glyph_node_size; + end; +pic_node,pdf_node: begin words:=total_pic_node_size(p); + r:=get_node(words); + end; +pdf_save_pos_node: + r := get_node(small_node_size); +othercases confusion("ext2") +@z + +@x +othercases confusion("ext3") +@y +native_word_node: begin free_native_glyph_info(p); free_node(p,native_size(p)); end; +glyph_node: free_node(p,glyph_node_size); +pic_node,pdf_node: free_node(p,total_pic_node_size(p)); +pdf_save_pos_node: + free_node(p, small_node_size); +othercases confusion("ext3") +@z + +@x +@ @=do_nothing +@y +@ @= +begin + if (subtype(p)=pic_node) + or (subtype(p)=pdf_node) + then begin + x := x + d + height(p); + d := depth(p); + if width(p) > w then w := width(p); + end; +end +@z + +@x +@ @=do_nothing +@y +@ @= +begin + case subtype(p) of + + native_word_node: + begin + { merge with any following word fragments in same font, discarding discretionary breaks } + while (link(q) <> p) do q := link(q); { bring q up in preparation for deletion of nodes starting at p } + pp := link(p); + restart: + if (pp <> null) and (not is_char_node(pp)) then begin + if (type(pp) = whatsit_node) + and (subtype(pp) = native_word_node) + and (native_font(pp) = native_font(p)) then begin + pp := link(pp); + goto restart; + end + else if (type(pp) = disc_node) then begin + ppp := link(pp); + if (ppp <> null) and (not is_char_node(ppp)) + and (type(ppp) = whatsit_node) + and (subtype(ppp) = native_word_node) + and (native_font(ppp) = native_font(p)) then begin + pp := link(ppp); + goto restart; + end + end + end; + + { now pp points to the non-native_word node that ended the chain, or null } + + { we can just check type(p)=whatsit_node below, as we know that the chain + contains only discretionaries and native_word nodes, no other whatsits or char_nodes } + + if (pp <> link(p)) then begin + { found a chain of at least two pieces starting at p } + total_chars := 0; + p := link(q); { the first fragment } + while (p <> pp) do begin + if (type(p) = whatsit_node) then + total_chars := total_chars + native_length(p); { accumulate char count } + ppp := p; { remember last node seen } + p := link(p); { point to next fragment or discretionary or terminator } + end; + + p := link(q); { the first fragment again } + pp := new_native_word_node(native_font(p), total_chars); { make new node for merged word } + link(q) := pp; { link to preceding material } + link(pp) := link(ppp); { attach remainder of hlist to it } + link(ppp) := null; { and detach from the old fragments } + + { copy the chars into new node } + total_chars := 0; + ppp := p; + repeat + if (type(ppp) = whatsit_node) then + for k := 0 to native_length(ppp)-1 do begin + set_native_char(pp, total_chars, get_native_char(ppp, k)); + incr(total_chars); + end; + ppp := link(ppp); + until (ppp = null); + + flush_node_list(p); { delete the fragments } + p := link(q); { update p to point to the new node } + set_native_metrics(p, XeTeX_use_glyph_metrics); { and measure it (i.e., re-do the OT layout) } + end; + + { now incorporate the native_word node measurements into the box we're packing } + if height(p) > h then + h := height(p); + if depth(p) > d then + d := depth(p); + x := x + width(p); + end; + + glyph_node, pic_node, pdf_node: + begin + if height(p) > h then + h := height(p); + if depth(p) > d then + d := depth(p); + x := x + width(p); + end; + + othercases + do_nothing + + endcases +end +@z + +@x +@ @=d:=0 +@y +@ @= +if (subtype(p)=native_word_node) +or (subtype(p)=glyph_node) +or (subtype(p)=pic_node) +or (subtype(p)=pdf_node) +then begin + d:=width(p); + goto found; +end else + d := 0 +@z + +@x +@ @d adv_past(#)==@+if subtype(#)=language_node then + begin cur_lang:=what_lang(#); l_hyf:=what_lhm(#); r_hyf:=what_rhm(#);@+end +@y +@ @d adv_past(#)==@+if subtype(#)=language_node then + begin cur_lang:=what_lang(#); l_hyf:=what_lhm(#); r_hyf:=what_rhm(#);@+end + else if (subtype(#)=native_word_node) + or (subtype(#)=glyph_node) + or (subtype(#)=pic_node) + or (subtype(#)=pdf_node) + then + begin act_width:=act_width+width(#); end +@z + +@x +@ @= +goto contribute +@y +@ @= +begin + if (subtype(p)=pic_node) + or (subtype(p)=pdf_node) + then begin + page_total := page_total + page_depth + height(p); + page_depth := depth(p); + end; + goto contribute; +end +@z + +@x +@ @= +goto not_found +@y +@ @= +begin + if (subtype(p)=pic_node) + or (subtype(p)=pdf_node) + then begin + cur_height := cur_height + prev_dp + height(p); prev_dp := depth(p); + end; + goto not_found; +end +@z + +@x +@ @= +out_what(p) +@y +@ @= +begin + case subtype(p) of + glyph_node: begin + cur_v:=cur_v+height(p); + cur_h:=left_edge; + + { synch DVI state to TeX state } + synch_h; synch_v; + f := native_font(p); + if f<>dvi_f then @; + + dvi_out(set_glyph_string); + dvi_four(0); { width } + dvi_two(1); { glyph count } + dvi_four(0); { x-offset as fixed point } + dvi_two(native_glyph(p)); + + cur_v:=cur_v+depth(p); + cur_h:=left_edge; + end; + pic_node, pdf_node: begin + save_h:=dvi_h; save_v:=dvi_v; + cur_v:=cur_v+height(p); + pic_out(p, subtype(p) = pdf_node); + dvi_h:=save_h; dvi_v:=save_v; + cur_v:=save_v+depth(p); cur_h:=left_edge; + end; + + pdf_save_pos_node: + @; + + othercases + out_what(p) + + endcases +end +@z + +@x +@ @= +out_what(p) +@y +@ @= +begin + pdf_last_x_pos := cur_h + cur_h_offset; + pdf_last_y_pos := cur_page_height - cur_v - cur_v_offset +end + +@ @= +cur_h_offset := h_offset + (unity * 7227) / 100; +cur_v_offset := v_offset + (unity * 7227) / 100; +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 + +@ @= +@!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} + +@ @= +begin + case subtype(p) of + native_word_node, glyph_node: begin + { synch DVI state to TeX state } + synch_h; synch_v; + f := native_font(p); + if f<>dvi_f then @; + + if subtype(p) = glyph_node then begin + dvi_out(set_glyph_string); + dvi_four(width(p)); + dvi_two(1); { glyph count } + dvi_four(0); { x-offset as fixed point } + dvi_two(native_glyph(p)); + cur_h := cur_h + width(p); + end else begin + if native_glyph_info_ptr(p) <> null_ptr then begin + len := make_xdv_glyph_array_data(p); + for k := 0 to len-1 do + dvi_out(xdv_buffer_byte(k)); + end; + cur_h := cur_h + width(p); + end; + + dvi_h := cur_h; + end; + + pic_node, pdf_node: begin + save_h:=dvi_h; save_v:=dvi_v; + cur_v:=base_line; + edge:=cur_h+width(p); + if cur_dir=right_to_left then cur_h:=edge; + pic_out(p, subtype(p) = pdf_node); + dvi_h:=save_h; dvi_v:=save_v; + cur_h:=edge; cur_v:=base_line; + end; + + pdf_save_pos_node: + @; + + othercases + out_what(p) + + endcases +end +@z + +@x +procedure special_out(@!p:pointer); +var old_setting:0..max_selector; {holds print |selector|} +@!k:pool_pointer; {index into |str_pool|} +begin synch_h; synch_v;@/ +@y +procedure special_out(@!p:pointer); +var old_setting:0..max_selector; {holds print |selector|} +@!k:pool_pointer; {index into |str_pool|} +begin synch_h; synch_v;@/ +doing_special := true; +@z + +@x +spec_sout := spec_out; spec_out := write_stream(p) - mubyte_zero; +mubyte_sout := mubyte_out; mubyte_out := write_mubyte(p) - mubyte_zero; +active_noconvert := true; +mubyte_slog := mubyte_log; +mubyte_log := 0; +if (mubyte_out > 0) or (mubyte_out = -1) then mubyte_log := 1; +if (spec_out = 2) or (spec_out = 3) then +begin + if (mubyte_out > 0) or (mubyte_out = -1) then + begin + special_printing := true; mubyte_log := 1; + end; + if mubyte_out > 1 then cs_converting := true; +end; +@y +@z + +@x +if (spec_out = 1) or (spec_out = 3) then + for k:=str_start[str_ptr] to pool_ptr-1 do + str_pool[k] := si(xchr[so(str_pool[k])]); +for k:=str_start[str_ptr] to pool_ptr-1 do dvi_out(so(str_pool[k])); +spec_out := spec_sout; mubyte_out := mubyte_sout; mubyte_log := mubyte_slog; +special_printing := false; cs_converting := false; +active_noconvert := false; +pool_ptr:=str_start[str_ptr]; {erase the string} +@y +for k:=str_start_macro(str_ptr) to pool_ptr-1 do dvi_out(so(str_pool[k])); +pool_ptr:=str_start_macro(str_ptr); {erase the string} +doing_special := false; +@z + +@x +@!j:small_number; {write stream number} +@y +@!j:small_number; {write stream number} +@!k:integer; +@z + +@x +begin +mubyte_sout := mubyte_out; mubyte_out := write_mubyte(p) - mubyte_zero; +if (mubyte_out > 2) or (mubyte_out = -1) or (mubyte_out = -2) then + write_noexpanding := true; +@ 1 then cs_converting := true; +mubyte_slog := mubyte_log; +if (mubyte_out > 0) or (mubyte_out = -1) then mubyte_log := 1 +else mubyte_log := 0; +token_show(def_ref); print_ln; +cs_converting := false; write_noexpanding := false; +active_noconvert := false; +mubyte_out := mubyte_sout; mubyte_log := mubyte_slog; +@y +token_show(def_ref); print_ln; +@z + +@x + print(so(str_pool[str_start[str_ptr]+d])); {N.B.: not |print_char|} +@y + print(so(str_pool[str_start_macro(str_ptr)+d])); {N.B.: not |print_char|} +@z + +@x + begin str_pool[str_start[str_ptr]+d]:=xchr[str_pool[str_start[str_ptr]+d]]; + if (str_pool[str_start[str_ptr]+d]=null_code) +@y + begin + if (str_pool[str_start_macro(str_ptr)+d]=null_code) +@z + +@x + system(stringcast(address_of(str_pool[str_start[str_ptr]]))); +@y + if name_of_file then libc_free(name_of_file); + name_of_file := xmalloc(cur_length * 3 + 2); + k := 0; + for d:=0 to cur_length-1 do append_to_name(str_pool[str_start_macro(str_ptr)+d]); + name_of_file[k+1] := 0; + system(name_of_file + 1); +@z + +@x + pool_ptr:=str_start[str_ptr]; {erase the string} +@y + pool_ptr:=str_start_macro(str_ptr); {erase the string} +@z + +@x +@= +@y +@= +procedure pic_out(@!p:pointer; @!is_pdf:boolean); +var + i:integer; +begin +synch_h; synch_v; +dvi_out(pic_file); +if is_pdf then + dvi_out(pic_box_type(p)) +else + dvi_out(0); +dvi_four(pic_transform1(p)); +dvi_four(pic_transform2(p)); +dvi_four(pic_transform3(p)); +dvi_four(pic_transform4(p)); +dvi_four(pic_transform5(p)); +dvi_four(pic_transform6(p)); +dvi_two(pic_page(p)); +dvi_two(pic_path_length(p)); +for i:=0 to pic_path_length(p)-1 do + dvi_out(pic_path_byte(p, i)); +end; + +@z + +@x +language_node:do_nothing; +@y +language_node:do_nothing; +@z + +@x +@ @= +for k:=0 to 15 do if write_open[k] then a_close(write_file[k]) +@y +@ @= +terminate_font_manager; +for k:=0 to 15 do if write_open[k] then a_close(write_file[k]) + +@ @= +if abs(mode)=mmode then report_illegal_case +else load_picture(false) + +@ @= +if abs(mode)=mmode then report_illegal_case +else load_picture(true) + +@ @= +begin + if abs(mode)=vmode then begin + back_input; + new_graf(true); + end else if abs(mode)=mmode then report_illegal_case + else begin + if is_native_font(cur_font) then begin + new_whatsit(glyph_node,glyph_node_size); + scan_int; + if (cur_val<0)or(cur_val>65535) then + begin print_err("Bad glyph number"); + help2("A glyph number must be between 0 and 65535.")@/ + ("I changed this one to zero."); int_error(cur_val); cur_val:=0; + end; + native_font(tail):=cur_font; + native_glyph(tail):=cur_val; + set_native_glyph_metrics(tail, XeTeX_use_glyph_metrics); + end else not_native_font_error(extension, glyph_code, cur_font); + end +end + +@ Load a picture file and handle following keywords. + +@d calc_min_and_max== + begin + xmin := 1000000.0; + xmax := -xmin; + ymin := xmin; + ymax := xmax; + for i := 0 to 3 do begin + if xCoord(corners[i]) < xmin then xmin := xCoord(corners[i]); + if xCoord(corners[i]) > xmax then xmax := xCoord(corners[i]); + if yCoord(corners[i]) < ymin then ymin := yCoord(corners[i]); + if yCoord(corners[i]) > ymax then ymax := yCoord(corners[i]); + end; + end + +@d update_corners== + for i := 0 to 3 do + transform_point(address_of(corners[i]), address_of(t2)) + +@d do_size_requests==begin + { calculate current width and height } + calc_min_and_max; + if x_size_req = 0.0 then begin + make_scale(address_of(t2), y_size_req / (ymax - ymin), y_size_req / (ymax - ymin)); + end else if y_size_req = 0.0 then begin + make_scale(address_of(t2), x_size_req / (xmax - xmin), x_size_req / (xmax - xmin)); + end else begin + make_scale(address_of(t2), x_size_req / (xmax - xmin), y_size_req / (ymax - ymin)); + end; + update_corners; + x_size_req := 0.0; + y_size_req := 0.0; + transform_concat(address_of(t), address_of(t2)); +end + +@= +procedure load_picture(@!is_pdf:boolean); +var + pic_path: ^char; + bounds: real_rect; + t, t2: transform; + corners: array[0..3] of real_point; + x_size_req,y_size_req: real; + check_keywords: boolean; + x_size, y_size: real; + xmin,xmax,ymin,ymax: real; + i: small_number; + page: integer; + pdf_box_type: integer; + result: integer; +begin + { scan the filename and pack into name_of_file } + scan_file_name; + pack_cur_name; + + pdf_box_type := 0; + page := 0; + if is_pdf then begin + if scan_keyword("page") then begin + scan_int; + page := cur_val; + end; + pdf_box_type := pdfbox_crop; + if scan_keyword("crop") then do_nothing + else if scan_keyword("media") then pdf_box_type := pdfbox_media + else if scan_keyword("bleed") then pdf_box_type := pdfbox_bleed + else if scan_keyword("trim") then pdf_box_type := pdfbox_trim + else if scan_keyword("art") then pdf_box_type := pdfbox_art; + end; + + { access the picture file and check its size } + result := find_pic_file(address_of(pic_path), address_of(bounds), pdf_box_type, page); + + setPoint(corners[0], xField(bounds) * 72.27 / 72.0, yField(bounds) * 72.27 / 72.0); + setPoint(corners[1], xField(corners[0]), (yField(bounds) + htField(bounds)) * 72.27 / 72.0); + setPoint(corners[2], (xField(bounds) + wdField(bounds)) * 72.27 / 72.0, yField(corners[1])); + setPoint(corners[3], xField(corners[2]), yField(corners[0])); + + x_size_req := 0.0; + y_size_req := 0.0; + + { look for any scaling requests for this picture } + make_identity(address_of(t)); + + check_keywords := true; + while check_keywords do begin + if scan_keyword("scaled") then begin + scan_int; + if (x_size_req = 0.0) and (y_size_req = 0.0) then begin + make_scale(address_of(t2), float(cur_val) / 1000.0, float(cur_val) / 1000.0); + update_corners; + transform_concat(address_of(t), address_of(t2)); + end + end else if scan_keyword("xscaled") then begin + scan_int; + if (x_size_req = 0.0) and (y_size_req = 0.0) then begin + make_scale(address_of(t2), float(cur_val) / 1000.0, 1.0); + update_corners; + transform_concat(address_of(t), address_of(t2)); + end + end else if scan_keyword("yscaled") then begin + scan_int; + if (x_size_req = 0.0) and (y_size_req = 0.0) then begin + make_scale(address_of(t2), 1.0, float(cur_val) / 1000.0); + update_corners; + transform_concat(address_of(t), address_of(t2)); + end + end else if scan_keyword("width") then begin + scan_normal_dimen; + if cur_val <= 0 then begin + print_err("Improper image "); + print("size ("); + print_scaled(cur_val); + print("pt) will be ignored"); + help2("I can't scale images to zero or negative sizes, ") + ("so I'm ignoring this."); + error; + end else + x_size_req := Fix2X(cur_val); + end else if scan_keyword("height") then begin + scan_normal_dimen; + if cur_val <= 0 then begin + print_err("Improper image "); + print("size ("); + print_scaled(cur_val); + print("pt) will be ignored"); + help2("I can't scale images to zero or negative sizes, ") + ("so I'm ignoring this."); + error; + end else + y_size_req := Fix2X(cur_val); + end else if scan_keyword("rotated") then begin + scan_decimal; + if (x_size_req <> 0.0) or (y_size_req <> 0.0) then do_size_requests; + make_rotation(address_of(t2), Fix2X(cur_val) * 3.141592653589793 / 180.0); + update_corners; + calc_min_and_max; + setPoint(corners[0], xmin, ymin); + setPoint(corners[1], xmin, ymax); + setPoint(corners[2], xmax, ymax); + setPoint(corners[3], xmax, ymin); + transform_concat(address_of(t), address_of(t2)); + end else + check_keywords := false; + end; + + if (x_size_req <> 0.0) or (y_size_req <> 0.0) then do_size_requests; + + calc_min_and_max; + make_translation(address_of(t2), -xmin, -ymin); + transform_concat(address_of(t), address_of(t2)); + + if result = 0 then begin + + new_whatsit(pic_node, pic_node_size + (strlen(pic_path) + sizeof(memory_word) - 1) div sizeof(memory_word)); + if is_pdf then begin + subtype(tail) := pdf_node; + pic_box_type(tail) := pdf_box_type; + end; + pic_path_length(tail) := strlen(pic_path); + pic_page(tail) := page; + + width(tail) := X2Fix(xmax - xmin); + height(tail) := X2Fix(ymax - ymin); + depth(tail) := 0; + + pic_transform1(tail) := X2Fix(aField(t)); + pic_transform2(tail) := X2Fix(bField(t)); + pic_transform3(tail) := X2Fix(cField(t)); + pic_transform4(tail) := X2Fix(dField(t)); + pic_transform5(tail) := X2Fix(txField(t)); + pic_transform6(tail) := X2Fix(tyField(t)); + + memcpy(address_of(mem[tail + pic_node_size]), pic_path, strlen(pic_path)); + libc_free(pic_path); + + end else begin + + print_err("Unable to load picture or PDF file '"); + print_file_name(cur_name,cur_area,cur_ext); print("'"); + if result = -43 then begin { Mac OS file not found error } + help2("The requested image couldn't be read because ") + ("the file was not found."); + end + else begin { otherwise assume GraphicImport failed } + help2("The requested image couldn't be read because ") + ("it was not a recognized image format."); + end; + error; + + end; + +end; + +@ @= +begin + { scan a filename-like arg for the input encoding } + scan_and_pack_name; + + { convert it to "mode" and "encoding" values, and apply to the current input file } + i := get_encoding_mode_and_info(address_of(j)); + if i = XeTeX_input_mode_auto then begin + print_err("Encoding mode `auto' is not valid for \XeTeXinputencoding."); + help2("You can't use `auto' encoding here, only for \XeTeXdefaultencoding. ") + ("I'll ignore this and leave the current encoding unchanged."); + error; + end else set_input_file_encoding(input_file[in_open], i, j); +end + +@ @= +begin + { scan a filename-like arg for the input encoding } + scan_and_pack_name; + + { convert it to "mode" and "encoding" values, and store them as defaults for new input files } + XeTeX_default_input_mode := get_encoding_mode_and_info(address_of(j)); + XeTeX_default_input_encoding := j; +end + +@ @= +begin + { scan a filename-like arg for the locale name } + scan_file_name; + if length(cur_name) = 0 then XeTeX_linebreak_locale := 0 + else XeTeX_linebreak_locale := cur_name; { we ignore the area and extension! } +end + +@ @= +@!pdf_last_x_pos: integer; +@!pdf_last_y_pos: integer; + +@ @= +begin + new_whatsit(pdf_save_pos_node, small_node_size); +end + +@z + +@x +@d eTeX_version_code=eTeX_int {code for \.{\\eTeXversion}} +@y +@d eTeX_version_code=eTeX_int {code for \.{\\eTeXversion}} + +@d XeTeX_version_code=XeTeX_int {code for \.{\\XeTeXversion}} + +{ these are also in xetexmac.c and must correspond! } +@d XeTeX_count_glyphs_code=XeTeX_int+1 + +@d XeTeX_count_variations_code=XeTeX_int+2 +@d XeTeX_variation_code=XeTeX_int+3 +@d XeTeX_find_variation_by_name_code=XeTeX_int+4 +@d XeTeX_variation_min_code=XeTeX_int+5 +@d XeTeX_variation_max_code=XeTeX_int+6 +@d XeTeX_variation_default_code=XeTeX_int+7 + +@d XeTeX_count_features_code=XeTeX_int+8 +@d XeTeX_feature_code_code=XeTeX_int+9 +@d XeTeX_find_feature_by_name_code=XeTeX_int+10 +@d XeTeX_is_exclusive_feature_code=XeTeX_int+11 +@d XeTeX_count_selectors_code=XeTeX_int+12 +@d XeTeX_selector_code_code=XeTeX_int+13 +@d XeTeX_find_selector_by_name_code=XeTeX_int+14 +@d XeTeX_is_default_selector_code=XeTeX_int+15 + +@d XeTeX_OT_count_scripts_code=XeTeX_int+16 +@d XeTeX_OT_count_languages_code=XeTeX_int+17 +@d XeTeX_OT_count_features_code=XeTeX_int+18 +@d XeTeX_OT_script_code=XeTeX_int+19 +@d XeTeX_OT_language_code=XeTeX_int+20 +@d XeTeX_OT_feature_code=XeTeX_int+21 + +@d XeTeX_map_char_to_glyph_code=XeTeX_int+22 +@d XeTeX_glyph_index_code=XeTeX_int+23 +@d XeTeX_font_type_code=XeTeX_int+24 + +@d XeTeX_first_char_code=XeTeX_int+25 +@d XeTeX_last_char_code=XeTeX_int+26 + +@d pdf_last_x_pos_code = XeTeX_int+27 +@d pdf_last_y_pos_code = XeTeX_int+28 + +@d XeTeX_pdf_page_count_code = XeTeX_int+29 + +{ NB: must update eTeX_dim when items are added here! } +@z + +@x +@!@:eTeX_revision_}{\.{\\eTeXrevision} primitive@> +@y +@!@:eTeX_revision_}{\.{\\eTeXrevision} primitive@> + +primitive("XeTeXversion",last_item,XeTeX_version_code); +@!@:XeTeX_version_}{\.{\\XeTeXversion} primitive@> +primitive("XeTeXrevision",convert,XeTeX_revision_code);@/ +@!@:XeTeXrevision_}{\.{\\XeTeXrevision} primitive@> + +primitive("XeTeXcountglyphs",last_item,XeTeX_count_glyphs_code); + +primitive("XeTeXcountvariations",last_item,XeTeX_count_variations_code); +primitive("XeTeXvariation",last_item,XeTeX_variation_code); +primitive("XeTeXfindvariationbyname",last_item,XeTeX_find_variation_by_name_code); +primitive("XeTeXvariationmin",last_item,XeTeX_variation_min_code); +primitive("XeTeXvariationmax",last_item,XeTeX_variation_max_code); +primitive("XeTeXvariationdefault",last_item,XeTeX_variation_default_code); + +primitive("XeTeXcountfeatures",last_item,XeTeX_count_features_code); +primitive("XeTeXfeaturecode",last_item,XeTeX_feature_code_code); +primitive("XeTeXfindfeaturebyname",last_item,XeTeX_find_feature_by_name_code); +primitive("XeTeXisexclusivefeature",last_item,XeTeX_is_exclusive_feature_code); +primitive("XeTeXcountselectors",last_item,XeTeX_count_selectors_code); +primitive("XeTeXselectorcode",last_item,XeTeX_selector_code_code); +primitive("XeTeXfindselectorbyname",last_item,XeTeX_find_selector_by_name_code); +primitive("XeTeXisdefaultselector",last_item,XeTeX_is_default_selector_code); + +primitive("XeTeXvariationname",convert,XeTeX_variation_name_code); +primitive("XeTeXfeaturename",convert,XeTeX_feature_name_code); +primitive("XeTeXselectorname",convert,XeTeX_selector_name_code); + +primitive("XeTeXOTcountscripts",last_item,XeTeX_OT_count_scripts_code); +primitive("XeTeXOTcountlanguages",last_item,XeTeX_OT_count_languages_code); +primitive("XeTeXOTcountfeatures",last_item,XeTeX_OT_count_features_code); +primitive("XeTeXOTscripttag",last_item,XeTeX_OT_script_code); +primitive("XeTeXOTlanguagetag",last_item,XeTeX_OT_language_code); +primitive("XeTeXOTfeaturetag",last_item,XeTeX_OT_feature_code); + +primitive("XeTeXcharglyph", last_item, XeTeX_map_char_to_glyph_code); +primitive("XeTeXglyphindex", last_item, XeTeX_glyph_index_code); + +primitive("XeTeXglyphname",convert,XeTeX_glyph_name_code); + +primitive("XeTeXfonttype", last_item, XeTeX_font_type_code); + +primitive("XeTeXfirstfontchar", last_item, XeTeX_first_char_code); +primitive("XeTeXlastfontchar", last_item, XeTeX_last_char_code); + +primitive("pdflastxpos",last_item,pdf_last_x_pos_code); +primitive("pdflastypos",last_item,pdf_last_y_pos_code); + +primitive("XeTeXpdfpagecount",last_item,XeTeX_pdf_page_count_code); +@z + +@x +eTeX_version_code: print_esc("eTeXversion"); +@y +eTeX_version_code: print_esc("eTeXversion"); +XeTeX_version_code: print_esc("XeTeXversion"); + +XeTeX_count_glyphs_code: print_esc("XeTeXcountglyphs"); + +XeTeX_count_variations_code: print_esc("XeTeXcountvariations"); +XeTeX_variation_code: print_esc("XeTeXvariation"); +XeTeX_find_variation_by_name_code: print_esc("XeTeXfindvariationbyname"); +XeTeX_variation_min_code: print_esc("XeTeXvariationmin"); +XeTeX_variation_max_code: print_esc("XeTeXvariationmax"); +XeTeX_variation_default_code: print_esc("XeTeXvariationdefault"); + +XeTeX_count_features_code: print_esc("XeTeXcountfeatures"); +XeTeX_feature_code_code: print_esc("XeTeXfeaturecode"); +XeTeX_find_feature_by_name_code: print_esc("XeTeXfindfeaturebyname"); +XeTeX_is_exclusive_feature_code: print_esc("XeTeXisexclusivefeature"); +XeTeX_count_selectors_code: print_esc("XeTeXcountselectors"); +XeTeX_selector_code_code: print_esc("XeTeXselectorcode"); +XeTeX_find_selector_by_name_code: print_esc("XeTeXfindselectorbyname"); +XeTeX_is_default_selector_code: print_esc("XeTeXisdefaultselector"); + +XeTeX_OT_count_scripts_code: print_esc("XeTeXOTcountscripts"); +XeTeX_OT_count_languages_code: print_esc("XeTeXOTcountlanguages"); +XeTeX_OT_count_features_code: print_esc("XeTeXOTcountfeatures"); +XeTeX_OT_script_code: print_esc("XeTeXOTscripttag"); +XeTeX_OT_language_code: print_esc("XeTeXOTlanguagetag"); +XeTeX_OT_feature_code: print_esc("XeTeXOTfeaturetag"); + +XeTeX_map_char_to_glyph_code: print_esc("XeTeXcharglyph"); +XeTeX_glyph_index_code: print_esc("XeTeXglyphindex"); + +XeTeX_font_type_code: print_esc("XeTeXfonttype"); + +XeTeX_first_char_code: print_esc("XeTeXfirstfontchar"); +XeTeX_last_char_code: print_esc("XeTeXlastfontchar"); + + pdf_last_x_pos_code: print_esc("pdflastxpos"); + pdf_last_y_pos_code: print_esc("pdflastypos"); + +XeTeX_pdf_page_count_code: print_esc("XeTeXpdfpagecount"); +@z + +@x +eTeX_version_code: cur_val:=eTeX_version; +@y +eTeX_version_code: cur_val:=eTeX_version; +XeTeX_version_code: cur_val:=XeTeX_version; + +XeTeX_count_glyphs_code: + begin + scan_font_ident; n:=cur_val; + if is_atsu_font(n) then + cur_val:=atsu_font_get(m - XeTeX_int, font_layout_engine[n]) + else if is_otgr_font(n) then + cur_val:=ot_font_get(m - XeTeX_int, font_layout_engine[n]) + else + cur_val:=0; + end; + +XeTeX_count_variations_code: + begin + scan_font_ident; n:=cur_val; + if is_atsu_font(n) then + cur_val:=atsu_font_get(m - XeTeX_int, font_layout_engine[n]) + else begin + cur_val:=0; + end; + end; +XeTeX_count_features_code: + begin + scan_font_ident; n:=cur_val; + if is_atsu_font(n) then + cur_val:=atsu_font_get(m - XeTeX_int, font_layout_engine[n]) + else if is_gr_font(n) then + cur_val:=ot_font_get(m - XeTeX_int, font_layout_engine[n]) + else + cur_val:=0; + end; + +XeTeX_variation_code, +XeTeX_variation_min_code, +XeTeX_variation_max_code, +XeTeX_variation_default_code: + begin + scan_font_ident; n:=cur_val; + if is_atsu_font(n) then begin + scan_int; k:=cur_val; + cur_val:=atsu_font_get_1(m - XeTeX_int, font_layout_engine[n], k); + end else begin + not_atsu_font_error(last_item, m, n); cur_val:=-1; + end; + end; + +XeTeX_feature_code_code, +XeTeX_is_exclusive_feature_code, +XeTeX_count_selectors_code: + begin + scan_font_ident; n:=cur_val; + if is_atsu_font(n) then begin + scan_int; k:=cur_val; + cur_val:=atsu_font_get_1(m - XeTeX_int, font_layout_engine[n], k); + end else if is_gr_font(n) then begin + scan_int; k:=cur_val; + cur_val:=ot_font_get_1(m - XeTeX_int, font_layout_engine[n], k); + end else begin + not_atsu_gr_font_error(last_item, m, n); cur_val:=-1; + end; + end; + +XeTeX_selector_code_code, +XeTeX_is_default_selector_code: + begin + scan_font_ident; n:=cur_val; + if is_atsu_font(n) then begin + scan_int; k:=cur_val; scan_int; + cur_val:=atsu_font_get_2(m - XeTeX_int, font_layout_engine[n], k, cur_val); + end else if is_gr_font(n) then begin + scan_int; k:=cur_val; scan_int; + cur_val:=ot_font_get_2(m - XeTeX_int, font_layout_engine[n], k, cur_val); + end else begin + not_atsu_gr_font_error(last_item, m, n); cur_val:=-1; + end; + end; + +XeTeX_find_variation_by_name_code: + begin + scan_font_ident; n:=cur_val; + if is_atsu_font(n) then begin + scan_and_pack_name; + cur_val:=atsu_font_get_named(m - XeTeX_int, font_layout_engine[n]); + end else begin + not_atsu_font_error(last_item, m, n); cur_val:=-1; + end; + end; + +XeTeX_find_feature_by_name_code: + begin + scan_font_ident; n:=cur_val; + if is_atsu_font(n) then begin + scan_and_pack_name; + cur_val:=atsu_font_get_named(m - XeTeX_int, font_layout_engine[n]); + end else if is_gr_font(n) then begin + scan_and_pack_name; + cur_val:=gr_font_get_named(m - XeTeX_int, font_layout_engine[n]); + end else begin + not_atsu_gr_font_error(last_item, m, n); cur_val:=-1; + end; + end; + +XeTeX_find_selector_by_name_code: + begin + scan_font_ident; n:=cur_val; + if is_atsu_font(n) then begin + scan_int; k:=cur_val; scan_and_pack_name; + cur_val:=atsu_font_get_named_1(m - XeTeX_int, font_layout_engine[n], k); + end else if is_gr_font(n) then begin + scan_int; k:=cur_val; scan_and_pack_name; + cur_val:=gr_font_get_named_1(m - XeTeX_int, font_layout_engine[n], k); + end else begin + not_atsu_gr_font_error(last_item, m, n); cur_val:=-1; + end; + end; + +XeTeX_OT_count_scripts_code: + begin + scan_font_ident; n:=cur_val; + if is_ot_font(n) then + cur_val:=ot_font_get(m - XeTeX_int, font_layout_engine[n]) + else begin + cur_val:=0; + end; + end; + +XeTeX_OT_count_languages_code, +XeTeX_OT_script_code: + begin + scan_font_ident; n:=cur_val; + if is_ot_font(n) then begin + scan_int; + cur_val:=ot_font_get_1(m - XeTeX_int, font_layout_engine[n], cur_val); + end else begin + not_ot_font_error(last_item, m, n); cur_val:=-1; + end; + end; + +XeTeX_OT_count_features_code, +XeTeX_OT_language_code: + begin + scan_font_ident; n:=cur_val; + if is_ot_font(n) then begin + scan_int; k:=cur_val; scan_int; + cur_val:=ot_font_get_2(m - XeTeX_int, font_layout_engine[n], k, cur_val); + end else begin + not_ot_font_error(last_item, m, n); cur_val:=-1; + end; + end; + +XeTeX_OT_feature_code: + begin + scan_font_ident; n:=cur_val; + if is_ot_font(n) then begin + scan_int; k:=cur_val; scan_int; kk:=cur_val; scan_int; + cur_val:=ot_font_get_3(m - XeTeX_int, font_layout_engine[n], k, kk, cur_val); + end else begin + not_ot_font_error(last_item, m, n); cur_val:=-1; + end; + end; + +XeTeX_map_char_to_glyph_code: + begin + if is_native_font(cur_font) then begin + scan_int; n:=cur_val; cur_val:=map_char_to_glyph(cur_font, n) + end else begin + not_native_font_error(last_item, m, cur_font); cur_val:=0 + end + end; + +XeTeX_glyph_index_code: + begin + if is_native_font(cur_font) then begin + scan_and_pack_name; + cur_val:=map_glyph_to_index(cur_font) + end else begin + not_native_font_error(last_item, m, cur_font); cur_val:=0 + end + end; + +XeTeX_font_type_code: + begin + scan_font_ident; n:=cur_val; + if is_atsu_font(n) then cur_val:=1 + else if is_ot_font(n) then cur_val:=2 + else if is_gr_font(n) then cur_val:=3 + else cur_val:=0; + end; + +XeTeX_first_char_code,XeTeX_last_char_code: + begin + scan_font_ident; n:=cur_val; + if is_native_font(n) then + cur_val:=get_font_char_range(n, m = XeTeX_first_char_code) + else begin + if m = XeTeX_first_char_code then cur_val:=font_bc[n] + else cur_val:=font_ec[n]; + end + end; + + pdf_last_x_pos_code: cur_val := pdf_last_x_pos; + pdf_last_y_pos_code: cur_val := pdf_last_y_pos; + +XeTeX_pdf_page_count_code: + begin + scan_and_pack_name; + cur_val:=count_pdf_file_pages; + end; + +@ Slip in an extra procedure here and there.... + +@= +procedure scan_and_pack_name; forward; + +@ @= +procedure scan_and_pack_name; +begin + scan_file_name; pack_cur_name; +end; + +@ @= +procedure not_atsu_font_error(cmd, c: integer; f: integer); +begin + print_err("Cannot use "); print_cmd_chr(cmd, c); + print(" with "); print(font_name[f]); + print("; not an AAT font"); + error; +end; + +procedure not_atsu_gr_font_error(cmd, c: integer; f: integer); +begin + print_err("Cannot use "); print_cmd_chr(cmd, c); + print(" with "); print(font_name[f]); + print("; not an AAT or Graphite font"); + error; +end; + +procedure not_ot_font_error(cmd, c: integer; f: integer); +begin + print_err("Cannot use "); print_cmd_chr(cmd, c); + print(" with "); print(font_name[f]); + print("; not an OpenType Layout font"); + error; +end; + +procedure not_native_font_error(cmd, c: integer; f: integer); +begin + print_err("Cannot use "); print_cmd_chr(cmd, c); + print(" with "); print(font_name[f]); + print("; not a native platform font"); + error; +end; + +@ @= +eTeX_revision_code: print_esc("eTeXrevision"); +XeTeX_revision_code: print_esc("XeTeXrevision"); + +XeTeX_variation_name_code: print_esc("XeTeXvariationname"); +XeTeX_feature_name_code: print_esc("XeTeXfeaturename"); +XeTeX_selector_name_code: print_esc("XeTeXselectorname"); +XeTeX_glyph_name_code: print_esc("XeTeXglyphname"); + +@ @= +eTeX_revision_code: do_nothing; +XeTeX_revision_code: do_nothing; + +XeTeX_variation_name_code: + begin + scan_font_ident; fnt:=cur_val; + if is_atsu_font(fnt) then begin + scan_int; arg1:=cur_val; arg2:=0; + end else + not_atsu_font_error(convert, c, fnt); + end; + +XeTeX_feature_name_code: + begin + scan_font_ident; fnt:=cur_val; + if is_atsu_font(fnt) or is_gr_font(fnt) then begin + scan_int; arg1:=cur_val; arg2:=0; + end else + not_atsu_gr_font_error(convert, c, fnt); + end; + +XeTeX_selector_name_code: + begin + scan_font_ident; fnt:=cur_val; + if is_atsu_font(fnt) or is_gr_font(fnt) then begin + scan_int; arg1:=cur_val; scan_int; arg2:=cur_val; + end else + not_atsu_gr_font_error(convert, c, fnt); + end; + +XeTeX_glyph_name_code: + begin + scan_font_ident; fnt:=cur_val; + if is_native_font(fnt) then begin + scan_int; arg1:=cur_val; + end else + not_native_font_error(convert, c, fnt); + end; + +@ @= +eTeX_revision_code: print(eTeX_revision); +XeTeX_revision_code: print(XeTeX_revision); + +XeTeX_variation_name_code: + if is_atsu_font(fnt) then + atsu_print_font_name(c, font_layout_engine[fnt], arg1, arg2); + +XeTeX_feature_name_code, +XeTeX_selector_name_code: + if is_atsu_font(fnt) then + atsu_print_font_name(c, font_layout_engine[fnt], arg1, arg2) + else if is_gr_font(fnt) then + gr_print_font_name(c, font_layout_engine[fnt], arg1, arg2); + +XeTeX_glyph_name_code: + if is_native_font(fnt) then print_glyph_name(fnt, arg1); +@z + +@x +@ @= +dump_int(eTeX_mode); +for j:=0 to eTeX_states-1 do eTeX_state(j):=0; {disable all enhancements} +@y +@ @= +dump_int(eTeX_mode); +{ in a deliberate change from e-TeX, we allow non-zero state variables to be dumped } +@z + +@x +every_eof_loc: print_esc("everyeof"); +@y +every_eof_loc: print_esc("everyeof"); +XeTeX_inter_char_loc: print_esc("XeTeXinterchartoks"); +@z + +@x +font_char_wd_code, +font_char_ht_code, +font_char_dp_code, +font_char_ic_code: begin scan_font_ident; q:=cur_val; scan_char_num; + if (font_bc[q]<=cur_val)and(font_ec[q]>=cur_val) then + begin i:=char_info(q)(qi(cur_val)); + case m of + font_char_wd_code: cur_val:=char_width(q)(i); + font_char_ht_code: cur_val:=char_height(q)(height_depth(i)); + font_char_dp_code: cur_val:=char_depth(q)(height_depth(i)); + font_char_ic_code: cur_val:=char_italic(q)(i); + end; {there are no other cases} + end + else cur_val:=0; + end; +@y +font_char_wd_code, +font_char_ht_code, +font_char_dp_code, +font_char_ic_code: begin scan_font_ident; q:=cur_val; scan_usv_num; + if is_native_font(q) then begin + case m of + font_char_wd_code: cur_val := getnativecharwd(q, cur_val); + font_char_ht_code: cur_val := getnativecharht(q, cur_val); + font_char_dp_code: cur_val := getnativechardp(q, cur_val); + font_char_ic_code: cur_val := getnativecharic(q, cur_val); + end; {there are no other cases} + end else begin + if (font_bc[q]<=cur_val)and(font_ec[q]>=cur_val) then + begin i:=char_info(q)(qi(cur_val)); + case m of + font_char_wd_code: cur_val:=char_width(q)(i); + font_char_ht_code: cur_val:=char_height(q)(height_depth(i)); + font_char_dp_code: cur_val:=char_depth(q)(height_depth(i)); + font_char_ic_code: cur_val:=char_italic(q)(i); + end; {there are no other cases} + end + else cur_val:=0; + end + end; +@z + +@x +@d TeXXeT_en==(TeXXeT_state>0) {is \TeXXeT\ enabled?} +@y +@d TeXXeT_en==(TeXXeT_state>0) {is \TeXXeT\ enabled?} + +@d XeTeX_upwards_state==eTeX_state(XeTeX_upwards_code) +@d XeTeX_upwards==(XeTeX_upwards_state>0) + +@d XeTeX_use_glyph_metrics_state==eTeX_state(XeTeX_use_glyph_metrics_code) +@d XeTeX_use_glyph_metrics==(XeTeX_use_glyph_metrics_state>0) + +@d XeTeX_inter_char_tokens_state==eTeX_state(XeTeX_inter_char_tokens_code) +@d XeTeX_inter_char_tokens_en==(XeTeX_inter_char_tokens_state>0) + +@d XeTeX_dash_break_state == eTeX_state(XeTeX_dash_break_code) +@d XeTeX_dash_break_en == (XeTeX_dash_break_state>0) + +@d XeTeX_default_input_mode == eTeX_state(XeTeX_default_input_mode_code) +@d XeTeX_default_input_encoding == eTeX_state(XeTeX_default_input_encoding_code) +@z + +@x +eTeX_state_code+TeXXeT_code:print_esc("TeXXeTstate"); +@y +suppress_fontnotfound_error_code:print_esc("suppressfontnotfounderror"); +eTeX_state_code+TeXXeT_code:print_esc("TeXXeTstate"); +eTeX_state_code+XeTeX_upwards_code:print_esc("XeTeXupwardsmode"); +eTeX_state_code+XeTeX_use_glyph_metrics_code:print_esc("XeTeXuseglyphmetrics"); +eTeX_state_code+XeTeX_inter_char_tokens_code:print_esc("XeTeXinterchartokenstate"); +eTeX_state_code+XeTeX_dash_break_code:print_esc("XeTeXdashbreakstate"); +@z + +@x +primitive("TeXXeTstate",assign_int,eTeX_state_base+TeXXeT_code); +@!@:TeXXeT_state_}{\.{\\TeXXeT_state} primitive@> +@y +primitive("suppressfontnotfounderror",assign_int,int_base+suppress_fontnotfound_error_code);@/ +primitive("TeXXeTstate",assign_int,eTeX_state_base+TeXXeT_code); +@!@:TeXXeT_state_}{\.{\\TeXXeT_state} primitive@> +primitive("XeTeXupwardsmode",assign_int,eTeX_state_base+XeTeX_upwards_code); +@!@:XeTeX_upwards_mode_}{\.{\\XeTeX_upwards_mode} primitive@> +primitive("XeTeXuseglyphmetrics",assign_int,eTeX_state_base+XeTeX_use_glyph_metrics_code); +@!@:XeTeX_use_glyph_metrics_}{\.{\\XeTeX_use_glyph_metrics} primitive@> +primitive("XeTeXinterchartokenstate",assign_int,eTeX_state_base+XeTeX_inter_char_tokens_code); +@!@:XeTeX_use_inter_char_tokens_}{\.{\\XeTeX_use_inter_char_tokens} primitive@> + +primitive("XeTeXdashbreakstate",assign_int,eTeX_state_base+XeTeX_dash_break_code); +@!@:XeTeX_dash_break_state_}{\.{\\XeTeX_dash_break_state} primitive@> + +primitive("XeTeXinputencoding",extension,XeTeX_input_encoding_extension_code); +primitive("XeTeXdefaultencoding",extension,XeTeX_default_encoding_extension_code); +@z + +@x +@ Here we compute the effective width of a glue node as in |hlist_out|. + +@= +glue_node: begin round_glue; + @; + end; +@y +@ Need to measure native_word and picture nodes when reversing! +@= +whatsit_node: + if (subtype(p)=native_word_node) + or (subtype(p)=glyph_node) + or (subtype(p)=pic_node) + or (subtype(p)=pdf_node) + then + rule_wd:=width(p) + else + goto next_p; + +@ Here we compute the effective width of a glue node as in |hlist_out|. + +@= +glue_node: begin round_glue; + @; + end; +@z + +@x +str_pool[pool_ptr]:=si(" "); l:=str_start[s]; +@y +str_pool[pool_ptr]:=si(" "); l:=str_start_macro(s); +@z + +@x + buffer[m]:=info(p) mod @'400; incr(m); p:=link(p); +@y + buffer[m]:=info(p) mod max_char_val; incr(m); p:=link(p); +@z + +@x +if_font_char_code:begin scan_font_ident; n:=cur_val; scan_char_num; + if (font_bc[n]<=cur_val)and(font_ec[n]>=cur_val) then + b:=char_exists(char_info(n)(qi(cur_val))) + else b:=false; + end; +@y +if_font_char_code:begin scan_font_ident; n:=cur_val; scan_usv_num; + if is_native_font(n) then + b := (map_char_to_glyph(n, cur_val) > 0) + else begin + if (font_bc[n]<=cur_val)and(font_ec[n]>=cur_val) then + b:=char_exists(char_info(n)(qi(cur_val))) + else b:=false; + end; + end; +@z + +@x +@d mark_val=6 {the additional mark classes} +@y +@d mark_val=7 {the additional mark classes} +@z + +@x +for i:=int_val to tok_val do sa_root[i]:=null; +@y +for i:=int_val to inter_char_val do sa_root[i]:=null; +@z + +@x + for c := str_start[text(h)] to str_start[text(h) + 1] - 1 +@y + for c := str_start_macro(text(h)) to str_start_macro(text(h) + 1) - 1 +@z + +@x +@ Dumping the |xord|, |xchr|, and |xprn| arrays. We dump these always +in the format, so a TCX file loaded during format creation can set a +default for users of the format. + +@= +dump_things(xord[0], 256); +dump_things(xchr[0], 256); +dump_things(xprn[0], 256); + +@ Undumping the |xord|, |xchr|, and |xprn| arrays. This code is more +complicated, because we want to ensure that a TCX file specified on +the command line will override whatever is in the format. Since the +tcx file has already been loaded, that implies throwing away the data +in the format. Also, if no |translate_filename| is given, but +|eight_bit_p| is set we have to make all characters printable. + +@= +if translate_filename then begin + for k:=0 to 255 do undump_things(dummy_xord, 1); + for k:=0 to 255 do undump_things(dummy_xchr, 1); + for k:=0 to 255 do undump_things(dummy_xprn, 1); + end +else begin + undump_things(xord[0], 256); + undump_things(xchr[0], 256); + undump_things(xprn[0], 256); + if eight_bit_p then + for k:=0 to 255 do + xprn[k]:=1; +end; + + +@y +@z + +@x + while s>255 do {first 256 strings depend on implementation!!} +@y + while s>65535 do {first 64K strings don't really exist in the pool!} +@z + +@x +@!mltex_enabled_p:boolean; {enable character substitution} +@y +@!mltex_enabled_p:boolean; {enable character substitution} +@!native_font_type_flag:integer; {used by XeTeX font loading code to record which font technology was used} +@z + +@x +effective_char_info:=null_character; +exit:end; +@y +effective_char_info:=null_character; +exit:end; + +{ the following procedure has been moved so that new_native_character can call it } + +procedure char_warning(@!f:internal_font_number;@!c:integer); +var old_setting: integer; {saved value of |tracing_online|} +begin if tracing_lost_chars>0 then + begin old_setting:=tracing_online; + if eTeX_ex and(tracing_lost_chars>1) then tracing_online:=1; + begin begin_diagnostic; + print_nl("Missing character: There is no "); +@.Missing character@> + if c < @"10000 then print_ASCII(c) + else begin { non-Plane 0 Unicodes can't be sent through print_ASCII } + print("character number "); + print_hex(c); + end; + print(" in font "); + slow_print(font_name[f]); print_char("!"); end_diagnostic(false); + end; + tracing_online:=old_setting; + end; +end; + +{ additional functions for native font support } + +function new_native_word_node(@!f:internal_font_number;@!n:integer):pointer; + { note that this function creates the node, but does not actually set its metrics; + call set_native_metrics(node) if that is required! } +var + l: integer; + q: pointer; +begin + l := native_node_size + (n * sizeof(UTF16_code) + sizeof(memory_word) - 1) div sizeof(memory_word); + + q := get_node(l); + type(q) := whatsit_node; + subtype(q) := native_word_node; + + native_size(q) := l; + native_font(q) := f; + native_length(q) := n; + + native_glyph_count(q) := 0; + native_glyph_info_ptr(q) := null_ptr; + + new_native_word_node := q; +end; + +function new_native_character(@!f:internal_font_number;@!c:UnicodeScalar):pointer; +var + p: pointer; + i, len: integer; +begin + if font_mapping[f] <> 0 then begin + if c > @"FFFF then begin + str_room(2); + append_char((c - @"10000) div 1024 + @"D800); + append_char((c - @"10000) mod 1024 + @"DC00); + end + else begin + str_room(1); + append_char(c); + end; + len := apply_mapping(font_mapping[f], address_of(str_pool[str_start_macro(str_ptr)]), cur_length); + pool_ptr := str_start_macro(str_ptr); { flush the string, as we'll be using the mapped text instead } + + i := 0; + while i < len do begin + if (mapped_text[i] >= @"D800) and (mapped_text[i] < @"DC00) then begin + c := (mapped_text[i] - @"D800) * 1024 + mapped_text[i+1] - @"DC00 + @"10000; + if map_char_to_glyph(f, c) = 0 then begin + char_warning(f, c); + end; + i := i + 2; + end + else begin + if map_char_to_glyph(f, mapped_text[i]) = 0 then begin + char_warning(f, mapped_text[i]); + end; + i := i + 1; + end; + end; + + p := new_native_word_node(f, len); + for i := 0 to len-1 do begin + set_native_char(p, i, mapped_text[i]); + end + end + else begin + if tracing_lost_chars > 0 then + if map_char_to_glyph(f, c) = 0 then begin + char_warning(f, c); + end; + + p := get_node(native_node_size + 1); + type(p) := whatsit_node; + subtype(p) := native_word_node; + + native_size(p) := native_node_size + 1; + native_glyph_count(p) := 0; + native_glyph_info_ptr(p) := null_ptr; + native_font(p) := f; + + if c > @"FFFF then begin + native_length(p) := 2; + set_native_char(p, 0, (c - @"10000) div 1024 + @"D800); + set_native_char(p, 1, (c - @"10000) mod 1024 + @"DC00); + end + else begin + native_length(p) := 1; + set_native_char(p, 0, c); + end; + end; + + set_native_metrics(p, XeTeX_use_glyph_metrics); + + new_native_character := p; +end; + +procedure font_feature_warning(featureNameP:void_pointer; featLen:integer; + settingNameP:void_pointer; setLen:integer); +var + i: integer; +begin + begin_diagnostic; + print_nl("Unknown "); + if setLen > 0 then begin + print("selector `"); + print_utf8_str(settingNameP, setLen); + print("' for "); + end; + print("feature `"); + print_utf8_str(featureNameP, featLen); + print("' in font `"); + i := 1; + while ord(name_of_file[i]) <> 0 do begin + print_visible_char(name_of_file[i]); { this is already UTF-8 } + incr(i); + end; + print("'."); + end_diagnostic(false); +end; + +procedure font_mapping_warning(mappingNameP:void_pointer; mappingNameLen:integer); +var + i: integer; +begin + begin_diagnostic; + print_nl("Font mapping `"); + print_utf8_str(mappingNameP, mappingNameLen); + print("' for font `"); + i := 1; + while ord(name_of_file[i]) <> 0 do begin + print_visible_char(name_of_file[i]); { this is already UTF-8 } + incr(i); + end; + print("' not found."); + end_diagnostic(false); +end; + +procedure graphite_warning; +var + i: integer; +begin + begin_diagnostic; + print_nl("Font `"); + i := 1; + while ord(name_of_file[i]) <> 0 do begin + print_visible_char(name_of_file[i]); { this is already UTF-8 } + incr(i); + end; + print("' does not support Graphite. Trying ICU layout instead."); + end_diagnostic(false); +end; + +function load_native_font(u: pointer; nom, aire:str_number; s: scaled): internal_font_number; +label + done; +var + k: integer; + font_engine: void_pointer; {really an ATSUStyle or XeTeXLayoutEngine} + actual_size: scaled; {|s| converted to real size, if it was negative} + p: pointer; {for temporary |native_char| node we'll create} + ascent, descent, font_slant, x_ht, cap_ht: scaled; + f: internal_font_number; + full_name: str_number; +begin + { on entry here, the full name is packed into name_of_file in UTF8 form } + + load_native_font := null_font; + + if (s < 0) then actual_size := -s * unity div 100 else actual_size := s; + font_engine := find_native_font(name_of_file + 1, actual_size); + if font_engine = 0 then goto done; + + { look again to see if the font is already loaded, now that we know its canonical name } + str_room(name_length); + for k := 1 to name_length do + append_char(name_of_file[k]); + full_name := make_string; { not slow_make_string because we'll flush it if the font was already loaded } + + for f:=font_base+1 to font_ptr do + if (font_area[f] = native_font_type_flag) and str_eq_str(font_name[f], full_name) and (font_size[f] = actual_size) then begin + release_font_engine(font_engine, native_font_type_flag); + flush_string; + load_native_font := f; + goto done; + end; + + if (font_ptr = font_max) or (fmem_ptr + 8 > font_mem_size) then begin + @; + end; + + { we've found a valid installed font, and have room } + incr(font_ptr); + font_area[font_ptr] := native_font_type_flag; { set by find_native_font to either aat_font_flag or ot_font_flag } + + { store the canonical name } + font_name[font_ptr] := full_name; + + font_check[font_ptr].b0 := 0; + font_check[font_ptr].b1 := 0; + font_check[font_ptr].b2 := 0; + font_check[font_ptr].b3 := 0; + font_glue[font_ptr] := null; + font_dsize[font_ptr] := 10 * unity; + font_size[font_ptr] := actual_size; + + if (native_font_type_flag = aat_font_flag) then begin + atsu_get_font_metrics(font_engine, address_of(ascent), address_of(descent), + address_of(x_ht), address_of(cap_ht), address_of(font_slant)) + end else begin + ot_get_font_metrics(font_engine, address_of(ascent), address_of(descent), + address_of(x_ht), address_of(cap_ht), address_of(font_slant)); + end; + + height_base[font_ptr] := ascent; + depth_base[font_ptr] := -descent; + + font_params[font_ptr] := 8; { we add an extra \fontdimen: #8 -> cap_height } + font_bc[font_ptr] := 0; + font_ec[font_ptr] := 65535; + font_used[font_ptr] := false; + hyphen_char[font_ptr] := default_hyphen_char; + skew_char[font_ptr] := default_skew_char; + param_base[font_ptr] := fmem_ptr-1; + + font_layout_engine[font_ptr] := font_engine; + font_mapping[font_ptr] := 0; { don't use the mapping, if any, when measuring space here } + font_letter_space[font_ptr] := loaded_font_letter_space; + + {measure the width of the space character and set up font parameters} + p := new_native_character(font_ptr, " "); + s := width(p) + loaded_font_letter_space; + free_node(p, native_size(p)); + + font_info[fmem_ptr].sc := font_slant; {slant} + incr(fmem_ptr); + font_info[fmem_ptr].sc := s; {space = width of space character} + incr(fmem_ptr); + font_info[fmem_ptr].sc := s div 2; {space_stretch = 1/2 * space} + incr(fmem_ptr); + font_info[fmem_ptr].sc := s div 3; {space_shrink = 1/3 * space} + incr(fmem_ptr); + font_info[fmem_ptr].sc := x_ht; {x_height} + incr(fmem_ptr); + font_info[fmem_ptr].sc := font_size[font_ptr]; {quad = font size} + incr(fmem_ptr); + font_info[fmem_ptr].sc := s div 3; {extra_space = 1/3 * space} + incr(fmem_ptr); + font_info[fmem_ptr].sc := cap_ht; {cap_height} + incr(fmem_ptr); + + font_mapping[font_ptr] := loaded_font_mapping; + font_flags[font_ptr] := loaded_font_flags; + + load_native_font := font_ptr; +done: +end; + +procedure do_locale_linebreaks(s: integer; len: integer); +var + offs, prevOffs, i: integer; + use_penalty, use_skip: boolean; +begin + if (XeTeX_linebreak_locale = 0) or (len = 1) then begin + link(tail) := new_native_word_node(main_f, len); + tail := link(tail); + for i := 0 to len - 1 do + set_native_char(tail, i, native_text[s + i]); + set_native_metrics(tail, XeTeX_use_glyph_metrics); + end else begin + use_skip := XeTeX_linebreak_skip <> zero_glue; + use_penalty := XeTeX_linebreak_penalty <> 0 or not use_skip; + if (is_gr_font(main_f)) and (str_eq_str(XeTeX_linebreak_locale, "G")) then begin + initGraphiteBreaking(font_layout_engine[main_f], native_text + s, len); + offs := 0; + repeat + prevOffs := offs; + offs := findNextGraphiteBreak(offs, 15); {klbWordBreak = 15} + if offs > 0 then begin + if prevOffs <> 0 then begin + if use_penalty then + tail_append(new_penalty(XeTeX_linebreak_penalty)); + if use_skip then + tail_append(new_param_glue(XeTeX_linebreak_skip_code)); + end; + link(tail) := new_native_word_node(main_f, offs - prevOffs); + tail := link(tail); + for i := prevOffs to offs - 1 do + set_native_char(tail, i - prevOffs, native_text[s + i]); + set_native_metrics(tail, XeTeX_use_glyph_metrics); + end; + until offs < 0; + end + else begin + linebreak_start(XeTeX_linebreak_locale, native_text + s, len); + offs := 0; + repeat + prevOffs := offs; + offs := linebreak_next; + if offs > 0 then begin + if prevOffs <> 0 then begin + if use_penalty then + tail_append(new_penalty(XeTeX_linebreak_penalty)); + if use_skip then + tail_append(new_param_glue(XeTeX_linebreak_skip_code)); + end; + link(tail) := new_native_word_node(main_f, offs - prevOffs); + tail := link(tail); + for i := prevOffs to offs - 1 do + set_native_char(tail, i - prevOffs, native_text[s + i]); + set_native_metrics(tail, XeTeX_use_glyph_metrics); + end; + until offs < 0; + end + end +end; + +@z + +@x +@* \[54/enc\TeX] System-dependent changes for enc\TeX. + +@d encTeX_banner == ' encTeX v. Jun. 2004' + +@ The boolean variable |enctex_p| is set by web2c according to the given +command line option (or an entry in the configuration file) before any +\TeX{} function is called. + +@ = +@!enctex_p: boolean; + + +@ The boolean variable |enctex_enabled_p| is used to enable enc\TeX's +primitives. It is initialised to |false|. When loading a \.{FMT} it +is set to the value of the boolean |enctex_p| saved in the \.{FMT} file. +Additionally it is set to the value of |enctex_p| in Ini\TeX. + +@= +@!enctex_enabled_p:boolean; {enable encTeX} + + +@ @= +enctex_enabled_p:=false; + + +@ Auxiliary functions/procedures for enc\TeX{} (by Petr Olsak) follow. +These functions implement the \.{\\mubyte} code to convert +the multibytes in |buffer| to one byte or to one control +sequence. These functions manipulate a mubyte tree: each node of +this tree is token list with n+1 tokens (first token consist the byte +from the byte sequence itself and the other tokens point to the +branches). If you travel from root of the tree to a leaf then you +find exactly one byte sequence which we have to convert to one byte or +control sequence. There are two variants of the leaf: the ``definitive +end'' or the ``middle leaf'' if a longer byte sequence exists and the mubyte +tree continues under this leaf. First variant is implemented as one +memory word where the link part includes the token to +which we have to convert and type part includes the number 60 (normal +conversion) or 1..52 (insert the control sequence). +The second variant of ``middle leaf'' is implemented as two memory words: +first one has a type advanced by 64 and link points to the second +word where info part includes the token to which we have to convert +and link points to the next token list with the branches of +the subtree. + +The inverse: one byte to multi byte (for log printing and \.{\\write} +printing) is implemented via a pool. Each multibyte sequence is stored +in a pool as a string and |mubyte_write|[{\it printed char\/}] points +to this string. + +@d new_mubyte_node == + link (p) := get_avail; p := link (p); info (p) := get_avail; p := info (p) +@d subinfo (#) == subtype (#) + +@= +{ read |buffer|[|i|] and convert multibyte. |i| should have been + of type 0..|buf_size|, but web2c doesn't like that construct in + argument lists. } +function read_buffer(var i:integer):ASCII_code; +var p: pointer; + last_found: integer; + last_type: integer; +begin + mubyte_skip := 0; mubyte_token := 0; + read_buffer := buffer[i]; + if mubyte_in = 0 then + begin + if mubyte_keep > 0 then mubyte_keep := 0; + return ; + end; + last_found := -2; + if (i = start) and (not mubyte_start) then + begin + mubyte_keep := 0; + if (end_line_char >= 0) and (end_line_char < 256) then + if mubyte_read [end_line_char] <> null then + begin + mubyte_start := true; mubyte_skip := -1; + p := mubyte_read [end_line_char]; + goto continue; + end; + end; +restart: + mubyte_start := false; + if (mubyte_read [buffer[i]] = null) or (mubyte_keep > 0) then + begin + if mubyte_keep > 0 then decr (mubyte_keep); + return ; + end; + p := mubyte_read [buffer[i]]; +continue: + if type (p) >= 64 then + begin + last_type := type (p) - 64; + p := link (p); + mubyte_token := info (p); last_found := mubyte_skip; + end else if type (p) > 0 then + begin + last_type := type (p); + mubyte_token := link (p); + goto found; + end; + incr (mubyte_skip); + if i + mubyte_skip > limit then + begin + mubyte_skip := 0; + if mubyte_start then goto restart; + return; + end; + repeat + p := link (p); + if subinfo (info(p)) = buffer [i+mubyte_skip] then + begin + p := info (p); goto continue; + end; + until link (p) = null; + mubyte_skip := 0; + if mubyte_start then goto restart; + if last_found = -2 then return; { no found } + mubyte_skip := last_found; +found: + if mubyte_token < 256 then { multibyte to one byte } + begin + read_buffer := mubyte_token; mubyte_token := 0; + i := i + mubyte_skip; + if mubyte_start and (i >= start) then mubyte_start := false; + return; + end else begin { multibyte to control sequence } + read_buffer := 0; + if last_type = 60 then { normal conversion } + i := i + mubyte_skip + else begin { insert control sequence } + decr (i); mubyte_keep := last_type; + if i < start then mubyte_start := true; + if last_type = 52 then mubyte_keep := 10000; + if last_type = 51 then mubyte_keep := mubyte_skip + 1; + mubyte_skip := -1; + end; + if mubyte_start and (i >= start) then mubyte_start := false; + return; + end; +exit: end; + +@ @= +procedure mubyte_update; { saves new string to mubyte tree } +var j: pool_pointer; + p: pointer; + q: pointer; + in_mutree: integer; +begin + j := str_start [str_ptr]; + if mubyte_read [so(str_pool[j])] = null then + begin + in_mutree := 0; + p := get_avail; + mubyte_read [so(str_pool[j])] := p; + subinfo (p) := so(str_pool[j]); type (p) := 0; + end else begin + in_mutree := 1; + p := mubyte_read [so(str_pool[j])]; + end; + incr (j); + while j < pool_ptr do + begin + if in_mutree = 0 then + begin + new_mubyte_node; subinfo (p) := so(str_pool[j]); type (p) := 0; + end else { |in_mutree| = 1 } + if (type (p) > 0) and (type (p) < 64) then + begin + type (p) := type (p) + 64; + q := link (p); link (p) := get_avail; p := link (p); + info (p) := q; + new_mubyte_node; subinfo (p) := so(str_pool[j]); type (p) := 0; + in_mutree := 0; + end else begin + if type (p) >= 64 then p := link (p); + repeat + p := link (p); + if subinfo (info(p)) = so(str_pool[j]) then + begin + p := info (p); + goto continue; + end; + until link (p) = null; + new_mubyte_node; subinfo (p) := so(str_pool[j]); type (p) := 0; + in_mutree := 0; + end; +continue: + incr (j); + end; + if in_mutree = 1 then + begin + if type (p) = 0 then + begin + type (p) := mubyte_prefix + 64; + q := link (p); link (p) := get_avail; p := link (p); + link (p) := q; info (p) := mubyte_stoken; + return; + end; + if type (p) >= 64 then + begin + type (p) := mubyte_prefix + 64; + p := link (p); info (p) := mubyte_stoken; + return; + end; + end; + type (p) := mubyte_prefix; + link (p) := mubyte_stoken; +exit: end; +@# +procedure dispose_munode (p: pointer); { frees a mu subtree recursivelly } +var q: pointer; +begin + if (type (p) > 0) and (type (p) < 64) then free_avail (p) + else begin + if type (p) >= 64 then + begin + q := link (p); free_avail (p); p := q; + end; + q := link (p); free_avail (p); p := q; + while p <> null do + begin + dispose_munode (info (p)); + q := link (p); + free_avail (p); + p := q; + end; + end; +end; +@# +procedure dispose_mutableout (cs: pointer); { frees record from out table } +var p, q, r: pointer; +begin + p := mubyte_cswrite [cs mod 128]; + r := null; + while p <> null do + if info (p) = cs then + begin + if r <> null then link (r) := link (link (p)) + else mubyte_cswrite[cs mod 128] := link (link (p)); + q := link (link(p)); + free_avail (link(p)); free_avail (p); + p := q; + end else begin + r := link (p); p := link (r); + end; +end; + +@ The |print_buffer| procedure prints one character from |buffer|[|i|]. +It also increases |i| to the next character in the buffer. + +@= +{ print one char from |buffer|[|i|]. |i| should have been of type + 0..|buf_size|, but web2c doesn't like that construct in argument lists. } +procedure print_buffer(var i:integer); +var c: ASCII_code; +begin + if mubyte_in = 0 then print (buffer[i]) { normal TeX } + else if mubyte_log > 0 then print_char (buffer[i]) + else begin + c := read_buffer (i); + if mubyte_token > 0 then print_cs (mubyte_token-cs_token_flag) + else print (c); + end; + incr (i); +end; + +@ Additional material to dump for enc\TeX. This includes whether +enc\TeX is enabled, and if it is we also have to dump the \.{\\mubyte} +arrays. + +@= +dump_int(@"45435458); {enc\TeX's magic constant: "ECTX"} +if not enctex_p then dump_int(0) +else begin + dump_int(1); + dump_things(mubyte_read[0], 256); + dump_things(mubyte_write[0], 256); + dump_things(mubyte_cswrite[0], 128); +end; + +@ Undumping the additional material we dumped for enc\TeX. This includes +conditionally undumping the \.{\\mubyte} arrays. + +@= +undump_int(x); {check magic constant of enc\TeX} +if x<>@"45435458 then goto bad_fmt; +undump_int(x); {undump |enctex_p| flag into |enctex_enabled_p|} +if x=0 then enctex_enabled_p:=false +else if x<>1 then goto bad_fmt +else begin + enctex_enabled_p:=true; + undump_things(mubyte_read[0], 256); + undump_things(mubyte_write[0], 256); + undump_things(mubyte_cswrite[0], 128); +end; + +@y +@z + diff --git a/Build/source/texk/web2c/xetexdir/xetex.defines b/Build/source/texk/web2c/xetexdir/xetex.defines index 218d8228c97..6e8cb936507 100644 --- a/Build/source/texk/web2c/xetexdir/xetex.defines +++ b/Build/source/texk/web2c/xetexdir/xetex.defines @@ -53,18 +53,29 @@ authorization from SIL International. @define function uopenout(); @define procedure uclose(); @define function dviopenout(); -@define procedure dviclose(); +@define function dviclose(); @define function delcode1(); @define procedure setdelcode1(); @define function readcint1(); @define procedure setcint1(); +@define procedure printcstring(); @define procedure printutf8str(); @define procedure setinputfileencoding(); @define procedure terminatefontmanager; - +@define function initpool(); +@define type gzFile; +@define function weof(); + +@define procedure initGraphiteBreaking(); +@define function findNextGraphiteBreak(); +@define function usingOpenType(); +@define function usingGraphite(); +@define procedure grprintfontname(); +@define function grfontgetnamed(); +@define function grfontgetnamed1(); + +@define function strerror(); @define procedure memcpy(); -@define function casttoptr(); -@define function casttointeger(); @define function glyphinfobyte(); @define function casttoushort(); @@ -98,6 +109,7 @@ authorization from SIL International. @define function getotmathvariant(); @define function getotassemblyptr(); @define function getotmathitalcorr(); +@define function getotmathaccentpos(); @define function otpartcount(); @define function otpartglyph(); @@ -133,6 +145,7 @@ authorization from SIL International. @define function findpicfile(); @define function picpathbyte(); +@define function countpdffilepages; @define procedure makeidentity(); @define procedure makescale(); diff --git a/Build/source/texk/web2c/xetexdir/xetex.h b/Build/source/texk/web2c/xetexdir/xetex.h index 60ac046a0b8..b81ec543d0c 100644 --- a/Build/source/texk/web2c/xetexdir/xetex.h +++ b/Build/source/texk/web2c/xetexdir/xetex.h @@ -51,7 +51,7 @@ authorization from SIL International. #define makexdvglypharraydata(p) makeXDVGlyphArrayData(&(mem[p])) #define xdvbufferbyte(i) xdvbuffer[i] -void* getotassemblyptr(int f, int g); /* function in XeTeXOTMath.cpp */ +void* getotassemblyptr(int f, int g, int horiz); /* function in XeTeXOTMath.cpp */ #define pic_node_size 8 diff --git a/Build/source/texk/web2c/xetexdir/xetex.mk b/Build/source/texk/web2c/xetexdir/xetex.mk index 0c54f08a093..a8bbdc158fb 100644 --- a/Build/source/texk/web2c/xetexdir/xetex.mk +++ b/Build/source/texk/web2c/xetexdir/xetex.mk @@ -4,6 +4,10 @@ Makefile: $(srcdir)/xetexdir/xetex.mk +# this should probably move to common.mk some day, +# but need to check possible effect on other programs +ALL_CXXFLAGS = @CXXFLAGS@ + # We build xetex unless configure decides to skip it xetex = @XETEX@ xetex @@ -81,7 +85,14 @@ ZLIBSRCDIR = $(srcdir)/$(ZLIBDIR) FONTCONFIGCPPFLAGS = @FONTCONFIGCPPFLAGS@ FONTCONFIGLDFLAGS = @FONTCONFIGLDFLAGS@ -xetexlibs = $(LDICU) $(LDTECKIT) $(LDFREETYPE2) $(LDZLIB) +GRAPHITEDIR = ../../libs/graphite-engine +GRAPHITESRCDIR = $(srcdir)/$(GRAPHITEDIR) + +GRAPHITEFLAGS = @GRAPHITECPPFLAGS@ +LDGRAPHITE = @LDGRAPHITE@ +GRAPHITEDEP = @GRAPHITEDEP@ + +xetexlibs = $(LDICU) $(LDTECKIT) $(LDFREETYPE2) $(LDGRAPHITE) $(LDZLIB) # Font-related headers XeTeXFontHdrs = \ @@ -103,15 +114,21 @@ XeTeXImageHdrs = \ $(srcdir)/xetexdir/pngimage.h # Extract xetex version -xetexdir/xetex.version: $(srcdir)/xetexdir/xetex-new.ch +xetexdir/xetex.version: $(srcdir)/xetexdir/xetex.ch test -d xetexdir || mkdir xetexdir - grep '^@d XeTeX_version_string==' $(srcdir)/xetexdir/xetex-new.ch \ + grep '^@d XeTeX_version_string==' $(srcdir)/xetexdir/xetex.ch \ | sed "s/^.*'-//;s/'.*$$//" >xetexdir/xetex.version +# Extract etex version +xetexdir/etex.version: $(srcdir)/etexdir/etex.ch + test -d xetexdir || mkdir xetexdir + grep '^@d eTeX_version_string==' $(srcdir)/etexdir/etex.ch \ + | sed "s/^.*'-//;s/'.*$$//" >xetexdir/etex.version + # The C sources. xetex_c = xetexini.c xetex0.c xetex1.c xetex2.c xetex_o = xetexini.o xetex0.o xetex1.o xetex2.o xetexextra.o -xetex_add_o = trans.o XeTeX_ext.o $(xetex_platform_o) +xetex_add_o = trans.o XeTeX_ext.o xetex_pool.o $(xetex_platform_o) # these compilations require the path to TECkit headers; # just setting it in XCFLAGS doesn't seem to work when we're called @@ -126,6 +143,8 @@ xetex2.o: xetex2.c $(srcdir)/xetexdir/XeTeX_ext.h $(compile) $(TECKITFLAGS) $(ALL_CFLAGS) $(XETEX_DEFINES) -c $< -o $@ xetexextra.o: xetexextra.c $(srcdir)/xetexdir/XeTeX_ext.h $(compile) $(TECKITFLAGS) $(ALL_CFLAGS) $(XETEX_DEFINES) -c $< -o $@ +xetex_pool.o: xetex_pool.c $(srcdir)/xetexdir/XeTeX_ext.h + $(compile) $(TECKITFLAGS) $(ALL_CFLAGS) $(XETEX_DEFINES) -c $< -o $@ # image support mfileio.o: $(srcdir)/xetexdir/mfileio.c $(srcdir)/xetexdir/mfileio.h @@ -155,10 +174,11 @@ xetex_ot_layout_o = \ XeTeXLayoutInterface.o XeTeXOTLayoutEngine.o \ XeTeXFontInst.o cmaps.o FontTableCache.o \ XeTeXOTMath.o \ + XeTeXGrLayout.o \ $(xetex_platform_layout_o) XeTeXLayoutInterface.o: $(srcdir)/xetexdir/XeTeXLayoutInterface.cpp $(XeTeXFontHdrs) - $(CXX) $(ICUCFLAGS) $(FTFLAGS) $(FONTCONFIGCPPFLAGS) $(ALL_CXXFLAGS) $(XETEX_DEFINES) -c $< -o $@ + $(CXX) $(ICUCFLAGS) $(FTFLAGS) $(GRAPHITEFLAGS) $(FONTCONFIGCPPFLAGS) $(ALL_CXXFLAGS) $(XETEX_DEFINES) -c $< -o $@ XeTeXOTLayoutEngine.o: $(srcdir)/xetexdir/XeTeXOTLayoutEngine.cpp $(XeTeXFontHdrs) $(CXX) $(ICUCFLAGS) $(FTFLAGS) $(FONTCONFIGCPPFLAGS) $(ALL_CXXFLAGS) $(XETEX_DEFINES) -c $< -o $@ @@ -185,6 +205,9 @@ XeTeXFontInst_FT2.o: $(srcdir)/xetexdir/XeTeXFontInst_FT2.cpp $(XeTeXFontHdrs) XeTeXOTMath.o: $(srcdir)/xetexdir/XeTeXOTMath.cpp $(XeTeXFontHdrs) $(CXX) $(ICUCFLAGS) $(FTFLAGS) $(FONTCONFIGCPPFLAGS) $(ALL_CXXFLAGS) $(XETEX_DEFINES) -c $< -o $@ +XeTeXGrLayout.o: $(srcdir)/xetexdir/XeTeXGrLayout.cpp $(srcdir)/xetexdir/XeTeXGrLayout.h $(XeTeXFontHdrs) + $(CXX) $(ICUCFLAGS) $(FTFLAGS) $(GRAPHITEFLAGS) $(ALL_CXXFLAGS) $(XETEX_DEFINES) -c $< -o $@ + # special rules for files that need the TECkit headers as well XeTeX_ext.o: $(srcdir)/xetexdir/XeTeX_ext.c xetexd.h $(compile) $(ICUCFLAGS) $(FTFLAGS) $(TECKITFLAGS) $(LIBPNGCPPFLAGS) $(LIBXPDFCPPFLAGS) $(ZLIBCPPFLAGS) $(ALL_CFLAGS) $(XETEX_DEFINES) -c $< -o $@ @@ -205,16 +228,20 @@ $(xetex_c) xetexcoerce.h xetexd.h: xetex.p $(web2c_texmf) $(web2c) xetex xetexextra.c: lib/texmfmp.c xetexdir/xetexextra.h sed s/TEX-OR-MF-OR-MP/xetex/ $(srcdir)/lib/texmfmp.c >$@ -xetexdir/xetexextra.h: xetexdir/xetexextra.in xetexdir/xetex.version +xetexdir/xetexextra.h: xetexdir/xetexextra.in xetexdir/xetex.version xetexdir/etex.version test -d xetexdir || mkdir xetexdir - sed s/XETEX-VERSION/`cat xetexdir/xetex.version`/ \ + sed -e s/XETEX-VERSION/`cat xetexdir/xetex.version`/ \ + -e s/ETEX-VERSION/`cat xetexdir/etex.version`/ \ $(srcdir)/xetexdir/xetexextra.in >$@ +xetex_pool.c: xetex.pool + perl $(srcdir)/xetexdir/pool2c.pl $< $@ + # Tangling -xetex.p xetex.pool: ./otangle xetex.web # xetex.ch - ./otangle xetex.web # xetex.ch +xetex.p xetex.pool: ./otangle xetex.web + ./otangle xetex.web -# Generation of the web [and ch] file. +# Generation of the web file. # Sources for xetex.web: xetex_web_srcs = $(srcdir)/tex.web \ $(srcdir)/etexdir/etex.ch \ @@ -222,10 +249,7 @@ xetex_web_srcs = $(srcdir)/tex.web \ $(srcdir)/tex.ch \ $(srcdir)/etexdir/tex.ch1 \ $(srcdir)/etexdir/tex.ech \ - $(srcdir)/xetexdir/xetex-new.ch \ - $(srcdir)/xetexdir/xetex-noenc.ch \ - $(srcdir)/xetexdir/xetex-upwards.ch \ - $(srcdir)/xetexdir/xetex-otmath.ch + $(srcdir)/xetexdir/xetex.ch xetex.web: tie xetexdir/xetex.mk $(xetex_web_srcs) $(TIE) -m xetex.web $(xetex_web_srcs) @@ -258,7 +282,7 @@ xetex.web: tie xetexdir/xetex.mk $(xetex_web_srcs) clean:: xetex-clean xetex-clean: # etrip-clean $(LIBTOOL) --mode=clean $(RM) xetex - rm -f $(xetex_o) $(xetex_c) xetexextra.c xetexcoerce.h xetexd.h + rm -f $(xetex_o) $(xetex_c) xetexextra.c xetex_pool.c xetexcoerce.h xetexd.h rm -f xetexdir/xetexextra.h xetexdir/xetex.version rm -f xetex.p xetex.pool xetex.web xetex.ch rm -f xetex.fmt xetex.log @@ -289,7 +313,7 @@ xelatex.fmt: xetex # Install install-xetex: install-xetex-exec install-xetex-data install-xetex-exec: install-xetex-programs install-xetex-links -install-xetex-data: install-xetex-pool @FMU@ install-xetex-dumps +install-xetex-data: @FMU@ install-xetex-dumps install-xetex-dumps: install-xetex-fmts install-programs: @XETEX@ install-xetex-programs @@ -310,7 +334,5 @@ install-xetex-fmts: xefmts $(xefmtdir) (cd ${DESTDIR}$(bindir) && (rm -f $$base; $(LN) xetex $$base)); done install-data:: @XETEX@ install-xetex-data -install-xetex-pool: xetex.pool $(texpooldir) - $(INSTALL_DATA) xetex.pool ${DESTDIR}$(texpooldir)/xetex.pool # end of xetex.mk diff --git a/Build/source/texk/web2c/xetexdir/xetexextra.in b/Build/source/texk/web2c/xetexdir/xetexextra.in index 9286d98fe37..e9e883ab3b7 100644 --- a/Build/source/texk/web2c/xetexdir/xetexextra.in +++ b/Build/source/texk/web2c/xetexdir/xetexextra.in @@ -51,7 +51,7 @@ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#define BANNER "This is XeTeX, Version 3.141592-XETEX-VERSION" +#define BANNER "This is XeTeX, Version 3.141592-ETEX-VERSION-XETEX-VERSION" #define COPYRIGHT_HOLDER "SIL International" #define AUTHOR "Jonathan Kew" #define PROGRAM_HELP XETEXHELP diff --git a/Build/source/texk/xdv2pdf/xdv2pdf.cpp b/Build/source/texk/xdv2pdf/xdv2pdf.cpp index e51aa7fb216..277bfc0ff86 100755 --- a/Build/source/texk/xdv2pdf/xdv2pdf.cpp +++ b/Build/source/texk/xdv2pdf/xdv2pdf.cpp @@ -85,6 +85,8 @@ authorization from SIL International. #define XDV_FLAG_COLORED 0x0200 #define XDV_FLAG_FEATURES 0x0400 #define XDV_FLAG_VARIATIONS 0x0800 +#define XDV_FLAG_EXTEND 0x1000 +#define XDV_FLAG_SLANT 0x2000 #define pdfbox_crop 1 #define pdfbox_media 2 @@ -154,8 +156,8 @@ paperSizeRec gPaperSizes[] = { 0, 0, 0 } }; -static CGAffineTransform horizontalMatrix = { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }; -static CGAffineTransform verticalMatrix = { 0.0, 1.0, -1.0, 0.0, 0.0, 0.0 }; +static const CGAffineTransform kHorizontalMatrix = { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }; +static const CGAffineTransform kVerticalMatrix = { 0.0, 1.0, -1.0, 0.0, 0.0, 0.0 }; struct nativeFont { nativeFont() @@ -164,6 +166,7 @@ struct nativeFont { , atsuStyleH(0) , atsuStyleV(0) , size(Long2Fix(10)) + , matrix(kHorizontalMatrix) , isColored(false) , isVertical(false) { @@ -174,6 +177,7 @@ struct nativeFont { ATSUStyle atsuStyleV; Fixed size; CGColorRef color; + CGAffineTransform matrix; bool isColored; bool isVertical; }; @@ -454,7 +458,7 @@ setChar(UInt32 c, bool adv) flushGlyphs(); CGContextSetFont(gCtx, gTeXFonts[f].cgFont); CGContextSetFontSize(gCtx, Fix2X(gTeXFonts[f].size) * gMagScale); - CGContextSetTextMatrix(gCtx, horizontalMatrix); + CGContextSetTextMatrix(gCtx, kHorizontalMatrix); cur_cgFont = f; } @@ -545,8 +549,7 @@ doGlyphArray(FILE* xdv, bool yLocs) if (f != cur_cgFont) { CGContextSetFont(gCtx, sNativeFonts[f].cgFont); CGContextSetFontSize(gCtx, Fix2X(sNativeFonts[f].size)); - CGContextSetTextMatrix(gCtx, sNativeFonts[f].isVertical - ? verticalMatrix : horizontalMatrix); + CGContextSetTextMatrix(gCtx, sNativeFonts[f].matrix); cur_cgFont = f; } @@ -1756,7 +1759,7 @@ doNativeFontDef(FILE* xdv) delete[] axes; } } - + nativeFont fontRec; fontRec.cgFont = cgFont; fontRec.atsFont = fontRef; @@ -1789,6 +1792,23 @@ doNativeFontDef(FILE* xdv) vert = kATSUStronglyVertical; status = ATSUSetAttributes(style, numTags, tags, sizes, values); fontRec.atsuStyleV = style; + + fontRec.matrix = kVerticalMatrix; + } + + if (flags & XDV_FLAG_EXTEND) { + Fixed x = readUnsigned(xdv, 4); + if (fontRec.isVertical) + fontRec.matrix.c *= Fix2X(x); + else + fontRec.matrix.a *= Fix2X(x); + } + if (flags & XDV_FLAG_SLANT) { + Fixed s = readSigned(xdv, 4); + if (fontRec.isVertical) + fontRec.matrix.d = Fix2X(s); + else + fontRec.matrix.c = Fix2X(s); } sNativeFonts.insert(std::pair(f, fontRec)); @@ -2197,9 +2217,8 @@ xdv2pdf(int argc, char** argv) gTagLevel = -1; - double_t paperWd = 0.0; - double_t paperHt = 0.0; - + gPaperWd = gPaperHt = 0.0; + int ch; while ((ch = getopt(argc, argv, "o:p:m:d:hv" /*r:*/)) != -1) { switch (ch) { @@ -2212,7 +2231,7 @@ xdv2pdf(int argc, char** argv) break; case 'p': - if (!getPaperSize(optarg, paperWd, paperHt)) { + if (!getPaperSize(optarg, gPaperWd, gPaperHt)) { fprintf(stderr, "*** unknown paper name: %s\n", optarg); exit(1); } @@ -2236,7 +2255,7 @@ xdv2pdf(int argc, char** argv) } } - if ((paperWd == 0.0) || (paperHt == 0.0)) { + if ((gPaperWd == 0.0) || (gPaperHt == 0.0)) { // get default paper size from printing system PMRect paperRect = { 0, 0, 792, 612 }; PMPrintSession printSession; @@ -2257,12 +2276,12 @@ xdv2pdf(int argc, char** argv) } status = PMRelease(printSession); } - paperWd = paperRect.right - paperRect.left; - paperHt = paperRect.bottom - paperRect.top; + gPaperWd = paperRect.right - paperRect.left; + gPaperHt = paperRect.bottom - paperRect.top; } // set the media box for PDF generation - gMediaBox = CGRectMake(0, 0, paperWd, paperHt); + gMediaBox = CGRectMake(0, 0, gPaperWd, gPaperHt); argc -= optind; argv += optind; diff --git a/Build/source/texk/xdv2pdf/xdv2pdf_globals.h b/Build/source/texk/xdv2pdf/xdv2pdf_globals.h index a747a18b010..4a0e7a6a176 100644 --- a/Build/source/texk/xdv2pdf/xdv2pdf_globals.h +++ b/Build/source/texk/xdv2pdf/xdv2pdf_globals.h @@ -52,6 +52,9 @@ GLOBAL CGColorSpaceRef gGrayColorSpace; GLOBAL bool gPageStarted; GLOBAL CGRect gMediaBox; +GLOBAL double_t gPaperWd; +GLOBAL double_t gPaperHt; + struct dviVars { SInt32 h; diff --git a/Build/source/texk/xdv2pdf/xdv2pdf_specials.cpp b/Build/source/texk/xdv2pdf/xdv2pdf_specials.cpp index cad873900d2..a19e028da56 100644 --- a/Build/source/texk/xdv2pdf/xdv2pdf_specials.cpp +++ b/Build/source/texk/xdv2pdf/xdv2pdf_specials.cpp @@ -499,8 +499,19 @@ doColorSpecial(const char* s, bool background) } } +static bool +prefixMatch(const char* str, const char* prefix, const char*& remainder) +{ + int len = strlen(prefix); + if (strncmp(str, prefix, len) == 0) { + remainder = str + len; + return true; + } + return false; +} + static double_t -readDimen(const char* arg) // currently reads unsigned dimens only; no negative paper sizes! +readDimen(const char*& arg) // currently reads unsigned dimens only; no negative paper sizes! { double_t rval = 0.0; while ((*arg >= '0') && (*arg <= '9')) { @@ -519,7 +530,7 @@ readDimen(const char* arg) // currently reads unsigned dimens only; no negative } const dimenRec* dim = &sDimenRatios[0]; while (dim->name != 0) { - if (strcasecmp(arg, dim->name) == 0) { + if (prefixMatch(arg, dim->name, arg)) { rval *= dim->factor; break; } @@ -551,8 +562,10 @@ getPaperSize(const char* arg, double_t& paperWd, double_t& paperHt) char* s3 = strchr(s1, ','); if (s3 != NULL) { *s3++ = 0; - paperWd = readDimen(s1); - paperHt = readDimen(s3); + const char* s4 = s1; + paperWd = readDimen(s4); + s4 = s3; + paperHt = readDimen(s4); } } if (s2 != NULL && strcasecmp(s2, "landscape") == 0) { @@ -567,14 +580,32 @@ getPaperSize(const char* arg, double_t& paperWd, double_t& paperHt) } static bool -prefixMatch(const char* str, const char* prefix, const char*& remainder) +getPageSize(const char* arg, double_t& pageWd, double_t& pageHt) { - int len = strlen(prefix); - if (strncmp(str, prefix, len) == 0) { - remainder = str + len; - return true; + pageHt = pageWd = 0.0; + while (*arg) { + while (*arg == ' ') + ++arg; + if (prefixMatch(arg, "width", arg)) { + while (*arg == ' ') + ++arg; + pageWd = readDimen(arg); + continue; + } + if (prefixMatch(arg, "height", arg)) { + while (*arg == ' ') + ++arg; + pageHt = readDimen(arg); + continue; + } + if (prefixMatch(arg, "default", arg)) { + pageWd = gPaperWd; + pageHt = gPaperHt; + continue; + } + ++arg; } - return false; + return (pageHt > 0.0) && (pageWd > 0.0); } inline bool @@ -601,7 +632,29 @@ doSpecial(const char* special) int u = strlen(special); const char* specialArg; - if (prefixMatch(special, "pdf:", specialArg)) + if (prefixMatch(special, "pdf:pagesize", specialArg)) { + // NOTE: must come before the general pdf special check! + // syntax: \special{pdf:pagesize width height } etc + while (*specialArg && (*specialArg <= ' ')) + ++specialArg; + double_t paperWd, paperHt; + if (getPageSize(specialArg, paperWd, paperHt)) { + gMediaBox = CGRectMake(0, 0, paperWd, paperHt); + if (gPageStarted) { + fprintf(stderr, "\n### warning on page ["); + int i, j; + for (j = 9; j > 1; --j) + if (gCounts[j] != 0) + break; + for (i = 0; i < j; ++i) + fprintf(stderr, "%d.", gCounts[i]); + fprintf(stderr, "%d", gCounts[j]); + fprintf(stderr, "]: pdf page size \"%s\" will take effect from NEXT page ", specialArg); + } + } + } + + else if (prefixMatch(special, "pdf:", specialArg)) doPDFspecial(specialArg); else if (prefixMatch(special, "color ", specialArg)) @@ -770,9 +823,8 @@ doSpecial(const char* special) while (*specialArg && (*specialArg <= ' ')) ++specialArg; } - double_t paperWd, paperHt; - if (getPaperSize(specialArg, paperWd, paperHt)) { - gMediaBox = CGRectMake(0, 0, paperWd, paperHt); + if (getPaperSize(specialArg, gPaperWd, gPaperHt)) { + gMediaBox = CGRectMake(0, 0, gPaperWd, gPaperHt); if (gPageStarted) { fprintf(stderr, "\n### warning on page ["); int i, j; -- cgit v1.2.3