summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Kew <jfkthame@googlemail.com>2006-07-26 16:19:45 +0000
committerJonathan Kew <jfkthame@googlemail.com>2006-07-26 16:19:45 +0000
commit622bf4a7c90729be28a038c49e4c237ce9f31297 (patch)
tree77466d5c0a89c433bd1c08f4cbeaf410fda7b25c
parente88aafe4ca4779a73487925dea63e8b55dc5e251 (diff)
added main xetex source directory
git-svn-id: svn://tug.org/texlive/trunk@1920 c570f23f-e606-0410-a88d-b1316a301751
-rw-r--r--Build/source/texk/web2c/xetexdir/FontTableCache.cpp134
-rw-r--r--Build/source/texk/web2c/xetexdir/FontTableCache.h74
-rw-r--r--Build/source/texk/web2c/xetexdir/XeTeXFontInst.cpp295
-rw-r--r--Build/source/texk/web2c/xetexdir/XeTeXFontInst.h205
-rw-r--r--Build/source/texk/web2c/xetexdir/XeTeXFontInst_FC.cpp217
-rw-r--r--Build/source/texk/web2c/xetexdir/XeTeXFontInst_FC.h76
-rw-r--r--Build/source/texk/web2c/xetexdir/XeTeXFontInst_Mac.cpp111
-rw-r--r--Build/source/texk/web2c/xetexdir/XeTeXFontInst_Mac.h63
-rw-r--r--Build/source/texk/web2c/xetexdir/XeTeXFontMgr.cpp621
-rw-r--r--Build/source/texk/web2c/xetexdir/XeTeXFontMgr.h202
-rw-r--r--Build/source/texk/web2c/xetexdir/XeTeXFontMgr_Linux.cpp317
-rw-r--r--Build/source/texk/web2c/xetexdir/XeTeXFontMgr_Linux.h59
-rw-r--r--Build/source/texk/web2c/xetexdir/XeTeXFontMgr_Mac.h64
-rw-r--r--Build/source/texk/web2c/xetexdir/XeTeXFontMgr_Mac.mm280
-rw-r--r--Build/source/texk/web2c/xetexdir/XeTeXLayoutInterface.cpp519
-rw-r--r--Build/source/texk/web2c/xetexdir/XeTeXLayoutInterface.h134
-rw-r--r--Build/source/texk/web2c/xetexdir/XeTeXOTLayoutEngine.cpp281
-rw-r--r--Build/source/texk/web2c/xetexdir/XeTeXOTLayoutEngine.h128
-rw-r--r--Build/source/texk/web2c/xetexdir/XeTeX_ext.c2302
-rw-r--r--Build/source/texk/web2c/xetexdir/XeTeX_ext.h284
-rw-r--r--Build/source/texk/web2c/xetexdir/XeTeX_mac.c1022
-rw-r--r--Build/source/texk/web2c/xetexdir/XeTeX_pic.c111
-rw-r--r--Build/source/texk/web2c/xetexdir/XeTeXswap.h96
-rw-r--r--Build/source/texk/web2c/xetexdir/appleGlyphNames.c291
-rw-r--r--Build/source/texk/web2c/xetexdir/bmpimage.c201
-rw-r--r--Build/source/texk/web2c/xetexdir/bmpimage.h70
-rw-r--r--Build/source/texk/web2c/xetexdir/cmaps.cpp240
-rw-r--r--Build/source/texk/web2c/xetexdir/cmaps.h116
-rw-r--r--Build/source/texk/web2c/xetexdir/cpl1.0.txt213
-rw-r--r--Build/source/texk/web2c/xetexdir/jpegimage.c410
-rw-r--r--Build/source/texk/web2c/xetexdir/jpegimage.h166
-rw-r--r--Build/source/texk/web2c/xetexdir/mfileio.c126
-rw-r--r--Build/source/texk/web2c/xetexdir/mfileio.h61
-rw-r--r--Build/source/texk/web2c/xetexdir/numbers.c227
-rw-r--r--Build/source/texk/web2c/xetexdir/numbers.h82
-rw-r--r--Build/source/texk/web2c/xetexdir/pdfimage.cpp77
-rw-r--r--Build/source/texk/web2c/xetexdir/pdfimage.h27
-rw-r--r--Build/source/texk/web2c/xetexdir/pngimage.c161
-rw-r--r--Build/source/texk/web2c/xetexdir/pngimage.h70
-rw-r--r--Build/source/texk/web2c/xetexdir/sfnt.h285
-rw-r--r--Build/source/texk/web2c/xetexdir/tests.ac49
-rw-r--r--Build/source/texk/web2c/xetexdir/trans.c116
-rw-r--r--Build/source/texk/web2c/xetexdir/trans.h94
-rw-r--r--Build/source/texk/web2c/xetexdir/unicode-char-prep.pl116
-rw-r--r--Build/source/texk/web2c/xetexdir/xetex-new.ch6169
-rw-r--r--Build/source/texk/web2c/xetexdir/xetex-noenc.ch1144
-rw-r--r--Build/source/texk/web2c/xetexdir/xetex-upwards.ch244
-rw-r--r--Build/source/texk/web2c/xetexdir/xetex.defines136
-rw-r--r--Build/source/texk/web2c/xetexdir/xetex.h100
-rw-r--r--Build/source/texk/web2c/xetexdir/xetex.mk303
-rw-r--r--Build/source/texk/web2c/xetexdir/xetexextra.in65
51 files changed, 18954 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/xetexdir/FontTableCache.cpp b/Build/source/texk/web2c/xetexdir/FontTableCache.cpp
new file mode 100644
index 00000000000..af5cd710a00
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/FontTableCache.cpp
@@ -0,0 +1,134 @@
+/*
+ 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.
+*/
+
+/* from ICU sample code, extended by JK for XeTeX */
+
+/*
+ **********************************************************************
+ * Copyright (C) 2003, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ **********************************************************************
+ */
+
+#include "LETypes.h"
+
+#include "FontTableCache.h"
+
+#define TABLE_CACHE_INIT 5
+#define TABLE_CACHE_GROW 5
+
+struct FontTableCacheEntry
+{
+ LETag tag;
+ const void *table;
+};
+
+FontTableCache::FontTableCache()
+ : fTableCacheCurr(0), fTableCacheSize(TABLE_CACHE_INIT)
+{
+ initialize();
+}
+
+void
+FontTableCache::initialize()
+{
+ fTableCache = LE_NEW_ARRAY(FontTableCacheEntry, fTableCacheSize);
+
+ if (fTableCache == NULL) {
+ fTableCacheSize = 0;
+ return;
+ }
+
+ for (int i = 0; i < fTableCacheSize; i += 1) {
+ fTableCache[i].tag = 0;
+ fTableCache[i].table = NULL;
+ }
+}
+
+FontTableCache::~FontTableCache()
+{
+ dispose();
+}
+
+void FontTableCache::dispose()
+{
+ for (int i = fTableCacheCurr - 1; i >= 0; i -= 1) {
+ LE_DELETE_ARRAY(fTableCache[i].table);
+
+ fTableCache[i].tag = 0;
+ fTableCache[i].table = NULL;
+ }
+
+ fTableCacheCurr = 0;
+}
+
+const void *FontTableCache::find(LETag tableTag) const
+{
+ for (int i = 0; i < fTableCacheCurr; i += 1) {
+ if (fTableCache[i].tag == tableTag) {
+ return fTableCache[i].table;
+ }
+ }
+
+ const void *table = readFontTable(tableTag);
+
+ ((FontTableCache *) this)->add(tableTag, table);
+
+ return table;
+}
+
+void FontTableCache::add(LETag tableTag, const void *table)
+{
+ if (fTableCacheCurr >= fTableCacheSize) {
+ le_int32 newSize = fTableCacheSize + TABLE_CACHE_GROW;
+
+ fTableCache = (FontTableCacheEntry *) LE_GROW_ARRAY(fTableCache, newSize);
+
+ for (le_int32 i = fTableCacheSize; i < newSize; i += 1) {
+ fTableCache[i].tag = 0;
+ fTableCache[i].table = NULL;
+ }
+
+ fTableCacheSize = newSize;
+ }
+
+ fTableCache[fTableCacheCurr].tag = tableTag;
+ fTableCache[fTableCacheCurr].table = table;
+
+ fTableCacheCurr += 1;
+}
+
+void FontTableCache::flush()
+{
+ if (fTableCacheSize > 0) {
+ dispose();
+ initialize();
+ }
+}
diff --git a/Build/source/texk/web2c/xetexdir/FontTableCache.h b/Build/source/texk/web2c/xetexdir/FontTableCache.h
new file mode 100644
index 00000000000..03d71ac7110
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/FontTableCache.h
@@ -0,0 +1,74 @@
+/*
+ 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.
+*/
+/* from ICU sample code, extended by JK for XeTeX */
+
+/*
+ **********************************************************************
+ * Copyright (C) 2003, International Business Machines
+ * Corporation and others. All Rights Reserved.
+ **********************************************************************
+ */
+
+#ifndef __FONTTABLECACHE_H
+
+#define __FONTTABLECACHE_H
+
+#include "LETypes.h"
+
+struct FontTableCacheEntry;
+
+class FontTableCache
+{
+public:
+ FontTableCache();
+
+ virtual ~FontTableCache();
+
+ const void *find(LETag tableTag) const;
+
+ void flush();
+
+protected:
+ virtual const void *readFontTable(LETag tableTag) const = 0;
+
+private:
+
+ void initialize();
+ void dispose();
+
+ void add(LETag tableTag, const void *table);
+
+ FontTableCacheEntry *fTableCache;
+ le_int32 fTableCacheCurr;
+ le_int32 fTableCacheSize;
+};
+
+#endif
+
diff --git a/Build/source/texk/web2c/xetexdir/XeTeXFontInst.cpp b/Build/source/texk/web2c/xetexdir/XeTeXFontInst.cpp
new file mode 100644
index 00000000000..b11138b920b
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/XeTeXFontInst.cpp
@@ -0,0 +1,295 @@
+/****************************************************************************\
+ 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.
+\****************************************************************************/
+
+/*
+ * file name: XeTeXFontInst.cpp
+ *
+ * created on: 2005-10-22
+ * created by: Jonathan Kew
+ *
+ * originally based on PortableFontInstance.cpp from ICU
+ */
+
+
+#include "LETypes.h"
+#include "LEFontInstance.h"
+#include "LESwaps.h"
+
+#include "XeTeXFontInst.h"
+#include "XeTeXLayoutInterface.h"
+
+#ifdef XETEX_MAC
+#include <Carbon/Carbon.h>
+#endif
+
+#include "XeTeX_ext.h"
+
+#include "sfnt.h"
+
+#include <string.h>
+
+
+XeTeXFontInst::XeTeXFontInst(PlatformFontRef fontRef, float pointSize, LEErrorCode &status)
+ : fFontRef(fontRef)
+ , fPointSize(pointSize)
+ , fUnitsPerEM(0)
+ , fAscent(0)
+ , fDescent(0)
+ , fLeading(0)
+ , fXHeight(0)
+ , fItalicAngle(0)
+ , fCMAPMapper(NULL)
+ , fMetricsTable(NULL)
+ , fNumLongMetrics(0)
+ , fNumGlyphs(0)
+ , fNumGlyphsInited(false)
+ , fVertical(false)
+{
+ // the concrete subclass is responsible to call initialize()
+}
+
+XeTeXFontInst::~XeTeXFontInst()
+{
+ if (fMetricsTable != NULL)
+ deleteTable(fMetricsTable);
+
+ if (fCMAPMapper != NULL)
+ delete fCMAPMapper;
+}
+
+void XeTeXFontInst::initialize(LEErrorCode &status)
+{
+ const LETag headTag = LE_HEAD_TABLE_TAG;
+ const LETag hheaTag = LE_HHEA_TABLE_TAG;
+ const LETag vheaTag = LE_VHEA_TABLE_TAG;
+ const LETag postTag = LE_POST_TABLE_TAG;
+ const HEADTable *headTable = NULL;
+ const HHEATable *dirHeadTable = NULL;
+ const POSTTable *postTable = NULL;
+
+ // dispose of any cached metrics table
+ if (fMetricsTable != NULL) {
+ deleteTable(fMetricsTable);
+ fMetricsTable = NULL;
+ }
+
+ // read unitsPerEm from 'head' table
+ headTable = (const HEADTable *) readFontTable(headTag);
+
+ if (headTable == NULL) {
+ status = LE_MISSING_FONT_TABLE_ERROR;
+ goto error_exit;
+ }
+
+ fUnitsPerEM = SWAPW(headTable->unitsPerEm);
+ deleteTable(headTable);
+
+ // we use the fact that 'hhea' and 'vhea' have the same format!
+ dirHeadTable = (const HHEATable *) readFontTable(fVertical ? vheaTag : hheaTag);
+
+ if (dirHeadTable == NULL) {
+ status = LE_MISSING_FONT_TABLE_ERROR;
+ goto error_exit;
+ }
+
+ fAscent = yUnitsToPoints((float)(le_int16)SWAPW(dirHeadTable->ascent));
+ fDescent = yUnitsToPoints((float)(le_int16)SWAPW(dirHeadTable->descent));
+ fLeading = yUnitsToPoints((float)(le_int16)SWAPW(dirHeadTable->lineGap));
+
+ fNumLongMetrics = SWAPW(dirHeadTable->numOfLongHorMetrics);
+
+ deleteTable(dirHeadTable);
+
+ fCMAPMapper = findUnicodeMapper();
+
+ if (fCMAPMapper == NULL) {
+ status = LE_MISSING_FONT_TABLE_ERROR;
+ goto error_exit;
+ }
+
+ postTable = (const POSTTable *) readFontTable(postTag);
+
+ if (postTable != NULL) {
+ fItalicAngle = Fix2X(SWAPL(postTable->italicAngle));
+ deleteTable(postTable);
+ }
+
+ return;
+
+error_exit:
+ return;
+}
+
+void XeTeXFontInst::setLayoutDirVertical(bool vertical)
+{
+ fVertical = vertical;
+ LEErrorCode status = LE_NO_ERROR;
+ initialize(status);
+}
+
+void XeTeXFontInst::deleteTable(const void *table) const
+{
+ LE_DELETE_ARRAY(table);
+}
+
+const void *XeTeXFontInst::getFontTable(LETag tableTag) const
+{
+ return FontTableCache::find(tableTag);
+}
+
+const void *XeTeXFontInst::readFontTable(LETag tableTag) const
+{
+ le_uint32 len;
+
+ return readTable(tableTag, &len);
+}
+
+const void *XeTeXFontInst::readFontTable(LETag tableTag, le_uint32& len) const
+{
+ return readTable(tableTag, &len);
+}
+
+CMAPMapper *XeTeXFontInst::findUnicodeMapper()
+{
+ LETag cmapTag = LE_CMAP_TABLE_TAG;
+ const CMAPTable *cmap = (CMAPTable *) readFontTable(cmapTag);
+
+ if (cmap == NULL) {
+ return NULL;
+ }
+
+ return CMAPMapper::createUnicodeMapper(cmap);
+}
+
+
+le_uint16 XeTeXFontInst::getNumGlyphs() const
+{
+ if (!fNumGlyphsInited) {
+ LETag maxpTag = LE_MAXP_TABLE_TAG;
+ const MAXPTable *maxpTable = (MAXPTable *) readFontTable(maxpTag);
+
+ if (maxpTable != NULL) {
+ XeTeXFontInst *realThis = (XeTeXFontInst *) this;
+ realThis->fNumGlyphs = SWAPW(maxpTable->numGlyphs);
+ deleteTable(maxpTable);
+ realThis->fNumGlyphsInited = true;
+ }
+ }
+
+ return fNumGlyphs;
+}
+
+void XeTeXFontInst::getGlyphAdvance(LEGlyphID glyph, LEPoint &advance) const
+{
+ TTGlyphID ttGlyph = (TTGlyphID) LE_GET_GLYPH(glyph);
+
+ if (fMetricsTable == NULL) {
+ // we use the fact that 'hmtx' and 'vmtx' have the same format
+ LETag metricsTag = fVertical ? LE_VMTX_TABLE_TAG : LE_HMTX_TABLE_TAG;
+ XeTeXFontInst *realThis = (XeTeXFontInst *) this;
+ realThis->fMetricsTable = (const HMTXTable *) readFontTable(metricsTag);
+ }
+
+ le_uint16 index = ttGlyph;
+
+ if (ttGlyph >= getNumGlyphs() || fMetricsTable == NULL) {
+ advance.fX = advance.fY = 0;
+ return;
+ }
+
+ if (ttGlyph >= fNumLongMetrics) {
+ index = fNumLongMetrics - 1;
+ }
+
+ advance.fX = xUnitsToPoints(SWAPW(fMetricsTable->hMetrics[index].advanceWidth));
+ advance.fY = 0;
+}
+
+le_bool XeTeXFontInst::getGlyphPoint(LEGlyphID glyph, le_int32 pointNumber, LEPoint &point) const
+{
+ return FALSE;
+}
+
+float
+XeTeXFontInst::getGlyphWidth(LEGlyphID gid)
+{
+ LEPoint advance;
+ getGlyphAdvance(gid, advance);
+ return advance.fX;
+}
+
+void
+XeTeXFontInst::getGlyphHeightDepth(LEGlyphID gid, float* ht, float* dp)
+{
+ GlyphBBox bbox;
+ getGlyphBounds(gid, &bbox);
+
+ *ht = bbox.yMax;
+ *dp = -bbox.yMin;
+}
+
+void
+XeTeXFontInst::getGlyphSidebearings(LEGlyphID gid, float* lsb, float* rsb)
+{
+ LEPoint adv;
+ getGlyphAdvance(gid, adv);
+
+ GlyphBBox bbox;
+ getGlyphBounds(gid, &bbox);
+
+ *lsb = bbox.xMin;
+ *rsb = adv.fX - bbox.xMax;
+}
+
+float
+XeTeXFontInst::getGlyphItalCorr(LEGlyphID gid)
+{
+ float rval = 0.0;
+
+ LEPoint adv;
+ getGlyphAdvance(gid, adv);
+
+ GlyphBBox bbox;
+ getGlyphBounds(gid, &bbox);
+
+ if (bbox.xMax > adv.fX)
+ rval = bbox.xMax - adv.fX;
+
+ return rval;
+}
+
+LEGlyphID
+XeTeXFontInst::mapGlyphToIndex(const char* glyphName) const
+ /* default implementation, may be overridden (e.g. by Freetype-based XeTeXFontInst_ */
+{
+ le_uint32 len;
+ const char *p = (const char*)readFontTable(LE_POST_TABLE_TAG, len);
+ return findGlyphInPostTable(p, len, glyphName);
+}
diff --git a/Build/source/texk/web2c/xetexdir/XeTeXFontInst.h b/Build/source/texk/web2c/xetexdir/XeTeXFontInst.h
new file mode 100644
index 00000000000..d158186b66f
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/XeTeXFontInst.h
@@ -0,0 +1,205 @@
+/****************************************************************************\
+ 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.
+\****************************************************************************/
+
+/*
+ * file name: XeTeXFontInst.h
+ *
+ * created on: 2005-10-22
+ * created by: Jonathan Kew
+ *
+ * originally based on PortableFontInstance.h from ICU
+ */
+
+
+#ifndef __XeTeXFontInst_H
+#define __XeTeXFontInst_H
+
+#include <stdio.h>
+
+#include "LETypes.h"
+#include "LEFontInstance.h"
+
+#include "FontTableCache.h"
+
+#include "sfnt.h"
+#include "cmaps.h"
+
+#include "XeTeXFontMgr.h"
+#include "XeTeX_ext.h"
+
+extern "C" {
+ void *xmalloc(unsigned); // from kpathsea
+};
+
+// Abstract superclass that XeTeXOTLayoutEngine uses;
+// create specific subclasses for each supported platform
+
+class XeTeXFontInst : public LEFontInstance, protected FontTableCache
+{
+protected:
+ PlatformFontRef fFontRef;
+
+ float fPointSize;
+
+ le_int32 fUnitsPerEM;
+ float fAscent;
+ float fDescent;
+ float fLeading;
+
+ float fDeviceScaleX;
+ float fDeviceScaleY;
+
+ float fXHeight;
+ float fItalicAngle;
+
+ CMAPMapper *fCMAPMapper;
+
+ const HMTXTable *fMetricsTable;
+ le_uint16 fNumLongMetrics;
+ le_uint16 fNumGlyphs;
+ bool fNumGlyphsInited;
+
+ bool fVertical; // false = horizontal, true = vertical
+
+ virtual const void *readTable(LETag tag, le_uint32 *length) const = 0;
+ void deleteTable(const void *table) const;
+ void getMetrics();
+
+ CMAPMapper *findUnicodeMapper();
+
+ const void *readFontTable(LETag tableTag) const;
+ const void *readFontTable(LETag tableTag, le_uint32& len) const;
+
+public:
+ XeTeXFontInst(PlatformFontRef fontRef, float pointSize, LEErrorCode &status);
+
+ virtual ~XeTeXFontInst();
+
+ virtual PlatformFontRef getFontRef() const
+ { return fFontRef; }
+
+ virtual void initialize(LEErrorCode &status);
+
+ virtual const void *getFontTable(LETag tableTag) const;
+
+ virtual void setLayoutDirVertical(bool vertical);
+
+ virtual bool getLayoutDirVertical() const
+ {
+ return fVertical;
+ };
+
+ virtual le_int32 getUnitsPerEM() const
+ {
+ return fUnitsPerEM;
+ };
+
+ virtual le_int32 getAscent() const
+ {
+ return (le_int32)fAscent;
+ }
+
+ virtual le_int32 getDescent() const
+ {
+ return (le_int32)fDescent;
+ }
+
+ virtual le_int32 getLeading() const
+ {
+ return (le_int32)fLeading;
+ }
+
+ virtual float getExactAscent() const
+ {
+ return fAscent;
+ }
+
+ virtual float getExactDescent() const
+ {
+ return fDescent;
+ }
+
+ virtual float getExactLeading() const
+ {
+ return fLeading;
+ }
+
+ virtual LEGlyphID mapCharToGlyph(LEUnicode32 ch) const
+ {
+ return fCMAPMapper->unicodeToGlyph(ch);
+ }
+
+ virtual LEGlyphID mapGlyphToIndex(const char* glyphName) const;
+
+ virtual le_uint16 getNumGlyphs() const;
+
+ virtual void getGlyphAdvance(LEGlyphID glyph, LEPoint &advance) const;
+
+ virtual le_bool getGlyphPoint(LEGlyphID glyph, le_int32 pointNumber, LEPoint &point) const;
+
+ virtual void getGlyphBounds(LEGlyphID glyph, GlyphBBox *bbox) = 0; /* must be implemented by subclass */
+
+ float getGlyphWidth(LEGlyphID glyph);
+ void getGlyphHeightDepth(LEGlyphID glyph, float *ht, float* dp);
+ void getGlyphSidebearings(LEGlyphID glyph, float* lsb, float* rsb);
+ float getGlyphItalCorr(LEGlyphID glyph);
+
+ float getXPixelsPerEm() const
+ {
+ return fPointSize;
+ };
+
+ float getYPixelsPerEm() const
+ {
+ return fPointSize;
+ };
+
+ float getScaleFactorX() const
+ {
+ return 1.0;
+ }
+
+ float getScaleFactorY() const
+ {
+ return 1.0;
+ }
+
+ float getXHeight() const
+ {
+ return fXHeight;
+ }
+
+ float getItalicAngle() const
+ {
+ return fItalicAngle;
+ }
+};
+
+#endif
diff --git a/Build/source/texk/web2c/xetexdir/XeTeXFontInst_FC.cpp b/Build/source/texk/web2c/xetexdir/XeTeXFontInst_FC.cpp
new file mode 100644
index 00000000000..499ed7d19b0
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/XeTeXFontInst_FC.cpp
@@ -0,0 +1,217 @@
+/****************************************************************************\
+ 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.
+\****************************************************************************/
+
+/*
+ * file name: XeTeXFontInst_FC.cpp
+ *
+ * created on: 2005-10-25
+ * created by: Jonathan Kew
+ */
+
+
+#include "XeTeXFontInst_FC.h"
+
+#include FT_TRUETYPE_TABLES_H
+#include FT_TYPE1_TABLES_H
+#include FT_GLYPH_H
+
+static FT_Library gLibrary = 0;
+
+
+XeTeXFontInst_FC::XeTeXFontInst_FC(FcPattern* pattern, float pointSize, LEErrorCode &status)
+ : XeTeXFontInst(pattern, pointSize, status)
+ , face(0)
+ , fFreeTypeOnly(false)
+{
+ if (LE_FAILURE(status)) {
+ return;
+ }
+
+ FT_Error err;
+ if (!gLibrary) {
+ err = FT_Init_FreeType(&gLibrary);
+ if (err != 0) {
+ fprintf(stderr, "FreeType initialization failed! (%d)\n", err);
+ exit(1);
+ }
+ }
+
+ FcChar8* pathname = 0;
+ FcPatternGetString(pattern, FC_FILE, 0, &pathname);
+ int index;
+ FcPatternGetInteger(pattern, FC_INDEX, 0, &index);
+
+ err = FT_New_Face(gLibrary, (char*)pathname, index, &face);
+
+ if (err != 0) {
+ status = LE_FONT_FILE_NOT_FOUND_ERROR;
+ return;
+ }
+
+ initialize(status);
+}
+
+XeTeXFontInst_FC::~XeTeXFontInst_FC()
+{
+ if (face != 0) {
+ FT_Done_Face(face);
+ face = 0;
+ }
+}
+
+void XeTeXFontInst_FC::initialize(LEErrorCode &status)
+{
+ if (face == 0) {
+ status = LE_FONT_FILE_NOT_FOUND_ERROR;
+ return;
+ }
+
+ XeTeXFontInst::initialize(status);
+
+ if (LE_FAILURE(status)) {
+ /* font can ONLY be used via FreeType APIs, not direct table access */
+ fFreeTypeOnly = true;
+ status = LE_NO_ERROR;
+
+ /* fill in fields that XeTeXFontInst::initialize failed to get for us */
+ fUnitsPerEM = face->units_per_EM;
+ fAscent = yUnitsToPoints(face->ascender);
+ fDescent = yUnitsToPoints(face->descender);
+// fLeading = ;
+ fItalicAngle = 0;
+ PS_FontInfoRec font_info;
+ if (FT_Get_PS_Font_Info(face, &font_info) == 0) {
+ // will return error if it wasn't a PS font
+ fItalicAngle = font_info.italic_angle;
+ }
+ }
+
+ return;
+}
+
+const void *XeTeXFontInst_FC::readTable(LETag tag, le_uint32 *length) const
+{
+ *length = 0;
+ FT_ULong tmpLength = 0;
+ FT_Error err = FT_Load_Sfnt_Table(face, tag, 0, NULL, &tmpLength);
+ if (err != 0)
+ return NULL;
+
+ void* table = LE_NEW_ARRAY(char, tmpLength);
+ if (table != NULL) {
+ err = FT_Load_Sfnt_Table(face, tag, 0, (FT_Byte*)table, &tmpLength);
+ if (err != 0) {
+ LE_DELETE_ARRAY(table);
+ return NULL;
+ }
+ *length = tmpLength;
+ }
+
+ return table;
+}
+
+char* XeTeXFontInst_FC::getPSName() const
+{
+ if (face == NULL)
+ return NULL;
+
+ const char* facePSName = FT_Get_Postscript_Name(face);
+ if (facePSName == NULL)
+ return NULL;
+
+ le_uint32 length = strlen(facePSName);
+ char* name = (char*)xmalloc(length + 1);
+ strcpy(name, facePSName);
+
+ return name;
+}
+
+void
+XeTeXFontInst_FC::getGlyphBounds(LEGlyphID gid, GlyphBBox* bbox)
+{
+ bbox->xMin = bbox->yMin = bbox->xMax = bbox->yMax = 0.0;
+
+ FT_Error err = FT_Load_Glyph(face, gid, FT_LOAD_NO_SCALE);
+ if (err != 0)
+ return;
+
+ FT_Glyph glyph;
+ err = FT_Get_Glyph(face->glyph, &glyph);
+ if (err == 0) {
+ FT_BBox ft_bbox;
+ FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_UNSCALED, &ft_bbox);
+ bbox->xMin = ft_bbox.xMin * fPointSize / fUnitsPerEM;
+ bbox->yMin = ft_bbox.yMin * fPointSize / fUnitsPerEM;
+ bbox->xMax = ft_bbox.xMax * fPointSize / fUnitsPerEM;
+ bbox->yMax = ft_bbox.yMax * fPointSize / fUnitsPerEM;
+ FT_Done_Glyph(glyph);
+ }
+}
+
+LEGlyphID
+XeTeXFontInst_FC::mapCharToGlyph(LEUnicode32 ch) const
+{
+ if (!fFreeTypeOnly)
+ return XeTeXFontInst::mapCharToGlyph(ch);
+
+ return FT_Get_Char_Index(face, ch);
+}
+
+le_uint16
+XeTeXFontInst_FC::getNumGlyphs() const
+{
+ return face->num_glyphs;
+}
+
+void
+XeTeXFontInst_FC::getGlyphAdvance(LEGlyphID glyph, LEPoint &advance) const
+{
+ if (!fFreeTypeOnly)
+ XeTeXFontInst::getGlyphAdvance(glyph, advance);
+ else {
+ FT_Error err = FT_Load_Glyph(face, glyph, FT_LOAD_NO_SCALE);
+ if (err != 0) {
+ advance.fX = advance.fY = 0;
+ }
+ else {
+ advance.fX = fVertical ? 0 : face->glyph->metrics.horiAdvance * fPointSize / fUnitsPerEM;
+ advance.fY = fVertical ? face->glyph->metrics.vertAdvance * fPointSize / fUnitsPerEM : 0;
+ }
+ }
+}
+
+LEGlyphID
+XeTeXFontInst_FC::mapGlyphToIndex(const char* glyphName) const
+{
+ LEGlyphID rval = FT_Get_Name_Index(face, const_cast<char*>(glyphName));
+ if (rval == 0)
+ rval = XeTeXFontInst::mapGlyphToIndex(glyphName);
+ return rval;
+}
diff --git a/Build/source/texk/web2c/xetexdir/XeTeXFontInst_FC.h b/Build/source/texk/web2c/xetexdir/XeTeXFontInst_FC.h
new file mode 100644
index 00000000000..fc88f509c13
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/XeTeXFontInst_FC.h
@@ -0,0 +1,76 @@
+/****************************************************************************\
+ 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.
+\****************************************************************************/
+
+/*
+ * file name: XeTeXFontInst_FC.h
+ *
+ * created on: 2005-10-25
+ * created by: Jonathan Kew
+ */
+
+
+#ifndef __XeTeXFontInst_FC_H
+#define __XeTeXFontInst_FC_H
+
+#include "XeTeXFontInst.h"
+
+#include <fontconfig/fontconfig.h>
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+class XeTeXFontInst_FC : public XeTeXFontInst
+{
+protected:
+
+ const void * readTable(LETag tag, le_uint32 *length) const;
+
+ FT_Face face;
+ bool fFreeTypeOnly;
+
+public:
+ XeTeXFontInst_FC(FcPattern* pattern, float pointSize, LEErrorCode &status);
+
+ virtual ~XeTeXFontInst_FC();
+
+ virtual void initialize(LEErrorCode &status);
+
+ virtual char* getPSName() const; // returns a malloced string
+
+ virtual void getGlyphBounds(LEGlyphID gid, GlyphBBox* bbox);
+
+ // overrides of XeTeXFontInst methods, in case it's not an sfnt
+ virtual le_uint16 getNumGlyphs() const;
+ virtual void getGlyphAdvance(LEGlyphID glyph, LEPoint &advance) const;
+ virtual LEGlyphID mapCharToGlyph(LEUnicode32 ch) const;
+ virtual LEGlyphID mapGlyphToIndex(const char* glyphName) const;
+};
+
+#endif
diff --git a/Build/source/texk/web2c/xetexdir/XeTeXFontInst_Mac.cpp b/Build/source/texk/web2c/xetexdir/XeTeXFontInst_Mac.cpp
new file mode 100644
index 00000000000..2fb44248152
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/XeTeXFontInst_Mac.cpp
@@ -0,0 +1,111 @@
+/****************************************************************************\
+ 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.
+\****************************************************************************/
+
+/*
+ * file name: XeTeXFontInst_Mac.cpp
+ *
+ * created on: 2005-10-22
+ * created by: Jonathan Kew
+ */
+
+
+#include "XeTeXFontInst_Mac.h"
+#include "XeTeX_ext.h"
+
+XeTeXFontInst_Mac::XeTeXFontInst_Mac(ATSFontRef atsFont, float pointSize, LEErrorCode &status)
+ : XeTeXFontInst(atsFont, pointSize, status)
+ , fStyle(0)
+{
+ if (LE_FAILURE(status)) {
+ return;
+ }
+
+ initialize(status);
+}
+
+XeTeXFontInst_Mac::~XeTeXFontInst_Mac()
+{
+ if (fStyle != 0)
+ ATSUDisposeStyle(fStyle);
+}
+
+void XeTeXFontInst_Mac::initialize(LEErrorCode &status)
+{
+ if (fFontRef == 0) {
+ status = LE_FONT_FILE_NOT_FOUND_ERROR;
+ return;
+ }
+
+ XeTeXFontInst::initialize(status);
+
+ if (status != LE_NO_ERROR)
+ fFontRef = 0;
+
+ if (ATSUCreateStyle(&fStyle) == noErr) {
+ ATSUFontID font = FMGetFontFromATSFontRef(fFontRef);
+ Fixed size = X2Fix(fPointSize * 72.0 / 72.27); /* convert TeX to Quartz points */
+ ATSStyleRenderingOptions options = kATSStyleNoHinting;
+ ATSUAttributeTag tags[3] = { kATSUFontTag, kATSUSizeTag, kATSUStyleRenderingOptionsTag };
+ ByteCount valueSizes[3] = { sizeof(ATSUFontID), sizeof(Fixed), sizeof(ATSStyleRenderingOptions) };
+ ATSUAttributeValuePtr values[3] = { &font, &size, &options };
+ ATSUSetAttributes(fStyle, 3, tags, valueSizes, values);
+ }
+ else {
+ status = LE_FONT_FILE_NOT_FOUND_ERROR;
+ fFontRef = 0;
+ }
+
+ return;
+}
+
+const void *XeTeXFontInst_Mac::readTable(LETag tag, le_uint32 *length) const
+{
+ OSStatus status = ATSFontGetTable(fFontRef, tag, 0, 0, 0, (ByteCount*)length);
+ if (status != noErr) {
+ *length = 0;
+ return NULL;
+ }
+ void* table = LE_NEW_ARRAY(char, *length);
+ if (table != NULL) {
+ status = ATSFontGetTable(fFontRef, tag, 0, *length, table, (ByteCount*)length);
+ if (status != noErr) {
+ *length = 0;
+ LE_DELETE_ARRAY(table);
+ return NULL;
+ }
+ }
+
+ return table;
+}
+
+void XeTeXFontInst_Mac::getGlyphBounds(LEGlyphID gid, GlyphBBox* bbox)
+{
+ GetGlyphBBox_AAT(fStyle, gid, bbox);
+}
diff --git a/Build/source/texk/web2c/xetexdir/XeTeXFontInst_Mac.h b/Build/source/texk/web2c/xetexdir/XeTeXFontInst_Mac.h
new file mode 100644
index 00000000000..bc3b8831e8b
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/XeTeXFontInst_Mac.h
@@ -0,0 +1,63 @@
+/****************************************************************************\
+ 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.
+\****************************************************************************/
+
+/*
+ * file name: XeTeXFontInst_Mac.h
+ *
+ * created on: 2005-10-22
+ * created by: Jonathan Kew
+ */
+
+
+#ifndef __XeTeXFontInst_Mac_H
+#define __XeTeXFontInst_Mac_H
+
+#include "XeTeXFontInst.h"
+
+#include <ApplicationServices/ApplicationServices.h>
+
+class XeTeXFontInst_Mac : public XeTeXFontInst
+{
+protected:
+ const void *readTable(LETag tag, le_uint32 *length) const;
+
+ ATSUStyle fStyle;
+
+public:
+ XeTeXFontInst_Mac(ATSFontRef atsFont, float pointSize, LEErrorCode &status);
+
+ virtual ~XeTeXFontInst_Mac();
+
+ virtual void initialize(LEErrorCode &status);
+
+ virtual void getGlyphBounds(LEGlyphID gid, GlyphBBox* bbox);
+};
+
+#endif
diff --git a/Build/source/texk/web2c/xetexdir/XeTeXFontMgr.cpp b/Build/source/texk/web2c/xetexdir/XeTeXFontMgr.cpp
new file mode 100644
index 00000000000..e6a3efdbdbb
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/XeTeXFontMgr.cpp
@@ -0,0 +1,621 @@
+/****************************************************************************\
+ 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.
+\****************************************************************************/
+
+#ifdef XETEX_MAC
+#include "XeTeXFontMgr_Mac.h"
+#else
+#include "XeTeXFontMgr_Linux.h"
+#endif
+
+#include "XeTeXLayoutInterface.h"
+#include "XeTeXswap.h"
+
+#include "Features.h"
+#include "GlyphPositioningTables.h"
+
+#include "sfnt.h"
+
+#include <math.h>
+
+XeTeXFontMgr* XeTeXFontMgr::sFontManager = NULL;
+char XeTeXFontMgr::sReqEngine = 0;
+
+/* use our own fmax function because it seems to be missing on certain platforms
+ (solaris2.9, at least) */
+static inline double
+my_fmax(double x, double y)
+{
+ return (x > y) ? x : y;
+}
+
+XeTeXFontMgr*
+XeTeXFontMgr::GetFontManager()
+{
+ if (sFontManager == NULL) {
+#ifdef XETEX_MAC
+ sFontManager = new XeTeXFontMgr_Mac;
+#else
+ sFontManager = new XeTeXFontMgr_Linux;
+#endif
+ sFontManager->initialize();
+ }
+
+ return sFontManager;
+}
+
+void
+XeTeXFontMgr::Terminate()
+{
+ if (sFontManager != NULL) {
+ sFontManager->terminate();
+ // we don't actually deallocate the manager, just ask it to clean up
+ // any auxiliary data such as the cocoa pool or freetype/fontconfig stuff
+ // as we still need to access font names after this is called
+ }
+}
+
+PlatformFontRef
+XeTeXFontMgr::findFont(const char* name, char* variant, double ptSize)
+ // ptSize is in TeX points
+ // "variant" string will be shortened (in-place) by removal of /B and /I if present
+{
+ std::string nameStr(name);
+ Font* font = NULL;
+
+ for (int pass = 0; pass < 2; ++pass) {
+ // try full name as given
+ std::map<std::string,Font*>::iterator i = nameToFont.find(nameStr);
+ if (i != nameToFont.end()) {
+ font = i->second;
+ break;
+ }
+
+ // if there's a hyphen, split there and try Family-Style
+ int hyph = nameStr.find('-');
+ if (hyph > 0 && hyph < nameStr.length() - 1) {
+ std::string family(nameStr.begin(), nameStr.begin() + hyph);
+ std::map<std::string,Family*>::iterator f = nameToFamily.find(family);
+ if (f != nameToFamily.end()) {
+ std::string style(nameStr.begin() + hyph + 1, nameStr.end());
+ i = f->second->styles->find(style);
+ if (i != f->second->styles->end()) {
+ font = i->second;
+ break;
+ }
+ }
+ }
+
+ // try as PostScript name
+ i = psNameToFont.find(nameStr);
+ if (i != psNameToFont.end()) {
+ font = i->second;
+ break;
+ }
+
+ // try for the name as a family name
+ std::map<std::string,Family*>::iterator f = nameToFamily.find(nameStr);
+
+ if (f != nameToFamily.end()) {
+ // look for a family member with the "regular" bit set in OS/2
+ for (i = f->second->styles->begin(); i != f->second->styles->end(); ++i)
+ if (i->second->isReg) {
+ font = i->second;
+ break;
+ }
+
+ if (font == NULL) {
+ // try for style "Regular", "Plain", or "Normal"
+ i = f->second->styles->find("Regular");
+ if (i != f->second->styles->end())
+ font = i->second;
+ else {
+ i = f->second->styles->find("Plain");
+ if (i != f->second->styles->end())
+ font = i->second;
+ else {
+ i = f->second->styles->find("Normal");
+ if (i != f->second->styles->end())
+ font = i->second;
+ }
+ }
+ }
+
+ if (font == NULL) {
+ // look through the family for the (weight, width, slant) nearest to (80, 100, 0)
+ font = bestMatchFromFamily(f->second, 80, 100, 0);
+ }
+
+ if (font != NULL)
+ break;
+ }
+
+ if (pass == 0) {
+ // didn't find it in our caches, so do a platform search (may be relatively expensive);
+ // this will update the caches with any fonts that seem to match the name given,
+ // so that the second pass might find it
+ searchForHostPlatformFonts(nameStr);
+ }
+ }
+
+ if (font == NULL)
+ return 0;
+
+ Family* parent = font->parent;
+
+ // if there are variant requests, try to apply them
+ // and delete B or I codes from the string
+ sReqEngine = 0;
+ bool reqBold = false;
+ bool reqItal = false;
+ if (font != NULL && variant != NULL) {
+ std::string varString;
+ char* cp = variant;
+ while (*cp) {
+ if (strncmp(cp, "AAT", 3) == 0) {
+ sReqEngine = 'A';
+ cp += 3;
+ if (varString.length() > 0 && *(varString.end() - 1) != '/')
+ varString.append("/");
+ varString.append("AAT");
+ goto skip_to_slash;
+ }
+ if (strncmp(cp, "ICU", 3) == 0) {
+ sReqEngine = 'I';
+ cp += 3;
+ if (varString.length() > 0 && *(varString.end() - 1) != '/')
+ varString.append("/");
+ varString.append("ICU");
+ goto skip_to_slash;
+ }
+/*
+ if (strncmp(cp, "USP", 3) == 0) {
+ sReqEngine = 'U';
+ cp += 3;
+ if (varString.length() > 0 && *(varString.end() - 1) != '/')
+ varString.append("/");
+ varString.append("USP");
+ goto skip_to_slash;
+ }
+ if (strncmp(cp, "PAN", 5) == 0) {
+ sReqEngine = 'P';
+ cp += 3;
+ if (varString.length() > 0 && *(varString.end() - 1) != '/')
+ varString.append("/");
+ varString.append("PAN");
+ goto skip_to_slash;
+ }
+ if (strncmp(cp, "GRA", 8) == 0) {
+ sReqEngine = 'G';
+ cp += 3;
+ if (varString.length() > 0 && *(varString.end() - 1) != '/')
+ varString.append("/");
+ varString.append("GRA");
+ goto skip_to_slash;
+ }
+*/
+ if (*cp == 'S') {
+ char* start = cp;
+ ++cp;
+ if (*cp == '=')
+ ++cp;
+ ptSize = 0.0;
+ while (*cp >= '0' && *cp <= '9') {
+ ptSize = ptSize * 10 + *cp - '0';
+ ++cp;
+ }
+ if (*cp == '.') {
+ double dec = 1.0;
+ ++cp;
+ while (*cp >= '0' && *cp <= '9') {
+ dec = dec * 10.0;
+ ptSize = ptSize + (*cp - '0') / dec;
+ ++cp;
+ }
+ }
+ if (varString.length() > 0 && *(varString.end() - 1) != '/')
+ varString.append("/");
+ varString.append(start, cp);
+ goto skip_to_slash;
+ }
+
+ /* if the code is "B" or "I", we skip putting it in varString */
+ while (1) {
+ if (*cp == 'B') {
+ reqBold = true;
+ ++cp;
+ continue;
+ }
+ if (*cp == 'I') {
+ reqItal = true;
+ ++cp;
+ continue;
+ }
+ break;
+ }
+
+ skip_to_slash:
+ while (*cp && *cp != '/')
+ ++cp;
+ if (*cp == '/')
+ ++cp;
+ }
+ strcpy(variant, varString.c_str());
+
+ std::map<std::string,Font*>::iterator i;
+ if (reqItal) {
+ Font* bestMatch = font;
+ if (font->slant < parent->maxSlant)
+ // try for a face with more slant
+ bestMatch = bestMatchFromFamily(parent, font->weight, font->width, parent->maxSlant);
+
+ if (bestMatch == font && font->slant > parent->minSlant)
+ // maybe the slant is negated, or maybe this was something like "Times-Italic/I"
+ bestMatch = bestMatchFromFamily(parent, font->weight, font->width, parent->minSlant);
+
+ if (parent->minWeight == parent->maxWeight && bestMatch->isBold != font->isBold) {
+ // try again using the bold flag, as we can't trust weight values
+ Font* newBest = NULL;
+ for (i = parent->styles->begin(); i != parent->styles->end(); ++i) {
+ if (i->second->isBold == font->isBold) {
+ if (newBest == NULL && i->second->isItalic != font->isItalic) {
+ newBest = i->second;
+ break;
+ }
+ }
+ }
+ if (newBest != NULL)
+ bestMatch = newBest;
+ }
+
+ if (bestMatch == font) {
+ // maybe slant values weren't present; try the style bits as a fallback
+ bestMatch = NULL;
+ for (i = parent->styles->begin(); i != parent->styles->end(); ++i)
+ if (i->second->isItalic == !font->isItalic)
+ if (parent->minWeight != parent->maxWeight) {
+ // weight info was available, so try to match that
+ if (bestMatch == NULL || weightAndWidthDiff(i->second, font) < weightAndWidthDiff(bestMatch, font))
+ bestMatch = i->second;
+ }
+ else {
+ // no weight info, so try matching style bits
+ if (bestMatch == NULL && i->second->isBold == font->isBold) {
+ bestMatch = i->second;
+ break; // found a match, no need to look further as we can't distinguish!
+ }
+ }
+ }
+ if (bestMatch != NULL)
+ font = bestMatch;
+ }
+
+ if (reqBold) {
+ // try for more boldness, with the same width and slant
+ Font* bestMatch = font;
+ if (font->weight < parent->maxWeight) {
+ bestMatch = bestMatchFromFamily(parent, parent->maxWeight, font->width, font->slant);
+ if (parent->minSlant == parent->maxSlant) {
+ // double-check the italic flag, as we can't trust slant values
+ Font* newBest = NULL;
+ for (i = parent->styles->begin(); i != parent->styles->end(); ++i) {
+ if (i->second->isItalic == font->isItalic) {
+ if (newBest == NULL || weightAndWidthDiff(i->second, bestMatch) < weightAndWidthDiff(newBest, bestMatch))
+ newBest = i->second;
+ }
+ }
+ if (newBest != NULL)
+ bestMatch = newBest;
+ }
+ }
+ if (bestMatch == font && !font->isBold) {
+ for (i = parent->styles->begin(); i != parent->styles->end(); ++i) {
+ if (i->second->isItalic == font->isItalic && i->second->isBold) {
+ bestMatch = i->second;
+ break;
+ }
+ }
+ }
+ font = bestMatch;
+ }
+ }
+
+ // if there's optical size info, try to apply it
+ if (font != NULL && font->opSizeInfo.subFamilyID != 0 && ptSize != 0.0) {
+ ptSize = ptSize * 720 / 72.27; // convert TeX points to PS decipoints for comparison with the opSize values
+ double bestMismatch = my_fmax(font->opSizeInfo.minSize - ptSize, ptSize - font->opSizeInfo.maxSize);
+ if (bestMismatch > 0.0) {
+ Font* bestMatch = font;
+ for (std::map<std::string,Font*>::iterator i = parent->styles->begin(); i != parent->styles->end(); ++i) {
+ if (i->second->opSizeInfo.subFamilyID != font->opSizeInfo.subFamilyID)
+ continue;
+ double mismatch = my_fmax(i->second->opSizeInfo.minSize - ptSize, ptSize - i->second->opSizeInfo.maxSize);
+ if (mismatch < bestMismatch) {
+ bestMatch = i->second;
+ bestMismatch = mismatch;
+ }
+ if (bestMismatch <= 0.0)
+ break;
+ }
+ font = bestMatch;
+ }
+ }
+
+ return font->fontRef;
+}
+
+const char*
+XeTeXFontMgr::getPSName(PlatformFontRef font) const
+{
+ std::map<PlatformFontRef,Font*>::const_iterator i = platformRefToFont.find(font);
+ if (i == platformRefToFont.end())
+ die("internal error %d in XeTeXFontMgr", 1);
+ return i->second->psName->c_str();
+}
+
+const char*
+XeTeXFontMgr::getFullName(PlatformFontRef font) const
+{
+ std::map<PlatformFontRef,Font*>::const_iterator i = platformRefToFont.find(font);
+ if (i == platformRefToFont.end())
+ die("internal error %d in XeTeXFontMgr", 2);
+ if (i->second->fullName != NULL)
+ return i->second->fullName->c_str();
+ else
+ return i->second->psName->c_str();
+}
+
+void
+XeTeXFontMgr::getNames(PlatformFontRef font, const char** psName,
+ const char** famName, const char** styName) const
+{
+ std::map<PlatformFontRef,Font*>::const_iterator i = platformRefToFont.find(font);
+ if (i == platformRefToFont.end())
+ die("internal error %d in XeTeXFontMgr", 3);
+ *psName = i->second->psName->c_str();
+ *famName = i->second->familyName->c_str();
+ *styName = i->second->styleName->c_str();
+}
+
+char
+XeTeXFontMgr::getReqEngine() const
+{
+ return sReqEngine;
+}
+
+int
+XeTeXFontMgr::weightAndWidthDiff(const Font* a, const Font* b) const
+{
+ if (a->weight == 0 && a->width == 0) {
+ // assume there was no OS/2 info
+ if (a->isBold == b->isBold)
+ return 0;
+ else
+ return 10000;
+ }
+
+ int widDiff = labs(a->width - b->width);
+ if (widDiff < 10)
+ widDiff *= 50;
+
+ return labs(a->weight - b->weight) + widDiff;
+}
+
+int
+XeTeXFontMgr::styleDiff(const Font* a, int wt, int wd, int slant) const
+{
+ int widDiff = labs(a->width - wd);
+ if (widDiff < 10)
+ widDiff *= 200;
+
+ return labs(labs(a->slant) - labs(slant)) * 2 + labs(a->weight - wt) + widDiff;
+}
+
+XeTeXFontMgr::Font*
+XeTeXFontMgr::bestMatchFromFamily(const Family* fam, int wt, int wd, int slant) const
+{
+ Font* bestMatch = NULL;
+ for (std::map<std::string,Font*>::iterator s = fam->styles->begin(); s != fam->styles->end(); ++s)
+ if (bestMatch == NULL || styleDiff(s->second, wt, wd, slant) < styleDiff(bestMatch, wt, wd, slant))
+ bestMatch = s->second;
+ return bestMatch;
+}
+
+void
+XeTeXFontMgr::getOpSizeRecAndStyleFlags(Font* theFont)
+{
+ XeTeXFont font = createFont(theFont->fontRef, 655360);
+ if (font != 0) {
+ const GlyphPositioningTableHeader* gposTable = (const GlyphPositioningTableHeader*)getFontTablePtr(font, LE_GPOS_TABLE_TAG);
+ if (gposTable != NULL) {
+ FeatureListTable* featureListTable = (FeatureListTable*)((char*)gposTable + SWAP(gposTable->featureListOffset));
+ for (int i = 0; i < SWAP(featureListTable->featureCount); ++i) {
+ UInt32 tag = SWAPT(featureListTable->featureRecordArray[i].featureTag);
+ if (tag == LE_SIZE_FEATURE_TAG) {
+ FeatureTable* feature = (FeatureTable*)((char*)featureListTable + SWAP(featureListTable->featureRecordArray[i].featureTableOffset));
+ OpSizeRec* pSizeRec = (OpSizeRec*)((char*)featureListTable + SWAP(feature->featureParamsOffset));
+ theFont->opSizeInfo.designSize = SWAP(pSizeRec->designSize);
+ theFont->opSizeInfo.subFamilyID = SWAP(pSizeRec->subFamilyID);
+ theFont->opSizeInfo.nameCode = SWAP(pSizeRec->nameCode);
+ theFont->opSizeInfo.minSize = SWAP(pSizeRec->minSize);
+ theFont->opSizeInfo.maxSize = SWAP(pSizeRec->maxSize);
+ break;
+ }
+ }
+ }
+
+ const OS2TableHeader* os2Table = (const OS2TableHeader*)getFontTablePtr(font, LE_OS_2_TABLE_TAG);
+ if (os2Table != NULL) {
+ theFont->weight = SWAP(os2Table->usWeightClass);
+ theFont->width = SWAP(os2Table->usWidthClass);
+ UInt16 sel = SWAP(os2Table->fsSelection);
+ theFont->isReg = (sel & (1 << 6)) != 0;
+ theFont->isBold = (sel & (1 << 5)) != 0;
+ theFont->isItalic = (sel & (1 << 0)) != 0;
+ }
+
+ const HEADTable* headTable = (const HEADTable*)getFontTablePtr(font, LE_HEAD_TABLE_TAG);
+ if (headTable != NULL) {
+ UInt16 ms = SWAP(headTable->macStyle);
+ if ((ms & (1 << 0)) != 0)
+ theFont->isBold = true;
+ if ((ms & (1 << 1)) != 0)
+ theFont->isItalic = true;
+ }
+
+ const POSTTable* postTable = (const POSTTable*)getFontTablePtr(font, LE_POST_TABLE_TAG);
+ if (postTable != NULL) {
+ theFont->slant = (int)(1000 * (tan(Fix2X(-SWAP(postTable->italicAngle)) * M_PI / 180.0)));
+ }
+ deleteFont(font);
+ }
+}
+
+// append a name but only if it's not already in the list
+void
+XeTeXFontMgr::appendToList(std::list<std::string>* list, const char* str)
+{
+ for (std::list<std::string>::const_iterator i = list->begin(); i != list->end(); ++i)
+ if (*i == str)
+ return;
+ list->push_back(str);
+}
+
+// prepend a name, removing it from later in the list if present
+void
+XeTeXFontMgr::prependToList(std::list<std::string>* list, const char* str)
+{
+ for (std::list<std::string>::iterator i = list->begin(); i != list->end(); ++i)
+ if (*i == str) {
+ list->erase(i);
+ break;
+ }
+ list->push_front(str);
+}
+
+void
+XeTeXFontMgr::addToMaps(PlatformFontRef platformFont, const NameCollection* names)
+{
+ if (names->psName.length() == 0)
+ return; // can't use a font that lacks a PostScript name
+
+ if (psNameToFont.find(names->psName) != psNameToFont.end())
+ return; // duplicates an earlier PS name, so skip
+
+ Font* thisFont = new Font(platformFont);
+ thisFont->psName = new std::string(names->psName);
+ getOpSizeRecAndStyleFlags(thisFont);
+
+ psNameToFont[names->psName] = thisFont;
+ platformRefToFont[platformFont] = thisFont;
+
+ if (names->fullNames.size() > 0)
+ thisFont->fullName = new std::string(*(names->fullNames.begin()));
+
+ if (names->familyNames.size() > 0)
+ thisFont->familyName = new std::string(*(names->familyNames.begin()));
+ else
+ thisFont->familyName = new std::string(names->psName);
+
+ if (names->styleNames.size() > 0)
+ thisFont->styleName = new std::string(*(names->styleNames.begin()));
+ else
+ thisFont->styleName = new std::string;
+
+ std::list<std::string>::const_iterator i;
+ for (i = names->familyNames.begin(); i != names->familyNames.end(); ++i) {
+ std::map<std::string,Family*>::iterator iFam = nameToFamily.find(*i);
+ Family* family;
+ if (iFam == nameToFamily.end()) {
+ family = new Family;
+ nameToFamily[*i] = family;
+ family->minWeight = thisFont->weight;
+ family->maxWeight = thisFont->weight;
+ family->minWidth = thisFont->width;
+ family->maxWidth = thisFont->width;
+ family->minSlant = thisFont->slant;
+ family->maxSlant = thisFont->slant;
+ }
+ else {
+ family = iFam->second;
+ if (thisFont->weight < family->minWeight)
+ family->minWeight = thisFont->weight;
+ if (thisFont->weight > family->maxWeight)
+ family->maxWeight = thisFont->weight;
+ if (thisFont->width < family->minWidth)
+ family->minWidth = thisFont->width;
+ if (thisFont->width > family->maxWidth)
+ family->maxWidth = thisFont->width;
+ if (thisFont->slant < family->minSlant)
+ family->minSlant = thisFont->slant;
+ if (thisFont->slant > family->maxSlant)
+ family->maxSlant = thisFont->slant;
+ }
+
+ if (thisFont->parent == NULL)
+ thisFont->parent = family;
+
+ // ensure all style names in the family point to thisFont
+ for (std::list<std::string>::const_iterator j = names->styleNames.begin(); j != names->styleNames.end(); ++j) {
+ std::map<std::string,Font*>::iterator iFont = family->styles->find(*j);
+ if (iFont == family->styles->end())
+ (*family->styles)[*j] = thisFont;
+/*
+ else if (iFont->second != thisFont)
+ fprintf(stderr, "# Font name warning: ambiguous Style \"%s\" in Family \"%s\" (PSNames \"%s\" and \"%s\")\n",
+ j->c_str(), i->c_str(), iFont->second->psName->c_str(), thisFont->psName->c_str());
+*/
+ }
+ }
+
+ for (i = names->fullNames.begin(); i != names->fullNames.end(); ++i) {
+ std::map<std::string,Font*>::iterator iFont = nameToFont.find(*i);
+ if (iFont == nameToFont.end())
+ nameToFont[*i] = thisFont;
+/*
+ else if (iFont->second != thisFont)
+ fprintf(stderr, "# Font name warning: ambiguous FullName \"%s\" (PSNames \"%s\" and \"%s\")\n",
+ i->c_str(), iFont->second->psName->c_str(), thisFont->psName->c_str());
+*/
+ }
+}
+
+void
+XeTeXFontMgr::die(const char*s, int i) const
+{
+ fprintf(stderr, s, i);
+ fprintf(stderr, " - exiting\n");
+ exit(3);
+}
+
+void
+XeTeXFontMgr::terminate()
+{
+}
+
diff --git a/Build/source/texk/web2c/xetexdir/XeTeXFontMgr.h b/Build/source/texk/web2c/xetexdir/XeTeXFontMgr.h
new file mode 100644
index 00000000000..4a540fc644a
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/XeTeXFontMgr.h
@@ -0,0 +1,202 @@
+/****************************************************************************\
+ 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.
+\****************************************************************************/
+
+#ifndef __XETEX_FONT_MANAGER_H
+#define __XETEX_FONT_MANAGER_H
+
+#include "XeTeX_ext.h"
+
+#ifdef XETEX_MAC
+#include <Carbon/Carbon.h>
+typedef ATSFontRef PlatformFontRef;
+#else
+#include <fontconfig/fontconfig.h>
+#include <ft2build.h>
+#include FT_FREETYPE_H
+typedef FcPattern* PlatformFontRef;
+#endif
+
+#ifdef __cplusplus /* allow inclusion in plain C files just to get the typedefs above */
+
+#include <string>
+#include <map>
+#include <list>
+#include <vector>
+
+class XeTeXFontMgr
+{
+public:
+ static XeTeXFontMgr* GetFontManager();
+ // returns the global fontmanager (creating it if necessary)
+ static void Terminate();
+ // clean up (may be required if using the cocoa implementation)
+
+ PlatformFontRef findFont(const char* name, char* variant, double ptSize);
+ // 1st arg is name as specified by user (C string, UTF-8)
+ // 2nd is /B/I/AAT/ICU[/USP]/S=## qualifiers
+ // 1. try name given as "full name"
+ // 2. if there's a hyphen, split and try "family-style"
+ // 3. try as PostScript name
+ // 4. try name as family with "Regular/Plain/Normal" style
+ // apply style qualifiers and optical sizing if present
+
+ // SIDE EFFECT: sets sReqEngine to 'A' or 'I' [or 'U'] if appropriate,
+ // else clears it to 0
+
+ // SIDE EFFECT: updates TeX variables /nameoffile/ and /namelength/,
+ // to match the actual font found
+
+ // SIDE EFFECT: edits /variant/ string in-place removing /B or /I
+
+ const char* getPSName(PlatformFontRef font) const;
+ // return PostScript name of a font, suitable for use in the .xdv file
+
+ const char* getFullName(PlatformFontRef font) const;
+ // return the full name of the font, suitable for use in XeTeX source
+ // without requiring style qualifiers
+
+ void getNames(PlatformFontRef font, const char** psName,
+ const char** famName, const char** styName) const;
+ // return Postscript, family, and style names, for use in .xdv
+
+
+ char getReqEngine() const;
+ // return the requested rendering technology for the most recent findFont
+ // or 0 if no specific technology was requested
+
+protected:
+ static XeTeXFontMgr* sFontManager;
+ static char sReqEngine;
+
+ XeTeXFontMgr()
+ { }
+ virtual ~XeTeXFontMgr()
+ { }
+
+ virtual void initialize() = 0;
+ virtual void terminate();
+
+ class Font;
+ class Family;
+
+ struct OpSizeRec {
+ unsigned short designSize;
+ unsigned short subFamilyID;
+ unsigned short nameCode;
+ unsigned short minSize;
+ unsigned short maxSize;
+ };
+
+ class Font {
+ public:
+ Font(PlatformFontRef ref)
+ : fullName(NULL), psName(NULL), familyName(NULL), styleName(NULL)
+ , parent(NULL)
+ , fontRef(ref), weight(0), width(0), slant(0)
+ , isReg(false), isBold(false), isItalic(false)
+ { opSizeInfo.subFamilyID = 0; }
+ ~Font()
+ { delete fullName; delete psName; }
+
+ std::string* fullName;
+ std::string* psName;
+ std::string* familyName; // default family and style names that should locate this font
+ std::string* styleName;
+ Family* parent;
+ PlatformFontRef fontRef;
+ OpSizeRec opSizeInfo;
+ UInt16 weight;
+ UInt16 width;
+ SInt16 slant;
+ bool isReg;
+ bool isBold;
+ bool isItalic;
+ };
+
+ class Family {
+ public:
+ Family()
+ : minWeight(0), maxWeight(0)
+ , minWidth(0), maxWidth(0)
+ , minSlant(0), maxSlant(0)
+ {
+ styles = new std::map<std::string,Font*>;
+ }
+ ~Family()
+ {
+ delete styles;
+ }
+
+ std::map<std::string,Font*>* styles;
+ UInt16 minWeight;
+ UInt16 maxWeight;
+ UInt16 minWidth;
+ UInt16 maxWidth;
+ SInt16 minSlant;
+ SInt16 maxSlant;
+ };
+
+ class NameCollection {
+ public:
+ std::list<std::string> familyNames;
+ std::list<std::string> styleNames;
+ std::list<std::string> fullNames;
+ std::string psName;
+ std::string subFamily;
+ };
+
+ std::map<std::string,Font*> nameToFont; // maps full name (as used in TeX source) to font record
+ std::map<std::string,Family*> nameToFamily;
+ std::map<PlatformFontRef,Font*> platformRefToFont;
+ std::map<std::string,Font*> psNameToFont; // maps PS name (as used in .xdv) to font record
+
+ int weightAndWidthDiff(const Font* a, const Font* b) const;
+ int styleDiff(const Font* a, int wt, int wd, int slant) const;
+ Font* bestMatchFromFamily(const Family* fam, int wt, int wd, int slant) const;
+ void appendToList(std::list<std::string>* list, const char* str);
+ void prependToList(std::list<std::string>* list, const char* str);
+ void addToMaps(PlatformFontRef platformFont, const NameCollection* names);
+
+ virtual void getOpSizeRecAndStyleFlags(Font* theFont);
+ virtual void searchForHostPlatformFonts(const std::string& name) = 0;
+
+#ifdef XETEX_MAC
+ virtual NameCollection* readNames(ATSUFontID fontID) = 0;
+#else
+ virtual NameCollection* readNames(PlatformFontRef fontRef) = 0;
+#endif
+
+ void die(const char*s, int i) const; /* for fatal internal errors! */
+};
+
+#endif /* __cplusplus */
+
+
+#endif /* __XETEX_FONT_MANAGER_H */
diff --git a/Build/source/texk/web2c/xetexdir/XeTeXFontMgr_Linux.cpp b/Build/source/texk/web2c/xetexdir/XeTeXFontMgr_Linux.cpp
new file mode 100644
index 00000000000..c10fc81f985
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/XeTeXFontMgr_Linux.cpp
@@ -0,0 +1,317 @@
+/****************************************************************************\
+ 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.
+\****************************************************************************/
+
+#include "XeTeXFontMgr_Linux.h"
+
+#include FT_SFNT_NAMES_H
+#include FT_TRUETYPE_IDS_H
+
+#include "unicode/ucnv.h"
+
+#define kFontFamilyName 1
+#define kFontStyleName 2
+#define kFontFullName 4
+#define kPreferredFamilyName 16
+#define kPreferredSubfamilyName 17
+
+static UConverter* macRomanConv = NULL;
+static UConverter* utf16beConv = NULL;
+static UConverter* utf8Conv = NULL;
+
+static char*
+convertToUtf8(UConverter* conv, const unsigned char* name, int len)
+{
+static char* buffer1 = NULL;
+static char* buffer2 = NULL;
+static int bufSize = -1;
+
+ if (2 * (len + 1) > bufSize) {
+ if (buffer1 != NULL) {
+ delete[] buffer1;
+ delete[] buffer2;
+ }
+ bufSize = 2 * len + 100;
+ buffer1 = new char[bufSize];
+ buffer2 = new char[bufSize];
+ }
+
+ UErrorCode status = U_ZERO_ERROR;
+ len = ucnv_toUChars(conv, (UChar*)buffer1, bufSize, (const char*)name, len, &status);
+ len = ucnv_fromUChars(utf8Conv, buffer2, bufSize, (UChar*)buffer1, len, &status);
+ buffer2[len] = 0;
+
+ return buffer2;
+}
+
+XeTeXFontMgr::NameCollection*
+XeTeXFontMgr_Linux::readNames(FcPattern* pat)
+{
+ NameCollection* names = new NameCollection;
+
+ char* pathname;
+ if (FcPatternGetString(pat, FC_FILE, 0, (FcChar8**)&pathname) == FcTrue)
+ return names;
+ int index;
+ if (FcPatternGetInteger(pat, FC_INDEX, 0, &index) == FcTrue)
+ return names;
+
+ FT_Face face;
+ if (FT_New_Face(ftLib, pathname, index, &face) != 0)
+ return names;
+
+ const char* name = FT_Get_Postscript_Name(face);
+ if (name == NULL)
+ return names;
+ names->psName = name;
+
+ // for sfnt containers, we'll read the name table ourselves, not rely on Fontconfig
+ if (FT_IS_SFNT(face)) {
+ std::list<std::string> familyNames;
+ std::list<std::string> subFamilyNames;
+ FT_SfntName nameRec;
+ for (index = 0; index < FT_Get_Sfnt_Name_Count(face); ++index) {
+ char* utf8name = NULL;
+ if (FT_Get_Sfnt_Name(face, index, &nameRec) != 0)
+ continue;
+ switch (nameRec.name_id) {
+ case kFontFullName:
+ case kFontFamilyName:
+ case kFontStyleName:
+ case kPreferredFamilyName:
+ case kPreferredSubfamilyName:
+ {
+ bool preferredName = false;
+ if (nameRec.platform_id == TT_PLATFORM_MACINTOSH
+ && nameRec.encoding_id == TT_MAC_ID_ROMAN && nameRec.language_id == 0) {
+ utf8name = convertToUtf8(macRomanConv, nameRec.string, nameRec.string_len);
+ preferredName = true;
+ }
+ else if ((nameRec.platform_id == TT_PLATFORM_APPLE_UNICODE)
+ || (nameRec.platform_id == TT_PLATFORM_MICROSOFT))
+ utf8name = convertToUtf8(utf16beConv, nameRec.string, nameRec.string_len);
+
+ if (utf8name != NULL) {
+ std::list<std::string>* nameList = NULL;
+ switch (nameRec.name_id) {
+ case kFontFullName:
+ nameList = &names->fullNames;
+ break;
+ case kFontFamilyName:
+ nameList = &names->familyNames;
+ break;
+ case kFontStyleName:
+ nameList = &names->styleNames;
+ break;
+ case kPreferredFamilyName:
+ nameList = &familyNames;
+ break;
+ case kPreferredSubfamilyName:
+ nameList = &subFamilyNames;
+ break;
+ }
+ if (preferredName)
+ prependToList(nameList, utf8name);
+ else
+ appendToList(nameList, utf8name);
+ }
+ }
+ break;
+ }
+ }
+ if (familyNames.size() > 0)
+ names->familyNames = familyNames;
+ if (subFamilyNames.size() > 0)
+ names->styleNames = subFamilyNames;
+ }
+ else {
+ index = 0;
+ while (FcPatternGetString(pat, FC_FULLNAME, index++, (FcChar8**)&name) == FcFalse)
+ appendToList(&names->fullNames, name);
+ index = 0;
+ while (FcPatternGetString(pat, FC_FAMILY, index++, (FcChar8**)&name) == FcFalse)
+ appendToList(&names->familyNames, name);
+ index = 0;
+ while (FcPatternGetString(pat, FC_STYLE, index++, (FcChar8**)&name) == FcFalse)
+ appendToList(&names->styleNames, name);
+
+ if (names->fullNames.size() == 0) {
+ std::string fullName(names->familyNames.front());
+ if (names->styleNames.size() > 0) {
+ fullName += " ";
+ fullName += names->styleNames.front();
+ }
+ names->fullNames.push_back(fullName);
+ }
+ }
+
+ FT_Done_Face(face);
+
+ return names;
+}
+
+void
+XeTeXFontMgr_Linux::getOpSizeRecAndStyleFlags(Font* theFont)
+{
+ XeTeXFontMgr::getOpSizeRecAndStyleFlags(theFont);
+
+ if (theFont->weight == 0 && theFont->width == 0) {
+ // try to get values from FontConfig, as it apparently wasn't an sfnt
+ FcPattern* pat = theFont->fontRef;
+ int value;
+ if (FcPatternGetInteger(pat, FC_WEIGHT, 0, &value) == FcFalse)
+ theFont->weight = value;
+ if (FcPatternGetInteger(pat, FC_WIDTH, 0, &value) == FcFalse)
+ theFont->width = value;
+ if (FcPatternGetInteger(pat, FC_SLANT, 0, &value) == FcFalse)
+ theFont->slant = value;
+ }
+}
+
+void
+XeTeXFontMgr_Linux::searchForHostPlatformFonts(const std::string& name)
+{
+ static bool cacheAll = false;
+ static FcFontSet* allFonts = NULL;
+
+ if (cacheAll) // we've already loaded everything on an earlier search
+ return;
+
+ if (allFonts == NULL) {
+ FcPattern* pat = FcNameParse((const FcChar8*)":outline=true");
+ FcObjectSet* os = FcObjectSetBuild(FC_FAMILY, FC_STYLE, FC_FILE, FC_INDEX,
+ FC_FULLNAME, FC_WEIGHT, FC_WIDTH, FC_SLANT, NULL);
+
+ allFonts = FcFontList(FcConfigGetCurrent(), pat, os);
+
+ FcObjectSetDestroy(os);
+ FcPatternDestroy(pat);
+ }
+
+ std::string famName;
+ int hyph = name.find('-');
+ if (hyph > 0 && hyph < name.length() - 1)
+ famName.assign(name.begin(), name.begin() + hyph);
+ else
+ hyph = 0;
+
+ bool found = false;
+ while (1) {
+ for (int f = 0; f < allFonts->nfont; ++f) {
+ restart:
+ FcPattern* pat = allFonts->fonts[f];
+ if (platformRefToFont.find(pat) != platformRefToFont.end())
+ continue;
+
+ if (cacheAll) {
+ // failed to find it via FC; add everything to our maps (potentially slow) as a last resort
+ NameCollection* names = readNames(pat);
+ addToMaps(pat, names);
+ delete names;
+ continue;
+ }
+
+ char* s;
+ int i;
+ for (i = 0; FcPatternGetString(pat, FC_FULLNAME, i, (FcChar8**)&s) == FcFalse; ++i) {
+ if (name == s) {
+ NameCollection* names = readNames(pat);
+ addToMaps(pat, names);
+ delete names;
+ found = true;
+ goto next_font;
+ }
+ }
+
+ for (i = 0; FcPatternGetString(pat, FC_FAMILY, i, (FcChar8**)&s) == FcFalse; ++i) {
+ if (name == s || (hyph && famName == s)) {
+ NameCollection* names = readNames(pat);
+ addToMaps(pat, names);
+ delete names;
+ found = true;
+ goto next_font;
+ }
+ char* t;
+ for (int j = 0; FcPatternGetString(pat, FC_STYLE, j, (FcChar8**)&t) == FcFalse; ++j) {
+ std::string full(s);
+ full += " ";
+ full += t;
+ if (name == full) {
+ // need to ensure we'll pick up the whole family
+ famName = s;
+ hyph = 1;
+ f = 0;
+ goto restart;
+ }
+ }
+ }
+
+ next_font:
+ ;
+ }
+
+ if (found || cacheAll)
+ break;
+ cacheAll = true;
+ }
+}
+
+void
+XeTeXFontMgr_Linux::initialize()
+{
+ if (FcInit() == FcFalse) {
+ fprintf(stderr, "fontconfig initialization failed!\n");
+ exit(9);
+ }
+
+ if (FT_Init_FreeType(&ftLib) != 0) {
+ fprintf(stderr, "FreeType initialization failed!\n");
+ exit(9);
+ }
+
+ UErrorCode err = U_ZERO_ERROR;
+ macRomanConv = ucnv_open("macintosh", &err);
+ utf16beConv = ucnv_open("UTF16BE", &err);
+ utf8Conv = ucnv_open("UTF8", &err);
+ if (err != 0) {
+ fprintf(stderr, "internal error; cannot read font names\n");
+ exit(3);
+ }
+}
+
+void
+XeTeXFontMgr_Linux::terminate()
+{
+ if (macRomanConv != NULL)
+ ucnv_close(macRomanConv);
+ if (utf16beConv != NULL)
+ ucnv_close(utf16beConv);
+ if (utf8Conv != NULL)
+ ucnv_close(utf8Conv);
+}
diff --git a/Build/source/texk/web2c/xetexdir/XeTeXFontMgr_Linux.h b/Build/source/texk/web2c/xetexdir/XeTeXFontMgr_Linux.h
new file mode 100644
index 00000000000..bea40c3deea
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/XeTeXFontMgr_Linux.h
@@ -0,0 +1,59 @@
+/****************************************************************************\
+ 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.
+\****************************************************************************/
+
+#ifndef __XETEX_FONT_MGR_LINUX_H
+#define __XETEX_FONT_MGR_LINUX_H
+
+#include "XeTeXFontMgr.h"
+
+class XeTeXFontMgr_Linux
+ : public XeTeXFontMgr
+{
+public:
+ XeTeXFontMgr_Linux()
+ { }
+ virtual ~XeTeXFontMgr_Linux()
+ { }
+
+protected:
+
+ virtual void initialize();
+ virtual void terminate();
+
+ virtual void getOpSizeRecAndStyleFlags(Font* theFont);
+ virtual void searchForHostPlatformFonts(const std::string& name);
+
+ virtual NameCollection* readNames(FcPattern* pat);
+
+private:
+ FT_Library ftLib;
+};
+
+#endif /* __XETEX_FONT_MGR_LINUX_H */
diff --git a/Build/source/texk/web2c/xetexdir/XeTeXFontMgr_Mac.h b/Build/source/texk/web2c/xetexdir/XeTeXFontMgr_Mac.h
new file mode 100644
index 00000000000..e889d62102d
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/XeTeXFontMgr_Mac.h
@@ -0,0 +1,64 @@
+/****************************************************************************\
+ 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.
+\****************************************************************************/
+
+#ifndef __XETEX_FONT_MGR_MAC_H
+#define __XETEX_FONT_MGR_MAC_H
+
+#include "XeTeXFontMgr.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+
+class XeTeXFontMgr_Mac
+ : public XeTeXFontMgr
+{
+public:
+ XeTeXFontMgr_Mac()
+ { }
+ virtual ~XeTeXFontMgr_Mac()
+ { }
+
+protected:
+
+ virtual void initialize();
+ virtual void terminate();
+
+ virtual void searchForHostPlatformFonts(const std::string& name);
+
+ virtual NameCollection* readNames(ATSUFontID fontID);
+
+private:
+ void addFontsToCaches(CFArrayRef fonts);
+
+ void addFamilyToCaches(ATSFontFamilyRef familyRef);
+
+ void addFontAndSiblingsToCaches(ATSFontRef fontRef);
+};
+
+#endif /* __XETEX_FONT_MGR_MAC_H */
diff --git a/Build/source/texk/web2c/xetexdir/XeTeXFontMgr_Mac.mm b/Build/source/texk/web2c/xetexdir/XeTeXFontMgr_Mac.mm
new file mode 100644
index 00000000000..c7c7652a10c
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/XeTeXFontMgr_Mac.mm
@@ -0,0 +1,280 @@
+/****************************************************************************\
+ 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.
+\****************************************************************************/
+
+#ifdef XETEX_MAC // this file only for Mac OS X
+
+#include "XeTeXFontMgr_Mac.h"
+
+#include <Cocoa/Cocoa.h>
+
+XeTeXFontMgr::NameCollection*
+XeTeXFontMgr_Mac::readNames(ATSFontRef fontRef)
+{
+ const int BUFUNIT = 256;
+ static int bufSize = BUFUNIT;
+ static char* buffer = new char[bufSize];
+
+ NameCollection* names = new NameCollection;
+
+ CFStringRef psName;
+ OSStatus status = ATSFontGetPostScriptName(fontRef, kATSOptionFlagsDefault, &psName);
+ if (status != noErr)
+ return names;
+
+ // extract UTF-8 form of name
+ CFIndex length = CFStringGetLength(psName); // in 16-bit character units
+ if (length > 0) {
+ length = length * 6 + 1;
+ if (length >= bufSize) {
+ delete[] buffer;
+ bufSize = ((length / BUFUNIT) + 1) * BUFUNIT;
+ buffer = new char[bufSize];
+ }
+ if (CFStringGetCString(psName, buffer, bufSize, kCFStringEncodingUTF8))
+ names->psName = buffer;
+ }
+ CFRelease(psName);
+
+ ATSUFontID fontID = FMGetFontFromATSFontRef(fontRef);
+
+ ItemCount nameCount;
+ status = ATSUCountFontNames(fontID, &nameCount);
+ if (status != noErr)
+ die("ATSUCountFontNames failed, status=%d", status);
+
+ std::list<std::string> familyNames;
+ std::list<std::string> subFamilyNames;
+
+ for (int n = 0; n < nameCount; ++n) {
+ ByteCount nameLength;
+ FontNameCode nameCode;
+ FontPlatformCode namePlatform;
+ FontScriptCode nameScript;
+ FontLanguageCode nameLang;
+ status = ATSUGetIndFontName(fontID, n, 0, 0, &nameLength,
+ &nameCode, &namePlatform, &nameScript, &nameLang);
+ if (status != noErr && status != kATSUNoFontNameErr)
+ die("ATSUGetIndFontName failed, status=%d", status);
+ if (status == noErr && nameLength > 0) {
+ switch (nameCode) {
+ case kFontFullName:
+ case kFontFamilyName:
+ case kFontStyleName:
+ case 16: // preferred family -- use instead of family, if present
+ case 17: // preferred subfamily -- use instead of style, if present
+ {
+ bool preferredName = false;
+ TextEncoding encoding;
+ CFStringRef nameStr = 0;
+ if (nameLength >= bufSize) {
+ delete[] buffer;
+ bufSize = ((nameLength / BUFUNIT) + 1) * BUFUNIT;
+ buffer = new char[bufSize];
+ }
+ status = ATSUGetIndFontName(fontID, n, bufSize, buffer, &nameLength,
+ &nameCode, &namePlatform, &nameScript, &nameLang);
+ if (namePlatform == kFontMacintoshPlatform) {
+ GetTextEncodingFromScriptInfo(nameScript, nameLang, 0, &encoding);
+ nameStr = CFStringCreateWithBytes(0, (UInt8*)buffer, nameLength, encoding, false);
+ if (nameScript == kFontRomanScript && nameLang == kFontEnglishLanguage)
+ preferredName = true;
+ }
+ else if ((namePlatform == kFontUnicodePlatform) || (namePlatform == kFontMicrosoftPlatform))
+ nameStr = CFStringCreateWithCharacters(0, (UniChar*)buffer, nameLength / 2);
+ if (nameStr != 0) {
+ std::list<std::string>* nameList = NULL;
+ switch (nameCode) {
+ case kFontFullName:
+ nameList = &names->fullNames;
+ break;
+ case kFontFamilyName:
+ nameList = &names->familyNames;
+ break;
+ case kFontStyleName:
+ nameList = &names->styleNames;
+ break;
+ case 16:
+ nameList = &familyNames;
+ break;
+ case 17:
+ nameList = &subFamilyNames;
+ break;
+ }
+
+ // extract UTF-8 form of name
+ length = CFStringGetLength(nameStr); // in 16-bit character units
+ if (length > 0) {
+ length = length * 6 + 1;
+ if (length >= bufSize) {
+ delete[] buffer;
+ bufSize = ((length / BUFUNIT) + 1) * BUFUNIT;
+ buffer = new char[bufSize];
+ }
+ if (CFStringGetCString(nameStr, buffer, bufSize, kCFStringEncodingUTF8)) {
+ if (buffer[0] != 0) {
+ if (nameList != NULL) {
+ if (preferredName)
+ prependToList(nameList, buffer);
+ else
+ appendToList(nameList, buffer);
+ }
+ }
+ }
+ }
+
+ CFRelease(nameStr);
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ if (familyNames.size() > 0)
+ names->familyNames = familyNames;
+ if (subFamilyNames.size() > 0)
+ names->styleNames = subFamilyNames;
+
+ return names;
+}
+
+void
+XeTeXFontMgr_Mac::addFontsToCaches(CFArrayRef fonts)
+{
+ NSEnumerator* enumerator = [(NSArray*)fonts objectEnumerator];
+ while (id aFont = [enumerator nextObject]) {
+ ATSFontRef fontRef = ATSFontFindFromPostScriptName((CFStringRef)[aFont objectAtIndex: 0], kATSOptionFlagsDefault);
+ NameCollection* names = readNames(fontRef);
+ addToMaps(fontRef, names);
+ delete names;
+ }
+}
+
+void
+XeTeXFontMgr_Mac::addFamilyToCaches(ATSFontFamilyRef familyRef)
+{
+ CFStringRef nameStr;
+ OSStatus status = ATSFontFamilyGetName(familyRef, kATSOptionFlagsDefault, &nameStr);
+ if (status == noErr) {
+ NSArray* members = [[NSFontManager sharedFontManager]
+ availableMembersOfFontFamily: (NSString*)nameStr];
+ CFRelease(nameStr);
+ addFontsToCaches((CFArrayRef)members);
+ }
+}
+
+void
+XeTeXFontMgr_Mac::addFontAndSiblingsToCaches(ATSFontRef fontRef)
+{
+ CFStringRef name;
+ OSStatus status = ATSFontGetPostScriptName(fontRef, kATSOptionFlagsDefault, &name);
+ if (status == noErr) {
+ NSFont* font = [NSFont fontWithName:(NSString*)name size:10.0];
+ CFRelease(name);
+ NSArray* members = [[NSFontManager sharedFontManager]
+ availableMembersOfFontFamily: [font familyName]];
+ addFontsToCaches((CFArrayRef)members);
+ }
+}
+
+void
+XeTeXFontMgr_Mac::searchForHostPlatformFonts(const std::string& name)
+{
+ // the name might be:
+ // FullName
+ // Family-Style (if there's a hyphen)
+ // PSName
+ // Family
+ // ...so we need to try it as each of these
+
+ CFStringRef nameStr = CFStringCreateWithCString(kCFAllocatorDefault, name.c_str(), kCFStringEncodingUTF8);
+ ATSFontRef fontRef = ATSFontFindFromName(nameStr, kATSOptionFlagsDefault);
+ if (fontRef != kATSFontRefUnspecified) {
+ // found it, so locate the family, and add all members to the caches
+ addFontAndSiblingsToCaches(fontRef);
+ return;
+ }
+
+ int hyph = name.find('-');
+ if (hyph > 0 && hyph < name.length() - 1) {
+ std::string family(name.begin(), name.begin() + hyph);
+ CFStringRef familyStr = CFStringCreateWithCString(kCFAllocatorDefault, family.c_str(), kCFStringEncodingUTF8);
+
+ NSArray* familyMembers = [[NSFontManager sharedFontManager]
+ availableMembersOfFontFamily: (NSString*)familyStr];
+ if ([familyMembers count] > 0) {
+ addFontsToCaches((CFArrayRef)familyMembers);
+ return;
+ }
+
+ ATSFontFamilyRef familyRef = ATSFontFamilyFindFromName(familyStr, kATSOptionFlagsDefault);
+ if (familyRef != 0xffffffff) {
+ addFamilyToCaches(familyRef);
+ return;
+ }
+ }
+
+ fontRef = ATSFontFindFromPostScriptName(nameStr, kATSOptionFlagsDefault);
+ if (fontRef != kATSFontRefUnspecified) {
+ addFontAndSiblingsToCaches(fontRef);
+ return;
+ }
+
+ NSArray* familyMembers = [[NSFontManager sharedFontManager]
+ availableMembersOfFontFamily: (NSString*)nameStr];
+ if ([familyMembers count] > 0) {
+ addFontsToCaches((CFArrayRef)familyMembers);
+ return;
+ }
+
+ ATSFontFamilyRef familyRef = ATSFontFamilyFindFromName(nameStr, kATSOptionFlagsDefault);
+ if (familyRef != 0xffffffff) {
+ addFamilyToCaches(familyRef);
+ return;
+ }
+}
+
+NSAutoreleasePool* pool = NULL;
+
+void
+XeTeXFontMgr_Mac::initialize()
+{
+ pool = [[NSAutoreleasePool alloc] init];
+}
+
+void
+XeTeXFontMgr_Mac::terminate()
+{
+ if (pool != NULL) {
+ [pool release];
+ }
+}
+
+#endif // XETEX_MAC
diff --git a/Build/source/texk/web2c/xetexdir/XeTeXLayoutInterface.cpp b/Build/source/texk/web2c/xetexdir/XeTeXLayoutInterface.cpp
new file mode 100644
index 00000000000..9a9a48713a7
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/XeTeXLayoutInterface.cpp
@@ -0,0 +1,519 @@
+/****************************************************************************\
+ 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.
+\****************************************************************************/
+
+#include "XeTeXLayoutInterface.h"
+
+#include "XeTeXOTLayoutEngine.h"
+#include "XeTeXFontInst.h"
+#ifdef XETEX_MAC
+#include "XeTeXFontInst_Mac.h"
+#else
+#include "XeTeXFontInst_FC.h"
+#endif
+
+#include "XeTeXFontMgr.h"
+
+#include "XeTeXswap.h"
+
+#include "Features.h"
+#include "ScriptAndLanguage.h"
+
+#include "unicode/ubidi.h"
+
+#include <math.h>
+
+struct XeTeXLayoutEngine_rec
+{
+ LayoutEngine* layoutEngine;
+ XeTeXFontInst* font;
+ UInt32 scriptTag;
+ UInt32 languageTag;
+ UInt32* addedFeatures;
+ UInt32* removedFeatures;
+ UInt32 rgbValue;
+};
+
+/*******************************************************************/
+/* Glyph bounding box cache to speed up \XeTeXuseglyphmetrics mode */
+/*******************************************************************/
+#include <map>
+
+// key is combined value representing (font_id << 16) + glyph
+// value is glyph bounding box in TeX points
+static std::map<UInt32,GlyphBBox> sGlyphBoxes;
+
+int
+getCachedGlyphBBox(UInt16 fontID, UInt16 glyphID, GlyphBBox* bbox)
+{
+ UInt32 key = ((UInt32)fontID << 16) + glyphID;
+ std::map<UInt32,GlyphBBox>::const_iterator i = sGlyphBoxes.find(key);
+ if (i == sGlyphBoxes.end()) {
+ return 0;
+ }
+ *bbox = i->second;
+ return 1;
+}
+
+void
+cacheGlyphBBox(UInt16 fontID, UInt16 glyphID, const GlyphBBox* bbox)
+{
+ UInt32 key = ((UInt32)fontID << 16) + glyphID;
+ sGlyphBoxes[key] = *bbox;
+}
+/*******************************************************************/
+
+void terminatefontmanager()
+{
+ XeTeXFontMgr::Terminate();
+}
+
+XeTeXFont createFont(PlatformFontRef fontRef, Fixed pointSize)
+{
+ LEErrorCode status = LE_NO_ERROR;
+#ifdef XETEX_MAC
+ XeTeXFontInst* font = new XeTeXFontInst_Mac((ATSFontRef)fontRef, Fix2X(pointSize), status);
+#else
+ XeTeXFontInst* font = new XeTeXFontInst_FC((FcPattern*)fontRef, Fix2X(pointSize), status);
+#endif
+ if (LE_FAILURE(status)) {
+ delete font;
+ return NULL;
+ }
+ return (XeTeXFont)font;
+}
+
+void setFontLayoutDir(XeTeXFont font, int vertical)
+{
+ ((XeTeXFontInst*)font)->setLayoutDirVertical(vertical != 0);
+}
+
+PlatformFontRef getFontRef(XeTeXLayoutEngine engine)
+{
+ return engine->font->getFontRef();
+}
+
+PlatformFontRef findFontByName(const char* name, char* var, double size)
+{
+ return (XeTeXFontMgr::GetFontManager()->findFont(name, var, size));
+}
+
+char getReqEngine()
+{
+ return XeTeXFontMgr::GetFontManager()->getReqEngine();
+}
+
+const char* getFullName(PlatformFontRef fontRef)
+{
+ return XeTeXFontMgr::GetFontManager()->getFullName(fontRef);
+}
+
+const char* getPSName(PlatformFontRef fontRef)
+{
+ return XeTeXFontMgr::GetFontManager()->getPSName(fontRef);
+}
+
+void getNames(PlatformFontRef fontRef, const char** psName, const char** famName, const char** styName)
+{
+ XeTeXFontMgr::GetFontManager()->getNames(fontRef, psName, famName, styName);
+}
+
+void deleteFont(XeTeXFont font)
+{
+ delete (XeTeXFontInst*)font;
+}
+
+void* getFontTablePtr(XeTeXFont font, UInt32 tableTag)
+{
+ return const_cast<void*>(((XeTeXFontInst*)font)->getFontTable(tableTag));
+}
+
+/* apparently M_PI isn't defined by <math.h> under VC++ */
+#ifdef WIN32
+#ifndef M_PI
+#define M_PI 3.1415926535898
+#endif
+#endif
+
+Fixed getSlant(XeTeXFont font)
+{
+ float italAngle = ((XeTeXFontInst*)font)->getItalicAngle();
+ return X2Fix(tan(-italAngle * M_PI / 180.0));
+}
+
+static const ScriptListTable*
+getLargerScriptListTable(XeTeXFont font)
+{
+ const ScriptListTable* scriptListSub = NULL;
+ const ScriptListTable* scriptListPos = NULL;
+
+ const GlyphSubstitutionTableHeader* gsubTable = (const GlyphSubstitutionTableHeader*)((XeTeXFontInst*)font)->getFontTable(kGSUB);
+ UInt32 scriptCountSub = 0;
+ if (gsubTable != NULL) {
+ scriptListSub = (const ScriptListTable*)((const char*)gsubTable + SWAP(gsubTable->scriptListOffset));
+ scriptCountSub = SWAP(scriptListSub->scriptCount);
+ }
+
+ const GlyphPositioningTableHeader* gposTable = (const GlyphPositioningTableHeader*)((XeTeXFontInst*)font)->getFontTable(kGPOS);
+ UInt32 scriptCountPos = 0;
+ if (gposTable != NULL) {
+ scriptListPos = (const ScriptListTable*)((const char*)gposTable + SWAP(gposTable->scriptListOffset));
+ scriptCountPos = SWAP(scriptListPos->scriptCount);
+ }
+
+ return scriptCountPos > scriptCountSub ? scriptListPos : scriptListSub;
+}
+
+UInt32 countScripts(XeTeXFont font)
+{
+ const ScriptListTable* scriptList = getLargerScriptListTable(font);
+ if (scriptList == NULL)
+ return 0;
+
+ return SWAP(scriptList->scriptCount);
+}
+
+UInt32 getIndScript(XeTeXFont font, UInt32 index)
+{
+ const ScriptListTable* scriptList = getLargerScriptListTable(font);
+ if (scriptList == NULL)
+ return 0;
+
+ if (index < SWAP(scriptList->scriptCount))
+ return SWAPT(scriptList->scriptRecordArray[index].tag);
+
+ return 0;
+}
+
+UInt32 countScriptLanguages(XeTeXFont font, UInt32 script)
+{
+ const ScriptListTable* scriptList = getLargerScriptListTable(font);
+ if (scriptList == NULL)
+ return 0;
+
+ const ScriptTable* scriptTable = scriptList->findScript(script);
+ if (scriptTable == NULL)
+ return 0;
+
+ UInt32 langCount = SWAP(scriptTable->langSysCount);
+
+ return langCount;
+}
+
+UInt32 getIndScriptLanguage(XeTeXFont font, UInt32 script, UInt32 index)
+{
+ const ScriptListTable* scriptList = getLargerScriptListTable(font);
+ if (scriptList == NULL)
+ return 0;
+
+ const ScriptTable* scriptTable = scriptList->findScript(script);
+ if (scriptTable == NULL)
+ return 0;
+
+ if (index < SWAP(scriptTable->langSysCount))
+ return SWAPT(scriptTable->langSysRecordArray[index].tag);
+
+ return 0;
+}
+
+UInt32 countFeatures(XeTeXFont font, UInt32 script, UInt32 language)
+{
+ UInt32 total = 0;
+ const GlyphLookupTableHeader* table;
+ for (int i = 0; i < 2; ++i) {
+ table = (const GlyphLookupTableHeader*)((XeTeXFontInst*)font)->getFontTable(i == 0 ? kGSUB : kGPOS);
+ if (table != NULL) {
+ const ScriptListTable* scriptList = (const ScriptListTable*)((const char*)table + SWAP(table->scriptListOffset));
+ const ScriptTable* scriptTable = scriptList->findScript(script);
+ if (scriptTable != NULL) {
+ const LangSysTable* langTable = scriptTable->findLanguage(language, (language != 0));
+ if (langTable != NULL) {
+ total += SWAP(langTable->featureCount);
+ if (langTable->reqFeatureIndex != 0xffff)
+ total += 1;
+ }
+ }
+ }
+ }
+
+ return total;
+}
+
+UInt32 getIndFeature(XeTeXFont font, UInt32 script, UInt32 language, UInt32 index)
+{
+ const GlyphLookupTableHeader* table;
+ UInt16 featureIndex = 0xffff;
+ for (int i = 0; i < 2; ++i) {
+ table = (const GlyphLookupTableHeader*)((XeTeXFontInst*)font)->getFontTable(i == 0 ? kGSUB : kGPOS);
+ if (table != NULL) {
+ const ScriptListTable* scriptList = (const ScriptListTable*)((const char*)table + SWAP(table->scriptListOffset));
+ const ScriptTable* scriptTable = scriptList->findScript(script);
+ if (scriptTable != NULL) {
+ const LangSysTable* langTable = scriptTable->findLanguage(language, (language != 0));
+ if (langTable != NULL) {
+ if (SWAP(langTable->reqFeatureIndex) != 0xffff)
+ if (index == 0)
+ featureIndex = SWAP(langTable->reqFeatureIndex);
+ else
+ index -= 1;
+ if (index < SWAP(langTable->featureCount))
+ featureIndex = SWAP(langTable->featureIndexArray[index]);
+ index -= SWAP(langTable->featureCount);
+ }
+ }
+ if (featureIndex != 0xffff) {
+ LETag featureTag;
+ const FeatureListTable* featureListTable = (const FeatureListTable*)((const char*)table + SWAP(table->featureListOffset));
+ (void)featureListTable->getFeatureTable(featureIndex, &featureTag);
+ return featureTag;
+ }
+ }
+ }
+
+ return 0;
+}
+
+float getGlyphWidth(XeTeXFont font, UInt32 gid)
+{
+ LEPoint adv;
+ ((XeTeXFontInst*)font)->getGlyphAdvance(gid, adv);
+ return adv.fX;
+}
+
+UInt32
+countGlyphs(XeTeXFont font)
+{
+ return ((XeTeXFontInst*)font)->getNumGlyphs();
+}
+
+XeTeXFont getFont(XeTeXLayoutEngine engine)
+{
+ return (XeTeXFont)(engine->font);
+}
+
+XeTeXLayoutEngine createLayoutEngine(XeTeXFont font, UInt32 scriptTag, UInt32 languageTag,
+ UInt32* addFeatures, UInt32* removeFeatures, UInt32 rgbValue)
+{
+ LEErrorCode status = LE_NO_ERROR;
+ XeTeXLayoutEngine result = new XeTeXLayoutEngine_rec;
+ result->font = (XeTeXFontInst*)font;
+ result->scriptTag = scriptTag;
+ result->languageTag = languageTag;
+ result->addedFeatures = addFeatures;
+ result->removedFeatures = removeFeatures;
+ result->rgbValue = rgbValue;
+ result->layoutEngine = XeTeXOTLayoutEngine::LayoutEngineFactory((XeTeXFontInst*)font,
+ scriptTag, languageTag, (LETag*)addFeatures, (LETag*)removeFeatures, status);
+ if (LE_FAILURE(status) || result->layoutEngine == NULL) {
+ delete result;
+ return NULL;
+ }
+
+ return result;
+}
+
+void deleteLayoutEngine(XeTeXLayoutEngine engine)
+{
+ delete engine->layoutEngine;
+ delete engine->font;
+}
+
+SInt32 layoutChars(XeTeXLayoutEngine engine, UInt16 chars[], SInt32 offset, SInt32 count, SInt32 max,
+ char rightToLeft, float x, float y, SInt32* status)
+{
+ LEErrorCode success = (LEErrorCode)*status;
+ le_int32 glyphCount = engine->layoutEngine->layoutChars(chars, offset, count, max, rightToLeft, x, y, success);
+ *status = success;
+ return glyphCount;
+}
+
+void getGlyphs(XeTeXLayoutEngine engine, UInt32 glyphs[], SInt32* status)
+{
+ LEErrorCode success = (LEErrorCode)*status;
+ engine->layoutEngine->getGlyphs((LEGlyphID*)glyphs, success);
+ *status = success;
+}
+
+void getGlyphPositions(XeTeXLayoutEngine engine, float positions[], SInt32* status)
+{
+ LEErrorCode success = (LEErrorCode)*status;
+ engine->layoutEngine->getGlyphPositions(positions, success);
+ *status = success;
+}
+
+void getGlyphPosition(XeTeXLayoutEngine engine, SInt32 index, float* x, float* y, SInt32* status)
+{
+ LEErrorCode success = (LEErrorCode)*status;
+ engine->layoutEngine->getGlyphPosition(index, *x, *y, success);
+ *status = success;
+}
+
+UInt32 getScriptTag(XeTeXLayoutEngine engine)
+{
+ return engine->scriptTag;
+}
+
+UInt32 getLanguageTag(XeTeXLayoutEngine engine)
+{
+ return engine->languageTag;
+}
+
+float getPointSize(XeTeXLayoutEngine engine)
+{
+ return engine->font->getXPixelsPerEm();
+}
+
+void getAscentAndDescent(XeTeXLayoutEngine engine, float* ascent, float* descent)
+{
+ *ascent = engine->font->getExactAscent();
+ *descent = engine->font->getExactDescent();
+}
+
+UInt32* getAddedFeatures(XeTeXLayoutEngine engine)
+{
+ return engine->addedFeatures;
+}
+
+UInt32* getRemovedFeatures(XeTeXLayoutEngine engine)
+{
+ return engine->removedFeatures;
+}
+
+int getDefaultDirection(XeTeXLayoutEngine engine)
+{
+ switch (engine->scriptTag) {
+ case kArabic:
+ case kSyriac:
+ case kThaana:
+ case kHebrew:
+ return UBIDI_DEFAULT_RTL;
+ }
+ return UBIDI_DEFAULT_LTR;
+}
+
+UInt32 getRgbValue(XeTeXLayoutEngine engine)
+{
+ return engine->rgbValue;
+}
+
+void getGlyphBounds(XeTeXLayoutEngine engine, UInt32 glyphID, GlyphBBox* bbox)
+{
+ engine->font->getGlyphBounds(glyphID, bbox);
+}
+
+float getGlyphWidthFromEngine(XeTeXLayoutEngine engine, UInt32 glyphID)
+{
+ return engine->font->getGlyphWidth(glyphID);
+}
+
+void getGlyphHeightDepth(XeTeXLayoutEngine engine, UInt32 glyphID, float* height, float* depth)
+{
+ engine->font->getGlyphHeightDepth(glyphID, height, depth);
+}
+
+void getGlyphSidebearings(XeTeXLayoutEngine engine, UInt32 glyphID, float* lsb, float* rsb)
+{
+ engine->font->getGlyphSidebearings(glyphID, lsb, rsb);
+}
+
+float getGlyphItalCorr(XeTeXLayoutEngine engine, UInt32 glyphID)
+{
+ return engine->font->getGlyphItalCorr(glyphID);
+}
+
+UInt32 mapCharToGlyph(XeTeXLayoutEngine engine, UInt32 charCode)
+{
+ return engine->font->mapCharToGlyph(charCode);
+}
+
+#include "appleGlyphNames.c"
+
+int
+findGlyphInPostTable(const char* buffer, int tableSize, const char* glyphName)
+{
+ const postTable* p = (const postTable*)buffer;
+ UInt16 g = 0;
+ switch (SWAP(p->format)) {
+ case 0x00010000:
+ {
+ char* cp;
+ while ((cp = appleGlyphNames[g]) != 0) {
+ if (strcmp(glyphName, cp) == 0)
+ return g;
+ ++g;
+ }
+ }
+ break;
+
+ case 0x00020000:
+ {
+ const UInt16* n = (UInt16*)(p + 1);
+ UInt16 numGlyphs = SWAP(*n++);
+ const UInt8* ps = (const UInt8*)(n + numGlyphs);
+ std::vector<std::string> newNames;
+ while (ps < (const UInt8*)buffer + tableSize) {
+ newNames.push_back(std::string((char*)ps + 1, *ps));
+ ps += *ps + 1;
+ }
+ for (g = 0; g < numGlyphs; ++g) {
+ if (SWAP(*n) < 258) {
+ if (strcmp(appleGlyphNames[SWAP(*n)], glyphName) == 0)
+ return g;
+ }
+ else {
+ if (strcmp(newNames[SWAP(*n) - 258].c_str(), glyphName) == 0)
+ return g;
+ }
+ ++n;
+ }
+ }
+ break;
+
+ case 0x00028000:
+ break;
+
+ case 0x00030000:
+ // TODO: see if it's a CFF OpenType font, and if so, get the glyph names from the CFF data
+ break;
+
+ case 0x00040000:
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+int
+mapGlyphToIndex(XeTeXLayoutEngine engine, const char* glyphName)
+{
+ return engine->font->mapGlyphToIndex(glyphName);
+}
diff --git a/Build/source/texk/web2c/xetexdir/XeTeXLayoutInterface.h b/Build/source/texk/web2c/xetexdir/XeTeXLayoutInterface.h
new file mode 100644
index 00000000000..ccfbbe531ec
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/XeTeXLayoutInterface.h
@@ -0,0 +1,134 @@
+/****************************************************************************\
+ 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.
+\****************************************************************************/
+
+#ifdef XETEX_MAC
+#include <Carbon/Carbon.h>
+#endif
+
+#include "XeTeX_ext.h"
+#include "XeTeXFontMgr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct XeTeXFont_rec* XeTeXFont;
+typedef struct XeTeXLayoutEngine_rec* XeTeXLayoutEngine;
+
+extern char gPrefEngine;
+
+int getCachedGlyphBBox(UInt16 fontID, UInt16 glyphID, GlyphBBox* bbox);
+void cacheGlyphBBox(UInt16 fontID, UInt16 glyphID, const GlyphBBox* bbox);
+
+void terminatefontmanager();
+
+#ifdef XETEX_MAC
+XeTeXFont createFont(ATSFontRef atsFont, Fixed pointSize);
+#else
+// appropriate functions for other platforms
+XeTeXFont createFont(PlatformFontRef fontRef, Fixed pointSize);
+#endif
+
+void setFontLayoutDir(XeTeXFont font, int vertical);
+
+PlatformFontRef getFontRef(XeTeXLayoutEngine engine);
+PlatformFontRef findFontByName(const char* name, char* var, double size);
+
+char getReqEngine();
+const char* getFullName(PlatformFontRef fontRef);
+const char* getPSName(PlatformFontRef fontRef);
+void getNames(PlatformFontRef fontRef, const char** psName, const char** famName, const char** styName);
+
+void deleteFont(XeTeXFont font);
+
+void* getFontTablePtr(XeTeXFont font, UInt32 tableTag);
+
+Fixed getSlant(XeTeXFont font);
+
+UInt32 countScripts(XeTeXFont font);
+UInt32 getIndScript(XeTeXFont font, UInt32 index);
+UInt32 countScriptLanguages(XeTeXFont font, UInt32 script);
+UInt32 getIndScriptLanguage(XeTeXFont font, UInt32 script, UInt32 index);
+UInt32 countFeatures(XeTeXFont font, UInt32 script, UInt32 language);
+UInt32 getIndFeature(XeTeXFont font, UInt32 script, UInt32 language, UInt32 index);
+float getGlyphWidth(XeTeXFont font, UInt32 gid);
+UInt32 countGlyphs(XeTeXFont font);
+
+XeTeXLayoutEngine createLayoutEngine(XeTeXFont font, UInt32 scriptTag, UInt32 languageTag,
+ UInt32* addFeatures, UInt32* removeFeatures, UInt32 rgbValue);
+
+void deleteLayoutEngine(XeTeXLayoutEngine engine);
+
+XeTeXFont getFont(XeTeXLayoutEngine engine);
+
+SInt32 layoutChars(XeTeXLayoutEngine engine, UInt16* chars, SInt32 offset, SInt32 count, SInt32 max,
+ char rightToLeft, float x, float y, SInt32* status);
+
+void getGlyphs(XeTeXLayoutEngine engine, UInt32* glyphs, SInt32* status);
+
+void getGlyphPositions(XeTeXLayoutEngine engine, float* positions, SInt32* status);
+
+void getGlyphPosition(XeTeXLayoutEngine engine, SInt32 index, float* x, float* y, SInt32* status);
+
+UInt32 getScriptTag(XeTeXLayoutEngine engine);
+
+UInt32 getLanguageTag(XeTeXLayoutEngine engine);
+
+float getPointSize(XeTeXLayoutEngine engine);
+
+void getAscentAndDescent(XeTeXLayoutEngine engine, float* ascent, float* descent);
+
+UInt32* getAddedFeatures(XeTeXLayoutEngine engine);
+
+UInt32* getRemovedFeatures(XeTeXLayoutEngine engine);
+
+int getDefaultDirection(XeTeXLayoutEngine engine);
+
+UInt32 getRgbValue(XeTeXLayoutEngine engine);
+
+void getGlyphBounds(XeTeXLayoutEngine engine, UInt32 glyphID, GlyphBBox* bbox);
+
+float getGlyphWidthFromEngine(XeTeXLayoutEngine engine, UInt32 glyphID);
+
+void getGlyphHeightDepth(XeTeXLayoutEngine engine, UInt32 glyphID, float* height, float* depth);
+
+void getGlyphSidebearings(XeTeXLayoutEngine engine, UInt32 glyphID, float* lsb, float* rsb);
+
+float getGlyphItalCorr(XeTeXLayoutEngine engine, UInt32 glyphID);
+
+UInt32 mapCharToGlyph(XeTeXLayoutEngine engine, UInt32 charCode);
+
+int mapGlyphToIndex(XeTeXLayoutEngine engine, const char* glyphName);
+
+int findGlyphInPostTable(const char* p, int tableSize, const char* glyphName);
+
+#ifdef __cplusplus
+};
+#endif
diff --git a/Build/source/texk/web2c/xetexdir/XeTeXOTLayoutEngine.cpp b/Build/source/texk/web2c/xetexdir/XeTeXOTLayoutEngine.cpp
new file mode 100644
index 00000000000..8eedae283ce
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/XeTeXOTLayoutEngine.cpp
@@ -0,0 +1,281 @@
+/****************************************************************************\
+ 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.
+\****************************************************************************/
+
+#include "XeTeXOTLayoutEngine.h"
+
+#include "ThaiLayoutEngine.h"
+#include "KhmerLayoutEngine.h"
+
+#include "LEScripts.h"
+#include "LELanguages.h"
+
+const LETag emptyTag = 0x00000000;
+
+static le_int32 getScriptCode(LETag scriptTag)
+{
+ for (le_int32 i = 0; i < scriptCodeCount; ++i)
+ if (OpenTypeLayoutEngine::getScriptTag(i) == scriptTag)
+ return i;
+ return -1;
+}
+
+static le_int32 getLanguageCode(LETag languageTag)
+{
+ for (le_int32 i = 0; i < languageCodeCount; ++i)
+ if (OpenTypeLayoutEngine::getLangSysTag(i) == languageTag)
+ return i;
+ return -1;
+}
+
+LayoutEngine* XeTeXOTLayoutEngine::LayoutEngineFactory
+ (const XeTeXFontInst* fontInstance,
+ LETag scriptTag, LETag languageTag,
+ const LETag* addFeatures, const LETag* removeFeatures,
+ LEErrorCode &success)
+{
+ static le_uint32 gsubTableTag = LE_GSUB_TABLE_TAG;
+
+ if (LE_FAILURE(success))
+ return NULL;
+
+ const GlyphSubstitutionTableHeader* gsubTable = (const GlyphSubstitutionTableHeader*)fontInstance->getFontTable(gsubTableTag);
+ LayoutEngine *result = NULL;
+
+ le_uint32 scriptCode = getScriptCode(scriptTag);
+ le_uint32 languageCode = getLanguageCode(languageTag);
+
+ le_int32 typoFlags = 3;
+
+ if (gsubTable != NULL && gsubTable->coversScript(scriptTag)) {
+ switch (scriptCode) {
+ case bengScriptCode:
+ case devaScriptCode:
+ case gujrScriptCode:
+ case kndaScriptCode:
+ case mlymScriptCode:
+ case oryaScriptCode:
+ case guruScriptCode:
+ case tamlScriptCode:
+ case teluScriptCode:
+// result = new XeTeXIndicLayoutEngine(fontInstance, scriptTag, languageTag, gsubTable, addFeatures, removeFeatures);
+ result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable);
+ break;
+
+ case arabScriptCode:
+ case syrcScriptCode:
+ case mongScriptCode:
+// result = new XeTeXArabicLayoutEngine(fontInstance, scriptTag, languageTag, gsubTable, addFeatures, removeFeatures);
+ result = new ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable);
+ break;
+
+ case bopoScriptCode:
+ case haniScriptCode:
+ case hangScriptCode:
+ case hiraScriptCode:
+ case kanaScriptCode:
+ case hrktScriptCode:
+ result = new XeTeXHanLayoutEngine(fontInstance, scriptTag, languageTag, gsubTable, addFeatures, removeFeatures);
+ break;
+
+ case khmrScriptCode:
+ result = new KhmerOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable);
+ break;
+
+ default:
+ result = new XeTeXOTLayoutEngine(fontInstance, scriptTag, languageTag, gsubTable, addFeatures, removeFeatures);
+ break;
+ }
+ }
+ else {
+ switch (scriptCode) {
+ case bengScriptCode:
+ case devaScriptCode:
+ case gujrScriptCode:
+ case kndaScriptCode:
+ case mlymScriptCode:
+ case oryaScriptCode:
+ case guruScriptCode:
+ case tamlScriptCode:
+ case teluScriptCode:
+ result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags);
+ break;
+
+ case arabScriptCode:
+ case hebrScriptCode:
+ result = new UnicodeArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags);
+ break;
+
+ case thaiScriptCode:
+ result = new ThaiLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags);
+ break;
+
+ default:
+ result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags);
+ break;
+ }
+ }
+
+ if (result == NULL)
+ success = LE_MEMORY_ALLOCATION_ERROR;
+
+ return result;
+}
+
+/*
+ * XeTeXOTLayoutEngine
+ */
+
+const char XeTeXOTLayoutEngine::fgClassID=0;
+
+XeTeXOTLayoutEngine::XeTeXOTLayoutEngine(
+ const LEFontInstance* fontInstance, LETag scriptTag, LETag languageTag,
+ const GlyphSubstitutionTableHeader* gsubTable,
+ const LETag* addFeatures, const LETag* removeFeatures)
+ : OpenTypeLayoutEngine(fontInstance, getScriptCode(scriptTag), getLanguageCode(languageTag), 3, gsubTable)
+{
+ static le_uint32 gposTableTag = LE_GPOS_TABLE_TAG;
+
+ fDefaultFeatures = fFeatureList;
+
+ // check the result of setScriptAndLanguageTags(), in case they were unknown to ICU
+ if (fScriptTag != scriptTag || fLangSysTag != languageTag) {
+ fScriptTag = scriptTag;
+ fLangSysTag = languageTag;
+
+ // 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;
+ }
+ }
+
+ adjustFeatures(addFeatures, removeFeatures);
+}
+
+XeTeXOTLayoutEngine::~XeTeXOTLayoutEngine()
+{
+ if (fFeatureList != NULL && fFeatureList != fDefaultFeatures)
+ LE_DELETE_ARRAY(fFeatureList);
+}
+
+void XeTeXOTLayoutEngine::adjustFeatures(const LETag* addTags, const LETag* removeTags)
+{
+ // 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++;
+ }
+
+ // 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;
+ pTag = fFeatureList;
+ while (*pTag != emptyTag) {
+ const LETag* t = removeTags;
+ if (t != NULL)
+ while (*t != emptyTag)
+ if (*t == *pTag)
+ break;
+ else
+ t++;
+ if (t == NULL || *t == emptyTag)
+ *dest++ = *pTag;
+ pTag++;
+ }
+
+ // copy the added tags, skipping any already present
+ pTag = addTags;
+ if (pTag != NULL)
+ while (*pTag != emptyTag) {
+ const LETag* t = newList;
+ while (t < dest)
+ if (*t == *pTag)
+ break;
+ else
+ t++;
+ if (t == dest)
+ *dest++ = *pTag;
+ pTag++;
+ }
+
+ // 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;
+}
+
+
+/*
+ * XeTeXHanLayoutEngine
+ */
+
+const char XeTeXHanLayoutEngine::fgClassID=0;
+
+static const LETag loclFeatureTag = LE_LOCL_FEATURE_TAG;
+static const LETag smplFeatureTag = LE_SMPL_FEATURE_TAG;
+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};
+
+XeTeXHanLayoutEngine::XeTeXHanLayoutEngine(const XeTeXFontInst *fontInstance, LETag scriptTag, LETag languageTag,
+ const GlyphSubstitutionTableHeader *gsubTable,
+ const LETag *addFeatures, const LETag *removeFeatures)
+ : XeTeXOTLayoutEngine(fontInstance, scriptTag, languageTag, gsubTable, NULL, NULL)
+{
+ // reset the default feature list
+ fFeatureList = fontInstance->getLayoutDirVertical() ? verticalFeatures : horizontalFeatures;
+ fDefaultFeatures = fFeatureList;
+
+ // then apply any adjustments
+ adjustFeatures(addFeatures, removeFeatures);
+}
+
+XeTeXHanLayoutEngine::~XeTeXHanLayoutEngine()
+{
+}
diff --git a/Build/source/texk/web2c/xetexdir/XeTeXOTLayoutEngine.h b/Build/source/texk/web2c/xetexdir/XeTeXOTLayoutEngine.h
new file mode 100644
index 00000000000..9e29f475963
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/XeTeXOTLayoutEngine.h
@@ -0,0 +1,128 @@
+/****************************************************************************\
+ 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.
+\****************************************************************************/
+
+#ifndef __XeTeXOTLayoutEngine_h
+#define __XeTeXOTLayoutEngine_h
+
+#include "OpenTypeLayoutEngine.h"
+#include "ArabicLayoutEngine.h"
+#include "IndicLayoutEngine.h"
+#include "HanLayoutEngine.h"
+
+#include "XeTeXFontInst.h"
+
+class XeTeXOTLayoutEngine : public OpenTypeLayoutEngine
+{
+public:
+ XeTeXOTLayoutEngine(const LEFontInstance* fontInstance, LETag scriptTag, LETag languageTag,
+ const GlyphSubstitutionTableHeader* gsubTable,
+ const LETag* addFeatures, const LETag* removeFeatures);
+
+ virtual ~XeTeXOTLayoutEngine();
+
+ virtual void adjustFeatures(const LETag* addTags, const LETag* removeTags);
+
+ virtual inline UClassID getDynamicClassID() const { return getStaticClassID(); }
+ static inline UClassID getStaticClassID() { return (UClassID)&fgClassID; }
+
+ static LayoutEngine* LayoutEngineFactory
+ (const XeTeXFontInst* fontInstance,
+ LETag scriptTag, LETag languageTag,
+ const LETag* addFeatures, const LETag* removeFeatures,
+ LEErrorCode &success);
+
+protected:
+ const LETag* fDefaultFeatures;
+
+private:
+ static const char fgClassID;
+
+};
+
+class XeTeXArabicLayoutEngine : public ArabicOpenTypeLayoutEngine
+{
+public:
+ XeTeXArabicLayoutEngine(const LEFontInstance *fontInstance, LETag scriptTag, LETag languageTag,
+ const GlyphSubstitutionTableHeader *gsubTable,
+ const LETag *addFeatures, const LETag *removeFeatures);
+
+ virtual ~XeTeXArabicLayoutEngine();
+
+ virtual void adjustFeatures(const LETag* addTags, const LETag* removeTags);
+
+ virtual inline UClassID getDynamicClassID() const { return getStaticClassID(); }
+ static inline UClassID getStaticClassID() { return (UClassID)&fgClassID; }
+
+private:
+ static const char fgClassID;
+
+ const LETag* fDefaultFeatures;
+};
+
+class XeTeXIndicLayoutEngine : public IndicOpenTypeLayoutEngine
+{
+public:
+ XeTeXIndicLayoutEngine(const LEFontInstance *fontInstance, LETag scriptTag, LETag languageTag,
+ const GlyphSubstitutionTableHeader *gsubTable,
+ const LETag *addFeatures, const LETag *removeFeatures);
+
+ virtual ~XeTeXIndicLayoutEngine();
+
+ virtual void adjustFeatures(const LETag* addTags, const LETag* removeTags);
+
+ virtual inline UClassID getDynamicClassID() const { return getStaticClassID(); }
+ static inline UClassID getStaticClassID() { return (UClassID)&fgClassID; }
+
+private:
+ static const char fgClassID;
+
+ const LETag* fDefaultFeatures;
+};
+
+class XeTeXHanLayoutEngine : public XeTeXOTLayoutEngine
+{
+public:
+ XeTeXHanLayoutEngine(const XeTeXFontInst *fontInstance, LETag scriptTag, LETag languageTag,
+ const GlyphSubstitutionTableHeader *gsubTable,
+ const LETag *addFeatures, const LETag *removeFeatures);
+
+ virtual ~XeTeXHanLayoutEngine();
+
+// virtual void adjustFeatures(const LETag* addTags, const LETag* removeTags);
+
+ virtual inline UClassID getDynamicClassID() const { return getStaticClassID(); }
+ static inline UClassID getStaticClassID() { return (UClassID)&fgClassID; }
+
+private:
+ static const char fgClassID;
+};
+
+#endif
+
diff --git a/Build/source/texk/web2c/xetexdir/XeTeX_ext.c b/Build/source/texk/web2c/xetexdir/XeTeX_ext.c
new file mode 100644
index 00000000000..99db577faca
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/XeTeX_ext.c
@@ -0,0 +1,2302 @@
+/****************************************************************************\
+ 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.
+\****************************************************************************/
+
+/* XeTeX_ext.c
+ * additional plain C extensions for XeTeX - mostly platform-neutral
+ */
+
+#define EXTERN extern
+#include "xetexd.h"
+
+#ifdef XETEX_MAC
+#undef input /* this is defined in texmfmp.h, but we don't need it and it confuses the carbon headers */
+#include <Carbon/Carbon.h>
+#endif
+
+#include "XeTeX_ext.h"
+
+#include "TECkit_Engine.h"
+
+#include <kpathsea/c-ctype.h>
+#include <kpathsea/line.h>
+#include <kpathsea/readable.h>
+#include <kpathsea/variable.h>
+#include <kpathsea/absolute.h>
+
+#include <math.h> /* for fabs() */
+
+#include <time.h> /* For `struct tm'. */
+#if defined (HAVE_SYS_TIME_H)
+#include <sys/time.h>
+#elif defined (HAVE_SYS_TIMEB_H)
+#include <sys/timeb.h>
+#endif
+
+#if defined(__STDC__)
+#include <locale.h>
+#endif
+
+#include <signal.h> /* Catch interrupts. */
+
+#include "XeTeXLayoutInterface.h"
+
+#include "XeTeXswap.h"
+
+#include "unicode/ubidi.h"
+#include "unicode/ubrk.h"
+#include "unicode/ucnv.h"
+
+/*
+#include "sfnt.h"
+ doesn't work in plain C files :(
+*/
+
+typedef struct
+{
+ Fixed version;
+ UInt16 numGlyphs;
+ UInt16 maxPoints;
+ UInt16 maxContours;
+ UInt16 maxComponentPoints;
+ UInt16 maxComponentContours;
+ UInt16 maxZones;
+ UInt16 maxTwilightPoints;
+ UInt16 maxStorage;
+ UInt16 maxFunctionDefs;
+ UInt16 maxInstructionDefs;
+ UInt16 maxStackElements;
+ UInt16 maxSizeOfInstructions;
+ UInt16 maxComponentElements;
+ UInt16 maxComponentDepth;
+} MAXPTable;
+
+typedef struct
+{
+ Fixed version;
+ Fixed italicAngle;
+ SInt16 underlinePosition;
+ UInt16 underlineThickness;
+ UInt32 isFixedPitch;
+ UInt32 minMemType42;
+ UInt32 maxMemType42;
+ UInt32 minMemType1;
+ UInt32 maxMemType1;
+} POSTTable;
+
+enum {
+ LE_MAXP_TABLE_TAG = 0x6D617870UL, /**< 'maxp' */
+ LE_POST_TABLE_TAG = 0x706F7374UL, /**< 'post' */
+};
+
+/* tables/values used in UTF-8 interpretation -
+ code is based on ConvertUTF.[ch] sample code
+ published by the Unicode consortium */
+const UInt32
+offsetsFromUTF8[6] = {
+ 0x00000000UL,
+ 0x00003080UL,
+ 0x000E2080UL,
+ 0x03C82080UL,
+ 0xFA082080UL,
+ 0x82082080UL
+};
+
+const UInt8
+bytesFromUTF8[256] = {
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
+};
+
+const UInt8
+firstByteMark[7] = {
+ 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC
+};
+
+const int halfShift = 10;
+const UInt32 halfBase = 0x0010000UL;
+const UInt32 halfMask = 0x3FFUL;
+const UInt32 kSurrogateHighStart = 0xD800UL;
+const UInt32 kSurrogateHighEnd = 0xDBFFUL;
+const UInt32 kSurrogateLowStart = 0xDC00UL;
+const UInt32 kSurrogateLowEnd = 0xDFFFUL;
+const UInt32 byteMask = 0x000000BFUL;
+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"; /* for linux version with preliminary dvipdfmx-based driver */
+#endif
+
+
+extern char* gettexstring(int strNumber);
+void
+setinputfileencoding(UFILE* f, int mode, int encodingData)
+{
+ if ((f->encodingMode == ICUMAPPING) && (f->conversionData != NULL))
+ ucnv_close((UConverter*)(f->conversionData));
+ f->conversionData = 0;
+
+ switch (mode) {
+ case UTF8:
+ case UTF16BE:
+ case UTF16LE:
+ case RAW:
+ f->encodingMode = mode;
+ break;
+
+ case ICUMAPPING:
+ {
+ char* name = gettexstring(encodingData);
+ UErrorCode err = 0;
+ UConverter* cnv = ucnv_open(name, &err);
+ if (cnv == NULL) {
+ fprintf(stderr, "! Error %d creating Unicode converter for %s\n", err, name);
+ f->encodingMode = RAW;
+ }
+ else {
+ f->encodingMode = ICUMAPPING;
+ f->conversionData = cnv;
+ }
+ free(name);
+ }
+ break;
+ }
+}
+
+void
+uclose(UFILE* f)
+{
+ if (f != 0) {
+ fclose(f->f);
+ if ((f->encodingMode == ICUMAPPING) && (f->conversionData != NULL))
+ ucnv_close((UConverter*)(f->conversionData));
+ free((void*)f);
+ }
+}
+
+int
+input_line_icu(UFILE* f)
+{
+static char* byteBuffer = NULL;
+
+ UInt32 bytesRead = 0;
+ int i;
+ UConverter* cnv;
+ long outLen;
+ UErrorCode errorCode = 0;
+
+ if (byteBuffer == NULL)
+ byteBuffer = xmalloc(bufsize + 1);
+
+ /* Recognize either LF or CR as a line terminator; skip initial LF if prev line ended with CR. */
+ i = getc(f->f);
+ if (f->skipNextLF) {
+ f->skipNextLF = 0;
+ if (i == '\n')
+ i = getc(f->f);
+ }
+
+ if (i != EOF && i != '\n' && i != '\r')
+ byteBuffer[bytesRead++] = i;
+ if (i != EOF && i != '\n' && i != '\r')
+ while (bytesRead < bufsize && (i = getc(f->f)) != EOF && i != '\n' && i != '\r')
+ byteBuffer[bytesRead++] = i;
+
+ if (i == EOF && errno != EINTR && last == first)
+ return false;
+
+ if (i != EOF && i != '\n' && i != '\r') {
+ fprintf (stderr, "! Unable to read an entire line---bufsize=%u.\n",
+ (unsigned) bufsize);
+ fputs ("Please increase buf_size in texmf.cnf.\n", stderr);
+ uexit (1);
+ }
+
+ /* If line ended with CR, remember to skip following LF. */
+ if (i == '\r')
+ f->skipNextLF = 1;
+
+ /* 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);
+ if (errorCode != 0) {
+ fprintf(stderr, "! Unicode conversion failed: error code = %d\n", (int)errorCode);
+ return false;
+ }
+ last = first + outLen;
+ buffer[last] = ' ';
+
+ if (last >= maxbufstack)
+ maxbufstack = last;
+
+ /* Trim trailing whitespace. */
+ while (last > first && ISBLANK(buffer[last - 1]))
+ --last;
+
+ return true;
+}
+
+static void die(char*s, int i)
+{
+ fprintf(stderr, s, i);
+ fprintf(stderr, " - exiting\n");
+ exit(3);
+}
+
+static UBreakIterator* brkIter = NULL;
+static int brkLocaleStrNum = 0;
+
+void
+linebreakstart(int localeStrNum, const UniChar* text, int textLength)
+{
+ UErrorCode status = 0;
+ int i;
+
+ if ((localeStrNum != brkLocaleStrNum) && (brkIter != NULL)) {
+ ubrk_close(brkIter);
+ brkIter = NULL;
+ }
+
+ if (brkIter == NULL) {
+ char* locale = (char*)gettexstring(localeStrNum);
+ brkIter = ubrk_open(UBRK_LINE, locale, NULL, 0, &status);
+ if (U_FAILURE(status)) {
+ fprintf(stderr, "\n! error %d creating linebreak iterator for locale \"%s\", trying default. ", status, locale);
+ if (brkIter != NULL)
+ ubrk_close(brkIter);
+ status = 0;
+ brkIter = ubrk_open(UBRK_LINE, "en_us", NULL, 0, &status);
+ }
+ free(locale);
+ brkLocaleStrNum = localeStrNum;
+ }
+
+ if (brkIter == NULL) {
+ die("! failed to create linebreak iterator, status=%d", (int)status);
+ }
+
+ ubrk_setText(brkIter, text, textLength, &status);
+}
+
+int
+linebreaknext()
+{
+ return ubrk_next((UBreakIterator*)brkIter);
+}
+
+long
+getencodingmodeandinfo(long* info)
+{
+ /* \XeTeXinputencoding "enc-name"
+ * -> name is packed in |nameoffile| as a C string, starting at [1]
+ * Check if it's a built-in name; if not, try to open an ICU converter by that name
+ */
+ UErrorCode err = 0;
+ UConverter* cnv;
+ char* name = (char*)nameoffile + 1;
+ *info = 0;
+ if (strcasecmp(name, "auto") == 0) {
+ return AUTO;
+ }
+ if (strcasecmp(name, "utf8") == 0) {
+ return UTF8;
+ }
+ if (strcasecmp(name, "utf16") == 0) { /* depends on host platform */
+#ifdef WORDS_BIGENDIAN
+ return UTF16BE;
+#else
+ return UTF16LE;
+#endif
+ }
+ if (strcasecmp(name, "utf16be") == 0) {
+ return UTF16BE;
+ }
+ if (strcasecmp(name, "utf16le") == 0) {
+ return UTF16LE;
+ }
+ if (strcasecmp(name, "bytes") == 0) {
+ return RAW;
+ }
+
+ /* try for an ICU converter */
+ cnv = ucnv_open(name, &err);
+ if (cnv == NULL) {
+ fprintf(stderr, "! unknown encoding \"%s\"; reading as raw bytes\n", name);
+ return RAW;
+ }
+ else {
+ ucnv_close(cnv);
+ *info = maketexstring(name);
+ return ICUMAPPING;
+ }
+}
+
+void
+printutf8str(const unsigned char* str, int len)
+{
+ while (len-- > 0)
+ printvisiblechar(*(str++)); /* bypass utf-8 encoding done in print_char() */
+}
+
+void
+printchars(const unsigned short* str, int len)
+{
+ while (len-- > 0)
+ printchar(*(str++));
+}
+
+void*
+load_mapping_file(const char* s, const char* e)
+{
+ char* mapPath;
+ TECkit_Converter cnv = 0;
+ char* buffer = xmalloc(e - s + 5);
+ strncpy(buffer, s, e - s);
+ buffer[e - s] = 0;
+ strcat(buffer, ".tec");
+ mapPath = kpse_find_file(buffer, kpse_miscfonts_format, 1);
+
+ if (mapPath) {
+ FILE* mapFile = fopen(mapPath, "rb");
+ free(mapPath);
+ if (mapFile) {
+ UInt32 mappingSize;
+ Byte* mapping;
+ TECkit_Status status;
+ fseek(mapFile, 0, SEEK_END);
+ mappingSize = ftell(mapFile);
+ fseek(mapFile, 0, SEEK_SET);
+ mapping = xmalloc(mappingSize);
+ fread(mapping, 1, mappingSize, mapFile);
+ fclose(mapFile);
+ status = TECkit_CreateConverter(mapping, mappingSize,
+ true,
+#ifdef WORDS_BIGENDIAN
+ kForm_UTF16BE, kForm_UTF16BE,
+#else
+ kForm_UTF16LE, kForm_UTF16LE,
+#endif
+ &cnv);
+ free(mapping);
+ }
+ }
+ else
+ fontmappingwarning(buffer, strlen(buffer));
+
+ free(buffer);
+
+ return cnv;
+}
+
+static UInt32
+read_tag(const char* cp)
+{
+ UInt32 tag = 0;
+ int i;
+ for (i = 0; i < 4; ++i) {
+ tag <<= 8;
+ if (*cp && /* *cp < 128 && */ *cp != ',' && *cp != ';' && *cp != ':') {
+ tag += *(unsigned char*)cp;
+ ++cp;
+ }
+ else
+ tag += ' ';
+ }
+ return tag;
+}
+
+static void*
+loadOTfont(XeTeXFont font, Fixed scaled_size, const char* cp1)
+{
+ XeTeXLayoutEngine engine;
+ UInt32 scriptTag = kLatin;
+ UInt32 languageTag = 0;
+
+ UInt32* addFeatures = 0;
+ UInt32* removeFeatures = 0;
+
+ int nAdded = 0;
+ int nRemoved = 0;
+
+ const char* cp2;
+ const char* cp3;
+
+ UInt32 tag;
+
+ UInt32 rgbValue = 0x000000FF;
+
+ /* 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, "script", 6) == 0) {
+ cp3 = cp1 + 6;
+ if (*cp3 != '=')
+ goto bad_option;
+ scriptTag = read_tag(cp3 + 1);
+ goto next_option;
+ }
+
+ if (strncmp(cp1, "language", 8) == 0) {
+ cp3 = cp1 + 8;
+ if (*cp3 != '=')
+ goto bad_option;
+ languageTag = read_tag(cp3 + 1);
+ 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, "color", 5) == 0) {
+ unsigned alpha = 0;
+ int i;
+ 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;
+ else
+ rgbValue += 0xFF;
+
+ loadedfontflags |= FONT_FLAGS_COLORED;
+
+ goto next_option;
+ }
+
+ if (strncmp(cp1, "letterspace", 11) == 0) {
+ int sign = 1;
+ double val = 0.0;
+
+ 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;
+
+ goto next_option;
+ }
+
+ if (*cp1 == '+') {
+ tag = read_tag(cp1 + 1);
+ ++nAdded;
+ if (nAdded == 1)
+ addFeatures = xmalloc(sizeof(UInt32));
+ else
+ addFeatures = xrealloc(addFeatures, nAdded * sizeof(UInt32));
+ addFeatures[nAdded-1] = tag;
+ goto next_option;
+ }
+
+ if (*cp1 == '-') {
+ tag = read_tag(cp1 + 1);
+ ++nRemoved;
+ if (nRemoved == 1)
+ removeFeatures = xmalloc(sizeof(UInt32));
+ else
+ removeFeatures = xrealloc(removeFeatures, nRemoved * sizeof(UInt32));
+ removeFeatures[nRemoved-1] = tag;
+ goto next_option;
+ }
+
+ if (strncmp(cp1, "vertical", 8) == 0) {
+ cp3 = cp2;
+ if (*cp3 == ';' || *cp3 == ':')
+ --cp3;
+ while (*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 (addFeatures != 0) {
+ addFeatures = realloc(addFeatures, (nAdded + 1) * sizeof(UInt32));
+ addFeatures[nAdded] = 0;
+ }
+ if (removeFeatures != 0) {
+ removeFeatures = realloc(removeFeatures, (nRemoved + 1) * sizeof(UInt32));
+ removeFeatures[nRemoved] = 0;
+ }
+ }
+
+ if ((loadedfontflags & FONT_FLAGS_COLORED) == 0)
+ rgbValue = 0x000000FF;
+
+ if ((loadedfontflags & FONT_FLAGS_VERTICAL) != 0)
+ setFontLayoutDir(font, 1);
+
+ engine = createLayoutEngine(font, scriptTag, languageTag, addFeatures, removeFeatures, rgbValue);
+ if (engine == 0) {
+ deleteFont(font);
+ if (addFeatures)
+ free(addFeatures);
+ if (removeFeatures)
+ free(removeFeatures);
+ }
+ else
+ nativefonttypeflag = OT_FONT_FLAG;
+
+ return engine;
+}
+
+static void
+splitFontName(char* name, char** var, char** feat, char** end)
+{
+ *var = NULL;
+ *feat = NULL;
+ while (*name) {
+ if (*name == '/' && *var == NULL && *feat == NULL)
+ *var = name;
+ else if (*name == ':' && *feat == NULL)
+ *feat = name;
+ ++name;
+ }
+ *end = name;
+ if (*feat == NULL)
+ *feat = name;
+ if (*var == NULL)
+ *var = *feat;
+}
+
+void*
+findnativefont(unsigned char* uname, long scaled_size)
+ /* scaled_size here is in TeX points */
+{
+ void* rval = 0;
+ char* nameString;
+ char* var;
+ char* feat;
+ char* end;
+ char* name = (char*)uname;
+ char* varString = NULL;
+ char* featString = NULL;
+ PlatformFontRef fontRef;
+ XeTeXFont font;
+
+ loadedfontmapping = NULL;
+ loadedfontflags = 0;
+ loadedfontletterspace = 0;
+
+ splitFontName(name, &var, &feat, &end);
+
+ nameString = xmalloc(var - name + 1);
+ strncpy(nameString, name, var - name);
+ nameString[var - name] = 0;
+
+ if (feat > var) {
+ varString = xmalloc(feat - var);
+ strncpy(varString, var + 1, feat - var - 1);
+ varString[feat - var - 1] = 0;
+ }
+
+ if (end > feat) {
+ featString = xmalloc(end - feat);
+ strncpy(featString, feat + 1, end - feat - 1);
+ featString[end - feat - 1] = 0;
+ }
+
+ fontRef = findFontByName(nameString, varString, Fix2X(scaled_size));
+
+ if (fontRef != 0) {
+ /* update nameoffile to the full name of the font, for error messages during font loading */
+ const char* fullName = getFullName(fontRef);
+ namelength = strlen(fullName);
+ if (featString != NULL)
+ namelength += strlen(featString) + 1;
+ if (varString != NULL)
+ namelength += strlen(varString) + 1;
+ free(nameoffile);
+ nameoffile = xmalloc(namelength + 4); /* +2 would be correct: initial space, final NUL */
+ nameoffile[0] = ' ';
+ strcpy((char*)nameoffile + 1, fullName);
+
+#ifdef XETEX_MAC
+ /* decide whether to use AAT or OpenType rendering with this font */
+ if (getReqEngine() == 'A')
+ goto load_aat;
+#endif
+
+ font = createFont(fontRef, scaled_size);
+ if (font != 0) {
+#ifdef XETEX_MAC
+ if (getReqEngine() == 'I' || getFontTablePtr(font, kGSUB) != 0 || getFontTablePtr(font, kGPOS) != 0)
+#endif
+ rval = loadOTfont(font, scaled_size, featString);
+ if (rval == 0)
+ deleteFont(font);
+ }
+
+#ifdef XETEX_MAC
+ if (rval == 0) {
+ load_aat:
+ rval = loadAATfont(fontRef, scaled_size, featString);
+ }
+#endif
+
+ /* append the style and feature strings, so that \show\fontID will give a full result */
+ if (varString != NULL && *varString != 0) {
+ strcat((char*)nameoffile + 1, "/");
+ strcat((char*)nameoffile + 1, varString);
+ }
+ if (featString != NULL && *featString != 0) {
+ strcat((char*)nameoffile + 1, ":");
+ strcat((char*)nameoffile + 1, featString);
+ }
+ namelength = strlen((char*)nameoffile + 1);
+ }
+
+ if (varString != NULL)
+ free(varString);
+
+ if (featString != NULL)
+ free(featString);
+
+ free(nameString);
+
+ return rval;
+}
+
+void
+releasefontengine(void* engine, int type_flag)
+{
+#ifdef XETEX_MAC
+ if (type_flag == AAT_FONT_FLAG) {
+ ATSUDisposeStyle((ATSUStyle)engine);
+ }
+ else
+#endif
+ if (type_flag == OT_FONT_FLAG) {
+ deleteLayoutEngine((XeTeXLayoutEngine)engine);
+ }
+}
+
+/* params are given as 'integer' in the header file, but are really TeX scaled integers */
+void
+otgetfontmetrics(void* pEngine, scaled* ascent, scaled* descent, scaled* xheight, scaled* capheight, scaled* slant)
+{
+ XeTeXLayoutEngine engine = (XeTeXLayoutEngine)pEngine;
+ long rval = 0;
+ float a, d;
+ int glyphID;
+
+ getAscentAndDescent(engine, &a, &d);
+ *ascent = X2Fix(a);
+ *descent = X2Fix(d);
+
+ *slant = getSlant(getFont(engine));
+
+ glyphID = mapCharToGlyph(engine, 'x');
+ if (glyphID != 0) {
+ getGlyphHeightDepth(engine, glyphID, &a, &d);
+ *xheight = X2Fix(a);
+ }
+ else
+ *xheight = *ascent / 2; /* arbitrary figure if there's no 'x' in the font */
+
+ glyphID = mapCharToGlyph(engine, 'X');
+ if (glyphID != 0) {
+ getGlyphHeightDepth(engine, glyphID, &a, &d);
+ *capheight = X2Fix(a);
+ }
+ else
+ *capheight = *ascent; /* arbitrary figure if there's no 'X' in the font */
+}
+
+long
+otfontget(int what, void* pEngine)
+{
+ XeTeXLayoutEngine engine = (XeTeXLayoutEngine)pEngine;
+ XeTeXFont fontInst = getFont(engine);
+ switch (what) {
+ case XeTeX_count_glyphs:
+ return countGlyphs(fontInst);
+ break;
+
+ case XeTeX_OT_count_scripts:
+ return countScripts(fontInst);
+ break;
+ }
+ return 0;
+}
+
+
+long
+otfontget1(int what, void* pEngine, long param)
+{
+ XeTeXLayoutEngine engine = (XeTeXLayoutEngine)pEngine;
+ XeTeXFont fontInst = getFont(engine);
+ switch (what) {
+ case XeTeX_OT_count_languages:
+ return countScriptLanguages(fontInst, param);
+ break;
+
+ case XeTeX_OT_script_code:
+ return getIndScript(fontInst, param);
+ break;
+ }
+ return 0;
+}
+
+
+long
+otfontget2(int what, void* pEngine, long param1, long param2)
+{
+ XeTeXLayoutEngine engine = (XeTeXLayoutEngine)pEngine;
+ XeTeXFont fontInst = getFont(engine);
+ switch (what) {
+ case XeTeX_OT_language_code:
+ return getIndScriptLanguage(fontInst, param1, param2);
+ break;
+
+ case XeTeX_OT_count_features:
+ return countFeatures(fontInst, param1, param2);
+ break;
+ }
+
+ return 0;
+}
+
+
+long
+otfontget3(int what, void* pEngine, long param1, long param2, long param3)
+{
+ XeTeXLayoutEngine engine = (XeTeXLayoutEngine)pEngine;
+ XeTeXFont fontInst = getFont(engine);
+ switch (what) {
+ case XeTeX_OT_feature_code:
+ return getIndFeature(fontInst, param1, param2, param3);
+ break;
+ }
+
+ return 0;
+}
+
+#define XDV_FLAG_FONTTYPE_ATSUI 0x0001
+#define XDV_FLAG_FONTTYPE_ICU 0x0002
+
+#define XDV_FLAG_VERTICAL 0x0100
+#define XDV_FLAG_COLORED 0x0200
+#define XDV_FLAG_FEATURES 0x0400
+#define XDV_FLAG_VARIATIONS 0x0800
+
+#ifdef XETEX_MAC
+static UInt32
+atsuColorToRGBA32(ATSURGBAlphaColor a)
+{
+ UInt32 rval = (UInt8)(a.red * 255.0 + 0.5);
+ rval <<= 8;
+ rval += (UInt8)(a.green * 255.0 + 0.5);
+ rval <<= 8;
+ rval += (UInt8)(a.blue * 255.0 + 0.5);
+ rval <<= 8;
+ rval += (UInt8)(a.alpha * 255.0 + 0.5);
+ return rval;
+}
+#endif
+
+static int xdvBufSize = 0;
+
+int
+makeXDVGlyphArrayData(void* pNode)
+{
+ unsigned char* cp;
+ UInt16* glyphIDs;
+ memoryword* p = pNode;
+ void* glyph_info;
+ FixedPoint* locations;
+ int opcode;
+ Fixed wid;
+ UInt16 glyphCount = native_glyph_count(p);
+
+ int i = glyphCount * native_glyph_info_size + 8; /* to guarantee enough space in the buffer */
+ if (i > xdvBufSize) {
+ if (xdvbuffer != NULL)
+ free(xdvbuffer);
+ xdvBufSize = ((i / 1024) + 1) * 1024;
+ xdvbuffer = (char*)xmalloc(xdvBufSize);
+ }
+
+ glyph_info = (void*)native_glyph_info_ptr(p);
+ locations = (FixedPoint*)glyph_info;
+ glyphIDs = (UInt16*)(locations + glyphCount);
+
+ opcode = XDV_GLYPH_STRING;
+ for (i = 0; i < glyphCount; ++i)
+ if (locations[i].y != 0) {
+ opcode = XDV_GLYPH_ARRAY;
+ break;
+ }
+
+ cp = (unsigned char*)xdvbuffer;
+ *cp++ = opcode;
+
+ wid = node_width(p);
+ *cp++ = (wid >> 24) & 0xff;
+ *cp++ = (wid >> 16) & 0xff;
+ *cp++ = (wid >> 8) & 0xff;
+ *cp++ = wid & 0xff;
+
+ *cp++ = (glyphCount >> 8) & 0xff;
+ *cp++ = glyphCount & 0xff;
+
+ for (i = 0; i < glyphCount; ++i) {
+ Fixed x = locations[i].x;
+ *cp++ = (x >> 24) & 0xff;
+ *cp++ = (x >> 16) & 0xff;
+ *cp++ = (x >> 8) & 0xff;
+ *cp++ = x & 0xff;
+ if (opcode == XDV_GLYPH_ARRAY) {
+ Fixed y = locations[i].y;
+ *cp++ = (y >> 24) & 0xff;
+ *cp++ = (y >> 16) & 0xff;
+ *cp++ = (y >> 8) & 0xff;
+ *cp++ = y & 0xff;
+ }
+ }
+
+ for (i = 0; i < glyphCount; ++i) {
+ UInt16 g = glyphIDs[i];
+ *cp++ = (g >> 8) & 0xff;
+ *cp++ = g & 0xff;
+ }
+
+ return ((char*)cp - xdvbuffer);
+}
+
+long
+makefontdef(long f)
+{
+ PlatformFontRef fontRef;
+
+ UInt16 flags = 0;
+ UInt32 variationCount = 0;
+ UInt32 rgba;
+ Fixed size;
+ const char* psName;
+ const char* famName;
+ const char* styName;
+ UInt8 psLen;
+ UInt8 famLen;
+ UInt8 styLen;
+ int fontDefLength;
+ char* cp;
+
+#ifdef XETEX_MAC
+ ATSUStyle style = NULL;
+ if (fontarea[f] == AAT_FONT_FLAG) {
+ flags = XDV_FLAG_FONTTYPE_ATSUI;
+
+ style = (ATSUStyle)fontlayoutengine[f];
+ ATSUGetAllFontVariations(style, 0, 0, 0, &variationCount);
+
+ ATSUFontID fontID;
+ ATSUGetAttribute(style, kATSUFontTag, sizeof(ATSUFontID), &fontID, 0);
+
+ fontRef = FMGetATSFontRefFromFont(fontID);
+
+ ATSUVerticalCharacterType vert;
+ ATSUGetAttribute(style, kATSUVerticalCharacterTag, sizeof(ATSUVerticalCharacterType), &vert, 0);
+ if (vert == kATSUStronglyVertical)
+ flags |= XDV_FLAG_VERTICAL;
+
+ ATSURGBAlphaColor atsuColor;
+ ATSUGetAttribute(style, kATSURGBAlphaColorTag, sizeof(ATSURGBAlphaColor), &atsuColor, 0);
+ rgba = atsuColorToRGBA32(atsuColor);
+
+ ATSUGetAttribute(style, kATSUSizeTag, sizeof(Fixed), &size, 0);
+ }
+ else
+#endif
+ if (fontarea[f] == OT_FONT_FLAG) {
+ XeTeXLayoutEngine engine;
+ flags = XDV_FLAG_FONTTYPE_ICU;
+
+ engine = (XeTeXLayoutEngine)fontlayoutengine[f];
+ fontRef = getFontRef(engine);
+
+ rgba = getRgbValue(engine);
+ if ((fontflags[f] & FONT_FLAGS_VERTICAL) != 0)
+ flags |= XDV_FLAG_VERTICAL;
+
+ size = X2Fix(getPointSize(engine));
+ }
+ else {
+ fprintf(stderr, "\n! Internal error: bad native font flag\n");
+ exit(3);
+ }
+
+ getNames(fontRef, &psName, &famName, &styName);
+ /* returns ptrs to strings that belong to the font - do not free! */
+
+ psLen = strlen(psName);
+ famLen = strlen(famName);
+ styLen = strlen(styName);
+
+ /* parameters after internal font ID:
+ // size[4]
+ // flags[2]
+ // lp[1] lf[1] ls[1] ps[lp] fam[lf] sty[ls]
+ // if flags & COLORED:
+ // c[4]
+ // if flags & VARIATIONS:
+ // nv[2]
+ // a[4nv]
+ // v[4nv]
+ */
+
+ fontDefLength
+ = 4 /* size */
+ + 2 /* flags */
+ + 3 /* name length */
+ + psLen + famLen + styLen;
+
+ if ((fontflags[f] & FONT_FLAGS_COLORED) != 0) {
+ fontDefLength += 4; /* 32-bit RGBA value */
+ flags |= XDV_FLAG_COLORED;
+ }
+
+#ifdef XETEX_MAC
+ if (variationCount > 0) {
+ fontDefLength +=
+ 2 /* number of variations */
+ + 4 * variationCount
+ + 4 * variationCount; /* axes and values */
+ flags |= XDV_FLAG_VARIATIONS;
+ }
+#endif
+
+ if (fontDefLength > xdvBufSize) {
+ if (xdvbuffer != NULL)
+ free(xdvbuffer);
+ xdvBufSize = ((fontDefLength / 1024) + 1) * 1024;
+ xdvbuffer = (char*)xmalloc(xdvBufSize);
+ }
+ cp = xdvbuffer;
+
+ *(Fixed*)cp = SWAP32(size);
+ cp += 4;
+
+ *(UInt16*)cp = SWAP16(flags);
+ cp += 2;
+
+ *(UInt8*)cp = psLen;
+ cp += 1;
+ *(UInt8*)cp = famLen;
+ cp += 1;
+ *(UInt8*)cp = styLen;
+ cp += 1;
+ memcpy(cp, psName, psLen);
+ cp += psLen;
+ memcpy(cp, famName, famLen);
+ cp += famLen;
+ memcpy(cp, styName, styLen);
+ cp += styLen;
+
+ if ((fontflags[f] & FONT_FLAGS_COLORED) != 0) {
+ *(UInt32*)cp = SWAP32(rgba);
+ cp += 4;
+ }
+
+#ifdef XETEX_MAC
+ if (variationCount > 0) {
+ *(UInt16*)cp = SWAP16(variationCount);
+ cp += 2;
+ if (variationCount > 0) {
+ ATSUGetAllFontVariations(style, variationCount,
+ (UInt32*)(cp),
+ (SInt32*)(cp + 4 * variationCount),
+ 0);
+ while (variationCount > 0) {
+ /* (potentially) swap two 32-bit values per variation setting,
+ and advance cp past them all */
+ *(UInt32*)(cp) = SWAP32(*(UInt32*)(cp));
+ cp += 4;
+ *(UInt32*)(cp) = SWAP32(*(UInt32*)(cp));
+ cp += 4;
+ --variationCount;
+ }
+ }
+ }
+#endif
+
+ return fontDefLength;
+}
+
+int
+applymapping(void* pCnv, const UniChar* txtPtr, int txtLen)
+{
+ TECkit_Converter cnv = (TECkit_Converter)pCnv;
+ UInt32 inUsed, outUsed;
+ TECkit_Status status;
+ static UInt32 outLength = 0;
+
+ /* allocate outBuffer if not big enough */
+ if (outLength < txtLen * sizeof(UniChar) + 32) {
+ if (mappedtext != 0)
+ free(mappedtext);
+ outLength = txtLen * sizeof(UniChar) + 32;
+ mappedtext = xmalloc(outLength);
+ }
+
+ /* try the mapping */
+retry:
+ status = TECkit_ConvertBuffer(cnv,
+ (Byte*)txtPtr, txtLen * sizeof(UniChar), &inUsed,
+ (Byte*)mappedtext, outLength, &outUsed, true);
+
+ switch (status) {
+ case kStatus_NoError:
+ txtPtr = (const UniChar*)mappedtext;
+ return outUsed / sizeof(UniChar);
+
+ case kStatus_OutputBufferFull:
+ outLength += (txtLen * sizeof(UniChar)) + 32;
+ free(mappedtext);
+ mappedtext = xmalloc(outLength);
+ goto retry;
+
+ default:
+ return 0;
+ }
+}
+
+static void
+snap_zone(scaled* value, scaled snap_value, scaled fuzz)
+{
+ scaled difference = *value - snap_value;
+ if (difference <= fuzz && difference >= -fuzz)
+ *value = snap_value;
+}
+
+void
+getnativecharheightdepth(int font, int ch, scaled* height, scaled* depth)
+{
+#define QUAD(f) fontinfo[6+parambase[f]].cint
+#define X_HEIGHT(f) fontinfo[5+parambase[f]].cint
+#define CAP_HEIGHT(f) fontinfo[8+parambase[f]].cint
+
+ float ht = 0.0;
+ float dp = 0.0;
+ Fixed fuzz;
+
+#ifdef XETEX_MAC
+ if (fontarea[font] == AAT_FONT_FLAG) {
+ ATSUStyle style = (ATSUStyle)(fontlayoutengine[font]);
+ int gid = MapCharToGlyph_AAT(style, ch);
+ GetGlyphHeightDepth_AAT(style, gid, &ht, &dp);
+ }
+ else
+#endif
+ if (fontarea[font] == OT_FONT_FLAG) {
+ XeTeXLayoutEngine engine = (XeTeXLayoutEngine)fontlayoutengine[font];
+ int gid = mapCharToGlyph(engine, ch);
+ getGlyphHeightDepth(engine, gid, &ht, &dp);
+ }
+ else {
+ fprintf(stderr, "\n! Internal error: bad native font flag\n");
+ exit(3);
+ }
+
+ *height = X2Fix(ht);
+ *depth = X2Fix(dp);
+
+ /* snap to "known" zones for baseline, x-height, cap-height if within 4% of em-size */
+ fuzz = QUAD(font) / 25;
+ snap_zone(depth, 0, fuzz);
+ snap_zone(height, 0, fuzz);
+ snap_zone(height, X_HEIGHT(font), fuzz);
+ snap_zone(height, CAP_HEIGHT(font), fuzz);
+}
+
+scaled
+getnativecharht(int f, int c)
+{
+ scaled h, d;
+ getnativecharheightdepth(f, c, &h, &d);
+ return h;
+}
+
+scaled
+getnativechardp(int f, int c)
+{
+ scaled h, d;
+ getnativecharheightdepth(f, c, &h, &d);
+ return d;
+}
+
+void
+getnativecharsidebearings(int font, int ch, scaled* lsb, scaled* rsb)
+{
+ float l, r;
+
+#ifdef XETEX_MAC
+ if (fontarea[font] == AAT_FONT_FLAG) {
+ ATSUStyle style = (ATSUStyle)(fontlayoutengine[font]);
+ int gid = MapCharToGlyph_AAT(style, ch);
+ GetGlyphSidebearings_AAT(style, gid, &l, &r);
+ }
+ else
+#endif
+ if (fontarea[font] == OT_FONT_FLAG) {
+ XeTeXLayoutEngine engine = (XeTeXLayoutEngine)fontlayoutengine[font];
+ int gid = mapCharToGlyph(engine, ch);
+ getGlyphSidebearings(engine, gid, &l, &r);
+ }
+ else {
+ fprintf(stderr, "\n! Internal error: bad native font flag\n");
+ exit(3);
+ }
+
+ *lsb = X2Fix(l);
+ *rsb = X2Fix(r);
+}
+
+scaled
+getnativecharic(int f, int c)
+{
+ scaled lsb, rsb;
+ getnativecharsidebearings(f, c, &lsb, &rsb);
+ if (rsb < 0)
+ return fontletterspace[f] - rsb;
+ else
+ return fontletterspace[f];
+}
+
+scaled
+getnativecharwd(int f, int c)
+{
+ scaled wd = 0;
+#ifdef XETEX_MAC
+ if (fontarea[f] == AAT_FONT_FLAG) {
+ ATSUStyle style = (ATSUStyle)(fontlayoutengine[f]);
+ int gid = MapCharToGlyph_AAT(style, c);
+ wd = X2Fix(GetGlyphWidth_AAT(style, gid));
+ }
+ else
+#endif
+ if (fontarea[f] == OT_FONT_FLAG) {
+ XeTeXLayoutEngine engine = (XeTeXLayoutEngine)fontlayoutengine[f];
+ int gid = mapCharToGlyph(engine, c);
+ wd = X2Fix(getGlyphWidthFromEngine(engine, gid));
+ }
+ else {
+ fprintf(stderr, "\n! Internal error: bad native font flag\n");
+ exit(3);
+ }
+ return wd;
+}
+
+void
+store_justified_native_glyphs(void* node)
+{
+#ifdef XETEX_MAC /* this is only called for fonts used via ATSUI */
+ (void)DoAtsuiLayout(node, 1);
+#endif
+}
+
+void
+measure_native_node(void* pNode, int use_glyph_metrics)
+{
+ memoryword* node = (memoryword*)pNode;
+ int txtLen = native_length(node);
+ const UniChar* txtPtr = (UniChar*)(node + native_node_size);
+
+ unsigned f = native_font(node);
+
+#ifdef XETEX_MAC
+ if (fontarea[f] == AAT_FONT_FLAG) {
+ /* we're using this font in AAT mode, so fontlayoutengine[f] is actually an ATSUStyle */
+ DoAtsuiLayout(node, 0);
+ }
+ else
+#endif
+ if (fontarea[f] == OT_FONT_FLAG) {
+ /* using this font in OT Layout mode, so fontlayoutengine[f] is actually a XeTeXLayoutEngine */
+
+ 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 long 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);
+
+ 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), x, y, &status);
+
+ 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]);
+ locations[realGlyphCount].y = X2Fix(positions[2*i+1]);
+ ++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) = (long)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) {
+ 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;
+
+ 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];
+ locations[realGlyphCount].x = X2Fix(positions[2*i]);
+ locations[realGlyphCount].y = X2Fix(positions[2*i+1]);
+ ++realGlyphCount;
+ }
+ }
+ }
+
+ native_glyph_count(node) = realGlyphCount;
+ native_glyph_info_ptr(node) = (long)glyph_info;
+ }
+
+ ubidi_close(pBiDi);
+
+ if (fontletterspace[f] != 0) {
+ Fixed lsDelta = 0;
+ Fixed lsUnit = fontletterspace[f];
+ int i;
+ for (i = 0; i < realGlyphCount; ++i) {
+ if (getGlyphWidth(getFont(engine), glyphIDs[i]) == 0 && lsDelta != 0)
+ lsDelta -= lsUnit;
+ locations[i].x += lsDelta;
+ lsDelta += lsUnit;
+ }
+ if (lsDelta != 0) {
+ lsDelta -= lsUnit;
+ node_width(node) += lsDelta;
+ }
+ }
+ }
+ else {
+ fprintf(stderr, "\n! Internal error: bad native font flag\n");
+ exit(3);
+ }
+
+ if (use_glyph_metrics == 0 || native_glyph_count(node) == 0) {
+ /* for efficiency, height and depth are the font's ascent/descent,
+ not true values based on the actual content of the word,
+ unless use_glyph_metrics is non-zero */
+ node_height(node) = heightbase[f];
+ node_depth(node) = depthbase[f];
+ }
+ else {
+ /* this iterates over the glyph data whether it comes from ATSUI or ICU layout */
+ FixedPoint* locations = (FixedPoint*)native_glyph_info_ptr(node);
+ UInt16* glyphIDs = (UInt16*)(locations + native_glyph_count(node));
+ float yMin = 65536.0;
+ float yMax = -65536.0;
+ int i;
+ for (i = 0; i < native_glyph_count(node); ++i) {
+ float ht, dp;
+ float y = Fix2X(-locations[i].y); /* NB negative is upwards in locations[].y! */
+
+ GlyphBBox bbox;
+ if (getCachedGlyphBBox(f, glyphIDs[i], &bbox) == 0) {
+#ifdef XETEX_MAC
+ if (fontarea[f] == AAT_FONT_FLAG)
+ GetGlyphBBox_AAT((ATSUStyle)(fontlayoutengine[f]), glyphIDs[i], &bbox);
+ else
+#endif
+ if (fontarea[f] == OT_FONT_FLAG)
+ getGlyphBounds((XeTeXLayoutEngine)(fontlayoutengine[f]), glyphIDs[i], &bbox);
+
+ cacheGlyphBBox(f, glyphIDs[i], &bbox);
+ }
+
+ ht = bbox.yMax;
+ dp = -bbox.yMin;
+
+ if (y + ht > yMax)
+ yMax = y + ht;
+ if (y - dp < yMin)
+ yMin = y - dp;
+ }
+ node_height(node) = X2Fix(yMax);
+ node_depth(node) = -X2Fix(yMin);
+ }
+}
+
+Fixed
+get_native_ital_corr(void* pNode)
+{
+ memoryword* node = pNode;
+ unsigned f = native_font(node);
+ unsigned n = native_glyph_count(node);
+ if (n > 0) {
+ FixedPoint* locations = (FixedPoint*)native_glyph_info_ptr(node);
+ UInt16* glyphIDs = (UInt16*)(locations + n);
+
+#ifdef XETEX_MAC
+ if (fontarea[f] == AAT_FONT_FLAG)
+ return X2Fix(GetGlyphItalCorr_AAT((ATSUStyle)(fontlayoutengine[f]), glyphIDs[n-1]))
+ + fontletterspace[f];
+#endif
+ if (fontarea[f] == OT_FONT_FLAG)
+ return X2Fix(getGlyphItalCorr((XeTeXLayoutEngine)(fontlayoutengine[f]), glyphIDs[n-1]))
+ + fontletterspace[f];
+ }
+
+ return 0;
+}
+
+
+Fixed
+get_native_glyph_ital_corr(void* pNode)
+{
+ memoryword* node = pNode;
+ UInt16 gid = native_glyph(node);
+ unsigned f = native_font(node);
+
+#ifdef XETEX_MAC
+ if (fontarea[f] == AAT_FONT_FLAG)
+ return X2Fix(GetGlyphItalCorr_AAT((ATSUStyle)(fontlayoutengine[f]), gid));
+#endif
+ if (fontarea[f] == OT_FONT_FLAG)
+ return X2Fix(getGlyphItalCorr((XeTeXLayoutEngine)(fontlayoutengine[f]), gid));
+
+ return 0; /* can't actually happen */
+}
+
+void
+measure_native_glyph(void* pNode, int use_glyph_metrics)
+{
+ memoryword* node = pNode;
+ UInt16 gid = native_glyph(node);
+ unsigned f = native_font(node);
+
+ float ht = 0.0;
+ float dp = 0.0;
+
+#ifdef XETEX_MAC
+ if (fontarea[f] == AAT_FONT_FLAG) {
+ ATSUStyle style = (ATSUStyle)(fontlayoutengine[f]);
+ ATSGlyphIdealMetrics metrics;
+ OSStatus status = ATSUGlyphGetIdealMetrics(style, 1, &gid, 0, &metrics);
+ /* returns values in Quartz points, so we need to convert to TeX points */
+ node_width(node) = X2Fix(metrics.advance.x * 72.27 / 72.0);
+ if (use_glyph_metrics)
+ GetGlyphHeightDepth_AAT(style, gid, &ht, &dp);
+ }
+ else
+#endif
+ if (fontarea[f] == OT_FONT_FLAG) {
+ XeTeXLayoutEngine engine = (XeTeXLayoutEngine)fontlayoutengine[f];
+ XeTeXFont fontInst = getFont(engine);
+ node_width(node) = X2Fix(getGlyphWidth(fontInst, gid));
+ if (use_glyph_metrics)
+ getGlyphHeightDepth(engine, gid, &ht, &dp);
+ }
+ else {
+ fprintf(stderr, "\n! Internal error: bad native font flag\n");
+ exit(3);
+ }
+
+ if (use_glyph_metrics) {
+ node_height(node) = X2Fix(ht);
+ node_depth(node) = X2Fix(dp);
+ }
+ else {
+ node_height(node) = heightbase[f];
+ node_depth(node) = depthbase[f];
+ }
+}
+
+int
+mapchartoglyph(int font, unsigned int ch)
+{
+ if (ch > 0x10ffff || ((ch >= 0xd800) && (ch <= 0xdfff)))
+ return 0;
+#ifdef XETEX_MAC
+ if (fontarea[font] == AAT_FONT_FLAG)
+ return MapCharToGlyph_AAT((ATSUStyle)(fontlayoutengine[font]), ch);
+ else
+#endif
+ if (fontarea[font] == OT_FONT_FLAG)
+ return mapCharToGlyph((XeTeXLayoutEngine)(fontlayoutengine[font]), ch);
+ else {
+ fprintf(stderr, "\n! Internal error: bad native font flag\n");
+ exit(3);
+ }
+}
+
+int
+mapglyphtoindex(int font)
+ /* glyph name is at nameoffile+1 */
+{
+#ifdef XETEX_MAC
+ if (fontarea[font] == AAT_FONT_FLAG)
+ return MapGlyphToIndex_AAT((ATSUStyle)(fontlayoutengine[font]), (const char*)nameoffile + 1);
+ else
+#endif
+ if (fontarea[font] == OT_FONT_FLAG)
+ return mapGlyphToIndex((XeTeXLayoutEngine)(fontlayoutengine[font]), (const char*)nameoffile + 1);
+ else {
+ fprintf(stderr, "\n! Internal error: bad native font flag\n");
+ exit(3);
+ }
+}
+
+#ifndef XETEX_MAC
+Fixed X2Fix(double d)
+{
+ Fixed rval = (int)(d * 65536.0 + 0.5);
+ return rval;
+}
+
+double Fix2X(Fixed f)
+{
+ double rval = f / 65536.0;
+ return rval;
+}
+#endif
+
+/* these are here, not XeTeX_mac.c, because we need stubs on other platforms */
+#ifndef XETEX_MAC
+typedef void* ATSUStyle; /* dummy declaration just so the stubs can compile */
+#endif
+
+void
+atsugetfontmetrics(ATSUStyle style, Fixed* ascent, Fixed* descent, Fixed* xheight, Fixed* capheight, Fixed* slant)
+{
+#ifdef XETEX_MAC
+ *ascent = *descent = *xheight = *capheight = *slant = 0;
+
+ ATSUFontID fontID;
+ OSStatus status = ATSUGetAttribute(style, kATSUFontTag, sizeof(ATSUFontID), &fontID, 0);
+ if (status != noErr)
+ return;
+
+ ATSFontRef fontRef = FMGetATSFontRefFromFont(fontID);
+
+ Fixed size;
+ status = ATSUGetAttribute(style, kATSUSizeTag, sizeof(Fixed), &size, 0);
+ if (status != noErr)
+ return;
+ /* size from the ATSUStyle is in Quartz points; convert to TeX points here */
+ double floatSize = Fix2X(size) * 72.27 / 72.0;
+
+ ATSFontMetrics metrics;
+ status = ATSFontGetHorizontalMetrics(fontRef, kATSOptionFlagsDefault, &metrics);
+ if (status != noErr)
+ return;
+
+ *ascent = X2Fix(metrics.ascent * floatSize);
+ *descent = X2Fix(metrics.descent * floatSize);
+
+ if (metrics.italicAngle != 0.0) {
+ if (fabs(metrics.italicAngle) < 0.090)
+ metrics.italicAngle *= 1000.0; /* hack around apparent ATS bug */
+ *slant = X2Fix(tan(-metrics.italicAngle * M_PI / 180.0));
+ }
+ else {
+ /* try to get a (possibly synthetic) POST table, as ATSFontGetHorizontalMetrics
+ doesn't seem to return this value for OT/CFF fonts */
+ ByteCount tableSize;
+ if (ATSFontGetTable(fontRef, LE_POST_TABLE_TAG, 0, 0, 0, &tableSize) == noErr) {
+ POSTTable* post = xmalloc(tableSize);
+ ATSFontGetTable(fontRef, LE_POST_TABLE_TAG, 0, tableSize, post, 0);
+ *slant = X2Fix(tan(Fix2X( - SWAP32(post->italicAngle)) * M_PI / 180.0));
+ free(post);
+ }
+ }
+
+ 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);
+ *capheight = X2Fix(metrics.capHeight * floatSize);
+ }
+ else {
+ int glyphID = MapCharToGlyph_AAT(style, 'x');
+ float ht, dp;
+ if (glyphID != 0) {
+ GetGlyphHeightDepth_AAT(style, glyphID, &ht, &dp);
+ *xheight = X2Fix(ht);
+ }
+ else
+ *xheight = *ascent / 2; /* arbitrary figure if there's no 'x' in the font */
+
+ glyphID = MapCharToGlyph_AAT(style, 'X');
+ if (glyphID != 0) {
+ GetGlyphHeightDepth_AAT(style, glyphID, &ht, &dp);
+ *capheight = X2Fix(ht);
+ }
+ else
+ *capheight = *ascent; /* arbitrary figure if there's no 'X' in the font */
+ }
+#endif
+}
+
+long
+atsufontget(int what, ATSUStyle style)
+{
+ long rval = -1;
+
+#ifdef XETEX_MAC
+ ATSUFontID fontID;
+ ATSUGetAttribute(style, kATSUFontTag, sizeof(ATSUFontID), &fontID, 0);
+ ItemCount count;
+
+ switch (what) {
+ case XeTeX_count_glyphs:
+ {
+ ByteCount tableSize;
+ ATSFontRef fontRef = FMGetATSFontRefFromFont(fontID);
+ if (ATSFontGetTable(fontRef, LE_MAXP_TABLE_TAG, 0, 0, 0, &tableSize) == noErr) {
+ MAXPTable* table = xmalloc(tableSize);
+ ATSFontGetTable(fontRef, LE_MAXP_TABLE_TAG, 0, tableSize, table, 0);
+ rval = SWAP16(table->numGlyphs);
+ free(table);
+ }
+ }
+ break;
+
+ case XeTeX_count_variations:
+ if (ATSUCountFontVariations(fontID, &count) == noErr)
+ rval = count;
+ break;
+
+ case XeTeX_count_features:
+ if (ATSUCountFontFeatureTypes(fontID, &count) == noErr)
+ rval = count;
+ break;
+ }
+#endif
+ return rval;
+}
+
+long
+atsufontget1(int what, ATSUStyle style, int param)
+{
+ long rval = -1;
+
+#ifdef XETEX_MAC
+ ATSUFontID fontID;
+ ATSUGetAttribute(style, kATSUFontTag, sizeof(ATSUFontID), &fontID, 0);
+
+ ATSUFontVariationAxis axis;
+ ATSUFontVariationValue value;
+ ItemCount count;
+ Boolean exclusive;
+ switch (what) {
+ case XeTeX_variation:
+ if (ATSUGetIndFontVariation(fontID, param, &axis, 0, 0, 0) == noErr)
+ rval = axis;
+ break;
+
+ case XeTeX_variation_min:
+ case XeTeX_variation_max:
+ case XeTeX_variation_default:
+ if (ATSUCountFontVariations(fontID, &count) == noErr)
+ while (count-- > 0)
+ if (ATSUGetIndFontVariation(fontID, count, &axis,
+ (what == XeTeX_variation_min) ? &value : 0,
+ (what == XeTeX_variation_max) ? &value : 0,
+ (what == XeTeX_variation_default) ? &value : 0) == noErr)
+ if (axis == param) {
+ rval = value;
+ break;
+ }
+ break;
+
+ case XeTeX_feature_code:
+ if (ATSUCountFontFeatureTypes(fontID, &count) == noErr) {
+ if (param < count) {
+ ATSUFontFeatureType* types = xmalloc(count * sizeof(ATSUFontFeatureType));
+ if (ATSUGetFontFeatureTypes(fontID, count, types, 0) == noErr)
+ rval = types[param];
+ free(types);
+ }
+ }
+ break;
+
+ case XeTeX_is_exclusive_feature:
+ if (ATSUGetFontFeatureSelectors(fontID, param, 0, 0, 0, 0, &exclusive) == noErr)
+ rval = exclusive ? 1 : 0;
+ break;
+
+ case XeTeX_count_selectors:
+ if (ATSUCountFontFeatureSelectors(fontID, param, &count) == noErr)
+ rval = count;
+ break;
+ }
+#endif
+
+ return rval;
+}
+
+long
+atsufontget2(int what, ATSUStyle style, int param1, int param2)
+{
+ long rval = -1;
+
+#ifdef XETEX_MAC
+ ATSUFontID fontID;
+ ATSUGetAttribute(style, kATSUFontTag, sizeof(ATSUFontID), &fontID, 0);
+
+ ItemCount count;
+ if (ATSUCountFontFeatureSelectors(fontID, param1, &count) == noErr) {
+ ATSUFontFeatureSelector* selectors = xmalloc(count * sizeof(ATSUFontFeatureSelector));
+ Boolean* isDefault = xmalloc(count * sizeof(Boolean));
+ if (ATSUGetFontFeatureSelectors(fontID, param1, count, selectors, isDefault, 0, 0) == noErr) {
+ switch (what) {
+ case XeTeX_selector_code:
+ if (param2 < count)
+ rval = selectors[param2];
+ break;
+
+ case XeTeX_is_default_selector:
+ while (count-- > 0)
+ if (selectors[count] == param2) {
+ rval = isDefault[count] ? 1 : 0;
+ break;
+ }
+ break;
+ }
+ }
+ free(isDefault);
+ free(selectors);
+ }
+#endif
+
+ return rval;
+}
+
+long
+atsufontgetnamed(int what, ATSUStyle style)
+{
+ long rval = -1;
+
+#ifdef XETEX_MAC
+ ATSUFontID fontID;
+ ATSUGetAttribute(style, kATSUFontTag, sizeof(ATSUFontID), &fontID, 0);
+
+ switch (what) {
+ case XeTeX_find_variation_by_name:
+ rval = find_axis_by_name(fontID, nameoffile + 1, namelength);
+ if (rval == 0)
+ rval = -1;
+ break;
+
+ case XeTeX_find_feature_by_name:
+ rval = find_feature_by_name(fontID, nameoffile + 1, namelength);
+ if (rval == 0x0000FFFF)
+ rval = -1;
+ break;
+ }
+#endif
+
+ return rval;
+}
+
+long
+atsufontgetnamed1(int what, ATSUStyle style, int param)
+{
+ long rval = -1;
+
+#ifdef XETEX_MAC
+ ATSUFontID fontID;
+ ATSUGetAttribute(style, kATSUFontTag, sizeof(ATSUFontID), &fontID, 0);
+
+ switch (what) {
+ case XeTeX_find_selector_by_name:
+ rval = find_selector_by_name(fontID, param, nameoffile + 1, namelength);
+ if (rval == 0x0000FFFF)
+ rval = -1;
+ break;
+ }
+#endif
+
+ return rval;
+}
+
+void
+atsuprintfontname(int what, ATSUStyle style, int param1, int param2)
+{
+#ifdef XETEX_MAC
+ ATSUFontID fontID;
+ ATSUGetAttribute(style, kATSUFontTag, sizeof(ATSUFontID), &fontID, 0);
+
+ FontNameCode code;
+ OSStatus status = -1;
+ ItemCount count, i;
+ Boolean found = 0;
+
+ switch (what) {
+ case XeTeX_variation_name:
+ status = ATSUCountFontVariations(fontID, &count);
+ if (status == noErr) {
+ for (i = 0; i < count; ++i) {
+ ATSUFontVariationAxis axis;
+ ATSUFontVariationValue min, max, def;
+ status = ATSUGetIndFontVariation(fontID, i, &axis, &min, &max, &def);
+ if (status == noErr && axis == param1) {
+ status = ATSUGetFontVariationNameCode(fontID, param1, &code);
+ found = 1;
+ break;
+ }
+ }
+ }
+ break;
+
+ case XeTeX_feature_name:
+ case XeTeX_selector_name:
+ status = ATSUCountFontFeatureTypes(fontID, &count);
+ if (status == noErr) {
+ ATSUFontFeatureType* features = xmalloc(count * sizeof(ATSUFontFeatureType));
+ status = ATSUGetFontFeatureTypes(fontID, count, features, &count);
+ if (status == noErr) {
+ for (i = 0; i < count; ++i) {
+ if (features[i] == param1) {
+ /* the requested feature code is valid */
+ if (what == XeTeX_feature_name) {
+ status = ATSUGetFontFeatureNameCode(fontID, param1, kATSUNoSelector, &code);
+ found = 1;
+ }
+ else {
+ status = ATSUCountFontFeatureSelectors(fontID, param1, &count);
+ if (status == noErr) {
+ ATSUFontFeatureSelector* selectors = xmalloc(count * sizeof(ATSUFontFeatureSelector));
+ Boolean* onByDefault = xmalloc(count * sizeof(Boolean));
+ Boolean exclusive;
+ status = ATSUGetFontFeatureSelectors(fontID, param1, count, selectors, onByDefault, &count, &exclusive);
+ if (status == noErr) {
+ for (i = 0; i < count; ++i) {
+ if (selectors[i] == param2) {
+ /* feature/selector combination is valid */
+ status = ATSUGetFontFeatureNameCode(fontID, param1, param2, &code);
+ found = 1;
+ break;
+ }
+ }
+ }
+ free(onByDefault);
+ free(selectors);
+ }
+ }
+ break;
+ }
+ }
+ }
+ free(features);
+ }
+ break;
+ }
+
+ if (found && status == noErr) {
+#define NAME_BUF_SIZE 1024
+ ByteCount len = 0;
+ char name[NAME_BUF_SIZE]; /* should be more than enough for any sensible font name */
+ do {
+ if (ATSUFindFontName(fontID, code, kFontMacintoshPlatform, kFontRomanScript, kFontEnglishLanguage, NAME_BUF_SIZE, name, &len, 0) == noErr) break;
+ if (ATSUFindFontName(fontID, code, kFontMacintoshPlatform, kFontRomanScript, kFontNoLanguageCode, NAME_BUF_SIZE, name, &len, 0) == noErr) break;
+ } while (0);
+ if (len > 0) {
+ /* need to convert MacRoman name to Unicode */
+ CFStringRef str = CFStringCreateWithBytes(kCFAllocatorDefault, (UInt8*)name, len, kCFStringEncodingMacRoman, false);
+ if (str != NULL) {
+ len = CFStringGetLength(str);
+ UniChar* buf = xmalloc(len * sizeof(UniChar));
+ CFStringGetCharacters(str, CFRangeMake(0, len), buf);
+ printchars(buf, len);
+ free(buf);
+ CFRelease(str);
+ }
+ }
+ else {
+ do {
+ if (ATSUFindFontName(fontID, code, kFontUnicodePlatform, kFontNoScriptCode, kFontEnglishLanguage, NAME_BUF_SIZE, name, &len, 0) == noErr) break;
+ if (ATSUFindFontName(fontID, code, kFontMicrosoftPlatform, kFontNoScriptCode, kFontEnglishLanguage, NAME_BUF_SIZE, name, &len, 0) == noErr) break;
+ if (ATSUFindFontName(fontID, code, kFontUnicodePlatform, kFontNoScriptCode, kFontNoLanguageCode, NAME_BUF_SIZE, name, &len, 0) == noErr) break;
+ if (ATSUFindFontName(fontID, code, kFontMicrosoftPlatform, kFontNoScriptCode, kFontNoLanguageCode, NAME_BUF_SIZE, name, &len, 0) == noErr) break;
+ } while (0);
+ if (len > 0) {
+ printchars((unsigned short*)(&name[0]), len / 2);
+ }
+ }
+ }
+#endif
+}
+
+#ifdef XETEX_OTHER
+#if 0
+#include <wand/magick-wand.h>
+int
+find_pic_file(char** path, realrect* bounds, int pdfBoxType, int page)
+ /* FIXME: not yet handling /page/ parameter or PDFs properly */
+{
+ int err = -1;
+ MagickBooleanType status;
+ MagickWand *wand;
+ ResolutionType units;
+ double xRes, yRes;
+ char* pic_path = kpse_find_file((char*)nameoffile + 1, kpse_pict_format, 1);
+
+ *path = NULL;
+
+ wand = NewMagickWand();
+ status = MagickPingImage(wand, pic_path);
+ if (status == MagickTrue) {
+ status = MagickGetImageResolution(wand, &xRes, &yRes);
+ if (status == MagickTrue) {
+ bounds->x = bounds->y = 0;
+ units = MagickGetImageUnits(wand);
+ switch (units) {
+ default:
+ /* treat unknown as 72 pixels per inch horiz, and proportionately vertical */
+ bounds->wd = MagickGetImageWidth(wand);
+ if (xRes != 0.0 && yRes != 0.0)
+ bounds->ht = MagickGetImageHeight(wand) * xRes / yRes;
+ else
+ bounds->ht = MagickGetImageHeight(wand);
+ break;
+ case PixelsPerInchResolution:
+ bounds->wd = MagickGetImageWidth(wand) * 72.0 / xRes;
+ bounds->ht = MagickGetImageHeight(wand) * 72.0 / yRes;
+ break;
+ case PixelsPerCentimeterResolution:
+ bounds->wd = MagickGetImageWidth(wand) * 72.0 / (xRes * 2.54);
+ bounds->ht = MagickGetImageHeight(wand) * 72.0 / (yRes * 2.54);
+ break;
+ }
+ err = 0;
+ }
+ }
+
+ /* current API returns wand, but formerly returned void;
+ we don't need the result, and this allows XeTeX to build with older libraries */
+ (void)DestroyMagickWand(wand);
+
+ if (err != 0)
+ free(pic_path);
+ else
+ *path = pic_path;
+
+ return err;
+}
+#endif
+#endif
+
+boolean
+u_open_in(unicodefile* f, int filefmt, const_string fopen_mode, int mode, int encodingData)
+{
+ boolean rval;
+ *f = malloc(sizeof(UFILE));
+ (*f)->encodingMode = 0;
+ (*f)->conversionData = 0;
+ (*f)->savedChar = -1;
+ (*f)->skipNextLF = 0;
+ rval = open_input (&((*f)->f), filefmt, fopen_mode);
+ if (rval) {
+ int B1, B2;
+ if (mode == AUTO) {
+ /* sniff encoding form */
+ B1 = getc((*f)->f);
+ B2 = getc((*f)->f);
+ if (B1 == 0xfe && B2 == 0xff)
+ mode = UTF16BE;
+ else if (B2 == 0xfe && B1 == 0xff)
+ mode = UTF16LE;
+ else if (B1 == 0 && B2 != 0) {
+ mode = UTF16BE;
+ fseek((*f)->f, SEEK_SET, 0);
+ }
+ else if (B2 == 0 && B1 != 0) {
+ mode = UTF16LE;
+ fseek((*f)->f, SEEK_SET, 0);
+ }
+ else if (B1 == 0xef && B2 == 0xbb) {
+ int B3 = getc((*f)->f);
+ if (B3 == 0xbf)
+ mode = UTF8;
+ }
+ if (mode == AUTO) {
+ fseek((*f)->f, SEEK_SET, 0);
+ mode = UTF8;
+ }
+ }
+
+ setinputfileencoding(*f, mode, encodingData);
+ }
+ return rval;
+}
+
+boolean
+open_dvi_output(FILE** fptr)
+{
+ if (nopdfoutput) {
+ return open_output(fptr, FOPEN_WBIN_MODE);
+ }
+ else {
+ char* cmd2 = concat(outputdriver, " -o \"");
+ char* cmd = concat3(cmd2, (char*)nameoffile+1, "\"");
+ free(cmd2);
+ if (papersize != 0) {
+ cmd2 = concat3(cmd, " -p ", papersize);
+ free(cmd);
+ cmd = cmd2;
+ }
+ *fptr = popen(cmd, "w");
+ free(cmd);
+ return (*fptr != 0);
+ }
+}
+
+void
+dviclose(FILE* fptr)
+{
+ if (nopdfoutput)
+ fclose(fptr);
+ else
+ pclose(fptr);
+}
+
+int
+get_uni_c(UFILE* f)
+{
+ int rval;
+
+ if (f->savedChar != -1) {
+ rval = f->savedChar;
+ f->savedChar = -1;
+ return rval;
+ }
+
+ switch (f->encodingMode) {
+ case UTF8:
+ /* FIXME: we don't currently check for malformed UTF-8 */
+ rval = getc(f->f);
+ if (rval != EOF) {
+ UInt16 extraBytes = bytesFromUTF8[rval];
+ switch (extraBytes) { /* note: code falls through cases! */
+ case 5: rval <<= 6; rval += getc(f->f);
+ case 4: rval <<= 6; rval += getc(f->f);
+ case 3: rval <<= 6; rval += getc(f->f);
+ case 2: rval <<= 6; rval += getc(f->f);
+ case 1: rval <<= 6; rval += getc(f->f);
+ case 0: ;
+ };
+ rval -= offsetsFromUTF8[extraBytes];
+ if (rval > 0xFFFF) {
+ rval -= 0x10000;
+ f->savedChar = 0xdc00 + rval % 0x0400;
+ rval = 0xd800 + rval / 0x0400;
+ }
+ }
+ break;
+
+ case UTF16BE:
+ rval = getc(f->f);
+ rval <<= 8;
+ rval += getc(f->f);
+ break;
+
+ case UTF16LE:
+ rval = getc(f->f);
+ rval += (getc(f->f) << 8);
+ break;
+
+ case RAW:
+ rval = getc(f->f);
+ break;
+
+ default:
+ /* this can't happen */
+ fprintf(stderr, "! Internal error---file input mode=%d.\n", f->encodingMode);
+ uexit(3);
+ }
+
+ return rval;
+}
+
+boolean
+input_line(UFILE* f)
+{
+ int i;
+
+ if (f->encodingMode == ICUMAPPING)
+ return input_line_icu(f);
+
+ /* Recognize either LF or CR as a line terminator; skip initial LF if prev line ended with CR. */
+ i = get_uni_c(f);
+ if (f->skipNextLF) {
+ f->skipNextLF = 0;
+ if (i == '\n')
+ i = get_uni_c(f);
+ }
+
+ last = first;
+ if (last < bufsize && i != EOF && i != '\n' && i != '\r')
+ buffer[last++] = i;
+ if (i != EOF && i != '\n' && i != '\r')
+ while (last < bufsize && (i = get_uni_c(f)) != EOF && i != '\n' && i != '\r')
+ buffer[last++] = i;
+
+ if (i == EOF && errno != EINTR && last == first)
+ return false;
+
+ /* We didn't get the whole line because our buffer was too small. */
+ if (i != EOF && i != '\n' && i != '\r') {
+ fprintf (stderr, "! Unable to read an entire line---bufsize=%u.\n",
+ (unsigned) bufsize);
+ fputs ("Please increase buf_size in texmf.cnf.\n", stderr);
+ uexit (1);
+ }
+
+ buffer[last] = ' ';
+ if (last >= maxbufstack)
+ maxbufstack = last;
+
+ /* If line ended with CR, remember to skip following LF. */
+ if (i == '\r')
+ f->skipNextLF = 1;
+
+ /* Trim trailing whitespace. */
+ while (last > first && ISBLANK (buffer[last - 1]))
+ --last;
+
+ return true;
+}
+
+void
+makeutf16name()
+{
+ unsigned char* s = nameoffile + 1;
+ UInt32 rval;
+ UInt16* t;
+ static int name16len = 0;
+ if (name16len <= namelength) {
+ if (nameoffile16 != 0)
+ free(nameoffile16);
+ name16len = namelength + 10;
+ nameoffile16 = xmalloc(name16len * sizeof(UInt16));
+ }
+ t = nameoffile16;
+ while (s <= nameoffile + namelength) {
+ rval = *(s++);
+ UInt16 extraBytes = bytesFromUTF8[rval];
+ switch (extraBytes) { /* note: code falls through cases! */
+ case 5: rval <<= 6; if (*s) rval += *(s++);
+ case 4: rval <<= 6; if (*s) rval += *(s++);
+ case 3: rval <<= 6; if (*s) rval += *(s++);
+ case 2: rval <<= 6; if (*s) rval += *(s++);
+ case 1: rval <<= 6; if (*s) rval += *(s++);
+ case 0: ;
+ };
+ rval -= offsetsFromUTF8[extraBytes];
+ if (rval > 0xffff) {
+ rval -= 0x10000;
+ *(t++) = 0xd800 + rval / 0x0400;
+ *(t++) = 0xdc00 + rval % 0x0400;
+ }
+ else
+ *(t++) = rval;
+ }
+ namelength16 = t - nameoffile16;
+}
+
diff --git a/Build/source/texk/web2c/xetexdir/XeTeX_ext.h b/Build/source/texk/web2c/xetexdir/XeTeX_ext.h
new file mode 100644
index 00000000000..5a0bc59db50
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/XeTeX_ext.h
@@ -0,0 +1,284 @@
+/****************************************************************************\
+ 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.
+\****************************************************************************/
+
+#ifndef __XETEXEXT_H
+#define __XETEXEXT_H
+
+/***** copied from TeX/texk/web2c/config.h -- difficult to include in C++ source files ******/
+#ifndef INTEGER_TYPE
+
+#if SIZEOF_LONG > 4 && !defined (NO_DUMP_SHARE)
+/* If we have 64-bit longs and want to share format files (with 32-bit
+ machines), use `int'. */
+#define INTEGER_IS_INT
+#endif
+
+#ifdef INTEGER_IS_INT
+#define INTEGER_TYPE int
+#define INTEGER_MAX INT_MAX
+#define INTEGER_MIN INT_MIN
+#else
+#define INTEGER_TYPE long
+#define INTEGER_MAX LONG_MAX
+#define INTEGER_MIN LONG_MIN
+#endif /* not INTEGER_IS_INT */
+
+typedef INTEGER_TYPE integer;
+#endif /* not INTEGER_TYPE */
+/***** end of config.h stuff *****/
+
+#ifndef XETEX_UNICODE_FILE_DEFINED
+typedef struct UFILE* unicodefile;
+#endif
+
+#define AAT_FONT_FLAG 65535
+#define OT_FONT_FLAG 65534
+
+#define FONT_FLAGS_COLORED 0x01
+#define FONT_FLAGS_VERTICAL 0x02
+
+/* some typedefs that XeTeX uses - on Mac OS, we get these from Apple headers,
+ but otherwise we'll need these substitute definitions */
+
+#ifdef XETEX_MAC
+#include <Carbon/Carbon.h>
+#else
+#ifndef __TECkit_Common_H__
+typedef unsigned char UInt8;
+typedef unsigned short UInt16;
+typedef unsigned int UInt32;
+typedef UInt16 UniChar;
+#endif
+
+typedef signed char SInt8;
+typedef short SInt16;
+typedef int SInt32;
+
+typedef SInt32 OSStatus;
+typedef SInt32 Fixed;
+typedef struct {
+ Fixed x;
+ Fixed y;
+} FixedPoint;
+#endif
+
+
+/* these are also in xetex-new.ch and must correspond! */
+
+#define pdfbox_crop 1
+#define pdfbox_media 2
+#define pdfbox_bleed 3
+#define pdfbox_trim 4
+#define pdfbox_art 5
+
+
+#define XeTeX_count_glyphs 1
+
+#define XeTeX_count_variations 2
+#define XeTeX_variation 3
+#define XeTeX_find_variation_by_name 4
+#define XeTeX_variation_min 5
+#define XeTeX_variation_max 6
+#define XeTeX_variation_default 7
+
+#define XeTeX_count_features 8
+#define XeTeX_feature_code 9
+#define XeTeX_find_feature_by_name 10
+#define XeTeX_is_exclusive_feature 11
+#define XeTeX_count_selectors 12
+#define XeTeX_selector_code 13
+#define XeTeX_find_selector_by_name 14
+#define XeTeX_is_default_selector 15
+
+#define XeTeX_OT_count_scripts 16
+#define XeTeX_OT_count_languages 17
+#define XeTeX_OT_count_features 18
+#define XeTeX_OT_script_code 19
+#define XeTeX_OT_language_code 20
+#define XeTeX_OT_feature_code 21
+
+#define XeTeX_map_char_to_glyph_code 22
+
+#define XeTeX_variation_name 7 /* must match xetex.web */
+#define XeTeX_feature_name 8
+#define XeTeX_selector_name 9
+
+
+/* definitions used to access info in a native_word_node; must correspond with defines in xetex-new.ch */
+#define width_offset 1
+#define depth_offset 2
+#define height_offset 3
+#define native_info_offset 4
+#define native_glyph_info_offset 5
+
+#define node_width(node) node[width_offset].cint
+#define node_depth(node) node[depth_offset].cint
+#define node_height(node) node[height_offset].cint
+#define native_length(node) node[native_info_offset].hh.v.RH
+#define native_font(node) node[native_info_offset].hh.b1
+#define native_glyph_count(node) node[native_glyph_info_offset].hh.v.LH
+#define native_glyph_info_ptr(node) node[native_glyph_info_offset].hh.v.RH
+#define native_glyph_info_size 10 /* info for each glyph is location (FixedPoint) + glyph ID (UInt16) */
+
+#define native_glyph(p) native_length(p) /* glyph ID field in a glyph_node */
+
+#define XDV_GLYPH_STRING 254
+#define XDV_GLYPH_ARRAY 253
+
+/* OT-related constants we need */
+#define kGSUB 0x47535542
+#define kGPOS 0x47504f53
+
+#define kLatin 0x6c61746e
+#define kSyriac 0x73797263
+#define kArabic 0x61726162
+#define kThaana 0x74686161
+#define kHebrew 0x68656272
+
+
+struct postTable {
+ Fixed format;
+ Fixed italicAngle;
+ SInt16 underlinePosition;
+ SInt16 underlineThickness;
+ UInt16 isFixedPitch;
+ UInt16 reserved;
+ UInt32 minMemType42;
+ UInt32 maxMemType42;
+ UInt32 minMemType1;
+ UInt32 maxMemType1;
+};
+
+#define kPost 0x706f7374
+
+
+typedef struct
+{
+ float xMin;
+ float yMin;
+ float xMax;
+ float yMax;
+} GlyphBBox;
+
+
+extern char *outputdriver;
+extern char *papersize;
+
+/* For Unicode encoding form interpretation... */
+extern const UInt32 offsetsFromUTF8[6];
+extern const UInt8 bytesFromUTF8[256];
+extern const UInt8 firstByteMark[7];
+
+extern const int halfShift;
+extern const UInt32 halfBase;
+extern const UInt32 halfMask;
+extern const UInt32 kSurrogateHighStart;
+extern const UInt32 kSurrogateHighEnd;
+extern const UInt32 kSurrogateLowStart;
+extern const UInt32 kSurrogateLowEnd;
+extern const UInt32 byteMask;
+extern const UInt32 byteMark;
+
+#include "trans.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void setinputfileencoding(unicodefile f, int mode, int encodingData);
+ void uclose(unicodefile f);
+ int input_line_icu(unicodefile f);
+ void linebreakstart(int localeStrNum, const UniChar* text, int textLength);
+ int linebreaknext();
+ long getencodingmodeandinfo(long* info);
+ 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);
+ void* findnativefont(unsigned char* name, long scaled_size);
+ void releasefontengine(void* engine, int type_flag);
+
+ /* 'integer' params here are really TeX 'scaled' values, but that typedef isn't available every place this is included */
+ void otgetfontmetrics(void* engine, integer* ascent, integer* descent, integer* xheight, integer* capheight, integer* slant);
+ void getnativecharheightdepth(int font, int ch, integer* height, integer* depth);
+ void getnativecharsidebearings(int font, int ch, integer* lsb, integer* rsb);
+
+ /* single-purpose metrics accessors */
+ integer getnativecharwd(int font, int ch);
+ integer getnativecharht(int font, int ch);
+ integer getnativechardp(int font, int ch);
+ integer getnativecharic(int font, int ch);
+
+ long otfontget(int what, void* engine);
+ long otfontget1(int what, void* engine, long param);
+ long otfontget2(int what, void* engine, long param1, long param2);
+ long otfontget3(int what, void* engine, long param1, long param2, long param3);
+ int makeXDVGlyphArrayData(void* p);
+ long makefontdef(long f);
+ int applymapping(void* cnv, const UniChar* txtPtr, int txtLen);
+ void store_justified_native_glyphs(void* node);
+ void measure_native_node(void* node, int use_glyph_metrics);
+ Fixed get_native_ital_corr(void* node);
+ Fixed get_native_glyph_ital_corr(void* node);
+ void measure_native_glyph(void* node, int use_glyph_metrics);
+ int mapchartoglyph(int font, unsigned int ch);
+ int mapglyphtoindex(int font);
+
+ int find_pic_file(char** path, realrect* bounds, int pdfBoxType, int page);
+
+#ifdef XETEX_MAC
+/* functions in XeTeX_mac.c */
+ void* loadAATfont(ATSFontRef fontRef, long scaled_size, const char* cp1);
+ void DoAtsuiLayout(void* node, int justify);
+ void GetGlyphBBox_AAT(ATSUStyle style, UInt16 gid, GlyphBBox* bbox);
+ float GetGlyphWidth_AAT(ATSUStyle style, UInt16 gid);
+ void GetGlyphHeightDepth_AAT(ATSUStyle style, UInt16 gid, float* ht, float* dp);
+ void GetGlyphSidebearings_AAT(ATSUStyle style, UInt16 gid, float* lsb, float* rsb);
+ int MapCharToGlyph_AAT(ATSUStyle style, UInt32 ch);
+ int MapGlyphToIndex_AAT(ATSUStyle style, const char* glyphName);
+ float GetGlyphItalCorr_AAT(ATSUStyle style, UInt16 gid);
+#endif
+#ifdef __cplusplus
+};
+#endif
+
+
+/* some Mac OS X functions that we provide ourselves for other platforms */
+#ifndef XETEX_MAC
+#ifdef __cplusplus
+extern "C" {
+#endif
+ double Fix2X(Fixed f);
+ Fixed X2Fix(double d);
+#ifdef __cplusplus
+};
+#endif
+#endif
+
+#endif /* __XETEX_EXT_H */
+
diff --git a/Build/source/texk/web2c/xetexdir/XeTeX_mac.c b/Build/source/texk/web2c/xetexdir/XeTeX_mac.c
new file mode 100644
index 00000000000..8a892be8fc4
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/XeTeX_mac.c
@@ -0,0 +1,1022 @@
+/****************************************************************************\
+ 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.
+\****************************************************************************/
+
+/* XeTeX_mac.c
+ * additional plain C extensions for XeTeX - MacOS-specific routines
+ */
+
+#ifdef __POWERPC__
+#define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_2
+#else
+#define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_4
+#endif
+
+#define EXTERN extern
+#include "xetexd.h"
+
+#undef input /* this is defined in texmfmp.h, but we don't need it and it confuses the carbon headers */
+#include <Carbon/Carbon.h>
+#include <Quicktime/Quicktime.h>
+
+#include "TECkit_Engine.h"
+#include "XeTeX_ext.h"
+
+#include "XeTeXswap.h"
+
+static ATSUTextLayout sTextLayout = 0;
+
+static void
+InitializeLayout()
+{
+ OSStatus status = ATSUCreateTextLayout(&sTextLayout);
+ ATSUFontFallbacks fallbacks;
+ status = ATSUCreateFontFallbacks(&fallbacks);
+ status = ATSUSetObjFontFallbacks(fallbacks, 0, 0, kATSULastResortOnlyFallback);
+ ATSUAttributeTag tag = kATSULineFontFallbacksTag;
+ ByteCount valueSize = sizeof(fallbacks);
+ ATSUAttributeValuePtr value = &fallbacks;
+ status = ATSUSetLayoutControls(sTextLayout, 1, &tag, &valueSize, &value);
+ status = ATSUSetTransientFontMatching(sTextLayout, true);
+}
+
+static inline double
+TeXtoPSPoints(double pts)
+{
+ return pts * 72.0 / 72.27;
+}
+
+static inline double
+PStoTeXPoints(double pts)
+{
+ return pts * 72.27 / 72.0;
+}
+
+static inline Fixed
+FixedTeXtoPSPoints(Fixed pts)
+{
+ return X2Fix(TeXtoPSPoints(Fix2X(pts)));
+}
+
+static inline Fixed
+FixedPStoTeXPoints(Fixed pts)
+{
+ return X2Fix(PStoTeXPoints(Fix2X(pts)));
+}
+
+void
+DoAtsuiLayout(void* p, int justify)
+{
+ memoryword* node = (memoryword*)p;
+
+ unsigned f = native_font(node);
+ if (fontarea[f] != AAT_FONT_FLAG) {
+ fprintf(stderr, "internal error: do_atsui_layout called for non-ATSUI font\n");
+ exit(1);
+ }
+
+ if (sTextLayout == 0)
+ InitializeLayout();
+
+ OSStatus status = noErr;
+
+ long txtLen = native_length(node);
+ const UniChar* txtPtr = (UniChar*)(node + native_node_size);
+
+ status = ATSUSetTextPointerLocation(sTextLayout, txtPtr, 0, txtLen, txtLen);
+
+ // we're using this font in AAT mode, so fontlayoutengine[f] is actually an ATSUStyle
+ ATSUStyle style = (ATSUStyle)(fontlayoutengine[native_font(node)]);
+ status = ATSUSetRunStyle(sTextLayout, style, 0, txtLen);
+
+ ATSUAttributeTag tags[] = { kATSULineWidthTag, kATSULineJustificationFactorTag };
+ ItemCount numTags = sizeof(tags) / sizeof(ATSUAttributeTag);
+ if (justify) {
+ ByteCount valSizes[] = { sizeof(Fixed), sizeof(Fract) };
+ Fixed wid = FixedTeXtoPSPoints(node_width(node));
+ Fract just = fract1;
+ ATSUAttributeValuePtr valPtrs[] = { &wid, &just };
+ status = ATSUSetLayoutControls(sTextLayout, numTags, tags, valSizes, valPtrs);
+ }
+
+ ItemCount count;
+ ATSLayoutRecord* layoutRec = NULL;
+ status = ATSUDirectGetLayoutDataArrayPtrFromTextLayout(sTextLayout, 0,
+ kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void*)&layoutRec, &count);
+
+ int i;
+ int realGlyphCount = 0;
+ int lastRealGlyph = 0;
+ for (i = 0; i < count; ++i)
+ if (layoutRec[i].glyphID < 0xfffe) {
+ lastRealGlyph = i;
+ ++realGlyphCount;
+ }
+
+ void* glyph_info = xmalloc(realGlyphCount * native_glyph_info_size);
+ FixedPoint* locations = (FixedPoint*)glyph_info;
+ UInt16* glyphIDs = (UInt16*)(locations + realGlyphCount);
+
+ Fixed lsUnit = justify ? 0 : fontletterspace[f];
+ Fixed lsDelta = 0;
+
+ realGlyphCount = 0;
+ for (i = 0; i < count; ++i) {
+ if (layoutRec[i].glyphID < 0xfffe) {
+ if ((layoutRec[i].flags & kATSGlyphInfoIsAttachment) && (lsDelta != 0))
+ lsDelta -= lsUnit;
+ glyphIDs[realGlyphCount] = layoutRec[i].glyphID;
+ locations[realGlyphCount].y = 0; /* FIXME: won't handle baseline offsets */
+ locations[realGlyphCount].x = FixedPStoTeXPoints(layoutRec[i].realPos) + lsDelta;
+ lsDelta += lsUnit;
+ ++realGlyphCount;
+ }
+ }
+ if (lsDelta != 0)
+ lsDelta -= lsUnit;
+
+ native_glyph_count(node) = realGlyphCount;
+ native_glyph_info_ptr(node) = (long)glyph_info;
+
+ if (!justify)
+ node_width(node) = FixedPStoTeXPoints(layoutRec[count-1].realPos) + lsDelta;
+
+ ATSUDirectReleaseLayoutDataArrayPtr(NULL, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent, (void*)&layoutRec);
+
+ if (justify)
+ ATSUClearLayoutControls(sTextLayout, numTags, tags);
+}
+
+static OSStatus QuadraticClosePath(void *callBackDataPtr)
+{
+ return 0;
+}
+
+static OSStatus QuadraticCurve(const Float32Point *pt1, const Float32Point *controlPt, const Float32Point *pt2, void *callBackDataPtr)
+{
+ GlyphBBox* data = (GlyphBBox*)callBackDataPtr;
+
+ if (pt1->x < data->xMin)
+ data->xMin = pt1->x;
+ if (pt1->x > data->xMax)
+ data->xMax = pt1->x;
+ if (pt1->y < data->yMin)
+ data->yMin = pt1->y;
+ if (pt1->y > data->yMax)
+ data->yMax = pt1->y;
+
+ if (pt2->x < data->xMin)
+ data->xMin = pt2->x;
+ if (pt2->x > data->xMax)
+ data->xMax = pt2->x;
+ if (pt2->y < data->yMin)
+ data->yMin = pt2->y;
+ if (pt2->y > data->yMax)
+ data->yMax = pt2->y;
+
+ if (controlPt->x < data->xMin)
+ data->xMin = controlPt->x;
+ if (controlPt->x > data->xMax)
+ data->xMax = controlPt->x;
+ if (controlPt->y < data->yMin)
+ data->yMin = controlPt->y;
+ if (controlPt->y > data->yMax)
+ data->yMax = controlPt->y;
+
+ return 0;
+}
+
+static OSStatus QuadraticLine(const Float32Point *pt1, const Float32Point *pt2, void *callBackDataPtr)
+{
+ GlyphBBox* data = (GlyphBBox*)callBackDataPtr;
+
+ if (pt1->x < data->xMin)
+ data->xMin = pt1->x;
+ if (pt1->x > data->xMax)
+ data->xMax = pt1->x;
+ if (pt1->y < data->yMin)
+ data->yMin = pt1->y;
+ if (pt1->y > data->yMax)
+ data->yMax = pt1->y;
+
+ if (pt2->x < data->xMin)
+ data->xMin = pt2->x;
+ if (pt2->x > data->xMax)
+ data->xMax = pt2->x;
+ if (pt2->y < data->yMin)
+ data->yMin = pt2->y;
+ if (pt2->y > data->yMax)
+ data->yMax = pt2->y;
+
+ return 0;
+}
+
+static OSStatus QuadraticNewPath(void *callBackDataPtr)
+{
+ return 0;
+}
+
+static OSStatus CubicMoveTo(const Float32Point *pt, void *callBackDataPtr)
+{
+ GlyphBBox* data = (GlyphBBox*)callBackDataPtr;
+
+ if (pt->x < data->xMin)
+ data->xMin = pt->x;
+ if (pt->x > data->xMax)
+ data->xMax = pt->x;
+ if (pt->y < data->yMin)
+ data->yMin = pt->y;
+ if (pt->y > data->yMax)
+ data->yMax = pt->y;
+
+ return 0;
+}
+
+static OSStatus CubicLineTo(const Float32Point *pt, void *callBackDataPtr)
+{
+ GlyphBBox* data = (GlyphBBox*)callBackDataPtr;
+
+ if (pt->x < data->xMin)
+ data->xMin = pt->x;
+ if (pt->x > data->xMax)
+ data->xMax = pt->x;
+ if (pt->y < data->yMin)
+ data->yMin = pt->y;
+ if (pt->y > data->yMax)
+ data->yMax = pt->y;
+
+ return 0;
+}
+
+static OSStatus CubicCurveTo(const Float32Point *pt1, const Float32Point *pt2, const Float32Point *pt3, void *callBackDataPtr)
+{
+ GlyphBBox* data = (GlyphBBox*)callBackDataPtr;
+
+ if (pt1->x < data->xMin)
+ data->xMin = pt1->x;
+ if (pt1->x > data->xMax)
+ data->xMax = pt1->x;
+ if (pt1->y < data->yMin)
+ data->yMin = pt1->y;
+ if (pt1->y > data->yMax)
+ data->yMax = pt1->y;
+
+ if (pt2->x < data->xMin)
+ data->xMin = pt2->x;
+ if (pt2->x > data->xMax)
+ data->xMax = pt2->x;
+ if (pt2->y < data->yMin)
+ data->yMin = pt2->y;
+ if (pt2->y > data->yMax)
+ data->yMax = pt2->y;
+
+ if (pt3->x < data->xMin)
+ data->xMin = pt3->x;
+ if (pt3->x > data->xMax)
+ data->xMax = pt3->x;
+ if (pt3->y < data->yMin)
+ data->yMin = pt3->y;
+ if (pt3->y > data->yMax)
+ data->yMax = pt3->y;
+
+ return 0;
+}
+
+static OSStatus CubicClosePath(void *callBackDataPtr)
+{
+ return 0;
+}
+
+void GetGlyphBBox_AAT(ATSUStyle style, UInt16 gid, GlyphBBox* bbox)
+ /* returns glyph bounding box in TeX points */
+{
+ ATSCurveType curveType;
+ OSStatus status;
+
+ bbox->xMin = 65536.0;
+ bbox->yMin = 65536.0;
+ bbox->xMax = -65536.0;
+ bbox->yMax = -65536.0;
+
+ status = ATSUGetNativeCurveType(style, &curveType);
+ if (status == noErr) {
+ OSStatus cbStatus;
+
+ if (curveType == kATSCubicCurveType) {
+ static ATSCubicMoveToUPP cubicMoveToProc;
+ static ATSCubicLineToUPP cubicLineToProc;
+ static ATSCubicCurveToUPP cubicCurveToProc;
+ static ATSCubicClosePathUPP cubicClosePathProc;
+ if (cubicMoveToProc == NULL) {
+ cubicMoveToProc = NewATSCubicMoveToUPP(&CubicMoveTo);
+ cubicLineToProc = NewATSCubicLineToUPP(&CubicLineTo);
+ cubicCurveToProc = NewATSCubicCurveToUPP(&CubicCurveTo);
+ cubicClosePathProc = NewATSCubicClosePathUPP(&CubicClosePath);
+ }
+ status = ATSUGlyphGetCubicPaths(style, gid,
+ cubicMoveToProc, cubicLineToProc, cubicCurveToProc, cubicClosePathProc,
+ bbox, &cbStatus);
+ }
+ else {
+ static ATSQuadraticNewPathUPP quadraticNewPathProc;
+ static ATSQuadraticLineUPP quadraticLineProc;
+ static ATSQuadraticCurveUPP quadraticCurveProc;
+ static ATSQuadraticClosePathUPP quadraticClosePathProc;
+ if (quadraticNewPathProc == NULL) {
+ quadraticNewPathProc = NewATSQuadraticNewPathUPP(&QuadraticNewPath);
+ quadraticLineProc = NewATSQuadraticLineUPP(&QuadraticLine);
+ quadraticCurveProc = NewATSQuadraticCurveUPP(&QuadraticCurve);
+ quadraticClosePathProc = NewATSQuadraticClosePathUPP(&QuadraticClosePath);
+ }
+ status = ATSUGlyphGetQuadraticPaths(style, gid,
+ quadraticNewPathProc, quadraticLineProc, quadraticCurveProc, quadraticClosePathProc,
+ bbox, &cbStatus);
+ }
+ }
+
+ if (status != noErr || bbox->xMin == 65536.0)
+ bbox->xMin = bbox->yMin = bbox->xMax = bbox->yMax = 0;
+ else {
+ // convert PS to TeX points and flip y-axis
+ float tmp = bbox->yMin;
+ bbox->yMin = -bbox->yMax * 72.27 / 72.0;
+ bbox->yMax = -tmp * 72.27 / 72.0;
+ bbox->xMin *= 72.27 / 72.0;
+ bbox->xMax *= 72.27 / 72.0;
+ }
+}
+
+float GetGlyphWidth_AAT(ATSUStyle style, UInt16 gid)
+ /* returns TeX points */
+{
+ ATSGlyphIdealMetrics metrics;
+ OSStatus status = ATSUGlyphGetIdealMetrics(style, 1, &gid, 0, &metrics);
+ return PStoTeXPoints(metrics.advance.x);
+}
+
+void GetGlyphHeightDepth_AAT(ATSUStyle style, UInt16 gid, float* ht, float* dp)
+ /* returns TeX points */
+{
+ GlyphBBox bbox;
+
+ GetGlyphBBox_AAT(style, gid, &bbox);
+
+ *ht = bbox.yMax;
+ *dp = -bbox.yMin;
+}
+
+void GetGlyphSidebearings_AAT(ATSUStyle style, UInt16 gid, float* lsb, float* rsb)
+ /* returns TeX points */
+{
+ ATSGlyphIdealMetrics metrics;
+ OSStatus status = ATSUGlyphGetIdealMetrics(style, 1, &gid, 0, &metrics);
+ GlyphBBox bbox;
+ GetGlyphBBox_AAT(style, gid, &bbox);
+ *lsb = bbox.xMin;
+ *rsb = PStoTeXPoints(metrics.advance.x) - bbox.xMax;
+}
+
+float GetGlyphItalCorr_AAT(ATSUStyle style, UInt16 gid)
+{
+ float rval = 0.0;
+ ATSGlyphIdealMetrics metrics;
+ OSStatus status = ATSUGlyphGetIdealMetrics(style, 1, &gid, 0, &metrics);
+ GlyphBBox bbox;
+ GetGlyphBBox_AAT(style, gid, &bbox);
+ if (bbox.xMax > PStoTeXPoints(metrics.advance.x))
+ rval = bbox.xMax - PStoTeXPoints(metrics.advance.x);
+ return rval;
+}
+
+int MapCharToGlyph_AAT(ATSUStyle style, UInt32 ch)
+{
+ UniChar txt[2];
+ int len = 1;
+
+ if (sTextLayout == 0)
+ InitializeLayout();
+
+ if (ch > 0xffff) {
+ ch -= 0x10000;
+ txt[0] = 0xd800 + ch / 1024;
+ txt[1] = 0xdc00 + ch % 1024;
+ len = 2;
+ }
+ else
+ txt[0] = ch;
+
+ OSStatus status = ATSUSetTextPointerLocation(sTextLayout, &txt[0], 0, len, len);
+ status = ATSUSetRunStyle(sTextLayout, style, 0, len);
+
+ ByteCount bufferSize = sizeof(ATSUGlyphInfoArray);
+ ATSUGlyphInfoArray info;
+ status = ATSUGetGlyphInfo(sTextLayout, 0, len, &bufferSize, &info);
+ if (bufferSize > 0 && info.numGlyphs > 0)
+ return info.glyphs[0].glyphID;
+ else
+ return 0;
+}
+
+int MapGlyphToIndex_AAT(ATSUStyle style, const char* glyphName)
+{
+ ATSUFontID fontID;
+ ATSUGetAttribute(style, kATSUFontTag, sizeof(ATSUFontID), &fontID, 0);
+
+ ATSFontRef fontRef = FMGetATSFontRefFromFont(fontID);
+
+ ByteCount length;
+ OSStatus status = ATSFontGetTable(fontRef, kPost, 0, 0, 0, &length);
+ if (status != noErr)
+ return 0;
+
+ void* table = xmalloc(length);
+ status = ATSFontGetTable(fontRef, kPost, 0, length, table, &length);
+ if (status != noErr) {
+ free(table);
+ return 0;
+ }
+
+ int rval = findGlyphInPostTable(table, length, glyphName);
+ free(table);
+
+ return rval;
+}
+
+ATSUFontVariationAxis
+find_axis_by_name(ATSUFontID fontID, const char* name, int nameLength)
+{
+ ATSUFontVariationAxis result = 0;
+
+ Str255 inName;
+ inName[0] = nameLength;
+ int i;
+ for (i = 0; i < inName[0]; ++i)
+ inName[i + 1] = name[i];
+
+ ItemCount varCount;
+ ATSUCountFontVariations(fontID, &varCount);
+ if (varCount > 0) {
+ for (i = 0; i < varCount; ++i) {
+ ATSUFontVariationAxis axis;
+ ATSUGetIndFontVariation(fontID, i, &axis, 0, 0, 0);
+ FontNameCode nameCode;
+ ATSUGetFontVariationNameCode(fontID, axis, &nameCode);
+ Str255 name;
+ ByteCount nameLen;
+ ATSUFindFontName(fontID, nameCode, kFontMacintoshPlatform, kFontNoScript, kFontNoLanguage,
+ 255, (Ptr)&name[1], &nameLen, 0);
+ name[0] = nameLen;
+ if (EqualString(inName, name, false, true)) {
+ result = axis;
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+ATSUFontFeatureType
+find_feature_by_name(ATSUFontID fontID, const char* name, int nameLength)
+{
+ ATSUFontFeatureType result = 0x0000FFFF;
+
+ Str255 inName;
+ inName[0] = nameLength;
+ int i;
+ for (i = 0; i < inName[0]; ++i)
+ inName[i + 1] = name[i];
+
+ ItemCount typeCount;
+ ATSUCountFontFeatureTypes(fontID, &typeCount);
+ if (typeCount > 0) {
+ ATSUFontFeatureType* types = (ATSUFontFeatureType*)xmalloc(typeCount * sizeof(ATSUFontFeatureType));
+ ATSUGetFontFeatureTypes(fontID, typeCount, types, 0);
+ for (i = 0; i < typeCount; ++i) {
+ FontNameCode nameCode;
+ ATSUGetFontFeatureNameCode(fontID, types[i], 0x0000FFFF, &nameCode);
+ Str255 name;
+ ByteCount nameLen;
+ ATSUFindFontName(fontID, nameCode, kFontMacintoshPlatform, kFontNoScript, kFontNoLanguage,
+ 255, (Ptr)&name[1], &nameLen, 0);
+ name[0] = nameLen;
+ if (EqualString(inName, name, false, true)) {
+ result = types[i];
+ break;
+ }
+ }
+ free((char*)types);
+ }
+
+ return result;
+}
+
+ATSUFontFeatureSelector
+find_selector_by_name(ATSUFontID fontID, ATSUFontFeatureType featureType, const char* name, int nameLength)
+{
+ ATSUFontFeatureSelector result = 0x0000FFFF;
+
+ Str255 inName;
+ inName[0] = nameLength;
+ int i;
+ for (i = 0; i < inName[0]; ++i)
+ inName[i + 1] = name[i];
+
+ ItemCount selectorCount;
+ ATSUCountFontFeatureSelectors(fontID, featureType, &selectorCount);
+ if (selectorCount > 0) {
+ ATSUFontFeatureSelector* selectors = (ATSUFontFeatureSelector*)xmalloc(selectorCount * sizeof(ATSUFontFeatureSelector));
+ ATSUGetFontFeatureSelectors(fontID, featureType, selectorCount, selectors, 0, 0, 0);
+ for (i = 0; i < selectorCount; ++i) {
+ FontNameCode nameCode;
+ ATSUGetFontFeatureNameCode(fontID, featureType, selectors[i], &nameCode);
+ Str255 name;
+ ByteCount nameLen;
+ ATSUFindFontName(fontID, nameCode, kFontMacintoshPlatform, kFontNoScript, kFontNoLanguage,
+ 255, (Ptr)&name[1], &nameLen, 0);
+ name[0] = nameLen;
+ if (EqualString(inName, name, false, true)) {
+ result = selectors[i];
+ break;
+ }
+ }
+ free((char*)selectors);
+ }
+
+ return result;
+}
+
+void*
+loadAATfont(ATSFontRef fontRef, long scaled_size, const char* cp1)
+{
+ ATSUFontID fontID = FMGetFontFromATSFontRef(fontRef);
+ ATSUStyle style = 0;
+ OSStatus status = ATSUCreateStyle(&style);
+ if (status == noErr) {
+ UInt32 rgbValue;
+ Fixed tracking = 0x80000000;
+ Fixed atsuSize = FixedTeXtoPSPoints(scaled_size);
+
+ ATSStyleRenderingOptions options = kATSStyleNoHinting;
+ Fract hangInhibit = fract1;
+ ATSUAttributeTag tags[] = { kATSUFontTag, kATSUSizeTag, kATSUStyleRenderingOptionsTag, kATSUHangingInhibitFactorTag };
+ ByteCount sizes[] = { sizeof(ATSUFontID), sizeof(Fixed), sizeof(ATSStyleRenderingOptions), sizeof(Fract) };
+ ATSUAttributeValuePtr attrs[] = { &fontID, &atsuSize, &options, &hangInhibit };
+ ATSUSetAttributes(style, sizeof(tags) / sizeof(ATSUAttributeTag), tags, sizes, attrs);
+
+#define FEAT_ALLOC_CHUNK 8
+#define VAR_ALLOC_CHUNK 4
+
+ if (cp1 != NULL) {
+ int allocFeats = FEAT_ALLOC_CHUNK;
+ UInt16* featureTypes = (UInt16*)xmalloc(allocFeats * sizeof(UInt16));
+ UInt16* selectorValues = (UInt16*)xmalloc(allocFeats * sizeof(UInt16));
+ int numFeatures = 0;
+
+ int allocVars = VAR_ALLOC_CHUNK;
+ UInt32* axes = (UInt32*)xmalloc(allocVars * sizeof(UInt32));
+ SInt32* values = (SInt32*)xmalloc(allocVars * sizeof(SInt32));
+ int numVariations = 0;
+
+ // interpret features & variations following ":"
+ while (*cp1) {
+ // locate beginning of name=value pair
+ if (*cp1 == ':' || *cp1 == ';') // skip over separator
+ ++cp1;
+ while (*cp1 == ' ' || *cp1 == '\t') // skip leading whitespace
+ ++cp1;
+ if (*cp1 == 0) // break if end of string
+ break;
+
+ // scan to end of pair
+ const char* cp2 = cp1;
+ while (*cp2 && *cp2 != ';' && *cp2 != ':')
+ ++cp2;
+
+ // look for the '=' separator
+ const char* cp3 = cp1;
+ while (cp3 < cp2 && *cp3 != '=')
+ ++cp3;
+ if (cp3 == cp2)
+ goto bad_option;
+
+ // now cp1 points to option name, cp3 to '=', cp2 to ';' or null
+
+ // first try for a feature by this name
+ ATSUFontFeatureType featureType;
+ featureType = find_feature_by_name(fontID, cp1, cp3 - cp1);
+ if (featureType != 0x0000FFFF) {
+ // look past the '=' separator for setting names
+ int featLen = cp3 - cp1;
+ ++cp3;
+ while (cp3 < cp2) {
+ // skip leading whitespace
+ while (*cp3 == ' ' || *cp3 == '\t')
+ ++cp3;
+
+ // possibly multiple settings...
+ int disable = 0;
+ if (*cp3 == '!') { // check for negation
+ disable = 1;
+ ++cp3;
+ }
+
+ // scan for end of setting name
+ const char* cp4 = cp3;
+ while (cp4 < cp2 && *cp4 != ',')
+ ++cp4;
+
+ // now cp3 points to name, cp4 to ',' or ';' or null
+ ATSUFontFeatureSelector selectorValue = find_selector_by_name(fontID, featureType, cp3, cp4 - cp3);
+ if (selectorValue != 0x0000FFFF) {
+ if (numFeatures == allocFeats) {
+ allocFeats += FEAT_ALLOC_CHUNK;
+ featureTypes = xrealloc(featureTypes, allocFeats * sizeof(UInt16));
+ selectorValues = xrealloc(selectorValues, allocFeats * sizeof(UInt16));
+ }
+ featureTypes[numFeatures] = featureType;
+ selectorValues[numFeatures] = selectorValue + disable;
+ ++numFeatures;
+ }
+ else {
+ fontfeaturewarning(cp1, featLen, cp3, cp4 - cp3);
+ }
+
+ // point beyond setting name terminator
+ cp3 = cp4 + 1;
+ }
+
+ goto next_option;
+ }
+
+ // try to find a variation by this name
+ ATSUFontVariationAxis axis;
+ axis = find_axis_by_name(fontID, cp1, cp3 - cp1);
+ if (axis != 0) {
+ // look past the '=' separator for the value
+ ++cp3;
+ double value = 0.0, decimal = 1.0;
+ bool negate = false;
+ if (*cp3 == '-') {
+ ++cp3;
+ negate = true;
+ }
+ while (cp3 < cp2) {
+ int v = *cp3 - '0';
+ if (v >= 0 && v <= 9) {
+ if (decimal != 1.0) {
+ value += v / decimal;
+ decimal *= 10.0;
+ }
+ else
+ value = value * 10.0 + v;
+ }
+ else if (*cp3 == '.') {
+ if (decimal != 1.0)
+ break;
+ decimal = 10.0;
+ }
+ else
+ break;
+ ++cp3;
+ }
+ if (negate)
+ value = -value;
+ if (numVariations == allocVars) {
+ allocVars += VAR_ALLOC_CHUNK;
+ axes = xrealloc(axes, allocVars * sizeof(UInt32));
+ values = xrealloc(values, allocVars * sizeof(SInt32));
+ }
+ axes[numVariations] = axis;
+ values[numVariations] = value * 65536.0; // X2Fix(value);
+ ++numVariations;
+
+ goto next_option;
+ }
+
+ // didn't find feature or variation, try other options....
+
+ 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, "color", 5) == 0) {
+ 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;
+ else
+ rgbValue += 0xFF;
+
+ loadedfontflags |= FONT_FLAGS_COLORED;
+
+ goto next_option;
+ }
+
+ if (strncmp(cp1, "tracking", 8) == 0) {
+ cp3 = cp1 + 8;
+ 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);
+
+ goto next_option;
+ }
+
+ if (strncmp(cp1, "letterspace", 11) == 0) {
+ cp3 = cp1 + 11;
+ 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;
+
+ goto next_option;
+ }
+
+ bad_option:
+ // not a name=value pair, or not recognized....
+ // check for plain "vertical" before complaining
+ if (strncmp(cp1, "vertical", 8) == 0) {
+ cp3 = cp2;
+ if (*cp3 == ';' || *cp3 == ':')
+ --cp3;
+ while (*cp3 == ' ' || *cp3 == '\t')
+ --cp3;
+ if (*cp3)
+ ++cp3;
+ if (cp3 == cp1 + 8) {
+ ATSUVerticalCharacterType vert = kATSUStronglyVertical;
+ tags[0] = kATSUVerticalCharacterTag;
+ sizes[0] = sizeof(ATSUVerticalCharacterType);
+ attrs[0] = &vert;
+ ATSUSetAttributes(style, 1, tags, sizes, attrs);
+ goto next_option;
+ }
+ }
+
+ fontfeaturewarning(cp1, cp2 - cp1, 0, 0);
+
+ next_option:
+ // go to next name=value pair
+ cp1 = cp2;
+ }
+
+ if (numFeatures > 0)
+ ATSUSetFontFeatures(style, numFeatures, featureTypes, selectorValues);
+
+ if (numVariations > 0)
+ ATSUSetVariations(style, numVariations, axes, values);
+
+ if ((loadedfontflags & FONT_FLAGS_COLORED) != 0) {
+ ATSURGBAlphaColor rgba;
+ rgba.red = ((rgbValue & 0xFF000000) >> 24) / 255.0;
+ rgba.green = ((rgbValue & 0x00FF0000) >> 16) / 255.0;
+ rgba.blue = ((rgbValue & 0x0000FF00) >> 8 ) / 255.0;
+ rgba.alpha = ((rgbValue & 0x000000FF) ) / 255.0;
+ tags[0] = kATSURGBAlphaColorTag;
+ sizes[0] = sizeof(ATSURGBAlphaColor);
+ attrs[0] = &rgba;
+ ATSUSetAttributes(style, 1, tags, sizes, attrs);
+ }
+
+ if (tracking != 0x80000000) {
+ tags[0] = kATSUTrackingTag;
+ sizes[0] = sizeof(Fixed);
+ attrs[0] = &tracking;
+ ATSUSetAttributes(style, 1, tags, sizes, attrs);
+ }
+
+ free((char*)featureTypes);
+ free((char*)selectorValues);
+ free((char*)axes);
+ free((char*)values);
+ }
+ }
+
+ nativefonttypeflag = AAT_FONT_FLAG;
+ return style;
+}
+
+int
+find_pic_file(char** path, realrect* bounds, int pdfBoxType, int page)
+{
+ *path = NULL;
+
+ OSStatus result = fnfErr;
+ 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) {
+ /* get an FSRef for the URL we constructed */
+ FSRef picFileRef;
+ CFURLGetFSRef(picFileURL, &picFileRef);
+
+ if (pdfBoxType > 0) {
+ CGPDFDocumentRef document = CGPDFDocumentCreateWithURL(picFileURL);
+ if (document != NULL) {
+ int nPages = CGPDFDocumentGetNumberOfPages(document);
+ if (page < 0)
+ page = nPages + 1 + page;
+ if (page < 1)
+ page = 1;
+ if (page > nPages)
+ page = nPages;
+
+ CGRect r;
+#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_3
+ if (&CGPDFDocumentGetPage == NULL) {
+ switch (pdfBoxType) {
+ case pdfbox_crop:
+ default:
+ r = CGPDFDocumentGetCropBox(document, page);
+ break;
+ case pdfbox_media:
+ r = CGPDFDocumentGetMediaBox(document, page);
+ break;
+ case pdfbox_bleed:
+ r = CGPDFDocumentGetBleedBox(document, page);
+ break;
+ case pdfbox_trim:
+ r = CGPDFDocumentGetTrimBox(document, page);
+ break;
+ case pdfbox_art:
+ r = CGPDFDocumentGetArtBox(document, page);
+ break;
+ }
+ }
+ else
+#endif
+ {
+ CGPDFPageRef pageRef = CGPDFDocumentGetPage(document, page);
+ CGPDFBox boxType;
+ switch (pdfBoxType) {
+ case pdfbox_crop:
+ default:
+ boxType = kCGPDFCropBox;
+ break;
+ case pdfbox_media:
+ boxType = kCGPDFMediaBox;
+ break;
+ case pdfbox_bleed:
+ boxType = kCGPDFBleedBox;
+ break;
+ case pdfbox_trim:
+ boxType = kCGPDFTrimBox;
+ break;
+ case pdfbox_art:
+ boxType = kCGPDFArtBox;
+ break;
+ }
+ r = CGPDFPageGetBoxRect(pageRef, boxType);
+ }
+
+ bounds->x = r.origin.x;
+ bounds->y = r.origin.y;
+ bounds->wd = r.size.width;
+ bounds->ht = r.size.height;
+ CGPDFDocumentRelease(document);
+ result = noErr;
+ }
+ }
+ else {
+ /* make an FSSpec for the file, and try to import it as a pic */
+ FSSpec picFileSpec;
+ result = FSGetCatalogInfo(&picFileRef, kFSCatInfoNone, NULL, NULL, &picFileSpec, NULL);
+ if (result == noErr) {
+ ComponentInstance ci;
+ result = GetGraphicsImporterForFile(&picFileSpec, &ci);
+ if (result == noErr) {
+ ImageDescriptionHandle desc = NULL;
+ result = GraphicsImportGetImageDescription(ci, &desc);
+ bounds->x = 0;
+ bounds->y = 0;
+ bounds->wd = (*desc)->width * 72.0 / Fix2X((*desc)->hRes);
+ bounds->ht = (*desc)->height * 72.0 / Fix2X((*desc)->vRes);
+ DisposeHandle((Handle)desc);
+ (void)CloseComponent(ci);
+ }
+ }
+ }
+
+ CFRelease(picFileURL);
+ }
+
+ /* if we couldn't import it, toss the pathname as we'll be returning an error */
+ if (result != noErr)
+ free(pic_path);
+ else
+ *path = (char*)pic_path;
+ }
+
+ return result;
+}
diff --git a/Build/source/texk/web2c/xetexdir/XeTeX_pic.c b/Build/source/texk/web2c/xetexdir/XeTeX_pic.c
new file mode 100644
index 00000000000..a511b848038
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/XeTeX_pic.c
@@ -0,0 +1,111 @@
+/****************************************************************************\
+ Part of the XeTeX typesetting system
+ copyright (c) 1994-2005 by SIL International
+ written by Jonathan Kew
+
+ This software is distributed under the terms of the Common Public License,
+ version 1.0.
+ For details, see <http://www.opensource.org/licenses/cpl1.0.php> or the file
+ cpl1.0.txt included with the software.
+\****************************************************************************/
+
+/*
+XeTeX_pic.c
+ interface between xetex and graphics files
+ (not used on OS X -- we use QuickTime graphics importers instead)
+ only needs to get image dimensions, not actually load/process the file
+*/
+
+#define EXTERN extern
+#include "xetexd.h"
+
+#include "XeTeX_ext.h"
+
+#include <kpathsea/c-ctype.h>
+#include <kpathsea/line.h>
+#include <kpathsea/readable.h>
+#include <kpathsea/variable.h>
+#include <kpathsea/absolute.h>
+
+#include "pdfimage.h"
+#include "pngimage.h"
+#include "jpegimage.h"
+#include "bmpimage.h"
+
+/*
+ locate picture file from /nameoffile+1/ using kpathsearch
+ pdfBoxType indicates which pdf bounding box to use (0 for \XeTeXpicfile)
+ page indicates which page is wanted (0-based)
+ return 0 for success, or non-zero error code for failure
+ return full path in *path
+ return bounds (tex points) in *bounds
+*/
+int
+find_pic_file(char** path, realrect* bounds, int pdfBoxType, int page)
+{
+ int err = -1;
+ FILE* fp = NULL;
+ char* pic_path = kpse_find_file((char*)nameoffile + 1, kpse_pict_format, 1);
+
+ *path = NULL;
+ bounds->x = bounds->y = bounds->wd = bounds->ht = 0.0;
+
+ if (pic_path == NULL)
+ goto done;
+
+ /* if cmd was \XeTeXpdffile, use xpdflib to read it */
+ if (pdfBoxType != 0) {
+ err = pdf_get_rect(pic_path, page, pdfBoxType, bounds);
+ goto done;
+ }
+
+ /* otherwise try graphics formats that we know */
+ fp = fopen(pic_path, FOPEN_RBIN_MODE);
+ if (fp == NULL)
+ goto done;
+
+ if (check_for_jpeg(fp)) {
+ struct JPEG_info info;
+ err = JPEG_scan_file(&info, fp);
+ if (err == 0) {
+ bounds->wd = (info.width * 72.27) / info.xdpi;
+ bounds->ht = (info.height * 72.27) / info.ydpi;
+ }
+ goto done;
+ }
+
+ if (check_for_bmp(fp)) {
+ struct bmp_info info;
+ err = bmp_scan_file(&info, fp);
+ if (err == 0) {
+ bounds->wd = (info.width * 72.27) / info.xdpi;
+ bounds->ht = (info.height * 72.27) / info.ydpi;
+ }
+ goto done;
+ }
+
+ if (check_for_png(fp)) {
+ struct png_info info;
+ err = png_scan_file(&info, fp);
+ if (err == 0) {
+ bounds->wd = (info.width * 72.27) / info.xdpi;
+ bounds->ht = (info.height * 72.27) / info.ydpi;
+ }
+ goto done;
+ }
+
+ /* could support other file types here (TIFF, WMF, etc?) */
+
+done:
+ if (fp != NULL)
+ fclose(fp);
+
+ if (err == 0)
+ *path = pic_path;
+ else {
+ if (pic_path != NULL)
+ free(pic_path);
+ }
+
+ return err;
+}
diff --git a/Build/source/texk/web2c/xetexdir/XeTeXswap.h b/Build/source/texk/web2c/xetexdir/XeTeXswap.h
new file mode 100644
index 00000000000..311b8a791f8
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/XeTeXswap.h
@@ -0,0 +1,96 @@
+/****************************************************************************\
+ 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.
+\****************************************************************************/
+
+#ifndef __XeTeXswap_H
+#define __XeTeXswap_H
+
+#include "unicode/platform.h" // ICU's platform.h defines U_IS_BIG_ENDIAN for us
+
+#ifdef WIN32
+#define inline __inline /* for VC++ (non-C99); not sure about other compilers on W32 */
+#endif
+
+static inline UInt16
+SWAP16(const UInt16 p)
+{
+#if U_IS_BIG_ENDIAN
+ return p;
+#else
+ return (p >> 8) + (p << 8);
+#endif
+}
+
+static inline UInt32
+SWAP32(const UInt32 p)
+{
+#if U_IS_BIG_ENDIAN
+ return p;
+#else
+ return (p >> 24) + ((p >> 8) & 0x0000ff00) + ((p << 8) & 0x00ff0000) + (p << 24);
+#endif
+}
+
+#ifdef __cplusplus
+
+#ifdef XETEX_MAC
+#include "sfnt.h" /* for the 'fixed' typedef */
+static inline fixed
+SWAP(fixed p)
+{
+ return (fixed)SWAP32((UInt32)p);
+}
+#endif
+
+static inline UInt16
+SWAP(UInt16 p)
+{
+ return SWAP16(p);
+}
+
+static inline UInt32
+SWAP(UInt32 p)
+{
+ return SWAP32(p);
+}
+
+static inline SInt16
+SWAP(SInt16 p)
+{
+ return (SInt16)SWAP16((UInt16)p);
+}
+
+static inline SInt32
+SWAP(SInt32 p)
+{
+ return (SInt32)SWAP32((UInt32)p);
+}
+#endif
+
+#endif
diff --git a/Build/source/texk/web2c/xetexdir/appleGlyphNames.c b/Build/source/texk/web2c/xetexdir/appleGlyphNames.c
new file mode 100644
index 00000000000..21fe6cc6719
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/appleGlyphNames.c
@@ -0,0 +1,291 @@
+/****************************************************************************\
+ 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.
+\****************************************************************************/
+
+char* appleGlyphNames[] = {
+ ".notdef",
+ ".null",
+ "nonmarkingreturn",
+ "space",
+ "exclam",
+ "quotedbl",
+ "numbersign",
+ "dollar",
+ "percent",
+ "ampersand",
+ "quotesingle",
+ "parenleft",
+ "parenright",
+ "asterisk",
+ "plus",
+ "comma",
+ "hyphen",
+ "period",
+ "slash",
+ "zero",
+ "one",
+ "two",
+ "three",
+ "four",
+ "five",
+ "six",
+ "seven",
+ "eight",
+ "nine",
+ "colon",
+ "semicolon",
+ "less",
+ "equal",
+ "greater",
+ "question",
+ "at",
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z",
+ "bracketleft",
+ "backslash",
+ "bracketright",
+ "asciicircum",
+ "underscore",
+ "grave",
+ "a",
+ "b",
+ "c",
+ "d",
+ "e",
+ "f",
+ "g",
+ "h",
+ "i",
+ "j",
+ "k",
+ "l",
+ "m",
+ "n",
+ "o",
+ "p",
+ "q",
+ "r",
+ "s",
+ "t",
+ "u",
+ "v",
+ "w",
+ "x",
+ "y",
+ "z",
+ "braceleft",
+ "bar",
+ "braceright",
+ "asciitilde",
+ "Adieresis",
+ "Aring",
+ "Ccedilla",
+ "Eacute",
+ "Ntilde",
+ "Odieresis",
+ "Udieresis",
+ "aacute",
+ "agrave",
+ "acircumflex",
+ "adieresis",
+ "atilde",
+ "aring",
+ "ccedilla",
+ "eacute",
+ "egrave",
+ "ecircumflex",
+ "edieresis",
+ "iacute",
+ "igrave",
+ "icircumflex",
+ "idieresis",
+ "ntilde",
+ "oacute",
+ "ograve",
+ "ocircumflex",
+ "odieresis",
+ "otilde",
+ "uacute",
+ "ugrave",
+ "ucircumflex",
+ "udieresis",
+ "dagger",
+ "degree",
+ "cent",
+ "sterling",
+ "section",
+ "bullet",
+ "paragraph",
+ "germandbls",
+ "registered",
+ "copyright",
+ "trademark",
+ "acute",
+ "dieresis",
+ "notequal",
+ "AE",
+ "Oslash",
+ "infinity",
+ "plusminus",
+ "lessequal",
+ "greaterequal",
+ "yen",
+ "mu",
+ "partialdiff",
+ "summation",
+ "product",
+ "pi",
+ "integral",
+ "ordfeminine",
+ "ordmasculine",
+ "Omega",
+ "ae",
+ "oslash",
+ "questiondown",
+ "exclamdown",
+ "logicalnot",
+ "radical",
+ "florin",
+ "approxequal",
+ "Delta",
+ "guillemotleft",
+ "guillemotright",
+ "ellipsis",
+ "nonbreakingspace",
+ "Agrave",
+ "Atilde",
+ "Otilde",
+ "OE",
+ "oe",
+ "endash",
+ "emdash",
+ "quotedblleft",
+ "quotedblright",
+ "quoteleft",
+ "quoteright",
+ "divide",
+ "lozenge",
+ "ydieresis",
+ "Ydieresis",
+ "fraction",
+ "currency",
+ "guilsinglleft",
+ "guilsinglright",
+ "fi",
+ "fl",
+ "daggerdbl",
+ "periodcentered",
+ "quotesinglbase",
+ "quotedblbase",
+ "perthousand",
+ "Acircumflex",
+ "Ecircumflex",
+ "Aacute",
+ "Edieresis",
+ "Egrave",
+ "Iacute",
+ "Icircumflex",
+ "Idieresis",
+ "Igrave",
+ "Oacute",
+ "Ocircumflex",
+ "apple",
+ "Ograve",
+ "Uacute",
+ "Ucircumflex",
+ "Ugrave",
+ "dotlessi",
+ "circumflex",
+ "tilde",
+ "macron",
+ "breve",
+ "dotaccent",
+ "ring",
+ "cedilla",
+ "hungarumlaut",
+ "ogonek",
+ "caron",
+ "Lslash",
+ "lslash",
+ "Scaron",
+ "scaron",
+ "Zcaron",
+ "zcaron",
+ "brokenbar",
+ "Eth",
+ "eth",
+ "Yacute",
+ "yacute",
+ "Thorn",
+ "thorn",
+ "minus",
+ "multiply",
+ "onesuperior",
+ "twosuperior",
+ "threesuperior",
+ "onehalf",
+ "onequarter",
+ "threequarters",
+ "franc",
+ "Gbreve",
+ "gbreve",
+ "Idotaccent",
+ "Scedilla",
+ "scedilla",
+ "Cacute",
+ "cacute",
+ "Ccaron",
+ "ccaron",
+ "dcroat",
+ 0
+};
diff --git a/Build/source/texk/web2c/xetexdir/bmpimage.c b/Build/source/texk/web2c/xetexdir/bmpimage.c
new file mode 100644
index 00000000000..03846e4b932
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/bmpimage.c
@@ -0,0 +1,201 @@
+/****************************************************************************\
+ Part of the XeTeX typesetting system
+ copyright (c) 1994-2006 by SIL International
+ written by Jonathan Kew
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+\****************************************************************************/
+
+/* this file is derived from the dvipdfmx project;
+ the original header follows... */
+
+/* $Header: /home/cvsroot/dvipdfmx/src/bmpimage.c,v 1.2 2004/07/27 12:08:46 hirata Exp $
+
+ This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
+
+ Copyright (C) 2002 by Jin-Hwan Cho and Shunsaku Hirata,
+ the dvipdfmx project team <dvipdfmx@project.ktug.or.kr>
+
+ Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+*/
+
+/*
+ * BMP SUPPORT:
+ */
+
+#include "bmpimage.h"
+
+#define DIB_FILE_HEADER_SIZE 14
+#define DIB_CORE_HEADER_SIZE 14
+#define DIB_INFO_HEADER_SIZE 40
+
+#define DIB_COMPRESS_NONE 0
+#define DIB_COMPRESS_RLE8 1
+#define DIB_COMPRESS_RLE4 2
+
+#define DIB_HEADER_SIZE_MAX (DIB_FILE_HEADER_SIZE+DIB_INFO_HEADER_SIZE)
+
+static void
+WARN(const char *fmt, ...)
+{
+ va_list argp;
+
+ fprintf(stderr, "** WARNING ** ");
+ va_start(argp, fmt);
+ vfprintf(stderr, fmt, argp);
+ va_end(argp);
+ fprintf(stderr, "\n");
+}
+
+int
+check_for_bmp (FILE *fp)
+{
+ unsigned char sigbytes[2];
+
+ if (!fp)
+ return 0;
+
+ rewind(fp);
+ if (fread(sigbytes, 1, sizeof(sigbytes), fp) != sizeof(sigbytes) ||
+ sigbytes[0] != 'B' || sigbytes[1] != 'M')
+ return 0;
+ else
+ return 1;
+
+ return 0;
+}
+
+int
+bmp_scan_file(struct bmp_info *info, FILE *fp)
+{
+ unsigned char buf[DIB_HEADER_SIZE_MAX+4];
+ unsigned char *p;
+ long offset, fsize, hsize, compression;
+ long psize; /* Bytes per palette color: 3 for OS2, 4 for Win */
+ unsigned short bit_count; /* Bits per pix */
+ int num_palette, flip;
+ int i;
+ unsigned long biXPelsPerMeter, biYPelsPerMeter;
+
+ p = buf;
+
+ rewind(fp);
+ if (fread(buf, 1, DIB_FILE_HEADER_SIZE + 4, fp)
+ != DIB_FILE_HEADER_SIZE + 4) {
+ WARN("Could not read BMP file header...");
+ }
+
+ if (p[0] != 'B' || p[1] != 'M') {
+ WARN("File not starting with \'B\' \'M\'... Not a BMP file?");
+ return -1;
+ }
+ p += 2;
+
+#define ULONG_LE(b) ((b)[0] + ((b)[1] << 8) +\
+ ((b)[2] << 16) + ((b)[3] << 24))
+#define USHORT_LE(b) ((b)[0] + ((b)[1] << 8))
+
+ fsize = ULONG_LE(p); p += 4;
+ if (ULONG_LE(p) != 0) {
+ WARN("Not a BMP file???");
+ return -1;
+ }
+ p += 4;
+ offset = ULONG_LE(p); p += 4;
+
+ /* info header */
+ hsize = ULONG_LE(p); p += 4;
+ if (fread(p, sizeof(char), hsize - 4, fp) != hsize - 4) {
+ WARN("Could not read BMP file header...");
+ return -1;
+ }
+ flip = 1;
+ if (hsize == DIB_CORE_HEADER_SIZE) {
+ info->width = USHORT_LE(p); p += 2;
+ info->height = USHORT_LE(p); p += 2;
+ if (USHORT_LE(p) != 1) {
+ WARN("Unknown bcPlanes value in BMP COREHEADER.");
+ return -1;
+ }
+ p += 2;
+ bit_count = USHORT_LE(p); p += 2;
+ compression = DIB_COMPRESS_NONE;
+ psize = 3;
+ } else if (hsize == DIB_INFO_HEADER_SIZE) {
+ info->width = ULONG_LE(p); p += 4;
+ info->height = ULONG_LE(p); p += 4;
+ if (USHORT_LE(p) != 1) {
+ WARN("Unknown biPlanes value in BMP INFOHEADER.");
+ return -1;
+ }
+ p += 2;
+ bit_count = USHORT_LE(p); p += 2;
+ compression = ULONG_LE(p); p += 4;
+ /* ignore biSizeImage */ p += 4;
+ biXPelsPerMeter = ULONG_LE(p); p += 4;
+ biYPelsPerMeter = ULONG_LE(p); p += 4;
+ info->xdpi = biXPelsPerMeter * 0.0254; /* convert pixels per meter to DPI */
+ info->ydpi = biYPelsPerMeter * 0.0254;
+ if (info->height < 0) {
+ info->height = -info->height;
+ flip = 0;
+ }
+ psize = 4;
+ } else {
+ WARN("Unknown BMP header type.");
+ return -1;
+ }
+
+ if (bit_count < 24) {
+ if (bit_count != 1 &&
+ bit_count != 4 && bit_count != 8) {
+ WARN("Unsupported palette size: %ld", bit_count);
+ return -1;
+ }
+ num_palette = (offset - hsize - DIB_FILE_HEADER_SIZE) / psize;
+ info->bits_per_component = bit_count;
+ info->num_components = 1;
+ } else if (bit_count == 24) { /* full color */
+ num_palette = 1; /* dummy */
+ info->bits_per_component = 8;
+ info->num_components = 3;
+ } else {
+ WARN("Unkown BMP bitCount: %ld", bit_count);
+ return -1;
+ }
+
+ if (info->width == 0 || info->height == 0 || num_palette < 1) {
+ WARN("Invalid BMP file: width=%ld, height=%ld, #palette=%d",
+ info->width, info->height, num_palette);
+ return -1;
+ }
+
+ return 0;
+}
+
diff --git a/Build/source/texk/web2c/xetexdir/bmpimage.h b/Build/source/texk/web2c/xetexdir/bmpimage.h
new file mode 100644
index 00000000000..9c55b0c20f8
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/bmpimage.h
@@ -0,0 +1,70 @@
+/****************************************************************************\
+ Part of the XeTeX typesetting system
+ copyright (c) 1994-2006 by SIL International
+ written by Jonathan Kew
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+\****************************************************************************/
+
+/* this file is derived from the dvipdfmx project;
+ the original header follows... */
+
+/* $Header: /home/cvsroot/dvipdfmx/src/bmpimage.h,v 1.1 2004/07/25 11:54:20 hirata Exp $
+
+ This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
+
+ Copyright (C) 2002 by Jin-Hwan Cho and Shunsaku Hirata,
+ the dvipdfmx project team <dvipdfmx@project.ktug.or.kr>
+
+ Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+*/
+
+
+#ifndef _BMPIMAGE_H_
+#define _BMPIMAGE_H_
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "mfileio.h"
+
+struct bmp_info {
+ int width;
+ int height;
+ double xdpi;
+ double ydpi;
+ int bits_per_component;
+ int num_components;
+};
+
+extern int bmp_scan_file(struct bmp_info *info, FILE *file);
+extern int check_for_bmp(FILE *file);
+
+#endif /* _BMPIMAGE_H_ */
diff --git a/Build/source/texk/web2c/xetexdir/cmaps.cpp b/Build/source/texk/web2c/xetexdir/cmaps.cpp
new file mode 100644
index 00000000000..2b52ef50015
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/cmaps.cpp
@@ -0,0 +1,240 @@
+/*
+ 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.
+*/
+
+/* from ICU sample code, extended by JK for XeTeX */
+
+/***************************************************************************
+*
+* Copyright (C) 1998-2003, International Business Machines
+* Corporation and others. All Rights Reserved.
+*
+************************************************************************/
+
+#include "LETypes.h"
+#include "LESwaps.h"
+
+#include "sfnt.h"
+#include "cmaps.h"
+
+#define SWAPU16(code) ((LEUnicode16) SWAPW(code))
+#define SWAPU32(code) ((LEUnicode32) SWAPL(code))
+
+// read a 32-bit value that might only be 16-bit-aligned in memory
+#define READ_LONG(code) (le_uint32)((SWAPW(*(le_uint16*)&code) << 16) + SWAPW(*(((le_uint16*)&code) + 1)))
+
+//
+// Finds the high bit by binary searching
+// through the bits in value.
+//
+le_int8 highBit(le_uint32 value)
+{
+ le_uint8 bit = 0;
+
+ if (value >= 1 << 16) {
+ value >>= 16;
+ bit += 16;
+ }
+
+ if (value >= 1 << 8) {
+ value >>= 8;
+ bit += 8;
+ }
+
+ if (value >= 1 << 4) {
+ value >>= 4;
+ bit += 4;
+ }
+
+ if (value >= 1 << 2) {
+ value >>= 2;
+ bit += 2;
+ }
+
+ if (value >= 1 << 1) {
+ value >>= 1;
+ bit += 1;
+ }
+
+ return bit;
+}
+
+CMAPMapper *CMAPMapper::createUnicodeMapper(const CMAPTable *cmap)
+{
+ le_uint16 i;
+ le_uint16 nSubtables = SWAPW(cmap->numberSubtables);
+ const CMAPEncodingSubtable *subtable = NULL;
+ le_uint32 offset1 = 0, offset10 = 0;
+
+ for (i = 0; i < nSubtables; i += 1) {
+ const CMAPEncodingSubtableHeader *esh = &cmap->encodingSubtableHeaders[i];
+
+ switch (SWAPW(esh->platformID)) {
+ case 3: // Microsoft encodings
+ switch (SWAPW(esh->platformSpecificID)) {
+ case 1: // Unicode (really UCS-2?)
+ offset1 = READ_LONG(esh->encodingOffset);
+ break;
+
+ case 10: // UCS-4
+ offset10 = READ_LONG(esh->encodingOffset);
+ break;
+ }
+ break;
+
+ case 0: // Apple Unicode
+ offset10 = READ_LONG(esh->encodingOffset); // we ignore the unicode version
+ break;
+ }
+ }
+
+
+ if (offset10 != 0) {
+ subtable = (const CMAPEncodingSubtable *) ((const char *) cmap + offset10);
+ } else if (offset1 != 0) {
+ subtable = (const CMAPEncodingSubtable *) ((const char *) cmap + offset1);
+ } else {
+ return NULL;
+ }
+
+ switch (SWAPW(subtable->format)) {
+ case 4:
+ return new CMAPFormat4Mapper(cmap, (const CMAPFormat4Encoding *) subtable);
+
+ case 12:
+ {
+ const CMAPFormat12Encoding *encoding = (const CMAPFormat12Encoding *) subtable;
+
+ return new CMAPGroupMapper(cmap, encoding->groups, READ_LONG(encoding->nGroups));
+ }
+
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+CMAPFormat4Mapper::CMAPFormat4Mapper(const CMAPTable *cmap, const CMAPFormat4Encoding *header)
+ : CMAPMapper(cmap)
+{
+ le_uint16 segCount = SWAPW(header->segCountX2) / 2;
+
+ fEntrySelector = SWAPW(header->entrySelector);
+ fRangeShift = SWAPW(header->rangeShift) / 2;
+ fEndCodes = &header->endCodes[0];
+ fStartCodes = &header->endCodes[segCount + 1]; // + 1 for reservedPad...
+ fIdDelta = &fStartCodes[segCount];
+ fIdRangeOffset = &fIdDelta[segCount];
+}
+
+LEGlyphID CMAPFormat4Mapper::unicodeToGlyph(LEUnicode32 unicode32) const
+{
+ if (unicode32 >= 0x10000) {
+ return 0;
+ }
+
+ LEUnicode16 unicode = (LEUnicode16) unicode32;
+ le_uint16 index = 0;
+ le_uint16 probe = 1 << fEntrySelector;
+ TTGlyphID result = 0;
+
+ if (SWAPU16(fStartCodes[fRangeShift]) <= unicode) {
+ index = fRangeShift;
+ }
+
+ while (probe > (1 << 0)) {
+ probe >>= 1;
+
+ if (SWAPU16(fStartCodes[index + probe]) <= unicode) {
+ index += probe;
+ }
+ }
+
+ if (unicode >= SWAPU16(fStartCodes[index]) && unicode <= SWAPU16(fEndCodes[index])) {
+ if (fIdRangeOffset[index] == 0) {
+ result = (TTGlyphID) unicode;
+ } else {
+ le_uint16 offset = unicode - SWAPU16(fStartCodes[index]);
+ le_uint16 rangeOffset = SWAPW(fIdRangeOffset[index]);
+ le_uint16 *glyphIndexTable = (le_uint16 *) ((char *) &fIdRangeOffset[index] + rangeOffset);
+
+ result = SWAPW(glyphIndexTable[offset]);
+ }
+
+ result += SWAPW(fIdDelta[index]);
+ } else {
+ result = 0;
+ }
+
+ return LE_SET_GLYPH(0, result);
+}
+
+CMAPFormat4Mapper::~CMAPFormat4Mapper()
+{
+ // parent destructor does it all
+}
+
+CMAPGroupMapper::CMAPGroupMapper(const CMAPTable *cmap, const CMAPGroup *groups, le_uint32 nGroups)
+ : CMAPMapper(cmap), fGroups(groups)
+{
+ le_uint8 bit = highBit(nGroups);
+ fPower = 1 << bit;
+ fRangeOffset = nGroups - fPower;
+}
+
+LEGlyphID CMAPGroupMapper::unicodeToGlyph(LEUnicode32 unicode32) const
+{
+ le_int32 probe = fPower;
+ le_int32 range = 0;
+
+ if (READ_LONG(fGroups[fRangeOffset].startCharCode) <= unicode32) {
+ range = fRangeOffset;
+ }
+
+ while (probe > (1 << 0)) {
+ probe >>= 1;
+
+ if (READ_LONG(fGroups[range + probe].startCharCode) <= unicode32) {
+ range += probe;
+ }
+ }
+
+ if (READ_LONG(fGroups[range].startCharCode) <= unicode32 && READ_LONG(fGroups[range].endCharCode) >= unicode32) {
+ return (LEGlyphID) (READ_LONG(fGroups[range].startGlyphCode) + unicode32 - READ_LONG(fGroups[range].startCharCode));
+ }
+
+ return 0;
+}
+
+CMAPGroupMapper::~CMAPGroupMapper()
+{
+ // parent destructor does it all
+}
+
diff --git a/Build/source/texk/web2c/xetexdir/cmaps.h b/Build/source/texk/web2c/xetexdir/cmaps.h
new file mode 100644
index 00000000000..5f7dd81aeec
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/cmaps.h
@@ -0,0 +1,116 @@
+/*
+ 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.
+*/
+
+/* from ICU sample code, extended by JK for XeTeX */
+
+/***************************************************************************
+*
+* Copyright (C) 1998-2003, International Business Machines
+* Corporation and others. All Rights Reserved.
+*
+************************************************************************/
+
+
+#ifndef __CMAPS_H
+#define __CMAPS_H
+
+#include "LETypes.h"
+#include "sfnt.h"
+
+class CMAPMapper
+{
+public:
+ virtual LEGlyphID unicodeToGlyph(LEUnicode32 unicode32) const = 0;
+
+ virtual ~CMAPMapper();
+
+ static CMAPMapper *createUnicodeMapper(const CMAPTable *cmap);
+
+protected:
+ CMAPMapper(const CMAPTable *cmap);
+
+ CMAPMapper() {};
+
+private:
+ const CMAPTable *fcmap;
+};
+
+class CMAPFormat4Mapper : public CMAPMapper
+{
+public:
+ CMAPFormat4Mapper(const CMAPTable *cmap, const CMAPFormat4Encoding *header);
+
+ virtual ~CMAPFormat4Mapper();
+
+ virtual LEGlyphID unicodeToGlyph(LEUnicode32 unicode32) const;
+
+protected:
+ CMAPFormat4Mapper() {};
+
+private:
+ le_uint16 fEntrySelector;
+ le_uint16 fRangeShift;
+ const le_uint16 *fEndCodes;
+ const le_uint16 *fStartCodes;
+ const le_uint16 *fIdDelta;
+ const le_uint16 *fIdRangeOffset;
+};
+
+class CMAPGroupMapper : public CMAPMapper
+{
+public:
+ CMAPGroupMapper(const CMAPTable *cmap, const CMAPGroup *groups, le_uint32 nGroups);
+
+ virtual ~CMAPGroupMapper();
+
+ virtual LEGlyphID unicodeToGlyph(LEUnicode32 unicode32) const;
+
+protected:
+ CMAPGroupMapper() {};
+
+private:
+ le_int32 fPower;
+ le_int32 fRangeOffset;
+ const CMAPGroup *fGroups;
+};
+
+inline CMAPMapper::CMAPMapper(const CMAPTable *cmap)
+ : fcmap(cmap)
+{
+ // nothing else to do
+}
+
+inline CMAPMapper::~CMAPMapper()
+{
+ LE_DELETE_ARRAY(fcmap);
+}
+
+#endif
+
diff --git a/Build/source/texk/web2c/xetexdir/cpl1.0.txt b/Build/source/texk/web2c/xetexdir/cpl1.0.txt
new file mode 100644
index 00000000000..c9990a7ea45
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/cpl1.0.txt
@@ -0,0 +1,213 @@
+Common Public License Version 1.0
+
+THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS COMMON PUBLIC
+LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM
+CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
+
+1. DEFINITIONS
+
+"Contribution" means:
+
+ a) in the case of the initial Contributor, the initial code and
+documentation distributed under this Agreement, and
+
+ b) in the case of each subsequent Contributor:
+
+ i) changes to the Program, and
+
+ ii) additions to the Program;
+
+ where such changes and/or additions to the Program originate from and are
+distributed by that particular Contributor. A Contribution 'originates' from a
+Contributor if it was added to the Program by such Contributor itself or anyone
+acting on such Contributor's behalf. Contributions do not include additions to
+the Program which: (i) are separate modules of software distributed in
+conjunction with the Program under their own license agreement, and (ii) are not
+derivative works of the Program.
+
+"Contributor" means any person or entity that distributes the Program.
+
+"Licensed Patents " mean patent claims licensable by a Contributor which are
+necessarily infringed by the use or sale of its Contribution alone or when
+combined with the Program.
+
+"Program" means the Contributions distributed in accordance with this Agreement.
+
+"Recipient" means anyone who receives the Program under this Agreement,
+including all Contributors.
+
+2. GRANT OF RIGHTS
+
+ a) Subject to the terms of this Agreement, each Contributor hereby grants
+Recipient a non-exclusive, worldwide, royalty-free copyright license to
+reproduce, prepare derivative works of, publicly display, publicly perform,
+distribute and sublicense the Contribution of such Contributor, if any, and such
+derivative works, in source code and object code form.
+
+ b) Subject to the terms of this Agreement, each Contributor hereby grants
+Recipient a non-exclusive, worldwide, royalty-free patent license under Licensed
+Patents to make, use, sell, offer to sell, import and otherwise transfer the
+Contribution of such Contributor, if any, in source code and object code form.
+This patent license shall apply to the combination of the Contribution and the
+Program if, at the time the Contribution is added by the Contributor, such
+addition of the Contribution causes such combination to be covered by the
+Licensed Patents. The patent license shall not apply to any other combinations
+which include the Contribution. No hardware per se is licensed hereunder.
+
+ c) Recipient understands that although each Contributor grants the licenses
+to its Contributions set forth herein, no assurances are provided by any
+Contributor that the Program does not infringe the patent or other intellectual
+property rights of any other entity. Each Contributor disclaims any liability to
+Recipient for claims brought by any other entity based on infringement of
+intellectual property rights or otherwise. As a condition to exercising the
+rights and licenses granted hereunder, each Recipient hereby assumes sole
+responsibility to secure any other intellectual property rights needed, if any.
+For example, if a third party patent license is required to allow Recipient to
+distribute the Program, it is Recipient's responsibility to acquire that license
+before distributing the Program.
+
+ d) Each Contributor represents that to its knowledge it has sufficient
+copyright rights in its Contribution, if any, to grant the copyright license set
+forth in this Agreement.
+
+3. REQUIREMENTS
+
+A Contributor may choose to distribute the Program in object code form under its
+own license agreement, provided that:
+
+ a) it complies with the terms and conditions of this Agreement; and
+
+ b) its license agreement:
+
+ i) effectively disclaims on behalf of all Contributors all warranties and
+conditions, express and implied, including warranties or conditions of title and
+non-infringement, and implied warranties or conditions of merchantability and
+fitness for a particular purpose;
+
+ ii) effectively excludes on behalf of all Contributors all liability for
+damages, including direct, indirect, special, incidental and consequential
+damages, such as lost profits;
+
+ iii) states that any provisions which differ from this Agreement are offered
+by that Contributor alone and not by any other party; and
+
+ iv) states that source code for the Program is available from such
+Contributor, and informs licensees how to obtain it in a reasonable manner on or
+through a medium customarily used for software exchange.
+
+When the Program is made available in source code form:
+
+ a) it must be made available under this Agreement; and
+
+ b) a copy of this Agreement must be included with each copy of the Program.
+
+Contributors may not remove or alter any copyright notices contained within the
+Program.
+
+Each Contributor must identify itself as the originator of its Contribution, if
+any, in a manner that reasonably allows subsequent Recipients to identify the
+originator of the Contribution.
+
+4. COMMERCIAL DISTRIBUTION
+
+Commercial distributors of software may accept certain responsibilities with
+respect to end users, business partners and the like. While this license is
+intended to facilitate the commercial use of the Program, the Contributor who
+includes the Program in a commercial product offering should do so in a manner
+which does not create potential liability for other Contributors. Therefore, if
+a Contributor includes the Program in a commercial product offering, such
+Contributor ("Commercial Contributor") hereby agrees to defend and indemnify
+every other Contributor ("Indemnified Contributor") against any losses, damages
+and costs (collectively "Losses") arising from claims, lawsuits and other legal
+actions brought by a third party against the Indemnified Contributor to the
+extent caused by the acts or omissions of such Commercial Contributor in
+connection with its distribution of the Program in a commercial product
+offering. The obligations in this section do not apply to any claims or Losses
+relating to any actual or alleged intellectual property infringement. In order
+to qualify, an Indemnified Contributor must: a) promptly notify the Commercial
+Contributor in writing of such claim, and b) allow the Commercial Contributor to
+control, and cooperate with the Commercial Contributor in, the defense and any
+related settlement negotiations. The Indemnified Contributor may participate in
+any such claim at its own expense.
+
+For example, a Contributor might include the Program in a commercial product
+offering, Product X. That Contributor is then a Commercial Contributor. If that
+Commercial Contributor then makes performance claims, or offers warranties
+related to Product X, those performance claims and warranties are such
+Commercial Contributor's responsibility alone. Under this section, the
+Commercial Contributor would have to defend claims against the other
+Contributors related to those performance claims and warranties, and if a court
+requires any other Contributor to pay any damages as a result, the Commercial
+Contributor must pay those damages.
+
+5. NO WARRANTY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
+IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE,
+NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each
+Recipient is solely responsible for determining the appropriateness of using and
+distributing the Program and assumes all risks associated with its exercise of
+rights under this Agreement, including but not limited to the risks and costs of
+program errors, compliance with applicable laws, damage to or loss of data,
+programs or equipment, and unavailability or interruption of operations.
+
+6. DISCLAIMER OF LIABILITY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY
+CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST
+PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS
+GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+7. GENERAL
+
+If any provision of this Agreement is invalid or unenforceable under applicable
+law, it shall not affect the validity or enforceability of the remainder of the
+terms of this Agreement, and without further action by the parties hereto, such
+provision shall be reformed to the minimum extent necessary to make such
+provision valid and enforceable.
+
+If Recipient institutes patent litigation against a Contributor with respect to
+a patent applicable to software (including a cross-claim or counterclaim in a
+lawsuit), then any patent licenses granted by that Contributor to such Recipient
+under this Agreement shall terminate as of the date such litigation is filed. In
+addition, if Recipient institutes patent litigation against any entity
+(including a cross-claim or counterclaim in a lawsuit) alleging that the Program
+itself (excluding combinations of the Program with other software or hardware)
+infringes such Recipient's patent(s), then such Recipient's rights granted under
+Section 2(b) shall terminate as of the date such litigation is filed.
+
+All Recipient's rights under this Agreement shall terminate if it fails to
+comply with any of the material terms or conditions of this Agreement and does
+not cure such failure in a reasonable period of time after becoming aware of
+such noncompliance. If all Recipient's rights under this Agreement terminate,
+Recipient agrees to cease use and distribution of the Program as soon as
+reasonably practicable. However, Recipient's obligations under this Agreement
+and any licenses granted by Recipient relating to the Program shall continue and
+survive.
+
+Everyone is permitted to copy and distribute copies of this Agreement, but in
+order to avoid inconsistency the Agreement is copyrighted and may only be
+modified in the following manner. The Agreement Steward reserves the right to
+publish new versions (including revisions) of this Agreement from time to time.
+No one other than the Agreement Steward has the right to modify this Agreement.
+IBM is the initial Agreement Steward. IBM may assign the responsibility to serve
+as the Agreement Steward to a suitable separate entity. Each new version of the
+Agreement will be given a distinguishing version number. The Program (including
+Contributions) may always be distributed subject to the version of the Agreement
+under which it was received. In addition, after a new version of the Agreement
+is published, Contributor may elect to distribute the Program (including its
+Contributions) under the new version. Except as expressly stated in Sections
+2(a) and 2(b) above, Recipient receives no rights or licenses to the
+intellectual property of any Contributor under this Agreement, whether
+expressly, by implication, estoppel or otherwise. All rights in the Program not
+expressly granted under this Agreement are reserved.
+
+This Agreement is governed by the laws of the State of New York and the
+intellectual property laws of the United States of America. No party to this
+Agreement will bring a legal action under this Agreement more than one year
+after the cause of action arose. Each party waives its rights to a jury trial in
+any resulting litigation.
diff --git a/Build/source/texk/web2c/xetexdir/jpegimage.c b/Build/source/texk/web2c/xetexdir/jpegimage.c
new file mode 100644
index 00000000000..165a675f6f6
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/jpegimage.c
@@ -0,0 +1,410 @@
+/****************************************************************************\
+ Part of the XeTeX typesetting system
+ copyright (c) 1994-2006 by SIL International
+ written by Jonathan Kew
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+\****************************************************************************/
+
+/* this file is derived from the dvipdfmx project;
+ the original header follows... */
+
+/* $Header: /home/cvsroot/dvipdfmx/src/jpegimage.c,v 1.8 2004/09/05 13:30:05 hirata Exp $
+
+ This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
+
+ Copyright (C) 2002 by Jin-Hwan Cho and Shunsaku Hirata,
+ the dvipdfmx project team <dvipdfmx@project.ktug.or.kr>
+
+ Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+*/
+
+
+/*
+ * JPEG SUPPORT
+ *
+ * Accroding to Libjpeg document:
+ *
+ * CAUTION: it appears that Adobe Photoshop writes inverted data in CMYK
+ * JPEG files: 0 represents 100% ink coverage, rather than 0% ink as you'd
+ * expect....
+ *
+ * To wrok with this problem, we must detect whether CMYK JPEG file is
+ * created by Photoshop. But there are no reliable way to determine this.
+ *
+ * According to Adobe Technical Note #5516,
+ * "Supporting the DCT Filters in PostScript Level 2", Section 18, p.27.
+ *
+ * DCTDecode ignores and skips any APPE marker segment does not begin with
+ * the `Adobe' 5-character string.
+ *
+ * PDF Reference Manual 4th ed., p.61-62.
+ *
+ * The JPEG filter implementation in Adobe Acrobat products does not
+ * support features of the JPEG standard that are irrelevant to images.
+ * In addition, certain choices have been made regarding reserved marker
+ * codes and other optional features of the standard. For details, see
+ * Adobe Technical Note #5116, Supporting the DCT Filters in PostScript
+ * Level 2.
+ */
+
+#include "mfileio.h"
+#include "numbers.h"
+
+#include "jpegimage.h"
+
+#include <memory.h>
+
+#define JPEG_DEBUG_STR "JPEG"
+#define JPEG_DEBUG 3
+
+
+#define HAVE_APPn_JFIF (1 << 0)
+#define HAVE_APPn_ADOBE (1 << 1)
+#define HAVE_APPn_ICC (1 << 2)
+
+static void JPEG_info_init (struct JPEG_info *j_info);
+static void JPEG_info_clear (struct JPEG_info *j_info);
+
+#define RELEASE(p) free(p)
+#define NEW(n, t) (t*)xmalloc(n * sizeof(t))
+#define RENEW(p, n, t) ((p) ? (t*)xrealloc(p, (n) * sizeof(t)) : NEW(n, t))
+
+int
+check_for_jpeg (FILE *fp)
+{
+ unsigned char jpeg_sig[2];
+
+ rewind(fp);
+ if (fread(jpeg_sig, sizeof(unsigned char), 2, fp) != 2)
+ return 0;
+ else if (jpeg_sig[0] != 0xff || jpeg_sig[1] != JM_SOI)
+ return 0;
+
+ return 1;
+}
+
+static void
+JPEG_info_init (struct JPEG_info *j_info)
+{
+ j_info->width = 0;
+ j_info->height = 0;
+ j_info->bits_per_component = 0;
+ j_info->num_components = 0;
+
+ j_info->xdpi = 0;
+ j_info->ydpi = 0;
+
+ j_info->flags = 0;
+ j_info->num_appn = 0;
+ j_info->max_appn = 0;
+ j_info->appn = NULL;
+
+ memset(j_info->skipbits, 0, MAX_COUNT / 8 + 1);
+}
+
+static void
+JPEG_release_APPn_data (JPEG_marker marker, JPEG_APPn_sig app_sig, void *app_data)
+{
+ if (marker == JM_APP0 &&
+ app_sig == JS_APPn_JFIF) {
+ struct JPEG_APPn_JFIF *data;
+
+ data = (struct JPEG_APPn_JFIF *) app_data;
+ if (data->thumbnail)
+ RELEASE(data->thumbnail);
+ data->thumbnail = NULL;
+
+ RELEASE(data);
+ } else if (marker == JM_APP2 &&
+ app_sig == JS_APPn_ICC) {
+ struct JPEG_APPn_ICC *data;
+
+ data = (struct JPEG_APPn_ICC *) app_data;
+ if (data->chunk)
+ RELEASE(data->chunk);
+ data->chunk = NULL;
+
+ RELEASE(data);
+ } else if (marker == JM_APP14 &&
+ app_sig == JS_APPn_ADOBE) {
+ struct JPEG_APPn_Adobe *data;
+
+ data = (struct JPEG_APPn_Adobe *) app_data;
+
+ RELEASE(data);
+ }
+}
+
+static void
+JPEG_info_clear (struct JPEG_info *j_info)
+{
+ if (j_info->num_appn > 0 &&
+ j_info->appn != NULL) {
+ int i;
+
+ for (i = 0; i < j_info->num_appn; i++)
+ JPEG_release_APPn_data(j_info->appn[i].marker,
+ j_info->appn[i].app_sig, j_info->appn[i].app_data);
+ RELEASE(j_info->appn);
+ }
+ j_info->appn = NULL;
+ j_info->num_appn = 0;
+ j_info->max_appn = 0;
+ j_info->flags = 0;
+}
+
+static JPEG_marker
+JPEG_get_marker (FILE *fp)
+{
+ int c;
+
+ c = fgetc(fp);
+ if (c != 255)
+ return -1;
+
+ for (;;) {
+ c = fgetc(fp);
+ if (c < 0)
+ return -1;
+ else if (c > 0 && c < 255) {
+ return c;
+ }
+ }
+
+ return -1;
+}
+
+static int
+add_APPn_marker (struct JPEG_info *j_info,
+ JPEG_marker marker, int app_sig, void *app_data)
+{
+ int n;
+
+ if (j_info->num_appn >= j_info->max_appn) {
+ j_info->max_appn += 16;
+ j_info->appn = RENEW(j_info->appn, j_info->max_appn, struct JPEG_ext);
+ }
+ n = j_info->num_appn;
+
+ j_info->appn[n].marker = marker;
+ j_info->appn[n].app_sig = app_sig;
+ j_info->appn[n].app_data = app_data;
+
+ j_info->num_appn += 1;
+
+ return n;
+}
+
+static unsigned short
+read_APP14_Adobe (struct JPEG_info *j_info, FILE *fp, unsigned short length)
+{
+ struct JPEG_APPn_Adobe *app_data;
+
+ app_data = NEW(1, struct JPEG_APPn_Adobe);
+ app_data->version = get_unsigned_pair(fp);
+ app_data->flag0 = get_unsigned_pair(fp);
+ app_data->flag1 = get_unsigned_pair(fp);
+ app_data->transform = get_unsigned_byte(fp);
+
+ add_APPn_marker(j_info, JM_APP14, JS_APPn_ADOBE, app_data);
+
+ return 7;
+}
+
+static unsigned short
+read_APP0_JFIF (struct JPEG_info *j_info, FILE *fp, unsigned short length)
+{
+ struct JPEG_APPn_JFIF *app_data;
+ unsigned short thumb_data_len;
+
+ app_data = NEW(1, struct JPEG_APPn_JFIF);
+ app_data->version = get_unsigned_pair(fp);
+ app_data->units = get_unsigned_byte(fp);
+ app_data->Xdensity = get_unsigned_pair(fp);
+ app_data->Ydensity = get_unsigned_pair(fp);
+ app_data->Xthumbnail = get_unsigned_byte(fp);
+ app_data->Ythumbnail = get_unsigned_byte(fp);
+ thumb_data_len = 3 * app_data->Xthumbnail * app_data->Ythumbnail;
+ if (thumb_data_len > 0) {
+ app_data->thumbnail = NEW(thumb_data_len, unsigned char);
+ fread(app_data->thumbnail, 1, thumb_data_len, fp);
+ } else {
+ app_data->thumbnail = NULL;
+ }
+
+ add_APPn_marker(j_info, JM_APP0, JS_APPn_JFIF, app_data);
+
+ switch (app_data->units) {
+ case 1:
+ j_info->xdpi = app_data->Xdensity;
+ j_info->ydpi = app_data->Ydensity;
+ break;
+ case 2: /* density is in pixels per cm */
+ j_info->xdpi = app_data->Xdensity * 2.54;
+ j_info->ydpi = app_data->Ydensity * 2.54;
+ break;
+ default: /* FIXME: not sure what to do with this.... */
+ j_info->xdpi = 72.0;
+ j_info->ydpi = 72.0 * app_data->Ydensity / app_data->Xdensity;
+ break;
+ }
+
+ return (9 + thumb_data_len);
+}
+
+static unsigned short
+read_APP0_JFXX (struct JPEG_info *j_info, FILE *fp, unsigned short length)
+{
+ unsigned char extension_code;
+
+ extension_code = get_unsigned_byte(fp);
+ /* Extension Code:
+ *
+ * 0x10: Thumbnail coded using JPEG
+ * 0x11: Thumbnail stored using 1 byte/pixel
+ * 0x13: Thumbnail stored using 3 bytes/pixel
+ */
+ seek_relative(fp, length-1); /* Thunbnail image */
+
+ /* Ignore */
+
+ return length;
+}
+
+static unsigned short
+read_APP2_ICC (struct JPEG_info *j_info, FILE *fp, unsigned short length)
+{
+ struct JPEG_APPn_ICC *app_data;
+
+ app_data = NEW(1, struct JPEG_APPn_ICC);
+ app_data->seq_id = get_unsigned_byte(fp); /* Starting at 1 */
+ app_data->num_chunks = get_unsigned_byte(fp);
+ app_data->length = length - 2;
+ app_data->chunk = NEW(app_data->length, unsigned char);
+ fread(app_data->chunk, 1, app_data->length, fp);
+
+ add_APPn_marker(j_info, JM_APP2, JS_APPn_ICC, app_data);
+
+ return length;
+}
+
+
+int
+JPEG_scan_file (struct JPEG_info *j_info, FILE *fp)
+{
+ JPEG_marker marker;
+ unsigned short length;
+ int found_SOFn, count;
+ char app_sig[128];
+
+ JPEG_info_init(j_info);
+
+ rewind(fp);
+ count = 0;
+ found_SOFn = 0;
+ while (!found_SOFn &&
+ (marker = JPEG_get_marker(fp)) >= 0) {
+ if (marker == JM_SOI ||
+ (marker >= JM_RST0 && marker <= JM_RST7)) {
+ count++;
+ continue;
+ }
+ length = get_unsigned_pair(fp) - 2;
+ switch (marker) {
+ case JM_SOF0: case JM_SOF1: case JM_SOF2: case JM_SOF3:
+ case JM_SOF5: case JM_SOF6: case JM_SOF7: case JM_SOF9:
+ case JM_SOF10: case JM_SOF11: case JM_SOF13: case JM_SOF14:
+ case JM_SOF15:
+ j_info->bits_per_component = get_unsigned_byte(fp);
+ j_info->height = get_unsigned_pair(fp);
+ j_info->width = get_unsigned_pair(fp);
+ j_info->num_components = get_unsigned_byte(fp);
+ found_SOFn = 1;
+ break;
+ case JM_APP0:
+ if (length > 5) {
+ if (fread(app_sig, sizeof(char), 5, fp) != 5)
+ return -1;
+ length -= 5;
+ if (!memcmp(app_sig, "JFIF\000", 5)) {
+ j_info->flags |= HAVE_APPn_JFIF;
+ length -= read_APP0_JFIF(j_info, fp, length);
+ } else if (!memcmp(app_sig, "JFXX", 5)) {
+ length -= read_APP0_JFXX(j_info, fp, length);
+ }
+ }
+ seek_relative(fp, length);
+ break;
+ case JM_APP2:
+ if (length >= 14) {
+ if (fread(app_sig, sizeof(char), 12, fp) != 12)
+ return -1;
+ length -= 12;
+ if (!memcmp(app_sig, "ICC_PROFILE\000", 12)) {
+ j_info->flags |= HAVE_APPn_ICC;
+ length -= read_APP2_ICC(j_info, fp, length);
+ if (count < MAX_COUNT) {
+ j_info->skipbits[count / 8] |= (1 << (7 - (count % 8)));
+ }
+ }
+ }
+ seek_relative(fp, length);
+ break;
+ case JM_APP14:
+ if (length > 5) {
+ if (fread(app_sig, sizeof(char), 5, fp) != 5)
+ return -1;
+ length -= 5;
+ if (!memcmp(app_sig, "Adobe", 5)) {
+ j_info->flags |= HAVE_APPn_ADOBE;
+ length -= read_APP14_Adobe(j_info, fp, length);
+ } else {
+ if (count < MAX_COUNT) {
+ j_info->skipbits[count/8] |= (1 << (7 - (count % 8)));
+ }
+ }
+ }
+ seek_relative(fp, length);
+ break;
+ default:
+ seek_relative(fp, length);
+ if (marker >= JM_APP0 &&
+ marker <= JM_APP15) {
+ if (count < MAX_COUNT) {
+ j_info->skipbits[count / 8] |= (1 << (7 - (count % 8)));
+ }
+ }
+ break;
+ }
+ count++;
+ }
+
+ return (found_SOFn ? 0 : -1);
+}
diff --git a/Build/source/texk/web2c/xetexdir/jpegimage.h b/Build/source/texk/web2c/xetexdir/jpegimage.h
new file mode 100644
index 00000000000..03ef4ea56a3
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/jpegimage.h
@@ -0,0 +1,166 @@
+/****************************************************************************\
+ Part of the XeTeX typesetting system
+ copyright (c) 1994-2006 by SIL International
+ written by Jonathan Kew
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+\****************************************************************************/
+
+/* this file is derived from the dvipdfmx project;
+ the original header follows... */
+
+/* $Header: /home/cvsroot/dvipdfmx/src/jpegimage.h,v 1.2 2004/03/11 11:50:21 hirata Exp $
+
+ This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
+
+ Copyright (C) 2002 by Jin-Hwan Cho and Shunsaku Hirata,
+ the dvipdfmx project team <dvipdfmx@project.ktug.or.kr>
+
+ Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+*/
+
+#ifndef _JPEGIMAGE_H_
+#define _JPEGIMAGE_H_
+
+#include "mfileio.h"
+
+/* JPEG Markers */
+typedef enum {
+ JM_SOF0 = 0xc0,
+ JM_SOF1 = 0xc1,
+ JM_SOF2 = 0xc2,
+ JM_SOF3 = 0xc3,
+ JM_SOF5 = 0xc5,
+ JM_DHT = 0xc4,
+ JM_SOF6 = 0xc6,
+ JM_SOF7 = 0xc7,
+ JM_SOF9 = 0xc9,
+ JM_SOF10 = 0xca,
+ JM_SOF11 = 0xcb,
+ JM_DAC = 0xcc,
+ JM_SOF13 = 0xcd,
+ JM_SOF14 = 0xce,
+ JM_SOF15 = 0xcf,
+
+ JM_RST0 = 0xd0,
+ JM_RST1 = 0xd1,
+ JM_RST2 = 0xd2,
+ JM_RST3 = 0xd3,
+ JM_RST4 = 0xd4,
+ JM_RST5 = 0xd5,
+ JM_RST6 = 0xd6,
+ JM_RST7 = 0xd7,
+
+ JM_SOI = 0xd8,
+ JM_EOI = 0xd9,
+ JM_SOS = 0xda,
+ JM_DQT = 0xdb,
+ JM_DNL = 0xdc,
+ JM_DRI = 0xdd,
+ JM_DHP = 0xde,
+ JM_EXP = 0xdf,
+
+ JM_APP0 = 0xe0,
+ JM_APP2 = 0xe2,
+ JM_APP14 = 0xee,
+ JM_APP15 = 0xef,
+
+ JM_COM = 0xfe
+} JPEG_marker;
+
+typedef enum {
+ JS_APPn_JFIF,
+ JS_APPn_ADOBE,
+ JS_APPn_ICC
+} JPEG_APPn_sig;
+
+struct JPEG_APPn_JFIF /* APP0 */
+{
+ unsigned short version;
+ unsigned char units; /* 0: only aspect ratio
+ * 1: dots per inch
+ * 2: dots per cm
+ */
+ unsigned short Xdensity;
+ unsigned short Ydensity;
+ unsigned char Xthumbnail;
+ unsigned char Ythumbnail;
+ unsigned char *thumbnail; /* Thumbnail data. */
+};
+
+struct JPEG_APPn_ICC /* APP2 */
+{
+ unsigned char seq_id;
+ unsigned char num_chunks;
+ unsigned char *chunk;
+
+ /* Length of ICC profile data in this chunk. */
+ unsigned short length;
+};
+
+struct JPEG_APPn_Adobe /* APP14 */
+{
+ unsigned short version;
+ unsigned short flag0;
+ unsigned short flag1;
+ unsigned char transform; /* color transform code */
+};
+
+struct JPEG_ext
+{
+ JPEG_marker marker;
+ JPEG_APPn_sig app_sig;
+ void *app_data;
+};
+
+#define MAX_COUNT 1024
+struct JPEG_info
+{
+ unsigned short height;
+ unsigned short width;
+
+ unsigned char bits_per_component;
+ unsigned char num_components;
+
+ double xdpi;
+ double ydpi;
+
+ /* Application specific extensions */
+ int flags;
+ int num_appn, max_appn;
+ struct JPEG_ext *appn;
+
+ /* Skip chunks not necessary. */
+ char skipbits[MAX_COUNT / 8 + 1];
+};
+
+extern int check_for_jpeg(FILE *fp);
+extern int JPEG_scan_file(struct JPEG_info *info, FILE *fp);
+
+#endif /* _JPEGIMAGE_H_ */
diff --git a/Build/source/texk/web2c/xetexdir/mfileio.c b/Build/source/texk/web2c/xetexdir/mfileio.c
new file mode 100644
index 00000000000..e6c1a229850
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/mfileio.c
@@ -0,0 +1,126 @@
+/* $Header: /home/cvsroot/dvipdfmx/src/mfileio.c,v 1.3 2002/10/30 02:27:11 chofchof Exp $
+
+ This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
+
+ Copyright (C) 2002 by Jin-Hwan Cho and Shunsaku Hirata,
+ the dvipdfmx project team <dvipdfmx@project.ktug.or.kr>
+
+ Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "mfileio.h"
+
+#ifdef IODEBUG
+static FILE *iodebug_file = NULL;
+static long event = 0;
+static void io_debug_init(void)
+{
+ if (!iodebug_file) {
+ iodebug_file = fopen ("fopen.log", "wb");
+ fprintf (stderr, "\n*** File IO debugging started ***\n");
+ }
+ if (!iodebug_file) {
+ fprintf (stderr, "\nError opening io log\n");
+ }
+}
+#endif
+
+#ifdef IODEBUG
+FILE *mfopen(const char *name, const char *mode, const char *function, int line)
+{
+ FILE *tmp;
+ io_debug_init();
+ tmp = fopen (name, mode);
+ event += 1;
+ fprintf(iodebug_file, "%p %07ld [fopen] %s:%d\n", tmp, event,
+ function, line);
+ return tmp;
+}
+int mfclose(FILE *file, const char *function, int line)
+{
+ io_debug_init();
+ event += 1;
+ fprintf(iodebug_file, "%p %07ld [fclose] %s:%d\n", file, event,
+ function, line);
+ return fclose(file);
+}
+#endif
+
+static void os_error()
+{
+ fprintf (stderr, "io: An OS command failed that should not have.\n");
+ exit(-1);
+}
+
+void seek_absolute (FILE *file, long pos)
+{
+ if (fseek(file, pos, SEEK_SET)) {
+ os_error();
+ }
+}
+
+void seek_relative (FILE *file, long pos)
+{
+ if (fseek(file, pos, SEEK_CUR)) {
+ os_error();
+ }
+}
+
+
+void seek_end (FILE *file)
+{
+ if (fseek(file, 0L, SEEK_END)) {
+ os_error();
+ }
+}
+
+long tell_position (FILE *file)
+{
+ long size;
+ if ((size = ftell (file)) < 0) {
+ os_error();
+ }
+ return size;
+}
+
+long file_size (FILE *file)
+{
+ long size;
+ /* Seek to end */
+ seek_end (file);
+ size = tell_position (file);
+ rewind (file);
+ return (size);
+}
+
+/* Unlike fgets, mfgets works with \r, \n, or \r\n end of lines. */
+char *mfgets (char *buffer, unsigned long length, FILE *file)
+{
+ int ch = 0, i = 0;
+ while (i < length-1 && (ch = fgetc (file)) >= 0 && ch != '\n' && ch != '\r')
+ buffer[i++] = ch;
+ buffer[i] = 0;
+ if (ch < 0 && i == 0)
+ return NULL;
+ if (ch == '\r' && (ch = fgetc (file)) >= 0 && (ch != '\n'))
+ ungetc (ch, file);
+ return buffer;
+}
+
+char work_buffer[WORK_BUFFER_SIZE];
diff --git a/Build/source/texk/web2c/xetexdir/mfileio.h b/Build/source/texk/web2c/xetexdir/mfileio.h
new file mode 100644
index 00000000000..e31fef23244
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/mfileio.h
@@ -0,0 +1,61 @@
+/* $Header: /home/cvsroot/dvipdfmx/src/mfileio.h,v 1.3 2002/10/30 02:27:12 chofchof Exp $
+
+ This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
+
+ Copyright (C) 2002 by Jin-Hwan Cho and Shunsaku Hirata,
+ the dvipdfmx project team <dvipdfmx@project.ktug.or.kr>
+
+ Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+*/
+
+#ifndef _MFILEIO_H_
+#define _MFILEIO_H_
+
+#include <stdio.h>
+#include "numbers.h"
+
+#ifdef IODEBUG
+FILE *mfopen (const char *name, const char *mode,
+ const char *function, int line);
+int mfclose (FILE *file, const char *function, int line);
+#define MFOPEN(name,mode) \
+ mfopen((name),(mode),__FUNCTION__,__LINE__)
+#define MFCLOSE(file) \
+ mfclose((file),__FUNCTION__,__LINE__)
+#else
+#define MFOPEN(name,mode) fopen((name),(mode))
+#define MFCLOSE(file) fclose(file)
+#endif
+
+extern UNSIGNED_BYTE read_byte (FILE *);
+
+extern void seek_absolute (FILE *file, long pos);
+extern void seek_relative (FILE *file, long pos);
+
+extern void seek_end (FILE *file);
+
+extern long tell_position (FILE *file);
+
+extern long file_size (FILE *file);
+
+extern char *mfgets (char *buffer, unsigned long size, FILE *file);
+
+extern char work_buffer[];
+
+#define WORK_BUFFER_SIZE 1024
+
+#endif /* _MFILEIO_H_ */
diff --git a/Build/source/texk/web2c/xetexdir/numbers.c b/Build/source/texk/web2c/xetexdir/numbers.c
new file mode 100644
index 00000000000..06864f1e2bb
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/numbers.c
@@ -0,0 +1,227 @@
+/* $Header: /home/cvsroot/dvipdfmx/src/numbers.c,v 1.8 2004/03/03 13:19:00 hirata Exp $
+
+ This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
+
+ Copyright (C) 2002 by Jin-Hwan Cho and Shunsaku Hirata,
+ the dvipdfmx project team <dvipdfmx@project.ktug.or.kr>
+
+ Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+*/
+
+#include <stdlib.h>
+
+#include "mfileio.h"
+#include "numbers.h"
+
+UNSIGNED_BYTE get_unsigned_byte (FILE *file)
+{
+ int ch;
+ if ((ch = fgetc (file)) < 0) {
+ fprintf (stderr, "File ended prematurely\n");
+ exit(-1);
+ }
+ return (UNSIGNED_BYTE) ch;
+}
+
+UNSIGNED_BYTE sget_unsigned_byte (char *s)
+{
+ return *((unsigned char *) s);
+}
+
+SIGNED_BYTE get_signed_byte (FILE *file)
+{
+ int byte;
+ byte = get_unsigned_byte(file);
+ if (byte >= 0x80)
+ byte -= 0x100;
+ return (SIGNED_BYTE) byte;
+}
+
+UNSIGNED_PAIR get_unsigned_pair (FILE *file)
+{
+ int i;
+ UNSIGNED_BYTE byte;
+ UNSIGNED_PAIR pair = 0;
+ for (i=0; i<2; i++) {
+ byte = get_unsigned_byte(file);
+ pair = pair*0x100u + byte;
+ }
+ return pair;
+}
+
+UNSIGNED_PAIR sget_unsigned_pair (unsigned char *s)
+{
+ int i;
+ UNSIGNED_BYTE byte;
+ UNSIGNED_PAIR pair = 0;
+ for (i=0; i<2; i++) {
+ byte = *(s++);
+ pair = pair*0x100u + byte;
+ }
+ return pair;
+}
+
+SIGNED_PAIR get_signed_pair (FILE *file)
+{
+ int i;
+ long pair = 0;
+ for (i=0; i<2; i++) {
+ pair = pair*0x100 + get_unsigned_byte(file);
+ }
+ if (pair >= 0x8000) {
+ pair -= 0x10000l;
+ }
+ return (SIGNED_PAIR) pair;
+}
+
+
+UNSIGNED_TRIPLE get_unsigned_triple(FILE *file)
+{
+ int i;
+ long triple = 0;
+ for (i=0; i<3; i++) {
+ triple = triple*0x100u + get_unsigned_byte(file);
+ }
+ return (UNSIGNED_TRIPLE) triple;
+}
+
+SIGNED_TRIPLE get_signed_triple(FILE *file)
+{
+ int i;
+ long triple = 0;
+ for (i=0; i<3; i++) {
+ triple = triple*0x100 + get_unsigned_byte(file);
+ }
+ if (triple >= 0x800000l)
+ triple -= 0x1000000l;
+ return (SIGNED_TRIPLE) triple;
+}
+
+SIGNED_QUAD get_signed_quad(FILE *file)
+{
+ int byte, i;
+ long quad = 0;
+
+ /* Check sign on first byte before reading others */
+ byte = get_unsigned_byte(file);
+ quad = byte;
+ if (quad >= 0x80)
+ quad = byte - 0x100;
+ for (i=0; i<3; i++) {
+ quad = quad*0x100 + get_unsigned_byte(file);
+ }
+ return (SIGNED_QUAD) quad;
+}
+
+UNSIGNED_QUAD get_unsigned_quad(FILE *file)
+{
+ int i;
+ unsigned long quad = 0;
+ for (i=0; i<4; i++) {
+ quad = quad*0x100u + get_unsigned_byte(file);
+ }
+ return (UNSIGNED_QUAD) quad;
+}
+
+#if 0
+SIGNED_QUAD sqxfw (SIGNED_QUAD sq, fixword fw)
+{
+ int sign = 1;
+ unsigned long a, b, c, d, ad, bd, bc, ac;
+ unsigned long e, f, g, h, i, j, k;
+ unsigned long result;
+ /* Make positive. */
+ if (sq < 0) {
+ sign = -sign;
+ sq = -sq;
+ }
+ if (fw < 0) {
+ sign = -sign;
+ fw = -fw;
+ }
+ a = ((unsigned long) sq) >> 16u;
+ b = ((unsigned long) sq) & 0xffffu;
+ c = ((unsigned long) fw) >> 16u;
+ d = ((unsigned long) fw) & 0xffffu;
+ ad = a*d; bd = b*d; bc = b*c; ac = a*c;
+ e = bd >> 16u;
+ f = ad >> 16u;
+ g = ad & 0xffffu;
+ h = bc >> 16u;
+ i = bc & 0xffffu;
+ j = ac >> 16u;
+ k = ac & 0xffffu;
+ result = (e+g+i + (1<<3)) >> 4u; /* 1<<3 is for rounding */
+ result += (f+h+k) << 12u;
+ result += j << 28u;
+ return (sign > 0) ? result : result * -1L;
+}
+
+SIGNED_QUAD axboverc (SIGNED_QUAD n1, SIGNED_QUAD n2, SIGNED_QUAD divide)
+{
+ int sign = 1;
+ unsigned long a, b, c, d, ad, bd, bc, ac, e, f, g, h, i, j, o;
+ unsigned long high, low;
+ SIGNED_QUAD result = 0;
+ /* Make positive. */
+ if (n1 < 0) {
+ sign = -sign;
+ n1 = -n1;
+ }
+ if (n2 < 0) {
+ sign = -sign;
+ n2 = -n2;
+ }
+ if (divide < 0) {
+ sign = -sign;
+ divide = -divide;
+ }
+ a = ((unsigned long) n1) >> 16u;
+ b = ((unsigned long) n1) & 0xffffu;
+ c = ((unsigned long) n2) >> 16u;
+ d = ((unsigned long) n2) & 0xffffu;
+ ad = a*d; bd = b*d; bc = b*c; ac = a*c;
+ e = bd >> 16u; f = bd & 0xffffu;
+ g = ad >> 16u; h = ad & 0xffffu;
+ i = bc >> 16u; j = bc & 0xffffu;
+ o = e+h+j;
+ high = g+i+(o>>16u)+ac; o &= 0xffffu;
+ low = (o << 16) + f;
+ if (high >= divide)
+ ERROR ("Overflow in axboc");
+ {
+ int k;
+ for (k=0; k<32; k++) {
+ high *= 2;
+ result *= 2;
+ if (low >= 0x80000000) {
+ low -= 0x80000000;
+ high += 1;
+ }
+ low *= 2;
+ if (high > divide) {
+ high -= divide;
+ result += 1;
+ }
+ }
+ }
+ high *= 2;
+ if (high >= divide)
+ result += 1;
+ return (sign>0)?result:-result;
+}
+#endif
diff --git a/Build/source/texk/web2c/xetexdir/numbers.h b/Build/source/texk/web2c/xetexdir/numbers.h
new file mode 100644
index 00000000000..9e6b2306508
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/numbers.h
@@ -0,0 +1,82 @@
+/* $Header: /home/cvsroot/dvipdfmx/src/numbers.h,v 1.9 2005/07/20 10:41:54 hirata Exp $
+
+ This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
+
+ Copyright (C) 2002 by Jin-Hwan Cho and Shunsaku Hirata,
+ the dvipdfmx project team <dvipdfmx@project.ktug.or.kr>
+
+ Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+*/
+
+#ifndef _NUMBERS_H_
+#define _NUMBERS_H_
+
+#include <stdio.h>
+#include <math.h>
+
+typedef unsigned char Ubyte;
+typedef int UNSIGNED_BYTE, SIGNED_BYTE, SIGNED_PAIR;
+typedef unsigned UNSIGNED_PAIR;
+typedef long UNSIGNED_TRIPLE, SIGNED_TRIPLE, SIGNED_QUAD;
+typedef unsigned long UNSIGNED_QUAD;
+
+extern UNSIGNED_BYTE get_unsigned_byte (FILE *);
+extern UNSIGNED_BYTE sget_unsigned_byte (char *);
+extern SIGNED_BYTE get_signed_byte (FILE *);
+extern UNSIGNED_PAIR get_unsigned_pair (FILE *);
+extern UNSIGNED_PAIR sget_unsigned_pair (unsigned char *);
+extern SIGNED_PAIR get_signed_pair (FILE *);
+extern UNSIGNED_TRIPLE get_unsigned_triple (FILE *);
+extern SIGNED_TRIPLE get_signed_triple (FILE *);
+extern SIGNED_QUAD get_signed_quad (FILE *);
+extern UNSIGNED_QUAD get_unsigned_quad (FILE *);
+
+typedef signed long fixword;
+
+extern SIGNED_QUAD sqxfw (SIGNED_QUAD sq, fixword fw);
+extern SIGNED_QUAD axboverc (SIGNED_QUAD n1, SIGNED_QUAD n2, SIGNED_QUAD divide);
+
+#ifndef MAX
+# define MAX(a,b) ((a)>(b)?(a):(b))
+#endif
+#ifndef MIN
+# define MIN(a,b) ((a)<(b)?(a):(b))
+#endif
+#define ISODD(n) (((n)/2)*2!=(n))
+#define ISEVEN(n) (((n)/2)*2==(n))
+
+#ifndef M_PI
+# define M_PI (4.0*atan(1.0))
+#endif
+
+#define ROUND(n,acc) (floor(((double)n)/(acc)+0.5)*(acc))
+
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+# define __C99__
+#endif
+
+#ifndef __C99__
+# ifndef round
+# define round(v) (floor((v) + 0.5))
+# endif
+# ifndef trunc
+# define trunc(v) ((v) > 0.0 ? floor((v)) : ceil((v)))
+# endif
+#endif
+#define round_at(v,acc) (round(((double)(v))/(acc))*(acc))
+
+#endif /* _NUMBERS_H_ */
diff --git a/Build/source/texk/web2c/xetexdir/pdfimage.cpp b/Build/source/texk/web2c/xetexdir/pdfimage.cpp
new file mode 100644
index 00000000000..26d1bc79196
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/pdfimage.cpp
@@ -0,0 +1,77 @@
+/****************************************************************************\
+ Part of the XeTeX typesetting system
+ copyright (c) 2006 by SIL International
+ written by Jonathan Kew
+
+ This software is distributed under the terms of the Common Public License,
+ version 1.0.
+ For details, see <http://www.opensource.org/licenses/cpl1.0.php> or the file
+ cpl1.0.txt included with the software.
+\****************************************************************************/
+
+#include "pdfimage.h"
+
+#include "PDFDoc.h"
+#include "Catalog.h"
+#include "Page.h"
+#include "GString.h"
+
+#include "XeTeX_ext.h"
+
+int
+pdf_get_rect(char* filename, int page_num, int pdf_box, realrect* box)
+{
+ GString* name = new GString(filename);
+ PDFDoc* doc = new PDFDoc(name);
+
+ if (!doc) {
+ delete name;
+ return -1;
+ }
+
+ /* if the doc got created, it now owns name, so we mustn't delete it! */
+
+ if (!doc->isOk()) {
+ delete doc;
+ return -1;
+ }
+
+ int pages = doc->getNumPages();
+ if (page_num > pages)
+ page_num = pages;
+ if (page_num < 0)
+ page_num = pages + 1 - page_num;
+ if (page_num < 1)
+ page_num = 1;
+
+ Page* page = doc->getCatalog()->getPage(page_num);
+
+ PDFRectangle* r;
+ switch (pdf_box) {
+ default:
+ case pdfbox_crop:
+ r = page->getCropBox();
+ break;
+ case pdfbox_media:
+ r = page->getMediaBox();
+ break;
+ case pdfbox_bleed:
+ r = page->getBleedBox();
+ break;
+ case pdfbox_trim:
+ r = page->getTrimBox();
+ break;
+ case pdfbox_art:
+ r = page->getArtBox();
+ break;
+ }
+
+ box->x = 72 / 72.27 * fmin(r->x1, r->x2);
+ box->y = 72 / 72.27 * fmin(r->y1, r->y2);
+ box->wd = 72 / 72.27 * fabs(r->x2 - r->x1);
+ box->ht = 72 / 72.27 * fabs(r->y2 - r->y1);
+
+ delete doc;
+
+ return 0;
+}
diff --git a/Build/source/texk/web2c/xetexdir/pdfimage.h b/Build/source/texk/web2c/xetexdir/pdfimage.h
new file mode 100644
index 00000000000..0869c03aa1e
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/pdfimage.h
@@ -0,0 +1,27 @@
+/****************************************************************************\
+ Part of the XeTeX typesetting system
+ copyright (c) 2006 by SIL International
+ written by Jonathan Kew
+
+ This software is distributed under the terms of the Common Public License,
+ version 1.0.
+ For details, see <http://www.opensource.org/licenses/cpl1.0.php> or the file
+ cpl1.0.txt included with the software.
+\****************************************************************************/
+
+#ifndef __PDF_IMAGE_H__
+#define __PDF_IMAGE_H__
+
+#include "trans.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int pdf_get_rect(char* filename, int page_num, int pdf_box, realrect* box);
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif
diff --git a/Build/source/texk/web2c/xetexdir/pngimage.c b/Build/source/texk/web2c/xetexdir/pngimage.c
new file mode 100644
index 00000000000..9408fbabc39
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/pngimage.c
@@ -0,0 +1,161 @@
+/****************************************************************************\
+ Part of the XeTeX typesetting system
+ copyright (c) 1994-2006 by SIL International
+ written by Jonathan Kew
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+\****************************************************************************/
+
+/* this file is derived from the dvipdfmx project;
+ the original header follows... */
+
+/* $Header: /home/cvsroot/dvipdfmx/src/pngimage.c,v 1.24 2004/09/11 14:50:29 hirata Exp $
+
+ This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
+
+ Copyright (C) 2002 by Jin-Hwan Cho and Shunsaku Hirata,
+ the dvipdfmx project team <dvipdfmx@project.ktug.or.kr>
+
+ Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+*/
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/*
+ * PNG SUPPORT
+ *
+ * All bitdepth less than 16 is supported.
+ * Supported color types are: PALETTE, RGB, GRAY, RGB_ALPHA, GRAY_ALPHA.
+ * Supported ancillary chunks: tRNS, cHRM + gAMA, (sRGB), (iCCP)
+ *
+ * gAMA support is available only when cHRM exists. cHRM support is not
+ * tested well. CalRGB/CalGray colorspace is used for PNG images that
+ * have cHRM chunk (but not sRGB).
+ *
+ * LIMITATIONS
+ *
+ * Recent version of PDF (>= 1.5) support 16 bpc, but 16 bit bitdepth PNG
+ * images are automatically converted to 8 bit bitpedth image.
+ *
+ * TODO
+ *
+ * sBIT ? iTXT, tEXT and tIME as MetaData ?, pHYS (see below)
+ * 16 bpc support for PDF-1.5. JBIG compression for monochrome image.
+ * Predictor for deflate ?
+ */
+
+#define PNG_DEBUG_STR "PNG"
+#define PNG_DEBUG 3
+
+/*
+ * Write, MNG, Progressive not required.
+ */
+#define PNG_NO_WRITE_SUPPORTED
+#define PNG_NO_MNG_FEATURES
+#define PNG_NO_PROGRESSIVE_READ
+#if 0
+/* 16_TO_8 required. */
+#define PNG_NO_READ_TRANSFORMS
+#endif
+
+#include <png.h>
+#include "pngimage.h"
+
+#define PDF_TRANS_TYPE_NONE 0
+#define PDF_TRANS_TYPE_BINARY 1
+#define PDF_TRANS_TYPE_ALPHA 2
+
+int
+check_for_png (FILE *png_file)
+{
+ unsigned char sigbytes[4];
+
+ rewind (png_file);
+ if (fread (sigbytes, 1, sizeof(sigbytes), png_file) !=
+ sizeof(sigbytes) ||
+ (!png_check_sig (sigbytes, sizeof(sigbytes))))
+ return 0;
+ else
+ return 1;
+}
+
+int
+png_scan_file (struct png_info *info, FILE *png_file)
+{
+ png_bytep stream_data_ptr;
+ int trans_type;
+ /* Libpng stuff */
+ png_structp png_ptr;
+ png_infop png_info_ptr;
+ png_byte bpc, color_type;
+ png_uint_32 width, height, rowbytes;
+
+ rewind (png_file);
+ png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (png_ptr == NULL ||
+ (png_info_ptr = png_create_info_struct (png_ptr)) == NULL) {
+ fprintf(stderr, "WARNING: %s: Creating Libpng read/info struct failed.", PNG_DEBUG_STR);
+ if (png_ptr)
+ png_destroy_read_struct(&png_ptr, NULL, NULL);
+ return -1;
+ }
+
+ /* Inititializing file IO. */
+ png_init_io (png_ptr, png_file);
+
+ /* Read PNG info-header and get some info. */
+ png_read_info(png_ptr, png_info_ptr);
+ color_type = png_get_color_type (png_ptr, png_info_ptr);
+ width = png_get_image_width (png_ptr, png_info_ptr);
+ height = png_get_image_height(png_ptr, png_info_ptr);
+ bpc = png_get_bit_depth (png_ptr, png_info_ptr);
+
+ info->xdpi = png_get_x_pixels_per_meter(png_ptr, png_info_ptr) * 0.0254;
+ info->ydpi = png_get_y_pixels_per_meter(png_ptr, png_info_ptr) * 0.0254;
+
+ if (info->xdpi == 0)
+ info->xdpi = 72;
+ if (info->ydpi == 0)
+ info->ydpi = 72;
+
+ /* Values listed below will not be modified in the remaining process. */
+ info->width = width;
+ info->height = height;
+ info->bits_per_component = bpc;
+
+ /* Cleanup */
+ if (png_info_ptr)
+ png_destroy_info_struct(png_ptr, &png_info_ptr);
+ if (png_ptr)
+ png_destroy_read_struct(&png_ptr, NULL, NULL);
+
+ return 0;
+}
diff --git a/Build/source/texk/web2c/xetexdir/pngimage.h b/Build/source/texk/web2c/xetexdir/pngimage.h
new file mode 100644
index 00000000000..c00387ca4f0
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/pngimage.h
@@ -0,0 +1,70 @@
+/****************************************************************************\
+ Part of the XeTeX typesetting system
+ copyright (c) 1994-2006 by SIL International
+ written by Jonathan Kew
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+\****************************************************************************/
+
+/* this file is derived from the dvipdfmx project;
+ the original header follows... */
+
+/* $Header: /home/cvsroot/dvipdfmx/src/pngimage.h,v 1.4 2004/03/11 11:50:25 hirata Exp $
+
+ This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
+
+ Copyright (C) 2002 by Jin-Hwan Cho and Shunsaku Hirata,
+ the dvipdfmx project team <dvipdfmx@project.ktug.or.kr>
+
+ Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+*/
+
+
+#ifndef _PNGIMAGE_H_
+#define _PNGIMAGE_H_
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "mfileio.h"
+
+struct png_info {
+ int width;
+ int height;
+ double xdpi;
+ double ydpi;
+ int bits_per_component;
+ int num_components;
+};
+
+extern int png_scan_file (struct png_info *info, FILE *file);
+extern int check_for_png (FILE *file);
+
+#endif /* _PNGIMAGE_H_ */
diff --git a/Build/source/texk/web2c/xetexdir/sfnt.h b/Build/source/texk/web2c/xetexdir/sfnt.h
new file mode 100644
index 00000000000..05403a37d69
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/sfnt.h
@@ -0,0 +1,285 @@
+/*
+ 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.
+*/
+
+/* from ICU sample code, extended by JK for XeTeX */
+
+/***************************************************************************
+*
+* Copyright (C) 1998-2002, International Business Machines
+* Corporation and others. All Rights Reserved.
+*
+************************************************************************/
+
+#ifndef __SFNT_H
+#define __SFNT_H
+
+#include "LETypes.h"
+
+
+#ifndef ANY_NUMBER
+#define ANY_NUMBER 1
+#endif
+
+struct DirectoryEntry
+{
+ le_uint32 tag;
+ le_uint32 checksum;
+ le_uint32 offset;
+ le_uint32 length;
+};
+
+struct SFNTDirectory
+{
+ le_uint32 scalerType;
+ le_uint16 numTables;
+ le_uint16 searchRange;
+ le_uint16 entrySelector;
+ le_uint16 rangeShift;
+ DirectoryEntry tableDirectory[ANY_NUMBER];
+};
+
+
+struct CMAPEncodingSubtableHeader
+{
+ le_uint16 platformID;
+ le_uint16 platformSpecificID;
+ le_uint32 encodingOffset;
+};
+
+struct CMAPTable
+{
+ le_uint16 version;
+ le_uint16 numberSubtables;
+ CMAPEncodingSubtableHeader encodingSubtableHeaders[ANY_NUMBER];
+};
+
+struct CMAPEncodingSubtable
+{
+ le_uint16 format;
+ le_uint16 length;
+ le_uint16 language;
+};
+
+struct CMAPFormat0Encoding : CMAPEncodingSubtable
+{
+ le_uint8 glyphIndexArray[256];
+};
+
+struct CMAPFormat2Subheader
+{
+ le_uint16 firstCode;
+ le_uint16 entryCount;
+ le_int16 idDelta;
+ le_uint16 idRangeOffset;
+};
+
+struct CMAPFormat2Encoding : CMAPEncodingSubtable
+{
+ le_uint16 subHeadKeys[256];
+ CMAPFormat2Subheader subheaders[ANY_NUMBER];
+};
+
+struct CMAPFormat4Encoding : CMAPEncodingSubtable
+{
+ le_uint16 segCountX2;
+ le_uint16 searchRange;
+ le_uint16 entrySelector;
+ le_uint16 rangeShift;
+ le_uint16 endCodes[ANY_NUMBER];
+// le_uint16 reservedPad;
+// le_uint16 startCodes[ANY_NUMBER];
+// le_uint16 idDelta[ANY_NUMBER];
+// le_uint16 idRangeOffset[ANY_NUMBER];
+// le_uint16 glyphIndexArray[ANY_NUMBER];
+};
+
+struct CMAPFormat6Encoding : CMAPEncodingSubtable
+{
+ le_uint16 firstCode;
+ le_uint16 entryCount;
+ le_uint16 glyphIndexArray[ANY_NUMBER];
+};
+
+struct CMAPEncodingSubtable32
+{
+ le_uint16 format;
+ le_uint16 reserved;
+ le_uint32 length;
+ le_uint32 language;
+};
+
+struct CMAPGroup
+{
+ le_uint32 startCharCode;
+ le_uint32 endCharCode;
+ le_uint32 startGlyphCode;
+};
+
+struct CMAPFormat8Encoding : CMAPEncodingSubtable32
+{
+ le_uint32 is32[65536/32];
+ le_uint32 nGroups;
+ CMAPGroup groups[ANY_NUMBER];
+};
+
+struct CMAPFormat10Encoding : CMAPEncodingSubtable32
+{
+ le_uint32 startCharCode;
+ le_uint32 numCharCodes;
+ le_uint16 glyphs[ANY_NUMBER];
+};
+
+struct CMAPFormat12Encoding : CMAPEncodingSubtable32
+{
+ le_uint32 nGroups;
+ CMAPGroup groups[ANY_NUMBER];
+};
+
+typedef le_int32 fixed;
+
+struct BigDate
+{
+ le_uint32 bc;
+ le_uint32 ad;
+};
+
+struct HEADTable
+{
+ fixed version;
+ fixed fontRevision;
+ le_uint32 checksumAdjustment;
+ le_uint32 magicNumber;
+ le_uint16 flags;
+ le_uint16 unitsPerEm;
+ BigDate created;
+ BigDate modified;
+ le_int16 xMin;
+ le_int16 yMin;
+ le_int16 xMax;
+ le_int16 yMax;
+ le_uint16 macStyle;
+ le_uint16 lowestRecPPEM;
+ le_int16 fontDirectionHint;
+ le_int16 indexToLocFormat;
+ le_int16 glyphDataFormat;
+};
+
+struct MAXPTable
+{
+ fixed version;
+ le_uint16 numGlyphs;
+ le_uint16 maxPoints;
+ le_uint16 maxContours;
+ le_uint16 maxComponentPoints;
+ le_uint16 maxComponentContours;
+ le_uint16 maxZones;
+ le_uint16 maxTwilightPoints;
+ le_uint16 maxStorage;
+ le_uint16 maxFunctionDefs;
+ le_uint16 maxInstructionDefs;
+ le_uint16 maxStackElements;
+ le_uint16 maxSizeOfInstructions;
+ le_uint16 maxComponentElements;
+ le_uint16 maxComponentDepth;
+};
+
+struct HHEATable
+{
+ fixed version;
+ le_int16 ascent;
+ le_int16 descent;
+ le_int16 lineGap;
+ le_uint16 advanceWidthMax;
+ le_int16 minLeftSideBearing;
+ le_int16 minRightSideBearing;
+ le_int16 xMaxExtent;
+ le_int16 caretSlopeRise;
+ le_int16 caretSlopeRun;
+ le_int16 caretOffset;
+ le_int16 reserved1;
+ le_int16 reserved2;
+ le_int16 reserved3;
+ le_int16 reserved4;
+ le_int16 metricDataFormat;
+ le_uint16 numOfLongHorMetrics;
+};
+
+struct LongHorMetric
+{
+ le_uint16 advanceWidth;
+ le_int16 leftSideBearing;
+};
+
+struct HMTXTable
+{
+ LongHorMetric hMetrics[ANY_NUMBER]; // ANY_NUMBER = numOfLongHorMetrics from hhea table
+// le_int16 leftSideBearing[ANY_NUMBER]; // ANY_NUMBER = numGlyphs - numOfLongHorMetrics
+};
+
+struct POSTTable
+{
+ fixed version;
+ fixed italicAngle;
+ le_int16 underlinePosition;
+ le_uint16 underlineThickness;
+ le_uint32 isFixedPitch;
+ le_uint32 minMemType42;
+ le_uint32 maxMemType42;
+ le_uint32 minMemType1;
+ le_uint32 maxMemType1;
+};
+
+struct OS2TableHeader {
+ le_uint16 version;
+ le_int16 xAvgCharWidth;
+ le_uint16 usWeightClass;
+ le_uint16 usWidthClass;
+ le_int16 fsType;
+ le_int16 ySubscriptXSize;
+ le_int16 ySubscriptYSize;
+ le_int16 ySubscriptXOffset;
+ le_int16 ySubscriptYOffset;
+ le_int16 ySuperscriptXSize;
+ le_int16 ySuperscriptYSize;
+ le_int16 ySuperscriptXOffset;
+ le_int16 ySuperscriptYOffset;
+ le_int16 yStrikeoutSize;
+ le_int16 yStrikeoutPosition;
+ le_int16 sFamilyClass;
+ le_uint8 panose[10];
+ le_uint8 ulCharRange[16]; // spec'd as 4 longs, but do this to keep structure packed
+ le_int8 achVendID[4];
+ le_uint16 fsSelection;
+ le_uint16 fsFirstCharIndex;
+ le_uint16 fsLastCharIndex;
+};
+
+#endif
+
diff --git a/Build/source/texk/web2c/xetexdir/tests.ac b/Build/source/texk/web2c/xetexdir/tests.ac
new file mode 100644
index 00000000000..552aea23dc0
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/tests.ac
@@ -0,0 +1,49 @@
+# Extra configure tests to support XeTeX
+
+AC_DEFUN([AC_HAS_CARBON], [
+#
+# Check for Carbon framework on Mac OS X
+#
+ _cppflags=$CPPFLAGS _ldflags=$LDFLAGS
+ AC_MSG_CHECKING([for Apple Carbon framework])
+ AC_TRY_COMPILE(
+ [
+#include <Carbon/Carbon.h>
+ ], [
+ATSUStyle style;
+ ],
+ [ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_CARBON, 1, [Define if you have Carbon])
+ LDCARBON="-framework Carbon"
+ has_carbon=yes
+ ],
+ [ AC_MSG_RESULT(no)
+ LDCARBON=
+ has_carbon=no
+ ]
+ )
+])
+
+AC_DEFUN([AC_HAS_QUICKTIME], [
+#
+# Check for QuickTime framework on Mac OS X
+#
+ _cppflags=$CPPFLAGS _ldflags=$LDFLAGS
+ AC_MSG_CHECKING([for Apple QuickTime framework])
+ AC_TRY_COMPILE(
+ [
+#include <QuickTime/QuickTime.h>
+ ], [
+ImageDescriptionHandle h;
+ ],
+ [ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_QUICKTIME, 1, [Define if you have QuickTime])
+ LDQUICKTIME="-framework QuickTime"
+ has_quicktime=yes
+ ],
+ [ AC_MSG_RESULT(no)
+ LDQUICKTIME=
+ has_quicktime=no
+ ]
+ )
+])
diff --git a/Build/source/texk/web2c/xetexdir/trans.c b/Build/source/texk/web2c/xetexdir/trans.c
new file mode 100644
index 00000000000..7ac31c1616a
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/trans.c
@@ -0,0 +1,116 @@
+/****************************************************************************\
+ 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.
+\****************************************************************************/
+
+#include "trans.h"
+
+void makeidentity(transform* t)
+{
+#ifdef XETEX_MAC
+ *t = CGAffineTransformMake(1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
+#else
+ t->a = 1.0;
+ t->b = 0.0;
+ t->c = 0.0;
+ t->d = 1.0;
+ t->x = 0.0;
+ t->y = 0.0;
+#endif
+}
+
+void makescale(transform* t, double xscale, double yscale)
+{
+#ifdef XETEX_MAC
+ *t = CGAffineTransformMakeScale(xscale, yscale);
+#else
+ t->a = xscale;
+ t->b = 0.0;
+ t->c = 0.0;
+ t->d = yscale;
+ t->x = 0.0;
+ t->y = 0.0;
+#endif
+}
+
+void maketranslation(transform* t, double dx, double dy)
+{
+#ifdef XETEX_MAC
+ *t = CGAffineTransformMakeTranslation(dx, dy);
+#else
+ t->a = 1.0;
+ t->b = 0.0;
+ t->c = 0.0;
+ t->d = 1.0;
+ t->x = dx;
+ t->y = dy;
+#endif
+}
+#include <stdio.h>
+void makerotation(transform* t, double a)
+{
+#ifdef XETEX_MAC
+ *t = CGAffineTransformMakeRotation(a);
+#else
+ t->a = cos(a);
+ t->b = sin(a);
+ t->c = -sin(a);
+ t->d = cos(a);
+ t->x = 0.0;
+ t->y = 0.0;
+#endif
+}
+
+void transformpoint(realpoint* p, const transform* t)
+{
+#ifdef XETEX_MAC
+ CGPoint r = CGPointApplyAffineTransform(*(CGPoint*)p, *t);
+ *p = *(realpoint*)&r;
+#else
+ realpoint r;
+ r.x = t->a * p->x + t->c * p->y + t->x;
+ r.y = t->b * p->x + t->d * p->y + t->y;
+ *p = r;
+#endif
+}
+
+void transformconcat(transform* t1, const transform* t2)
+{
+#ifdef XETEX_MAC
+ *t1 = CGAffineTransformConcat(*t1, *t2);
+#else
+ transform r;
+ r.a = t1->a * t2->a + t1->b * t2->c + 0.0 * t2->x;
+ r.b = t1->a * t2->b + t1->b * t2->d + 0.0 * t2->y;
+ r.c = t1->c * t2->a + t1->d * t2->c + 0.0 * t2->x;
+ r.d = t1->c * t2->b + t1->d * t2->d + 0.0 * t2->y;
+ r.x = t1->x * t2->a + t1->y * t2->c + 1.0 * t2->x;
+ r.y = t1->x * t2->b + t1->y * t2->d + 1.0 * t2->y;
+ *t1 = r;
+#endif
+}
diff --git a/Build/source/texk/web2c/xetexdir/trans.h b/Build/source/texk/web2c/xetexdir/trans.h
new file mode 100644
index 00000000000..2a24a60f7ee
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/trans.h
@@ -0,0 +1,94 @@
+/****************************************************************************\
+ 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.
+\****************************************************************************/
+
+#ifndef _TRANS_H_
+#define _TRANS_H_
+
+#ifdef XETEX_MAC
+
+#include <Carbon/Carbon.h>
+
+typedef CGAffineTransform transform;
+
+#else
+
+#include <math.h>
+
+typedef struct {
+ double a;
+ double b;
+ double c;
+ double d;
+ double x;
+ double y;
+} transform;
+
+#endif
+
+typedef struct {
+ float x;
+ float y;
+} realpoint;
+
+typedef struct {
+ float x;
+ float y;
+ float wd;
+ float ht;
+} realrect;
+
+#define xCoord(p) p.x
+#define yCoord(p) p.y
+
+#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
+#ifdef XETEX_MAC
+#define xField(t) t.tx
+#define yField(t) t.ty
+#else
+#define xField(t) t.x
+#define yField(t) t.y
+#endif
+
+#define setPoint(P,X,Y) do { P.x = X; P.y = Y; } while (0)
+
+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);
+
+#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
new file mode 100644
index 00000000000..31b27de7dc9
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/unicode-char-prep.pl
@@ -0,0 +1,116 @@
+#!/usr/bin/perl
+
+# /****************************************************************************\
+# 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.
+# \****************************************************************************/
+
+# script to create unicode-letters.tex by processing UnicodeData.txt
+
+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/;
+ if ($u[2] =~ /^L/) {
+ push(@letters, $u[0]);
+ }
+ elsif ($u[2] =~ /^M/) {
+ push(@marks, $u[0]);
+ }
+ elsif (exists $lccode{$u[0]} or exists $uccode{$u[0]}) {
+ push(@casesym, $u[0]);
+ }
+ }
+}
+
+$date = `date`;
+chomp $date;
+print << "__EOT__";
+% Do not edit this file!
+% Created from UnicodeData.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
+\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\XeTeXextmathcode"#1="7"01"#1 } % letters default to class 7 (var), fam 1
+\def\l #1 {\L #1 #1 #1 } % letter without case mappings
+\let\m=\l % combining mark - treated as uncased letter
+__EOT__
+for (@letters) {
+ if (exists $uccode{$_} or exists $lccode{$_}) {
+ if (($lccode{$_} eq $_) and ($uccode{$_} eq $_)) {
+ print "\\l $_\n";
+ }
+ else {
+ print "\\L $_ ";
+ print exists $uccode{$_} ? $uccode{$_} : "0";
+ print " ";
+ print exists $lccode{$_} ? $lccode{$_} : "0";
+ print "\n";
+ }
+ }
+ else {
+ print "\\l $_\n";
+ }
+}
+for (@casesym) {
+ print "\\C $_ ";
+ print exists $uccode{$_} ? $uccode{$_} : "0";
+ print " ";
+ print exists $lccode{$_} ? $lccode{$_} : "0";
+ print "\n";
+}
+for (@marks) {
+ print "\\m $_\n";
+}
+print << '__EOT__';
+\endgroup
+__EOT__
diff --git a/Build/source/texk/web2c/xetexdir/xetex-new.ch b/Build/source/texk/web2c/xetexdir/xetex-new.ch
new file mode 100644
index 00000000000..8c8bf117e14
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/xetex-new.ch
@@ -0,0 +1,6169 @@
+% /****************************************************************************\
+% 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==".995"
+@d XeTeX_version_string=='-0.995' {current \eTeX\ 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.
+
+@<Types...@>=
+@!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
+
+@<Types...@>=
+@!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
+@!eight_bit_p:c_int_type; {make all characters printable by default}
+@!halt_on_error_p:c_int_type; {stop at first error}
+@!quoted_filename:boolean; {current filename is quoted}
+@y
+@!eight_bit_p:c_int_type; {make all characters printable by default}
+@!halt_on_error_p:c_int_type; {stop at first error}
+@z
+
+@x
+@* \[4] String handling.
+@y
+@* \[4] String handling.
+@z
+
+@x
+|str_start[s]<=j<str_start[s+1]|. Additional integer variables
+@y
+|str_start_macro[s]<=j<str_start_macro[s+1]|. Additional integer variables
+@z
+
+@x
+|str_pool[pool_ptr]| and |str_start[str_ptr]| are
+@y
+|str_pool[pool_ptr]| and |str_start_macro[str_ptr]| are
+@z
+
+@x
+@d si(#) == # {convert from |ASCII_code| to |packed_ASCII_code|}
+@d so(#) == # {convert from |packed_ASCII_code| to |ASCII_code|}
+@y
+@d si(#) == # {convert from |ASCII_code| to |packed_ASCII_code|}
+@d so(#) == # {convert from |packed_ASCII_code| to |ASCII_code|}
+@d str_start_macro(#) == str_start[(#) - too_big_char]
+@z
+
+@x
+@!packed_ASCII_code = 0..255; {elements of |str_pool| array}
+@y
+@!packed_ASCII_code = 0..65535; {elements of |str_pool| array}
+@z
+
+@x
+@d length(#)==(str_start[#+1]-str_start[#]) {the number of characters
+ in string number \#}
+@y
+@p function length(s:str_number):integer;
+ {the number of characters in string number |s|}
+begin if (s>=@"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 j<str_start[s+1] do
+@y
+begin j:=str_start_macro(s);
+while j<str_start_macro(s+1) do
+@z
+
+@x
+j:=str_start[s]; k:=str_start[t];
+while j<str_start[s+1] do
+ begin if str_pool[j]<>str_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 j<str_start_macro(s+1) do
+ begin if str_pool[j]<>str_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; {str_start_macro(0):=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 (@<Character |k| cannot be printed@>) 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;
+end
+@z
+
+@x
+@<Character |k| cannot be printed@>=
+ (k<" ")or(k>"~")
+@y
+@<Character |k| cannot be printed@>=
+{ 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 @<Character |s| is the current new-line character@> then
+ if selector<pseudo then
+ begin print_ln; return;
+ end;
+case selector of
+term_and_log: begin wterm(xchr[s]); wlog(xchr[s]);
+ incr(term_offset); incr(file_offset);
+ if term_offset=max_print_line then
+ begin wterm_cr; term_offset:=0;
+ end;
+ if file_offset=max_print_line then
+ begin wlog_cr; file_offset:=0;
+ end;
+ end;
+log_only: begin wlog(xchr[s]); incr(file_offset);
+ if file_offset=max_print_line then print_ln;
+ end;
+term_only: begin wterm(xchr[s]); incr(term_offset);
+ if term_offset=max_print_line then print_ln;
+ end;
+no_print: do_nothing;
+pseudo: if tally<trick_count then trick_buf[tally mod error_line]:=s;
+new_string: begin if pool_ptr<pool_size then append_char(s);
+ end; {we drop characters if the string space is full}
+othercases write(write_file[selector],xchr[s])
+endcases;@/
+incr(tally);
+exit:end;
+@y
+procedure print_visible_char(@!s:ASCII_code); {prints a single character}
+label exit; {label is not used but nonetheless kept (for other changes?)}
+begin
+case selector of
+term_and_log: begin wterm(xchr[s]); wlog(xchr[s]);
+ incr(term_offset); incr(file_offset);
+ if term_offset=max_print_line then
+ begin wterm_cr; term_offset:=0;
+ end;
+ if file_offset=max_print_line then
+ begin wlog_cr; file_offset:=0;
+ end;
+ end;
+log_only: begin wlog(xchr[s]); incr(file_offset);
+ if file_offset=max_print_line then print_ln;
+ end;
+term_only: begin wterm(xchr[s]); incr(term_offset);
+ if term_offset=max_print_line then print_ln;
+ end;
+no_print: do_nothing;
+pseudo: if tally<trick_count then trick_buf[tally mod error_line]:=s;
+new_string: begin if pool_ptr<pool_size then append_char(s);
+ end; {we drop characters if the string space is full}
+othercases write(write_file[selector],xchr[s])
+endcases;@/
+incr(tally);
+exit:end;
+
+@ The |print_char| procedure sends one character to the desired destination.
+Control sequence names, file names and string constructed with
+\.{\\string} might contain |ASCII_code| values that can't
+be printed using |print_visible_char|. These characters will be printed
+in three- or four-symbol form like `\.{\^\^A}' or `\.{\^\^e4}',
+unless the -8bit option is enabled.
+Output that goes to the terminal and/or log file is treated differently
+when it comes to determining whether a character is printable.
+
+@d print_lc_hex(#)==l:=#;
+ if l<10 then print_visible_char(l+"0")@+else print_visible_char(l-10+"a")
+
+@<Basic printing...@>=
+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 @<Character |s| is the current new-line character@> then
+ if selector<pseudo then
+ begin print_ln; return;
+ end;
+if (s < 32) and (eight_bit_p = 0) and (not doing_special) then begin
+ { control char: ^^X }
+ print_visible_char("^"); print_visible_char("^"); print_visible_char(s+64);
+end else if s < 127 then
+ { printable ASCII }
+ print_visible_char(s)
+else if (s = 127) then begin
+ { DEL }
+ if (eight_bit_p = 0) and (not doing_special) then begin
+ print_visible_char("^"); print_visible_char("^"); print_visible_char("?")
+ end else
+ print_visible_char(s)
+end else if (s < @"A0) and (eight_bit_p = 0) and (not doing_special) then begin { C1 controls: ^^xx }
+ print_visible_char("^"); print_visible_char("^");
+ print_lc_hex((s mod @"100) div @"10); print_lc_hex(s mod @"10);
+end else begin
+ { char >= 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;
+
+@ @<Glob...@>=
+doing_special: boolean;
+
+@ @<Set init...@>=
+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 (@<Character |s| is the current new-line character@>) then
+ if selector<pseudo then
+ begin print_ln; no_convert := false; return;
+ end
+ else if message_printing then
+ begin print_char(s); no_convert := false; return;
+ end;
+ if (mubyte_log>0) 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_start[s+1] do
+ begin print_char(so(str_pool[j])); incr(j);
+ end;
+ new_line_char:=nl; return;
+ end;
+j:=str_start[s];
+while j<str_start[s+1] do
+ begin print_char(so(str_pool[j])); incr(j);
+ end;
+exit:end;
+@y
+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<biggest_char then
+ if s<0 then s:="???" {can't happen}
+ else begin if selector>pseudo then
+ begin print_char(s); return; {internal strings are not expanded}
+ end;
+ if (@<Character |s| is the current new-line character@>) then
+ if selector<pseudo then
+ begin print_ln; return;
+ end;
+ nl:=new_line_char;
+ new_line_char:=-1;
+ print_char(s);
+ new_line_char:=nl;
+ return;
+ end;
+j:=str_start_macro(s);
+while j<str_start_macro(s+1) do
+ 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:
+
+@<Basic print...@>=
+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<str_start[s+1] do
+ begin print(so(str_pool[j])); incr(j);
+ end;
+ end;
+end;
+@y
+@ Old versions of \TeX\ needed a procedure called |slow_print| whose function
+is now subsumed by |print| and the new functionality of |print_char| and
+|print_visible_char|. We retain the old name |slow_print| here as a
+possible aid to future software arch\ae ologists.
+
+@d slow_print == print
+@z
+
+@x
+begin @<Set variable |c| to the current escape character@>;
+if c>=0 then if c<256 then print(c);
+@y
+begin @<Set variable |c| to the current escape character@>;
+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, and a length.
+Then there is a field containing two halfwords, a glyph count and a C pointer to a glyph info array;
+these 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 deleted_native_node=41 {native words that have been superseded by their successors}
+
+@d native_node_size=6 {size of a native_word node (plus the actual chars) -- see also xetex.h}
+@d native_size(#)==mem[#+4].hh.b0
+@d native_font(#)==mem[#+4].hh.b1
+@d native_length(#)==mem[#+4].hh.rh
+@d native_glyph_count(#)==mem[#+5].hh.lh
+@d native_glyph_info_ptr(#)==mem[#+5].hh.rh
+@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(#) <> 0 then begin
+ libc_free(cast_to_ptr(native_glyph_info_ptr(#)));
+ native_glyph_info_ptr(#) := 0;
+ 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) <> 0 then begin
+ glyph_count := native_glyph_count(src);
+ native_glyph_info_ptr(dest) := cast_to_integer(xmalloc_array(char, glyph_count * native_glyph_info_size));
+ memcpy(cast_to_ptr(native_glyph_info_ptr(dest)), cast_to_ptr(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
+@ @<Print a short indication of the contents of node |p|@>=
+case type(p) of
+hlist_node,vlist_node,ins_node,whatsit_node,mark_node,adjust_node,
+ unset_node: print("[]");
+@y
+@ @<Print a short indication of the contents of node |p|@>=
+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<math_font_base+16 then
+ begin print_esc("textfont"); print_int(n-math_font_base);
+ end
+else if n<math_font_base+32 then
+ begin print_esc("scriptfont"); print_int(n-math_font_base-16);
+ end
+else begin print_esc("scriptscriptfont"); print_int(n-math_font_base-32);
+@y
+begin if n=cur_font_loc then print("current font")
+else if n<math_font_base+script_size then
+ begin print_esc("textfont"); print_int(n-math_font_base);
+ end
+else if n<math_font_base+script_script_size then
+ begin print_esc("scriptfont"); print_int(n-math_font_base-script_size);
+ end
+else begin print_esc("scriptscriptfont");
+ print_int(n-math_font_base-script_script_size);
+@z
+
+@x
+@d eTeX_state_code=etex_int_base+9 {\eTeX\ state variables}
+@d etex_int_pars=eTeX_state_code+eTeX_states {total number of \eTeX's integer parameters}
+@y
+@d XeTeX_linebreak_locale_code=etex_int_base+9 {string number of locale to use for linebreak locations}
+@d XeTeX_linebreak_penalty_code=etex_int_base+10 {penalty to use at locale-dependent linebreak locations}
+@d eTeX_state_code=etex_int_base+11 {\eTeX\ state variables}
+@d etex_int_pars=eTeX_state_code+eTeX_states {total number of \eTeX's integer parameters}
+@z
+
+@x
+@d count_base=int_base+int_pars {256 user \.{\\count} registers}
+@d del_code_base=count_base+256 {256 delimiter code mappings}
+@d dimen_base=del_code_base+256 {beginning of region 6}
+@y
+@d count_base=int_base+int_pars {number_regs user \.{\\count} registers}
+@d del_code_base=count_base+number_regs {number_chars delimiter code mappings}
+@d dimen_base=del_code_base+number_chars {beginning of region 6}
+@z
+
+@x
+@d saving_hyph_codes==int_par(saving_hyph_codes_code)
+@y
+@d saving_hyph_codes==int_par(saving_hyph_codes_code)
+@d XeTeX_linebreak_locale==int_par(XeTeX_linebreak_locale_code)
+@d XeTeX_linebreak_penalty==int_par(XeTeX_linebreak_penalty_code)
+
+@ @<Global...@>=
+xetex_del_code_base:integer; { a hack, because WEB defined constants don't make it through to C }
+
+@ @<Set init...@>=
+xetex_del_code_base:=del_code_base;
+
+@ New sections slipped in above here.
+@z
+
+@x
+error_context_lines_code:print_esc("errorcontextlines");
+@y
+error_context_lines_code:print_esc("errorcontextlines");
+{XeTeX_linebreak_locale_code:print_esc("XeTeXlinebreaklocale");}
+XeTeX_linebreak_penalty_code:print_esc("XeTeXlinebreakpenalty");
+@z
+
+@x
+primitive("errorcontextlines",assign_int,int_base+error_context_lines_code);@/
+@!@:error_context_lines_}{\.{\\errorcontextlines} primitive@>
+@y
+primitive("errorcontextlines",assign_int,int_base+error_context_lines_code);@/
+@!@:error_context_lines_}{\.{\\errorcontextlines} primitive@>
+primitive("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}
+set_del_code1(".",0);
+@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("mathchar",math_char_num,0);@/
+@!@:math_char_}{\.{\\mathchar} primitive@>
+@y
+primitive("mathchar",math_char_num,0);@/
+primitive("XeTeXmathchar",math_char_num,1);@/
+primitive("XeTeXextmathchar",math_char_num,2);@/
+@!@:math_char_}{\.{\\mathchar} primitive@>
+@z
+
+@x
+primitive("relax",relax,256); {cf.\ |scan_file_name|}
+@y
+primitive("relax",relax,too_big_char); {cf.\ |scan_file_name|}
+@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_char_num: print_esc("mathchar");
+@y
+math_char_num: if chr_code=2 then print_esc("XeTeXextmathchar")
+ else if chr_code=1 then print_esc("XeTeXmathchar")
+ else print_esc("mathchar");
+@z
+
+@x
+@* \[19] Saving and restoring equivalents.
+@y
+@* \[19] Saving and restoring equivalents.
+@z
+
+@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 k<limit then
+ begin c:=buffer[k+1]; @+if c<@'200 then {yes, one is indeed present}
+ begin d:=2;
+ if is_hex(c) then @+if k+2<=limit then
+ begin cc:=buffer[k+2]; @+if is_hex(cc) then incr(d);
+ end;
+ if d>2 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 k<limit then
+ begin if (cur_chr=buffer[k+1]) and (cur_chr=buffer[k+2]) and
+ ((k+6)<=limit) then
+ begin c:=buffer[k+3]; cc:=buffer[k+4];
+ ccc:=buffer[k+5]; cccc:=buffer[k+6];
+ if is_hex(c) and is_hex(cc) and is_hex(ccc) and is_hex(cccc) then
+ begin d:=7; long_hex_to_cur_chr; buffer[k-1]:=cur_chr;
+ while k<=limit do
+ begin buffer[k]:=buffer[k+d]; incr(k);
+ end;
+ goto start_cs;
+ end
+ end
+ else begin
+ c:=buffer[k+1]; @+if c<@'200 then {yes, one is indeed present}
+ begin
+ d:=2;
+ if is_hex(c) then @+if k+2<=limit then
+ begin cc:=buffer[k+2]; @+if is_hex(cc) then incr(d);
+ end;
+ if d>2 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 start<limit then for k:=start to limit-1 do print(buffer[k]);
+@z
+
+@x
+if cur_cs=0 then cur_tok:=(cur_cmd*@'400)+cur_chr
+@y
+if cur_cs=0 then cur_tok:=(cur_cmd*max_char_val)+cur_chr
+@z
+
+@x
+ begin eq_define(cur_cs,relax,256); {N.B.: The |save_stack| might change}
+@y
+ begin eq_define(cur_cs,relax,too_big_char);
+ {N.B.: The |save_stack| might change}
+@z
+
+@x
+ buffer[j]:=info(p) mod @'400; incr(j); p:=link(p);
+@y
+ buffer[j]:=info(p) mod max_char_val; incr(j); p:=link(p);
+@z
+
+@x
+done: if cur_cs=0 then cur_tok:=(cur_cmd*@'400)+cur_chr
+@y
+done: if cur_cs=0 then cur_tok:=(cur_cmd*max_char_val)+cur_chr
+@z
+
+@x
+if cur_cs=0 then cur_tok:=(cur_cmd*@'400)+cur_chr
+@y
+if cur_cs=0 then cur_tok:=(cur_cmd*max_char_val)+cur_chr
+@z
+
+@x
+if (info(r)>match_token+255)or(info(r)<match_token) then s:=null
+@y
+if (info(r)>=end_match_token)or(info(r)<match_token) then s:=null
+@z
+
+@x
+@* \[26] Basic scanning subroutines.
+@y
+@* \[26] Basic scanning subroutines.
+@z
+
+@x
+begin p:=backup_head; link(p):=null; k:=str_start[s];
+while k<str_start[s+1] do
+@y
+begin p:=backup_head; link(p):=null;
+if s<too_big_char then begin
+ while true do
+ begin get_x_token; {recursion is possible here}
+@^recursion@>
+ 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<str_start_macro(s+1) do
+@z
+
+@x
+@!cur_val:integer; {value returned by numeric scanners}
+@y
+@!cur_val:integer; {value returned by numeric scanners}
+@!cur_val1:integer; {value returned by numeric scanners}
+@z
+
+@x
+var m:halfword; {|chr_code| part of the operand token}
+@y
+var m:halfword; {|chr_code| part of the operand token}
+ n, k, kk: integer; {accumulators}
+@z
+
+@x
+def_code: @<Fetch a character code from some table@>;
+@y
+def_code: @<Fetch a character code from some table@>;
+XeTeX_def_code:
+ begin
+ scan_char_num;
+ if m=math_code_base then begin
+ cur_val1:=ho(math_code(cur_val));
+ scanned_result(cur_val1)(int_val)
+ end
+ else if m=math_code_base+1 then begin
+ print_err("Can't use \XeTeXextmathcode as a number");
+ help2("\XeTeXextmathcode is for setting a mathcode from separate values;")@/
+ ("use \XeTeXmathcode to access them as single values."); error;
+ scanned_result(0)(int_val)
+ end
+ else begin
+ scanned_result(-1)(int_val); { FIXME - XeTeXdelcode }
+ 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 (math_class_field(cur_val1)>8) 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 (math_class_field(cur_val1) > 8) or
+ (math_fam_field(cur_val1) > 15) or
+ (math_char_field(cur_val1) > 255) 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
+ cur_val1:=del_code1(cur_val);
+ if (math_class_field(cur_val1) > 0) or
+ (math_fam_field(cur_val1) > 15) or
+ (math_char_field(cur_val1) > 255) then begin
+ print_err("Extended delcode used as 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(((math_class_field(del_code(cur_val))*@"1000) +
+ (math_fam_field(del_code(cur_val))*@"100) +
+ math_char_field(del_code(cur_val)))*@"1000 +
+ (math_fam_field(cur_val1)*@"100) +
+ math_char_field(cur_val1))(int_val);
+ end
+ 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+27 {first of \eTeX\ codes for dimensions}
+ {changed for \XeTeX\ to make room for \XeTeX\ integers}
+@z
+
+@x
+if (cur_val<0)or(cur_val>255) then
+@y
+if (cur_val<0)or(cur_val>biggest_reg) then
+@z
+
+@x
+ help2("A register number must be between 0 and 255.")@/
+@y
+ help2("A register number must be between 0 and 65535.")@/
+@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_fifteen_bit_int;
+begin scan_int;
+if (cur_val<0)or(cur_val>@'77777) then
+ begin print_err("Bad mathchar");
+@.Bad mathchar@>
+ help2("A mathchar number must be between 0 and 32767.")@/
+ ("I changed this one to zero."); int_error(cur_val); cur_val:=0;
+ end;
+end;
+ y
+procedure scan_real_fifteen_bit_int;
+begin scan_int;
+if (cur_val<0)or(cur_val>@'77777) then
+ begin print_err("Bad mathchar");
+@.Bad mathchar@>
+ help2("A mathchar number must be between 0 and 32767.")@/
+ ("I changed this one to zero."); int_error(cur_val); cur_val:=0;
+ end;
+end;
+
+procedure scan_fifteen_bit_int; { scans a \mathchar value and expands it to 32-bit form }
+begin scan_int;
+if (cur_val<0)or(cur_val>@'77777) then
+ begin print_err("Bad mathchar");
+@.Bad mathchar@>
+ help2("A mathchar number must be between 0 and 32767.")@/
+ ("I changed this one to zero."); int_error(cur_val); cur_val:=0;
+ end;
+cur_val := set_class_field(cur_val div @"1000) +
+ set_family_field((cur_val mod @"1000) div @"100) +
+ (cur_val mod @"100);
+end;
+ 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;
+cur_val1 := set_family_field((cur_val mod @"1000) div @"100) +
+ (cur_val mod @"100);
+cur_val := cur_val div @"1000;
+cur_val := set_family_field((cur_val mod @"1000) div @"100) +
+ set_class_field(cur_val div @"1000) +
+ (cur_val mod @"100);
+end;
+@z
+
+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;
+cur_val1 := (((cur_val mod @"1000) div @"100) * @"10000) +
+ (cur_val mod @"100);
+cur_val := cur_val div @"1000;
+cur_val := ((cur_val div @"1000) * @"1000000) +
+ (((cur_val mod @"1000) div @"100) * @"10000) +
+ (cur_val mod @"100);
+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
+@<Scan units and set |cur_val| to $x\cdot(|cur_val|+f/2^{16})$, where there
+ are |x| sp per unit; |goto attach_sign| if the units are internal@>;
+@<Scan an optional space@>;
+@y
+if requires_units then begin
+@<Scan units and set |cur_val| to $x\cdot(|cur_val|+f/2^{16})$, where there
+ are |x| sp per unit; |goto attach_sign| if the units are internal@>;
+@<Scan an optional space@>;
+end else begin
+ if cur_val>=@'40000 then arith_error:=true
+ else cur_val:=cur_val*unity+f;
+end;
+@z
+
+@x
+@ @<Fetch an internal dimension and |goto attach_sign|...@>=
+@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;
+
+@ @<Fetch an internal dimension and |goto attach_sign|...@>=
+@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 etex_convert_codes=XeTeX_selector_name_code+1 {end of \eTeX's command codes}
+@z
+
+@x
+ eTeX_revision_code: print_esc("eTeXrevision");
+@y
+ @/@<Cases of |convert| for |print_cmd_chr|@>@/
+@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
+@/@<Cases of `Scan the argument for command |c|'@>@/
+@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
+@/@<Cases of `Print the result of command |c|'@>@/
+@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;
+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
+else begin str_room(1); append_char(c); {contribute |c| to the current string}
+ if IS_DIR_SEP(c) then
+ begin area_delimiter:=cur_length; ext_delimiter:=0;
+ end
+ else if c="." then ext_delimiter:=cur_length;
+ more_name:=true;
+ end;
+end;
+@y
+@p function more_name(@!c:ASCII_code):boolean;
+begin if stop_at_space and (c=" ") then more_name:=false
+else begin
+ if (cur_length=0) and stop_at_space
+ and ((c="'") or (c="""") or (c="(")) then begin
+ if c="(" then file_name_quote_char:=")" else file_name_quote_char:=c;
+ stop_at_space:=false; more_name:=true;
+ end
+ else if (file_name_quote_char<>0) and (c=file_name_quote_char) then begin
+ stop_at_space:=true; more_name:=false;
+ end
+ else begin
+ str_room(1); append_char(c); {contribute |c| to the current string}
+ if IS_DIR_SEP(c) then
+ begin area_delimiter:=cur_length; ext_delimiter:=0;
+ end
+ else if c="." then ext_delimiter:=cur_length;
+ more_name:=true;
+ end;
+end;
+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 (j<>t) do begin
+ must_quote:=str_pool[j]=" "; incr(j);
+ end;
+ if must_quote then begin
+ for j:=pool_ptr-1 downto t do str_pool[j+2]:=str_pool[j];
+ str_pool[t+1]:="""";
+ for j:=t-1 downto s do str_pool[j+1]:=str_pool[j];
+ str_pool[s]:="""";
+ if ext_delimiter<>0 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 (j<>t) do begin
+ must_quote:=str_pool[j]=" "; incr(j);
+ end;
+if must_quote then begin
+ for j:=pool_ptr-1 downto t do str_pool[j+2]:=str_pool[j];
+ str_pool[t+1]:="""";
+ for j:=t-1 downto s do str_pool[j+1]:=str_pool[j];
+ str_pool[s]:="""";
+ if ext_delimiter<>0 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 (j<>t) do begin
+ must_quote:=str_pool[j]=" "; incr(j);
+ end;
+ if must_quote then begin
+ str_pool[t+1]:="""";
+ for j:=t-1 downto s do str_pool[j+1]:=str_pool[j];
+ str_pool[s]:="""";
+ pool_ptr:=pool_ptr+2;
+ end;
+ end;
+@y
+@p procedure end_name;
+var temp_str: str_number; {result of file name cache lookups}
+@!j: pool_pointer; {running index}
+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@>
+@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 (j<>str_start[a+1]) do begin
+ must_quote:=str_pool[j]=" "; incr(j);
+ end;
+end;
+if n<>0 then begin
+ j:=str_start[n];
+ while (not must_quote) and (j<>str_start[n+1]) do begin
+ must_quote:=str_pool[j]=" "; incr(j);
+ end;
+end;
+if e<>0 then begin
+ j:=str_start[e];
+ while (not must_quote) and (j<>str_start[e+1]) do begin
+ must_quote:=str_pool[j]=" "; incr(j);
+ end;
+end;
+{FIXME: Alternative is to assume that any filename that has to be quoted has
+ at least one quoted component...if we pick this, a number of insertions
+ of |print_file_name| should go away.
+|must_quote|:=((|a|<>0)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);
+begin slow_print(a); slow_print(n); slow_print(e);
+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
+@ @<Initialize the output...@>=output_file_name:=0;
+@y
+@ @<Initialize the output...@>=
+ 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<name_length16)and(more_name(name_of_file16[k])) do
+ incr(k);
+ stop_at_space:=true;
+ end_name;
+ name_in_progress:=false;
+ goto done;
+ end;
+@z
+
+@x
+@* \[30] Font metric data.
+@y
+@* \[30] Font metric data.
+@z
+
+@x
+@d non_char==qi(256) {a |halfword| code that can't match a real character}
+@y
+@d ot_font_flag=65534
+@d aat_font_flag=65535
+@d is_atsu_font(#)==(font_area[#]=aat_font_flag)
+@d is_ot_font(#)==(font_area[#]=ot_font_flag)
+@d is_native_font(#)==(is_atsu_font(#) or is_ot_font(#))
+ {native fonts have font_area = 65534 or 65535,
+ which would be a string containing an invalid Unicode character}
+
+@d non_char==qi(too_big_char) {a |halfword| code that can't match a real character}
+@z
+
+@x
+@!font_bc: ^eight_bits;
+ {beginning (smallest) character code}
+@!font_ec: ^eight_bits;
+ {ending (largest) character code}
+@y
+@!font_bc: ^UTF16_code;
+ {beginning (smallest) character code}
+@!font_ec: ^UTF16_code;
+ {ending (largest) character code}
+@z
+
+@x
+@!font_false_bchar: ^nine_bits;
+ {|font_bchar| if it doesn't exist in the font, otherwise |non_char|}
+@y
+@!font_false_bchar: ^nine_bits;
+ {|font_bchar| if it doesn't exist in the font, otherwise |non_char|}
+@#
+@!font_layout_engine: ^void_pointer; { either an ATSUStyle or a XeTeXLayoutEngine }
+@!font_mapping: ^void_pointer; { TECkit_Converter or 0 }
+@!font_flags: ^char; { flags:
+ 0x01: font_colored
+ 0x02: font_vertical }
+@!font_letter_space: ^scaled; { letterspacing to be applied to the font }
+@!loaded_font_mapping: void_pointer; { used by load_native_font to return mapping, if any }
+@!loaded_font_flags: char; { used by load_native_font to return flags }
+@!loaded_font_letter_space: scaled;
+@!mapped_text: ^UTF16_code; { scratch buffer used while applying font mappings }
+@!xdv_buffer: ^char; { scratch buffer used in generating XDV output }
+@z
+
+@x
+@<Read and check the font data; |abort| if the \.{TFM} file is
+@y
+file_opened:=false;
+pack_file_name(nom,aire,cur_ext);
+if file_name_quote_char<>0 then begin
+ { quoted name, so try for a native font }
+ g:=load_native_font(u,nom,aire,s);
+ if g=null_font then goto bad_tfm else goto done;
+end;
+{ it was an unquoted name, so try for a TFM file }
+@<Read and check the font data if file exists;
+ |abort| if the \.{TFM} file is
+@z
+
+@x
+bad_tfm: @<Report that the font won't be loaded@>;
+@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
+ @<Report that native font couldn't be found, and |goto done|@>;
+end;
+@<Report that the font won't be loaded@>;
+@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
+@ @<Read and check...@>=
+@<Open |tfm_file| for input@>;
+@y
+@ @<Report that native font couldn't be found, and |goto done|@>=
+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<same font id>=<substitute font name>'.");
+error;
+goto done
+
+@ @<Read and check...@>=
+@<Open |tfm_file| for input and |begin|@>;
+@z
+
+@x
+@<Make final adjustments and |goto done|@>
+@y
+@<Make final adjustments and |goto done|@>;
+end
+@z
+
+@x
+@ @<Open |tfm_file| for input@>=
+file_opened:=false;
+@y
+@ @<Open |tfm_file| for input...@>=
+@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
+@<Output the font name whose internal number is |f|@>;
+@y
+@<Output the font name whose internal number is |f|@>;
+end;
+@z
+
+@x
+@ @<Output the font name whose internal number is |f|@>=
+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
+@ @<Output the font name whose internal number is |f|@>=
+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
+@ @<Initialize variables as |ship_out| begins@>=
+dvi_h:=0; dvi_v:=0; cur_h:=h_offset; dvi_f:=null_font;
+@y
+@ @<Initialize variables as |ship_out| begins@>=
+dvi_h:=0; dvi_v:=0; cur_h:=h_offset; dvi_f:=null_font;
+@<Calculate page dimensions and margins@>;
+@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);
+@<Merge sequences of words using AAT fonts and inter-word spaces into single nodes@>;
+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)
+
+@<Merge sequences of words using AAT fonts and inter-word spaces into single nodes@>=
+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:
+ @<Advance |q| past ignorable nodes@>;
+ 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);
+ @<Advance |q| past ignorable nodes@>;
+ 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;
+ {@<Advance |q| past ignorable nodes@>;}
+ 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
+
+@ @<Advance |q| past ignorable nodes@>=
+while (q <> null) and (not is_char_node(q))
+ and ( (type(q) = disc_node) or ((type(q) = whatsit_node) and (subtype(q) = deleted_native_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_file_name(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<script_size;
+@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); depth(b):=depth(p); width(b):=width(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 with 256 families, this can be up to 768
+@!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
+ @<Complain about an undefined family and set |cur_i| null@>
+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
+ @<Complain about an undefined family and set |cur_i| null@>
+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
+ 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
+@ @<Create a character node |p| for |nucleus(q)|...@>=
+begin fetch(nucleus(q));
+if char_exists(cur_i) then
+@y
+@ @<Create a character node |p| for |nucleus(q)|...@>=
+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 if subtype(v)=deleted_native_node then do_nothing
+ 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 if subtype(s)=deleted_native_node then do_nothing
+ 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 if subtype(s)=deleted_native_node then do_nothing
+ 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 if subtype(s)=deleted_native_node then do_nothing
+ 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;
+
+@ @<Set initial values of key variables@>=
+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
+ @<Skip to node |hb|, putting letters into |hu| and |hc|@>;
+@y
+if (not is_char_node(ha)) and (type(ha) = whatsit_node) and (subtype(ha) = native_word_node) then begin
+ @<Check that nodes after |native_word| permit hyphenation; if not, |goto done1|@>;
+ @<Prepare a |native_word_node| for hyphenation@>;
+end else begin
+ @<Skip to node |hb|, putting letters into |hu| and |hc|@>;
+end;
+@z
+
+@x
+@ The first thing we need to do is find the node |ha| just before the
+first letter.
+@y
+@ @<Check that nodes after |native_word| permit hyphenation; if not, |goto done1|@>=
+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:
+
+@ @<Prepare a |native_word_node| for hyphenation@>=
+{ 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 }
+ @<Split the |native_word_node| at |l| and link the second part after |ha|@>;
+ 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 }
+ @<Split the |native_word_node| at |l| and link the second part after |ha|@>;
+ 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;
+
+@ @<Split the |native_word_node| at |l| and link the second part after |ha|@>=
+ 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);
+
+@ @<Local variables for line breaking@>=
+l: integer;
+i: integer;
+
+@ The first thing we need to do is find the node |ha| just before the
+first letter.
+@z
+
+@x
+ begin @<Advance \(p)past a whatsit node in the \(p)pre-hyphenation loop@>;
+ goto continue;
+@y
+ begin
+ if subtype(s) = native_word_node then begin
+ c := get_native_char(s, 0);
+ hf := native_font(s);
+ prev_s := s;
+ goto done2;
+ end else begin
+ @<Advance \(p)past a whatsit node in the \(p)pre-hyphenation loop@>;
+ goto continue;
+ end
+@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
+@<Replace nodes |ha..hb| by a sequence of nodes...@>=
+@y
+@<Replace nodes |ha..hb| by a sequence of nodes...@>=
+if (not is_char_node(ha)) and (type(ha) = whatsit_node) and (subtype(ha) = native_word_node) then begin
+ @<Hyphenate the |native_word_node| at |ha|@>;
+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
+
+@ @<Hyphenate the |native_word_node| at |ha|@>=
+{ 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
+ @<Ensure that |trie_max>=h+256|@>;
+@y
+ @<Ensure that |trie_max>=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
+@<Ensure that |trie_max>=h+256|@>=
+if trie_max<h+256 then
+ begin if trie_size<=h+256 then overflow("pattern memory",trie_size);
+@y
+@<Ensure that |trie_max>=h+max_hyph_char|@>=
+if trie_max<h+max_hyph_char then
+ begin if trie_size<=h+max_hyph_char then overflow("pattern memory",trie_size);
+@z
+
+@x
+ until trie_max=h+256;
+@y
+ until trie_max=h+max_hyph_char;
+@z
+
+@x
+if l<256 then
+ begin if z<256 then ll:=z @+else ll:=256;
+@y
+if l<max_hyph_char then
+ begin if z<max_hyph_char then ll:=z @+else ll:=max_hyph_char;
+@z
+
+@x
+ begin for r:=0 to 256 do clear_trie;
+ trie_max:=256;
+@y
+ begin for r:=0 to max_hyph_char do clear_trie;
+ trie_max:=max_hyph_char;
+@z
+
+@x
+ if k<63 then
+@y
+ if cur_chr>max_hyph_char then max_hyph_char:=cur_chr;
+ if k<63 then
+@z
+
+@x
+begin @<Get ready to compress the trie@>;
+@y
+begin
+incr(max_hyph_char);
+@<Get ready to compress the trie@>;
+@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:pointer; {another temporary register 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
+
+ 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) 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);
+
+ { flag the previous node as no longer valid }
+ free_native_glyph_info(main_pp);
+ subtype(main_pp) := deleted_native_node;
+
+ 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);
+
+ { flag the previous node as no longer valid }
+ free_native_glyph_info(main_pp);
+ subtype(main_pp) := deleted_native_node;
+ 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)<>deleted_native_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: @<Let |d| be the width of the whatsit |p|@>;
+@y
+whatsit_node: @<Let |d| be the width of the whatsit |p|, and |goto found| if ``visible''@>;
+@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 { \XeTeXextmathchar }
+ 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 { \XeTeXmathchar }
+ 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
+ scan_delimiter_int;
+ c := cur_val; {cur_val is the 'small' delimiter mathchar value}
+@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 { \XeTeXextmathchar }
+ 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 { \XeTeXmathchar }
+ 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
+ scan_delimiter_int;
+ set_math_char(cur_val);
+@z
+
+@x
+procedure set_math_char(@!c:integer);
+var p:pointer; {the new noad}
+begin if c>=@'100000 then
+ @<Treat |cur_chr|...@>
+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
+ @<Treat |cur_chr|...@>
+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 scan_delimiter_int
+@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); cur_val1:=del_code1(cur_chr);
+ end;
+ delim_num: scan_delimiter_int;
+ othercases begin cur_val:=-1; cur_val1:=-1; end;
+@z
+
+@x
+if cur_val<0 then @<Report that an invalid delimiter code is being changed
+ to null; set~|cur_val:=0|@>;
+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 @<Report that an invalid delimiter code is being changed
+ to null; set~|cur_val:=0|@>;
+ cur_val1:=0;
+ end;
+small_plane_and_fam_field(p) := (math_char_field(cur_val) div @"10000) * @"100 + math_fam_field(cur_val);
+small_char_field(p) := cur_val mod @"10000;
+large_plane_and_fam_field(p) := (math_char_field(cur_val1) div @"10000) * @"100 + math_fam_field(cur_val1);
+large_char_field(p) := cur_val1 mod @"10000;
+@z
+
+@x
+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
+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_def_code=8
+@d XeTeX_ext_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("XeTeXmathchardef",shorthand_def,XeTeX_math_char_def_code);@/
+primitive("XeTeXextmathchardef",shorthand_def,XeTeX_ext_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_ext_math_char_def_code: print_esc("XeTeXextmathchardef");
+@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_def_code: begin scan_xetex_math_char_int;
+ define(p, XeTeX_math_given, cur_val);
+ end;
+ XeTeX_ext_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("XeTeXmathcode",XeTeX_def_code,math_code_base);
+primitive("XeTeXextmathcode",XeTeX_def_code,math_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("XeTeXmathcode")
+ else if chr_code=math_code_base+1 then print_esc("XeTeXextmathcode")
+ else print_esc("XeTeXdelcode");
+def_family: print_size(chr_code-math_font_base);
+@z
+
+@x
+def_code: begin @<Let |n| be the largest legal code value, based on |cur_chr|@>;
+@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 do_nothing; {FIXME - XeTeXdelcode}
+ end;
+def_code: begin @<Let |n| be the largest legal code value, based on |cur_chr|@>;
+@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<math_code_base then define(p,data,cur_val)
+ else if p<del_code_base then define(p,data,hi(cur_val))
+@y
+ if p<math_code_base then define(p,data,cur_val)
+ else if p<del_code_base then begin
+ if cur_val=@"8000 then cur_val:=active_math_char
+ else cur_val:=set_class_field(cur_val div @"1000) +
+ set_family_field((cur_val mod @"1000) div @"100) +
+ (cur_val mod @"100);
+ define(p,data,hi(cur_val));
+ end
+@z
+
+ x
+ else word_define(p,cur_val);
+ y
+ else begin
+ cur_val1:=cur_val div @"1000;
+ cur_val1:=(cur_val1 div @"100)*@"10000 + (cur_val1 mod @"100);
+ cur_val:=cur_val mod @"1000;
+ cur_val:=(cur_val div @"100)*@"10000 + (cur_val mod @"100);
+ word_define(p,cur_val);
+ word_define1(p,cur_val1);
+ end;
+ z
+@x
+ else word_define(p,cur_val);
+@y
+ else begin
+ cur_val1 := cur_val mod @"1000; { large delim code }
+ cur_val1 := set_family_field(cur_val1 div @"100) + cur_val1 mod @"100;
+ cur_val := cur_val div @"1000;
+ cur_val := set_class_field((cur_val div @"1000) mod 8) +
+ set_family_field((cur_val div @"100) mod @"10) +
+ (cur_val mod @"100);
+ word_define(p, cur_val);
+ word_define1(p, cur_val1);
+ end;
+@z
+
+@x
+else n:=255
+@y
+else n:=biggest_char
+@z
+
+@x
+def_family: begin p:=cur_chr; scan_four_bit_int; p:=p+cur_val;
+@y
+def_family: begin p:=cur_chr; scan_math_fam_int; p:=p+cur_val;
+@z
+
+@x
+ if str_eq_str(font_name[f],cur_name)and str_eq_str(font_area[f],cur_area) then
+@y
+ if str_eq_str(font_name[f],cur_name) and
+ (((cur_area = "") and is_native_font(f)) or str_eq_str(font_area[f],cur_area)) then
+@z
+
+@x
+set_font:begin print("select font "); slow_print(font_name[chr_code]);
+@y
+set_font:begin print("select font ");
+ font_name_str:=font_name[chr_code];
+ if is_native_font(chr_code) then begin
+ quote_char:="""";
+ for n:=0 to length(font_name_str) - 1 do
+ if str_pool[str_start_macro(font_name_str) + n] = """" then quote_char:="'";
+ print_char(quote_char);
+ slow_print(font_name_str);
+ print_char(quote_char);
+ end else
+ slow_print(font_name_str);
+@z
+
+@x
+ begin a_close(read_file[n]); read_open[n]:=closed;
+@y
+ begin u_close(read_file[n]); read_open[n]:=closed;
+@z
+
+@x
+ and a_open_in(read_file[n], kpse_tex_format) then
+ read_open[n]:=just_open;
+@y
+ and u_open_in(read_file[n], kpse_tex_format, XeTeX_default_input_mode, XeTeX_default_input_encoding) then
+ begin 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;
+ read_open[n]:=just_open;
+ end;
+@z
+
+@x
+@!c:eight_bits; {character code}
+@y
+@!c:ASCII_code; {character code}
+@z
+
+@x
+ begin c:=t mod 256;
+@y
+ begin c:=t mod max_char_val;
+@z
+
+@x
+@* \[50] Dumping and undumping the tables.
+@y
+@* \[50] Dumping and undumping the tables.
+@z
+
+@x
+@!format_engine: ^text_char;
+@y
+@!format_engine: ^char;
+@z
+
+@x
+@!format_engine: ^text_char;
+@y
+@!format_engine: ^char;
+@z
+
+@x
+format_engine:=xmalloc_array(text_char,x+4);
+@y
+format_engine:=xmalloc_array(char,x+4);
+@z
+
+@x
+format_engine:=xmalloc_array(text_char, x);
+@y
+format_engine:=xmalloc_array(char, x);
+@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
+ 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
+ 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_file_name(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.
+
+@<Generate all \eTeX\ primitives@>=
+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:@<Implement \.{\\setlanguage}@>;
+@y
+set_language_code:@<Implement \.{\\setlanguage}@>;
+pic_file_code:@<Implement \.{\\XeTeXpicfile}@>;
+pdf_file_code:@<Implement \.{\\XeTeXpdffile}@>;
+glyph_code:@<Implement \.{\\XeTeXglyph}@>;
+XeTeX_input_encoding_extension_code:@<Implement \.{\\XeTeXinputencoding}@>;
+XeTeX_default_encoding_extension_code:@<Implement \.{\\XeTeXdefaultencoding}@>;
+XeTeX_linebreak_locale_extension_code:@<Implement \.{\\XeTeXlinebreaklocale}@>;
+
+pdf_save_pos_node: @<Implement \.{\\pdfsavepos}@>;
+@z
+
+@x
+@ @<Display the whatsit...@>=
+@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;
+
+@ @<Display the whatsit...@>=
+@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
+@ @<Make a partial copy of the whatsit...@>=
+@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))
+
+@<Make a partial copy of the whatsit...@>=
+@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):=0; native_glyph_count(r):=0;
+ copy_native_glyph_info(p, r);
+ end;
+deleted_native_node: begin words:=native_size(p);
+ r:=get_node(words);
+ 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;
+deleted_native_node: free_node(p,native_size(p));
+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
+@ @<Incorporate a whatsit node into a vbox@>=do_nothing
+@y
+@ @<Incorporate a whatsit node into a vbox@>=
+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
+@ @<Incorporate a whatsit node into an hbox@>=do_nothing
+@y
+@ @<Incorporate a whatsit node into an hbox@>=
+begin
+ case subtype(p) of
+
+ native_word_node:
+ begin
+ { merge with any following word fragments, 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)) and (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;
+ { now pp points to the non-native_word node that ended the chain, or null }
+
+ if (pp <> link(p)) then begin
+ { found a chain of at least two pieces starting at p }
+ total_chars := 0;
+ p := q;
+ while (p <> pp) do begin
+ p := link(p); { point to fragment }
+ total_chars := total_chars + native_length(p); { accumulate char count }
+ ppp := p; { remember last fragment seen }
+ p := link(p); { point to discretionary or other terminator }
+ end;
+
+ p := link(q); { the first fragment }
+ 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
+ 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);
+ if (ppp <> null) then ppp := link(ppp); { pass a disc_node }
+ 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
+@ @<Let |d| be the width of the whatsit |p|@>=d:=0
+@y
+@ @<Let |d| be the width of the whatsit |p|, and |goto found| if ``visible''@>=
+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
+@ @<Prepare to move whatsit |p| to the current page, then |goto contribute|@>=
+goto contribute
+@y
+@ @<Prepare to move whatsit |p| to the current page, then |goto contribute|@>=
+begin
+ if (subtype(p)=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
+@ @<Process whatsit |p| in |vert_break| loop, |goto not_found|@>=
+goto not_found
+@y
+@ @<Process whatsit |p| in |vert_break| loop, |goto not_found|@>=
+begin
+ if (subtype(p)=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
+@ @<Output the whatsit node |p| in a vlist@>=
+out_what(p)
+@y
+@ @<Output the whatsit node |p| in a vlist@>=
+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:
+ @<Save current position to |pdf_last_x_pos|, |pdf_last_y_pos|@>;
+
+ othercases
+ out_what(p)
+
+ endcases
+end
+@z
+
+@x
+@ @<Output the whatsit node |p| in an hlist@>=
+out_what(p)
+@y
+@ @<Save current position to |pdf_last_x_pos|, |pdf_last_y_pos|@>=
+begin
+ pdf_last_x_pos := cur_h + cur_h_offset;
+ pdf_last_y_pos := cur_page_height - cur_v - cur_v_offset
+end
+
+@ @<Calculate page dimensions and margins@>=
+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
+
+@ @<Glob...@>=
+@!cur_page_width: scaled; {width of page being shipped}
+@!cur_page_height: scaled; {height of page being shipped}
+@!cur_h_offset: scaled; {horizontal offset of page being shipped}
+@!cur_v_offset: scaled; {vertical offset of page being shipped}
+
+@ @<Output the whatsit node |p| in an hlist@>=
+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 @<Change font |dvi_f| to |f|@>;
+
+ 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) <> 0 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:
+ @<Save current position to |pdf_last_x_pos|, |pdf_last_y_pos|@>;
+
+ 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
+@<Declare procedures needed in |hlist_out|, |vlist_out|@>=
+@y
+@<Declare procedures needed in |hlist_out|, |vlist_out|@>=
+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,deleted_native_node:do_nothing;
+@z
+
+@x
+@ @<Finish the extensions@>=
+for k:=0 to 15 do if write_open[k] then a_close(write_file[k])
+@y
+@ @<Finish the extensions@>=
+terminate_font_manager;
+for k:=0 to 15 do if write_open[k] then a_close(write_file[k])
+
+@ @<Implement \.{\\XeTeXpicfile}@>=
+if abs(mode)=mmode then report_illegal_case
+else load_picture(false)
+
+@ @<Implement \.{\\XeTeXpdffile}@>=
+if abs(mode)=mmode then report_illegal_case
+else load_picture(true)
+
+@ @<Implement \.{\\XeTeXglyph}@>=
+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 begin
+ print_err("Invalid use of \XeTeXglyph");
+ help2("The \XeTeXglyph command can only be used with AAT or OT fonts,")
+ ("not TFM-based fonts. So I'm ignoring this.");
+ error;
+ end
+ 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
+
+@<Declare procedures needed in |do_extension|@>=
+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], 0.0, 0.0);
+ setPoint(corners[1], 0.0, htField(bounds) * 72.27 / 72.0);
+ setPoint(corners[2], wdField(bounds) * 72.27 / 72.0, htField(bounds) * 72.27 / 72.0);
+ setPoint(corners[3], wdField(bounds) * 72.27 / 72.0, 0.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(xField(t));
+ pic_transform6(tail) := X2Fix(yField(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;
+
+@ @<Implement \.{\\XeTeXinputencoding}@>=
+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
+
+@ @<Implement \.{\\XeTeXdefaultencoding}@>=
+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
+
+@ @<Implement \.{\\XeTeXlinebreaklocale}@>=
+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
+
+@ @<Glob...@>=
+@!pdf_last_x_pos: integer;
+@!pdf_last_y_pos: integer;
+
+@ @<Implement \.{\\pdfsavepos}@>=
+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 pdf_last_x_pos_code = XeTeX_int+25
+@d pdf_last_y_pos_code = XeTeX_int+26
+{ remember to update eTeX_dim when new 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("XeTeXfonttype", last_item, XeTeX_font_type_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");
+
+ 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;
+
+ 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....
+
+@<Error hand...@>=
+procedure scan_and_pack_name; forward;
+
+@ @<Declare procedures needed in |do_extension|@>=
+procedure scan_and_pack_name;
+begin
+ scan_file_name; pack_cur_name;
+end;
+
+@ @<Declare the procedure called |print_cmd_chr|@>=
+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;
+
+@ @<Cases of |convert| for |print_cmd_chr|@>=
+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");
+
+@ @<Cases of `Scan the argument for command |c|'@>=
+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, f);
+ 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, f);
+ end;
+
+@ @<Cases of `Print the result of command |c|'@>=
+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);
+@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|.
+
+@<Cases of |reverse|...@>=
+glue_node: begin round_glue;
+ @<Handle a glue node for mixed...@>;
+ end;
+@y
+@ Need to measure native_word and picture nodes when reversing!
+@<Cases of |reverse|...@>=
+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|.
+@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) := 0;
+
+ 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) := 0;
+ 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
+ @<Apologize for not loading the font, |goto done|@>;
+ 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
new file mode 100644
index 00000000000..71591ca8350
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/xetex-noenc.ch
@@ -0,0 +1,1144 @@
+% /****************************************************************************\
+% 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 \.{<libor@@informatics.muni.cz>}
+ and Petr Sojka \.{<sojka@@informatics.muni.cz>}. 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<hash_base then {single character}
+@y
+procedure print_cs(@!p:integer); {prints a purported control sequence}
+begin if p<hash_base then {single character}
+@z
+
+@x
+exit: end;
+@y
+end;
+@z
+
+@x
+if enctex_p then
+begin
+ primitive("endmubyte",end_cs_name,10);@/
+@!@:end_mubyte_}{\.{\\endmubyte} primitive@>
+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@>@<Declare additional routines for enc\TeX@>@/
+
+@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
+@ @<Scan ahead in the buffer...@>=
+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 an expanded...@>;
+ 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
+@ @<Scan ahead in the buffer...@>=
+begin repeat cur_chr:=buffer[k]; cat:=cat_code(cur_chr); incr(k);
+until (cat<>letter)or(k>limit);
+@<If an expanded...@>;
+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 <to be read again> should")@/
+("not appear in <byte sequence> between \mubyte and \endmubyte.");
+ back_error;
+ end;
+ p := link(r);
+ if (p = null) and mubyte_tablein then
+ begin
+ print_err("The empty <byte sequence>, ");
+ print_esc("mubyte"); print(" ignored");
+ help2("The <byte sequence> in")@/
+("\mubyte <token> <byte sequence>\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
+@<Dump enc\TeX-specific data@>;
+@y
+@z
+
+@x
+@!dummy_xord: ASCII_code;
+@!dummy_xchr: text_char;
+@!dummy_xprn: ASCII_code;
+@y
+@z
+
+@x
+@<Undump enc\TeX-specific data@>;
+@y
+@z
+
+@x
+@<Dump |xord|, |xchr|, and |xprn|@>;
+@y
+@z
+
+@x
+@<Undump |xord|, |xchr|, and |xprn|@>;
+@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
+@<Implement \.{\\special}@>=
+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
+@<Implement \.{\\special}@>=
+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;
+@<Expand macros in the token list
+@y
+begin @<Expand macros in the token list
+@z
+
+@x
+active_noconvert := true;
+if mubyte_out > 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 |xord|, |xchr|, and |xprn|@>=
+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.
+
+@<Undump |xord|, |xchr|, and |xprn|@>=
+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.
+
+@<Global...@> =
+@!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.
+
+@<Glob...@>=
+@!enctex_enabled_p:boolean; {enable encTeX}
+
+
+@ @<Set init...@>=
+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 (#)
+
+@<Basic printing...@>=
+{ 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;
+
+@ @<Declare additional routines for enc\TeX@>=
+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.
+
+@<Basic printing...@>=
+{ 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 enc\TeX-specific data@>=
+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 enc\TeX-specific data@>=
+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-upwards.ch b/Build/source/texk/web2c/xetexdir/xetex-upwards.ch
new file mode 100644
index 00000000000..64a423f1bb8
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/xetex-upwards.ch
@@ -0,0 +1,244 @@
+% /****************************************************************************\
+% 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
+@<Output a box in a vlist@>=
+if list_ptr(p)=null then cur_v:=cur_v+height(p)+depth(p)
+else begin cur_v:=cur_v+height(p); 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
+@<Output a box in a vlist@>=
+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 d<line_skip_limit then p:=new_param_glue(line_skip_code)
+ else begin p:=new_skip_param(baseline_skip_code);
+ width(temp_ptr):=d; {|temp_ptr=glue_ptr(p)|}
+ end;
+ link(tail):=p; tail:=p;
+ end;
+link(tail):=b; tail:=b; prev_depth:=depth(b);
+end;
+@y
+@p procedure append_to_vlist(@!b:pointer);
+var d:scaled; {deficiency of space between baselines}
+@!p:pointer; {a new glue specification}
+@!upwards:boolean;
+begin upwards:=XeTeX_upwards;
+ if prev_depth>ignore_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<line_skip_limit then p:=new_param_glue(line_skip_code)
+ else begin p:=new_skip_param(baseline_skip_code);
+ width(temp_ptr):=d; {|temp_ptr=glue_ptr(p)|}
+ end;
+ link(tail):=p; tail:=p;
+ end;
+link(tail):=b; tail:=b; if upwards then prev_depth:=height(b) else prev_depth:=depth(b);
+end;
+@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 @<Readjust the height and depth of |cur_box|,
+ for \.{\\vtop}@>;
+ 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 @<Readjust the height and depth of |cur_box|,
+ for \.{\\vtop}@>;
+ end;
+XeTeX_upwards_state:=v;
+pop_nest; box_end(saved(0));
+@z
+
+@x
+@ @<Dump the \eTeX\ state@>=
+dump_int(eTeX_mode);
+for j:=0 to eTeX_states-1 do eTeX_state(j):=0; {disable all enhancements}
+@y
+@ @<Dump the \eTeX\ state@>=
+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.defines b/Build/source/texk/web2c/xetexdir/xetex.defines
new file mode 100644
index 00000000000..d29e0fe281d
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/xetex.defines
@@ -0,0 +1,136 @@
+{
+/****************************************************************************\
+ 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.
+\****************************************************************************/
+}
+
+{ xetex.defines: additions for xetex }
+
+@define type voidpointer;
+@define function getnativechar();
+@define procedure setnativechar();
+@define procedure setnativemetrics();
+@define procedure setjustifiednativeglyphs();
+@define procedure setnativeglyphmetrics();
+@define function findnativefont();
+@define procedure releasefontengine();
+@define function sizeof();
+@define function makefontdef();
+@define function makexdvglypharraydata();
+@define function xdvbufferbyte();
+@define procedure fprintf();
+@define type unicodefile;
+@define function uopenin();
+@define function uopenout();
+@define procedure uclose();
+@define function dviopenout();
+@define procedure dviclose();
+@define function delcode1();
+@define procedure setdelcode1();
+@define function readcint1();
+@define procedure setcint1();
+@define procedure printutf8str();
+@define procedure setinputfileencoding();
+@define procedure terminatefontmanager;
+
+@define procedure memcpy();
+@define function casttoptr();
+@define function casttointeger();
+@define function glyphinfobyte();
+@define function casttoushort();
+
+@define function atsufontget();
+@define function atsufontget1();
+@define function atsufontget2();
+@define function atsufontgetnamed();
+@define function atsufontgetnamed1();
+@define procedure atsuprintfontname();
+@define function otfontget();
+@define function otfontget1();
+@define function otfontget2();
+@define function otfontget3();
+@define function mapchartoglyph();
+@define function mapglyphtoindex();
+@define procedure getnativecharheightdepth();
+@define procedure getnativecharsidebearings();
+@define function getnativeitaliccorrection();
+@define function getnativeglyphitaliccorrection();
+
+@define function getnativecharwd();
+@define function getnativecharht();
+@define function getnativechardp();
+@define function getnativecharic();
+
+@define function setfamilyfield();
+@define function setclassfield();
+@define function mathfamfield();
+@define function mathclassfield();
+@define function mathcharfield();
+
+@define procedure atsugetfontmetrics();
+@define procedure otgetfontmetrics();
+
+@define function getencodingmodeandinfo();
+
+@define procedure linebreakstart();
+@define function linebreaknext;
+
+{ extra stuff used in picfile code }
+@define type realpoint;
+@define type realrect;
+@define type transform;
+
+@define function deref();
+
+@define function X2Fix();
+@define function Fix2X();
+
+@define function findpicfile();
+@define function picpathbyte();
+
+@define procedure makeidentity();
+@define procedure makescale();
+@define procedure maketranslation();
+@define procedure makerotation();
+@define procedure transformpoint();
+@define procedure transformconcat();
+
+@define procedure setPoint();
+
+@define function xCoord();
+@define function yCoord();
+@define function aField();
+@define function bField();
+@define function cField();
+@define function dField();
+@define function xField();
+@define function yField();
+@define function wdField();
+@define function htField();
+@define function applymapping();
diff --git a/Build/source/texk/web2c/xetexdir/xetex.h b/Build/source/texk/web2c/xetexdir/xetex.h
new file mode 100644
index 00000000000..2078449f499
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/xetex.h
@@ -0,0 +1,100 @@
+/****************************************************************************\
+ 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.
+\****************************************************************************/
+
+/* additional declarations we want to slip in for xetex */
+
+#define native_node_size 6
+#define native_node_text(p) ((unsigned short*)(&(mem[(p) + native_node_size])))
+
+#define getnativechar(p,i) native_node_text(p)[i]
+#define setnativechar(p,i,v) native_node_text(p)[i] = v
+
+/* p is native_word node; g is XeTeX_use_glyph_metrics flag */
+#define setnativemetrics(p,g) measure_native_node(&(mem[p]), g)
+
+#define setnativeglyphmetrics(p,g) measure_native_glyph(&(mem[p]), g)
+
+#define setjustifiednativeglyphs(p) store_justified_native_glyphs(&(mem[p]))
+
+#define getnativeitaliccorrection(p) get_native_ital_corr(&(mem[p]))
+#define getnativeglyphitaliccorrection(p) get_native_glyph_ital_corr(&(mem[p]))
+
+#define makexdvglypharraydata(p) makeXDVGlyphArrayData(&(mem[p]))
+#define xdvbufferbyte(i) xdvbuffer[i]
+
+#define pic_node_size 8
+
+#define deref(p) (*(p))
+
+#define findpicfile(a,b,c,d) find_pic_file(a, b, c, d)
+
+#define picpathbyte(p,i) ((unsigned char*)&(mem[p+pic_node_size]))[i]
+
+#define dviopenout(f) open_dvi_output(&(f))
+
+#define readcint1(x) (x).cint1
+#define setcint1(x,y) (x).cint1 = (y)
+
+#define delcode1(x) readcint1(eqtb[xetexdelcodebase+(x)])
+#define setdelcode1(x,y) setcint1(eqtb[xetexdelcodebase+(x)],(y))
+
+#define casttoptr(x) (void*)(x)
+#define casttointeger(x) (long)(x)
+#define glyphinfobyte(p,k) ((unsigned char*)p)[k]
+#define casttoushort(x) (unsigned short)(x)
+
+/* easier to do the bit-twiddling here than in Pascal */
+/* read fields from a 32-bit math code */
+#define mathfamfield(x) (((unsigned)(x) >> 24) & 0xFF)
+#define mathclassfield(x) (((unsigned)(x) >> 21) & 0x07)
+#define mathcharfield(x) ((unsigned)(x) & 0x1FFFFF)
+/* calculate pieces to assign to a math code */
+#define setfamilyfield(x) (((unsigned)(x) & 0xFF) << 24)
+#define setclassfield(x) (((unsigned)(x) & 0x07) << 21)
+
+/* Unicode file reading modes */
+#define AUTO 0 /* default: will become one of 1..3 at file open time, after sniffing */
+#define UTF8 1
+#define UTF16BE 2
+#define UTF16LE 3
+#define RAW 4
+#define ICUMAPPING 5
+
+/* we don't use xchr, so change the cpascal.h definition of this... */
+#undef Xchr
+#define Xchr(x) (x)
+
+#ifdef XETEX_MAC
+#include <Carbon/Carbon.h> /* for Mac OS X, it's handy to have the Carbon APIs available */
+#endif
+
+#include "trans.h" /* functions for affine transform operations */
+#include "TECkit_Common.h" /* include this before XeTeX_ext.h */
+#include "XeTeX_ext.h" /* other extension functions */
diff --git a/Build/source/texk/web2c/xetexdir/xetex.mk b/Build/source/texk/web2c/xetexdir/xetex.mk
new file mode 100644
index 00000000000..321ea17686f
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/xetex.mk
@@ -0,0 +1,303 @@
+# Makefile fragment for XeTeX and web2c. -- Jonathan Kew -- Public domain.
+# This fragment contains the parts of the makefile that are most likely to
+# differ between releases of XeTeX.
+
+Makefile: $(srcdir)/xetexdir/xetex.mk
+
+# We build xetex unless configure decides to skip it
+xetex = @XETEX@ xetex
+
+### Platform-specific defines and files to be built
+
+# On Mac OS X:
+@XETEX_MACOSX@ xetex_platform_o = XeTeX_mac.o XeTeXFontMgr_Mac.o
+@XETEX_MACOSX@ xetex_platform_layout_o = XeTeXFontInst_Mac.o
+@XETEX_MACOSX@ xetex_platform_layout_cxx = XeTeXFontInst_Mac.cpp
+@XETEX_MACOSX@ xetex_images_o =
+
+@XETEX_MACOSX@ XETEX_DEFINES = -DXETEX_MAC
+
+@XETEX_MACOSX@ EXTRALIBS = -framework Carbon -framework Cocoa -framework QuickTime
+
+@XETEX_MACOSX@ EXTRADEPS =
+
+# On non-Mac platforms:
+@XETEX_GENERIC@ xetex_platform_o = XeTeXFontMgr_Linux.o
+@XETEX_GENERIC@ xetex_platform_layout_o = XeTeXFontInst_FC.o
+@XETEX_GENERIC@ xetex_platform_layout_cxx = XeTeXFontInst_FC.cpp
+@XETEX_GENERIC@ xetex_images_o = mfileio.o numbers.o pdfimage.o bmpimage.o jpegimage.o pngimage.o XeTeX_pic.o
+
+@XETEX_GENERIC@ XETEX_DEFINES = -DXETEX_OTHER
+
+@XETEX_GENERIC@ # FIXME: FontConfig not yet handled by configure
+@XETEX_GENERIC@ EXTRALIBS = @LDFREETYPE2@ @LDLIBXPDF@ @LDLIBPNG@ -lfontconfig
+
+@XETEX_GENERIC@ EXTRADEPS = @FREETYPE2DEP@ @LIBXPDFDEP@ @LIBPNGDEP@
+
+### end of platform-specific setup
+
+LDLIBXPDF=@LDLIBXPDF@
+LIBXPDFCPPFLAGS=@LIBXPDFCPPFLAGS@
+LIBXPDFDEP=@LIBXPDFDEP@
+
+LIBXPDFDIR=../../libs/xpdf
+LIBXPDFSRCDIR=$(srcdir)/$(LIBXPDFDIR)
+
+LDLIBPNG=@LDLIBPNG@
+LIBPNGCPPFLAGS=@LIBPNGCPPFLAGS@
+LIBPNGDEP=@LIBPNGDEP@
+
+LIBPNGDIR=../../libs/libpng
+LIBPNGSRCDIR=$(srcdir)/$(LIBPNGDIR)
+
+FTFLAGS = @FREETYPE2CPPFLAGS@
+
+FREETYPE2DIR = ../../libs/freetype2
+FREETYPE2SRCDIR = $(srcdir)/$(FREETYPE2DIR)
+
+TECKITFLAGS = @TECKITCPPFLAGS@
+LDTECKIT = @LDTECKIT@
+TECKITDEP = @TECKITDEP@
+
+TECKITDIR=../../libs/teckit
+TECKITSRCDIR=$(srcdir)/$(TECKITDIR)
+
+ICUFLAGS = @ICUCPPFLAGS@
+LDICU = @LDICU@
+ICUDEP = @ICUDEP@
+
+ICUDIR=../../libs/icu-xetex
+ICUSRCDIR=$(srcdir)/$(ICUDIR)
+
+ICUCFLAGS = @ICUCPPFLAGS@ -DLE_USE_CMEMORY
+
+
+# Font-related headers
+XeTeXFontHdrs = \
+ $(srcdir)/xetexdir/FontTableCache.h \
+ $(srcdir)/xetexdir/XeTeXFontInst.h \
+ $(srcdir)/xetexdir/XeTeXFontInst_FC.h \
+ $(srcdir)/xetexdir/XeTeXFontInst_Mac.h \
+ $(srcdir)/xetexdir/XeTeXFontMgr.h \
+ $(srcdir)/xetexdir/XeTeXFontMgr_Linux.h \
+ $(srcdir)/xetexdir/XeTeXFontMgr_Mac.h \
+ $(srcdir)/xetexdir/XeTeXLayoutInterface.h \
+ $(srcdir)/xetexdir/XeTeXOTLayoutEngine.h
+
+# Image-related headers
+XeTeXImageHdrs = \
+ $(srcdir)/xetexdir/bmpimage.h \
+ $(srcdir)/xetexdir/jpegimage.h \
+ $(srcdir)/xetexdir/pdfimage.h \
+ $(srcdir)/xetexdir/pngimage.h
+
+# Extract xetex version
+xetexdir/xetex.version: $(srcdir)/xetexdir/xetex-new.ch
+ test -d xetexdir || mkdir xetexdir
+ grep '^@d XeTeX_version_string==' $(srcdir)/xetexdir/xetex-new.ch \
+ | sed "s/^.*'-//;s/'.*$$//" >xetexdir/xetex.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)
+
+# these compilations require the path to TECkit headers;
+# just setting it in XCFLAGS doesn't seem to work when we're called
+# recursively from "make world" etc
+xetexini.o: xetexini.c $(srcdir)/xetexdir/XeTeX_ext.h
+ $(compile) $(TECKITFLAGS) $(ALL_CFLAGS) $(XETEX_DEFINES) -c $< -o $@
+xetex0.o: xetex0.c $(srcdir)/xetexdir/XeTeX_ext.h
+ $(compile) $(TECKITFLAGS) $(ALL_CFLAGS) $(XETEX_DEFINES) -c $< -o $@
+xetex1.o: xetex1.c $(srcdir)/xetexdir/XeTeX_ext.h
+ $(compile) $(TECKITFLAGS) $(ALL_CFLAGS) $(XETEX_DEFINES) -c $< -o $@
+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 $@
+
+# image support
+mfileio.o: $(srcdir)/xetexdir/mfileio.c $(srcdir)/xetexdir/mfileio.h
+ $(compile) $(ALL_CFLAGS) -c $< -o $@
+
+numbers.o: $(srcdir)/xetexdir/numbers.c $(srcdir)/xetexdir/numbers.h
+ $(compile) $(ALL_CFLAGS) -c $< -o $@
+
+bmpimage.o: $(srcdir)/xetexdir/bmpimage.c $(srcdir)/xetexdir/bmpimage.h
+ $(compile) $(ALL_CFLAGS) -c $< -o $@
+
+jpegimage.o: $(srcdir)/xetexdir/jpegimage.c $(srcdir)/xetexdir/jpegimage.h
+ $(compile) $(ALL_CFLAGS) -c $< -o $@
+
+pngimage.o: $(srcdir)/xetexdir/pngimage.c $(srcdir)/xetexdir/pngimage.h
+ $(compile) $(ALL_CFLAGS) $(LIBPNGCPPFLAGS) -c $< -o $@
+
+pdfimage.o: $(srcdir)/xetexdir/pdfimage.cpp $(srcdir)/xetexdir/pdfimage.h
+ $(compile) $(ALL_CFLAGS) $(LIBXPDFCPPFLAGS) -c $< -o $@
+
+XeTeX_pic.o: $(srcdir)/xetexdir/XeTeX_pic.c $(srcdir)/xetexdir/XeTeX_ext.h $(XeTeXImageHdrs)
+ $(compile) $(TECKITFLAGS) $(ALL_CFLAGS) $(XETEX_DEFINES) -c $< -o $@
+
+# Layout library
+xetex_ot_layout_o = \
+ XeTeXFontMgr.o \
+ XeTeXLayoutInterface.o XeTeXOTLayoutEngine.o \
+ XeTeXFontInst.o cmaps.o FontTableCache.o \
+ $(xetex_platform_layout_o)
+
+XeTeXLayoutInterface.o: $(srcdir)/xetexdir/XeTeXLayoutInterface.cpp $(XeTeXFontHdrs)
+ $(CXX) $(ICUCFLAGS) $(FTFLAGS) $(ALL_CXXFLAGS) $(XETEX_DEFINES) -c $< -o $@
+XeTeXOTLayoutEngine.o: $(srcdir)/xetexdir/XeTeXOTLayoutEngine.cpp $(XeTeXFontHdrs)
+ $(CXX) $(ICUCFLAGS) $(FTFLAGS) $(ALL_CXXFLAGS) $(XETEX_DEFINES) -c $< -o $@
+
+XeTeXFontMgr.o: $(srcdir)/xetexdir/XeTeXFontMgr.cpp $(XeTeXFontHdrs)
+ $(CXX) $(ICUCFLAGS) $(FTFLAGS) $(ALL_CXXFLAGS) $(XETEX_DEFINES) -c $< -o $@
+XeTeXFontMgr_Linux.o: $(srcdir)/xetexdir/XeTeXFontMgr_Linux.cpp $(XeTeXFontHdrs)
+ $(CXX) $(ICUCFLAGS) $(FTFLAGS) $(ALL_CXXFLAGS) $(XETEX_DEFINES) -c $< -o $@
+
+XeTeXFontMgr_Mac.o: $(srcdir)/xetexdir/XeTeXFontMgr_Mac.mm $(XeTeXFontHdrs)
+ gcc -ObjC++ $(ICUCFLAGS) $(FTFLAGS) $(ALL_CXXFLAGS) $(XETEX_DEFINES) -c $< -o $@
+
+cmaps.o: $(srcdir)/xetexdir/cmaps.cpp
+ $(CXX) $(ICUCFLAGS) $(ALL_CXXFLAGS) $(XETEX_DEFINES) -c $< -o $@
+FontTableCache.o: $(srcdir)/xetexdir/FontTableCache.cpp
+ $(CXX) $(ICUCFLAGS) $(ALL_CXXFLAGS) $(XETEX_DEFINES) -c $< -o $@
+
+XeTeXFontInst.o: $(srcdir)/xetexdir/XeTeXFontInst.cpp $(XeTeXFontHdrs)
+ $(CXX) $(ICUCFLAGS) $(FTFLAGS) $(ALL_CXXFLAGS) $(XETEX_DEFINES) -c $< -o $@
+XeTeXFontInst_Mac.o: $(srcdir)/xetexdir/XeTeXFontInst_Mac.cpp $(XeTeXFontHdrs)
+ $(CXX) $(ICUCFLAGS) $(ALL_CXXFLAGS) $(XETEX_DEFINES) -c $< -o $@
+XeTeXFontInst_FC.o: $(srcdir)/xetexdir/XeTeXFontInst_FC.cpp $(XeTeXFontHdrs)
+ $(CXX) $(ICUCFLAGS) $(FTFLAGS) $(ALL_CXXFLAGS) $(XETEX_DEFINES) -c $< -o $@
+
+
+xetexlibs = $(LDICU) $(LDTECKIT)
+
+# 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) $(ALL_CFLAGS) $(XETEX_DEFINES) -c $< -o $@
+XeTeX_mac.o: $(srcdir)/xetexdir/XeTeX_mac.c xetexd.h
+ $(compile) $(ICUCFLAGS) $(TECKITFLAGS) $(ALL_CFLAGS) $(XETEX_DEFINES) -c $< -o $@
+
+trans.o: $(srcdir)/xetexdir/trans.c
+ $(compile) $(ALL_CFLAGS) $(XETEX_DEFINES) -c $< -o $@
+
+# Making xetex.
+xetex: $(xetex_o) $(xetex_add_o) $(xetex_images_o) $(xetex_ot_layout_o) $(xetexlibs) $(EXTRADEPS)
+ $(kpathsea_cxx_link) $(xetex_o) $(xetex_add_o) $(xetex_images_o) $(xetex_ot_layout_o) \
+ $(socketlibs) $(LOADLIBES) \
+ $(xetexlibs) $(EXTRALIBS) -lz
+
+# C file dependencies
+$(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
+ test -d xetexdir || mkdir xetexdir
+ sed s/XETEX-VERSION/`cat xetexdir/xetex.version`/ \
+ $(srcdir)/xetexdir/xetexextra.in >$@
+
+# Tangling
+xetex.p xetex.pool: ./otangle xetex.web # xetex.ch
+ ./otangle xetex.web # xetex.ch
+
+# Generation of the web [and ch] file.
+# Sources for xetex.web:
+xetex_web_srcs = $(srcdir)/tex.web \
+ $(srcdir)/etexdir/etex.ch \
+ $(srcdir)/etexdir/tex.ch0 \
+ $(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
+xetex.web: tie xetexdir/xetex.mk $(xetex_web_srcs)
+ $(TIE) -m xetex.web $(xetex_web_srcs)
+
+################## FIXME: the rest of this isn't properly updated for xetex yet...
+################## e.g., we don't have real xetex tests to run!
+
+# Tests...
+#check: @XETEX@ xetex-check
+#xetex-check: etrip xetex.fmt
+# Test truncation (but don't bother showing the warning msg).
+# ./xetex --progname=xetex --output-comment="`cat $(srcdir)/PROJECTS`" \
+# $(srcdir)/tests/hello 2>/dev/null \
+# && ./dvitype hello.dvi | grep olaf@infovore.xs4all.nl >/dev/null
+# \openout should show up in \write's.
+# ./xetex --progname=xetex $(srcdir)/tests/openout && grep xfoo openout.log
+# one.two.tex -> one.two.log
+# ./xetex --progname=xetex $(srcdir)/tests/one.two && ls -l one.two.log
+# uno.dos -> uno.log
+# ./xetex --progname=xetex $(srcdir)/tests/uno.dos && ls -l uno.log
+# ./xetex --progname=xetex $(srcdir)/tests/just.texi && ls -l just.log
+# -./xetex --progname=xetex $(srcdir)/tests/batch.tex
+# ./xetex --progname=xetex --shell $(srcdir)/tests/write18 | grep echo
+# ./xetex --mltex --progname=xeinitex $(srcdir)/tests/mltextst
+# -./xetex --progname=xetex </dev/null
+# -PATH=`pwd`:$(kpathsea_dir):$(kpathsea_srcdir):$$PATH \
+# WEB2C=$(kpathsea_srcdir) TMPDIR=.. \
+# ./xetex --progname=xetex '\nonstopmode\font\foo=nonesuch\end'
+
+# Cleaning up.
+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 xetexdir/xetexextra.h xetexdir/xetex.version
+ rm -f xetex.p xetex.pool xetex.web xetex.ch
+ rm -f xetex.fmt xetex.log
+ rm -f hello.dvi hello.log xfoo.out openout.log one.two.log uno.log
+ rm -f just.log batch.log write18.log mltextst.log texput.log
+ rm -f missfont.log
+ rm -rf tfm
+
+# Dumps
+all_xefmts = xetex.fmt $(xefmts)
+
+dumps: @XETEX@ xefmts
+xefmts: $(all_xefmts)
+
+xefmtdir = $(web2cdir)/xetex
+$(xefmtdir)::
+ $(SHELL) $(top_srcdir)/../mkinstalldirs $(xefmtdir)
+
+xetex.fmt: xetex
+ $(dumpenv) $(MAKE) progname=xetex files="xetex.ini unicode-letters.tex plain.tex cmr10.tfm" prereq-check
+ $(dumpenv) ./xetex --progname=xetex --jobname=xetex --ini \*\\input xetex.ini \\dump </dev/null
+
+xelatex.fmt: xetex
+ $(dumpenv) $(MAKE) progname=xelatex files="xelatex.ini unicode-letters.tex latex.ltx" prereq-check
+ $(dumpenv) ./xetex --progname=xelatex --jobname=xelatex --ini \*\\input xelatex.ini </dev/null
+
+
+# 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-dumps: install-xetex-fmts
+
+install-programs: @XETEX@ install-xetex-programs
+install-xetex-programs: xetex $(bindir)
+ for p in xetex; do $(INSTALL_LIBTOOL_PROG) $$p $(bindir); done
+
+install-links: @XETEX@ install-xetex-links
+install-xetex-links: install-xetex-programs
+ #cd $(bindir) && (rm -f xeinitex xevirtex; \
+ # $(LN) xetex xeinitex; $(LN) xetex xevirtex)
+
+install-fmts: @XETEX@ install-xetex-fmts
+install-xetex-fmts: xefmts $(xefmtdir)
+ xefmts="$(all_xefmts)"; \
+ for f in $$xefmts; do $(INSTALL_DATA) $$f $(xefmtdir)/$$f; done
+ xefmts="$(xefmts)"; \
+ for f in $$xefmts; do base=`basename $$f .fmt`; \
+ (cd $(bindir) && (rm -f $$base; $(LN) xetex $$base)); done
+
+install-data:: @XETEX@ install-xetex-data
+install-xetex-pool: xetex.pool $(texpooldir)
+ $(INSTALL_DATA) xetex.pool $(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
new file mode 100644
index 00000000000..9286d98fe37
--- /dev/null
+++ b/Build/source/texk/web2c/xetexdir/xetexextra.in
@@ -0,0 +1,65 @@
+/* xetexextra.in: banner etc. for XeTeX.
+
+ This is included by XeTeX, from ../xetexextra.c
+ (generated from ../lib/texmfmp.c).
+
+ 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.
+*/
+
+/*
+Copyright (C) 1995, 96 Karl Berry.
+Copyright (C) 2004 Olaf Weber.
+Copyright (C) 2004 Jonathan Kew/SIL International.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define BANNER "This is XeTeX, Version 3.141592-XETEX-VERSION"
+#define COPYRIGHT_HOLDER "SIL International"
+#define AUTHOR "Jonathan Kew"
+#define PROGRAM_HELP XETEXHELP
+#define BUG_ADDRESS "nrsi@sil.org"
+#define DUMP_VAR TEXformatdefault
+#define DUMP_LENGTH_VAR formatdefaultlength
+#define DUMP_OPTION "fmt"
+#define DUMP_EXT ".fmt"
+#define INPUT_FORMAT kpse_tex_format
+#define INI_PROGRAM "xeinitex"
+#define VIR_PROGRAM "xevirtex"