diff options
author | Jonathan Kew <jfkthame@googlemail.com> | 2006-07-26 16:19:45 +0000 |
---|---|---|
committer | Jonathan Kew <jfkthame@googlemail.com> | 2006-07-26 16:19:45 +0000 |
commit | 622bf4a7c90729be28a038c49e4c237ce9f31297 (patch) | |
tree | 77466d5c0a89c433bd1c08f4cbeaf410fda7b25c | |
parent | e88aafe4ca4779a73487925dea63e8b55dc5e251 (diff) |
added main xetex source directory
git-svn-id: svn://tug.org/texlive/trunk@1920 c570f23f-e606-0410-a88d-b1316a301751
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] = | + 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" |