diff options
Diffstat (limited to 'Build/source/texk/dvisvgm/dvisvgm-src/libs/ff-woff/fontforge/tottf.c')
-rw-r--r-- | Build/source/texk/dvisvgm/dvisvgm-src/libs/ff-woff/fontforge/tottf.c | 6757 |
1 files changed, 0 insertions, 6757 deletions
diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/libs/ff-woff/fontforge/tottf.c b/Build/source/texk/dvisvgm/dvisvgm-src/libs/ff-woff/fontforge/tottf.c deleted file mode 100644 index 57c61c0cc24..00000000000 --- a/Build/source/texk/dvisvgm/dvisvgm-src/libs/ff-woff/fontforge/tottf.c +++ /dev/null @@ -1,6757 +0,0 @@ -/* Copyright (C) 2000-2012 by George Williams */ -/* - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - - * The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) 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 OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include "fontforge.h" -#include <math.h> -#include <time.h> -#include <utype.h> - -#ifdef __CygWin - #include <sys/types.h> - #include <sys/stat.h> - #include <unistd.h> -#endif - -#include "ttf.h" - -char *TTFFoundry=NULL; - -/* This file produces a ttf file given a splinefont. */ - -/* ************************************************************************** */ - -/* Required tables: - cmap encoding - head header data - hhea horizontal metrics header data - hmtx horizontal metrics (widths, lsidebearing) - maxp various maxima in the font - name various names associated with the font - post postscript names and other stuff -Required by windows but not mac - OS/2 bleah. -Required for TrueType - loca pointers to the glyphs - glyf character shapes -Required for OpenType (PostScript) - CFF A complete postscript CFF font here with all its internal tables -Required for bitmaps - bdat/EBDT bitmap data - bloc/EBLC pointers to bitmaps - bhed for apple bitmap only fonts, replaces head -Optional for bitmaps - EBSC bitmap scaling table (used in windows "bitmap-only" fonts) -"Advanced Typograpy" - Apple - feat (mapping between morx features and 'name' names) - kern (if data are present) - lcar (ligature caret, if data present) - morx (substitutions, if data present) - prop (glyph properties, if data present) - opbd (optical bounds, if data present) - OpenType - GPOS (opentype, if kern,anchor data are present) - GSUB (opentype, if ligature (other subs) data are present) - GDEF (opentype, if anchor data are present) -MATH - MATH (MS proposal, if math data present) -Apple variation tables (for distortable (multiple master type) fonts) - fvar (font variations) - gvar (glyph variations) - cvar (cvt variations) - avar (axis variations) -additional tables - cvt for hinting - gasp to control when things should be hinted - fpgm for hinting (currently only copied and dumped verbatim) - prep for hinting (currently only copied and dumped verbatim) -FontForge - PfEd My own table -TeX - TeX TeX specific info (stuff that used to live in tfm files) -*/ - -const char *ttfstandardnames[258] = { -".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" -}; -/* Relates Unicode blocks as in - http://unicode.org/Public/UNIDATA/Blocks.txt - to bit positions in the OpenType standard Unicode Character Range - field 'ulUnicodeRange'. - Note that the OpenType standard specifies bits for a subset - of the Unicode blocks. - */ -static int uniranges[][3] = { - { 0x20, 0x7e, 0 }, /* Basic Latin */ - { 0xa0, 0xff, 1 }, /* Latin-1 Supplement */ - { 0x100, 0x17f, 2 }, /* Latin Extended-A */ - { 0x180, 0x24f, 3 }, /* Latin Extended-B */ - { 0x250, 0x2af, 4 }, /* IPA Extensions */ - { 0x2b0, 0x2ff, 5 }, /* Spacing Modifier Letters */ - { 0x300, 0x36f, 6 }, /* Combining Diacritical Marks */ - { 0x370, 0x3ff, 7 }, /* Greek and Coptic */ - { 0x400, 0x52f, 9 }, /* Cyrillic / Cyrillic Supplement */ - { 0x530, 0x58f, 10 }, /* Armenian */ - { 0x590, 0x5ff, 11 }, /* Hebrew */ - { 0x600, 0x6ff, 13 }, /* Arabic */ - { 0x700, 0x74f, 71 }, /* Syriac */ - { 0x750, 0x77f, 13 }, /* Arabic Supplement */ - { 0x780, 0x7bf, 72 }, /* Thaana */ - { 0x7c0, 0x7ff, 14 }, /* N'Ko */ - /* { 0x800, 0x83f, ? }, Samaritan */ - /* { 0x840, 0x85f, ? }, Mandaic */ - { 0x900, 0x97f, 15 }, /* Devanagari */ - { 0x980, 0x9ff, 16 }, /* Bengali */ - { 0xa00, 0xa7f, 17 }, /* Gurmukhi */ - { 0xa80, 0xaff, 18 }, /* Gujarati */ - { 0xb00, 0xb7f, 19 }, /* Oriya */ - { 0xb80, 0xbff, 20 }, /* Tamil */ - { 0xc00, 0xc7f, 21 }, /* Telugu */ - { 0xc80, 0xcff, 22 }, /* Kannada */ - { 0xd00, 0xd7f, 23 }, /* Malayalam */ - { 0xd80, 0xdff, 73 }, /* Sinhala */ - { 0xe00, 0xe7f, 24 }, /* Thai */ - { 0xe80, 0xeff, 25 }, /* Lao */ - { 0xf00, 0xfbf, 70 }, /* Tibetan */ - { 0x1000, 0x109f, 74 }, /* Myanmar */ - { 0x10a0, 0x10ff, 26 }, /* Georgian */ - { 0x1100, 0x11ff, 28 }, /* Hangul Jamo */ - { 0x1200, 0x137f, 75 }, /* Ethiopic */ - { 0x1380, 0x139f, 75 }, /* Ethiopic Supplement */ - { 0x13a0, 0x13ff, 76 }, /* Cherokee */ - { 0x1400, 0x167f, 77 }, /* Unified Canadian Aboriginal Symbols */ - { 0x1680, 0x169f, 78 }, /* Ogham */ - { 0x16a0, 0x16ff, 79 }, /* Runic */ - { 0x1700, 0x1714, 84 }, /* Tagalog */ - { 0x1720, 0x1736, 84 }, /* Harunoo */ - { 0x1740, 0x1753, 84 }, /* Buhid */ - { 0x1750, 0x1773, 84 }, /* Tagbanwa */ - { 0x1780, 0x17ff, 80 }, /* Khmer */ - { 0x1800, 0x18af, 81 }, /* Mongolian */ - { 0x18B0, 0x18f5, 77 }, /* Unified Canadian Aboriginal Symbols Extended */ - { 0x1900, 0x194f, 93 }, /* Limbu */ - { 0x1950, 0x197f, 94 }, /* Tai Le */ - { 0x1980, 0x19DF, 95 }, /* New Tai Lue */ - { 0x19e0, 0x19ff, 80 }, /* Khmer Symbols */ - { 0x1A00, 0x1A1F, 96 }, /* Buginese */ - { 0x1B00, 0x1B7f, 27 }, /* Balinese */ - { 0x1B80, 0x1BB9, 112 }, /* Sudanese */ - /*{ 0x1bc0, 0x1bff, ? }, Batak */ - { 0x1C00, 0x1C4F, 113 }, /* Lepcha */ - { 0x1C50, 0x1C7F, 114 }, /* Ol Chiki */ - /*{ 0x1cd0, 0x1cff, ? }, Vedic Extensions */ - { 0x1d00, 0x1dbf, 4 }, /* Phonetic Extensions & Supplement */ - { 0x1d80, 0x1dff, 6 }, /* Combining Diacritical Marks Supplement */ - { 0x1e00, 0x1eff, 29 }, /* Latin Extended Additional */ - { 0x1f00, 0x1fff, 30 }, /* Greek Extended */ - { 0x2000, 0x206f, 31 }, /* General Punctuation */ - { 0x2070, 0x209f, 32 }, /* Superscripts and Subscripts */ - { 0x20a0, 0x20cf, 33 }, /* Currency Symbols */ - { 0x20d0, 0x20ff, 34 }, /* Combining Marks for Symbols */ - { 0x2100, 0x214f, 35 }, /* Letterlike Symbols */ - { 0x2150, 0x218f, 36 }, /* Number Forms */ - { 0x2190, 0x21ff, 37 }, /* Arrows */ - { 0x2200, 0x22ff, 38 }, /* Mathematical Operators */ - { 0x2300, 0x237f, 39 }, /* Miscellaneous Technical */ - { 0x2400, 0x243f, 40 }, /* Control Pictures */ - { 0x2440, 0x245f, 41 }, /* Optical Character Recognition */ - { 0x2460, 0x24ff, 42 }, /* Enclosed Alphanumerics */ - { 0x2500, 0x257f, 43 }, /* Box Drawing */ - { 0x2580, 0x259f, 44 }, /* Block Elements */ - { 0x25a0, 0x25ff, 45 }, /* Geometric Shapes */ - { 0x2600, 0x267f, 46 }, /* Miscellaneous Symbols */ - { 0x2700, 0x27bf, 47 }, /* Dingbats */ - { 0x27c0, 0x27ef, 38 }, /* Miscellaneous Mathematical Symbols-A */ - { 0x27f0, 0x27ff, 37 }, /* Supplementary Arrows-A */ - { 0x2800, 0x28ff, 82 }, /* Braille Patterns */ - { 0x2900, 0x297f, 37 }, /* Supplementary Arrows-B */ - { 0x2980, 0x2aff, 38 }, /* Miscellaneous Mathematical Symbols-B / - Supplemental Mathematical Operators */ - { 0x2b00, 0x2bff, 37 }, /* Miscellaneous Symbols and Arrows */ - { 0x2C00, 0x2C5E, 97 }, /* Glagolitic */ - { 0x2c60, 0x2c7f, 29 }, /* Latin Extended-C */ - { 0x2c80, 0x2cff, 8 }, /* Coptic */ - { 0x2D00, 0x2D25, 26 }, /* Georgian Supplement */ - { 0x2D30, 0x2D6F, 98 }, /* Tifinagh */ - { 0x2d80, 0x2ddf, 75 }, /* Ethiopic Extended */ - { 0x2de0, 0x2dff, 9 }, /* Cyrillic Extended-A */ - { 0x2e00, 0x2e7f, 31 }, /* Supplemental Punctuation */ - { 0x2e80, 0x2fff, 59 }, /* CJK Radicals Supplement / Kangxi Radicals / - Ideographic Description Characters */ - { 0x3000, 0x303f, 48 }, /* CJK Symbols and Punctuation */ - { 0x3040, 0x309f, 49 }, /* Hiragana */ - { 0x30a0, 0x30ff, 50 }, /* Katakana */ - { 0x3100, 0x312f, 51 }, /* Bopomofo */ - { 0x3130, 0x318f, 52 }, /* Hangul Compatibility Jamo */ - { 0x3190, 0x319f, 59 }, /* Kanbun */ - { 0x31a0, 0x31bf, 51 }, /* Bopomofo Extended */ - { 0x31f0, 0x31ff, 50 }, /* Katakana Phonetic Extensions */ - { 0x3200, 0x32ff, 54 }, /* Enclosed CJK Letters and Months */ - { 0x3300, 0x33ff, 55 }, /* CJK compatability */ - { 0x3400, 0x4dbf, 59 }, /* CJK Unified Ideographs Extension A */ - { 0x4dc0, 0x4dff, 99 }, /* Yijing Hexagram Symbols */ - { 0x4e00, 0x9fff, 59 }, /* CJK Unified Ideographs */ - { 0xa000, 0xa4cf, 81 }, /* Yi Syllables / Yi Radicals */ - /*{ 0xA4d0, 0xA4ff, ? }, Lisu */ - { 0xA500, 0xA62b, 12 }, /* Vai */ - { 0xa640, 0xa69f, 9 }, /* Cyrillic Extended-B */ - /*{ 0xa6a0, 0xa6ff, ? }, Bamum */ - { 0xa700, 0xa71f, 5 }, /* Modifier Tone Letters */ - { 0xa720, 0xa7ff, 29 }, /* Latin Extended-D */ - { 0xA800, 0xA82F, 100 }, /* Syloti Nagri */ - /*{ 0xa830, 0xa83f, ? }, Common Indic Number Forms */ - { 0xa840, 0xa87f, 53 }, /* Phags-pa */ - { 0xA880, 0xA8D9, 115 }, /* Saurashtra */ - /*{ 0xA8E0, 0xA8FF, ? }, Devanagari Extended */ - { 0xA900, 0xA92F, 116 }, /* Kayah Li */ - { 0xA930, 0xA95F, 117 }, /* Rejang */ - /*{ 0xA960, 0xA97F, 28? }, Hangul Jamo Extended-A */ - /*{ 0xA980, 0xA9DF, ? }, Javanese */ - { 0xAA00, 0xAA5F, 118 }, /* Cham */ - /*{ 0xAA60, 0xAA7F, 74? }, Myanmar Extended-A */ - /*{ 0xAA80, 0xAADF, ? }, Tai Viet */ - /*{ 0xab00, 0xab2f, 75? }, Ethiopic Extended-A */ - /*{ 0xabc0, 0xabff, ? }, Meetei Mayek */ - { 0xac00, 0xd7af, 56 }, /* Hangul Syllables */ - { 0xd800, 0xdfff, 57 }, /* Non-Plane 0 */ - { 0xe000, 0xf8ff, 60 }, /* Private Use Area */ - - { 0xf900, 0xfaff, 61 }, /* CJK Compatibility Ideographs */ - /* 12 ideographs in The IBM 32 Compatibility Additions are CJK unified - ideographs despite their names: see The Unicode Standard 4.0, p.475 */ - { 0xfa0e, 0xfa0f, 59 }, - { 0xfa10, 0xfa10, 61 }, - { 0xfa11, 0xfa11, 59 }, - { 0xfa12, 0xfa12, 61 }, - { 0xfa13, 0xfa14, 59 }, - { 0xfa15, 0xfa1e, 61 }, - { 0xfa1f, 0xfa1f, 59 }, - { 0xfa20, 0xfa20, 61 }, - { 0xfa21, 0xfa21, 59 }, - { 0xfa22, 0xfa22, 61 }, - { 0xfa23, 0xfa24, 59 }, - { 0xfa25, 0xfa26, 61 }, - { 0xfa27, 0xfa29, 59 }, - { 0xfa2a, 0xfaff, 61 }, /* CJK Compatibility Ideographs */ - - { 0xfb00, 0xfb4f, 62 }, /* Alphabetic Presentation Forms */ - { 0xfb50, 0xfdff, 63 }, /* Arabic Presentation Forms-A */ - { 0xfe00, 0xfe0f, 91 }, /* Variation Selectors */ - { 0xfe20, 0xfe2f, 64 }, /* Combining Half Marks */ - { 0xfe30, 0xfe4f, 65 }, /* CJK Compatibility Forms */ - { 0xfe50, 0xfe6f, 66 }, /* Small Form Variants */ - { 0xfe70, 0xfeef, 67 }, /* Arabic Presentation Forms-B */ - { 0xff00, 0xffef, 68 }, /* Halfwidth and Fullwidth Forms */ - { 0xfff0, 0xffff, 69 }, /* Specials */ - - { 0x10000, 0x1007f, 101 }, /* Linear B Syllabary */ - { 0x10080, 0x100ff, 101 }, /* Linear B Ideograms */ - { 0x10100, 0x1013f, 101 }, /* Aegean Numbers */ - { 0x10140, 0x1018F, 102 }, /* Ancient Greek Numbers */ - { 0x10190, 0x101CF, 119 }, /* Ancient Symbols */ - { 0x101D0, 0x101FF, 120 }, /* Phaistos Disc */ - { 0x102A0, 0x102D0, 121 }, /* Carian */ - { 0x10280, 0x1029C, 121 }, /* Lycian */ - { 0x10300, 0x1032f, 85 }, /* Old Italic */ - { 0x10330, 0x1034f, 86 }, /* Gothic */ - { 0x10380, 0x1039F, 103 }, /* Ugaritic */ - { 0x103A0, 0x103D6, 104 }, /* Old Persian */ - { 0x10400, 0x1044f, 87 }, /* Deseret */ - { 0x10450, 0x1047f, 105 }, /* Shavian */ - { 0x10480, 0x104af, 106 }, /* Osmanya */ - { 0x10800, 0x1083f, 107 }, /* Cypriot Syllabary */ - /*{ 0x10840, 0x1085f, ? }, Imperial Aramaic */ - { 0x10900, 0x1091f, 58 }, /* Phoenician */ - { 0x10920, 0x10939, 121 }, /* Lydian */ - { 0x10A00, 0x10A5F, 108 }, /* Kharoshthi */ - /*{ 0x10A60, 0x10A7F, ? }, Old South Arabian */ - /*{ 0x10B00, 0x10B3F, ? }, Avestan */ - /*{ 0x10B40, 0x10B5F, ? }, Inscriptional Parthian */ - /*{ 0x10B60, 0x10B7F, ? }, Inscriptional Pahlavi */ - /*{ 0x10C00, 0x10C4F, ? }, Old Turkic */ - /*{ 0x10E60, 0x10E7F, ? }, Rumi Numeral Symbols */ - /*{ 0x11000, 0x1107F, ? }, Brahmi */ - /*{ 0x11000, 0x1107F, ? }, Kaithi */ - { 0x12000, 0x1247F, 110 }, /* Cuneiform; Numbers & Punctuation */ - /*{ 0x13000, 0x1342F, ? }, Egyptian Hieroglyphs */ - /*{ 0x16800, 0x16A3F, ? }, Bamum Supplement */ - /*{ 0x1B000, 0x1B0FF, ? }, Kana Supplement */ - { 0x1d000, 0x1d1ff, 88 }, /* Byzantine Musical Symbols / Musical Symbols */ - /*{ 0x1D200, 0x1D24F, ? }, Ancient Greek Musical Notation */ - { 0x1d300, 0x1d35f, 109 }, /* Tai Xuan Jing Symbols */ - { 0x1D360, 0x1D37F, 111 }, /* Counting Rod Numerals */ - { 0x1d400, 0x1d7ff, 89 }, /* Mathematical Alphanumeric Symbols */ - { 0x1F000, 0x1F02B, 122 }, /* Mahjong Tiles */ - { 0x1F030, 0x1F093, 122 }, /* Dominos */ - /*{ 0x1F0A0, 0x1F0FF, ? }, Playing Cards */ - /*{ 0x1F100, 0x1F1FF, ? }, Enclosed Alphanumeric Supplement */ - /*{ 0x1F200, 0x1F2FF, ? }, Enclosed Ideographic Supplement */ - /*{ 0x1F300, 0x1F5FF, ? }, Miscellaneous Symbols And Pictographs */ - /*{ 0x1F600, 0x1F64F, ? }, Emoticons */ - /*{ 0x1F680, 0x1F6FF, ? }, Transport And Map Symbols */ - /*{ 0x1F700, 0x1F77F, ? }, Alchemical Symbols */ - { 0x20000, 0x2a6df, 59 }, /* CJK Unified Ideographs Extension B */ - /*{ 0x2A700, 0x2B73F, 59? }, CJK Unified Ideographs Extension C */ - /*{ 0x2B740, 0x2B81F, 59? }, CJK Unified Ideographs Extension D */ - { 0x2f800, 0x2fa1f, 61 }, /* CJK Compatibility Ideographs Supplement */ - { 0xe0000, 0xe007f, 92 }, /* Tags */ - { 0xe0100, 0xe01ef, 91 }, /* Variation Selectors Supplement */ - { 0xf0000, 0xffffd, 90 }, /* Supplementary Private Use Area-A */ - { 0x100000, 0x10fffd, 90 }, /* Supplementary Private Use Area-B */ -}; - -static int32 getuint32(FILE *ttf) { - int ch1 = getc(ttf); - int ch2 = getc(ttf); - int ch3 = getc(ttf); - int ch4 = getc(ttf); - if ( ch4==EOF ) -return( EOF ); -return( (ch1<<24)|(ch2<<16)|(ch3<<8)|ch4 ); -} - -static int short_too_long_warned = 0; - -void putshort(FILE *file,int sval) { - if ( sval<-32768 || sval>65535 ) - if (!short_too_long_warned) { - IError(_("Attempt to output %d into a 16-bit field. It will be truncated and the file may not be useful."), sval ); - short_too_long_warned = 1; - } - putc((sval>>8)&0xff,file); - putc(sval&0xff,file); -} - -static void putu24(FILE *file,int val) { - putc((val>>16)&0xff,file); - putc((val>>8)&0xff,file); - putc(val&0xff,file); -} - -void putlong(FILE *file,int val) { - putc((val>>24)&0xff,file); - putc((val>>16)&0xff,file); - putc((val>>8)&0xff,file); - putc(val&0xff,file); -} -#define dumpabsoffset putlong - -static void dumpoffset(FILE *file,int offsize,int val) { - if ( offsize==1 ) - putc(val,file); - else if ( offsize==2 ) - putshort(file,val); - else if ( offsize==3 ) { - putc((val>>16)&0xff,file); - putc((val>>8)&0xff,file); - putc(val&0xff,file); - } else - putlong(file,val); -} - -static void put2d14(FILE *file,real dval) { - int val; - int mant; - - val = floor(dval); - mant = floor(16384.*(dval-val)); - val = (val<<14) | mant; - putshort(file,val); -} - -void putfixed(FILE *file,real dval) { - int val; - int mant; - - val = floor(dval); - mant = floor(65536.*(dval-val)); - val = (val<<16) | mant; - putlong(file,val); -} - -int ttfcopyfile(FILE *ttf, FILE *other, int pos, const char *tab_name) { - int ch; - int ret = 1; - - if ( ferror(ttf) || ferror(other)) { - IError("Disk error of some nature. Perhaps no space on device?\nGenerated font will be unusable" ); - } else if ( pos!=ftell(ttf)) { - IError("File Offset wrong for ttf table (%s), %d expected %d", tab_name, ftell(ttf), pos ); - } - rewind(other); - while (( ch = getc(other))!=EOF ) - putc(ch,ttf); - if ( ferror(other)) ret = 0; - if ( fclose(other)) ret = 0; -return( ret ); -} - -static void FigureFullMetricsEnd(SplineFont *sf,struct glyphinfo *gi, int istt ) { - /* We can reduce the size of the width array by removing a run at the end */ - /* of the same width. So start at the end, find the width of the last */ - /* character we'll output, then run backwards as long as we've got the */ - /* same width */ - /* (do same thing for vertical metrics too */ - int i, lasti, lastv, lastdefault = istt ? 3 : 1; - int width, vwidth; - - lasti = lastv = gi->gcnt-1; - for ( i=gi->gcnt-1; i>lastdefault && gi->bygid[i]==-1; --i ); - if ( i>=lastdefault ) { - width = sf->glyphs[gi->bygid[i]]->width; - vwidth = sf->glyphs[gi->bygid[i]]->vwidth; - lasti = lastv = i; - for ( i=lasti-1; i>=lastdefault; --i ) { - if ( SCWorthOutputting(sf->glyphs[gi->bygid[i]]) ) { - if ( sf->glyphs[gi->bygid[i]]->width!=width ) - break; - else - lasti = i; - } - } - gi->lasthwidth = lasti; - if ( sf->hasvmetrics ) { - for ( i=lastv-1; i>=lastdefault; --i ) { - if ( SCWorthOutputting(sf->glyphs[gi->bygid[i]]) ) { - if ( sf->glyphs[gi->bygid[i]]->vwidth!=vwidth ) - break; - else - lastv = i; - } - } - gi->lastvwidth = lastv; - } - } else { - gi->lasthwidth = 0; - gi->lastvwidth = 0; - } -} - -static void dumpghstruct(struct glyphinfo *gi,struct glyphhead *gh) { - - putshort(gi->glyphs,gh->numContours); - putshort(gi->glyphs,gh->xmin); - putshort(gi->glyphs,gh->ymin); - putshort(gi->glyphs,gh->xmax); - putshort(gi->glyphs,gh->ymax); - if ( gh->xmin<gi->xmin ) gi->xmin = gh->xmin; - if ( gh->ymin<gi->ymin ) gi->ymin = gh->ymin; - if ( gh->xmax>gi->xmax ) gi->xmax = gh->xmax; - if ( gh->ymax>gi->ymax ) gi->ymax = gh->ymax; -} - -static void ttfdumpmetrics(SplineChar *sc,struct glyphinfo *gi,DBounds *b) { - int width=sc->width; - int vwidth=sc->vwidth; - - if ( width<0 ) width=0; - if ( vwidth<0 ) vwidth=0; - - if ( sc->ttf_glyph<=gi->lasthwidth ) - putshort(gi->hmtx,width); - putshort(gi->hmtx,b->minx); - if ( sc->parent->hasvmetrics ) { - if ( sc->ttf_glyph<=gi->lastvwidth ) - putshort(gi->vmtx,vwidth); - putshort(gi->vmtx, sc->parent->ascent - b->maxy); - } - if ( sc->ttf_glyph==gi->lasthwidth ) - gi->hfullcnt = sc->ttf_glyph+1; - if ( sc->ttf_glyph==gi->lastvwidth ) - gi->vfullcnt = sc->ttf_glyph+1; -} - -static SplineSet *SCttfApprox(SplineChar *sc,int layer) { - SplineSet *head=NULL, *last, *ss, *tss; - RefChar *ref; - - for ( ss=sc->layers[layer].splines; ss!=NULL; ss=ss->next ) { - tss = sc->layers[layer].order2 ? SplinePointListCopy1(ss) : SSttfApprox(ss); - if ( head==NULL ) head = tss; - else last->next = tss; - last = tss; - } - for ( ref=sc->layers[layer].refs; ref!=NULL; ref=ref->next ) { - for ( ss=ref->layers[0].splines; ss!=NULL; ss=ss->next ) { - tss = sc->layers[layer].order2 ? SplinePointListCopy1(ss) : SSttfApprox(ss); - if ( head==NULL ) head = tss; - else last->next = tss; - last = tss; - } - } -return( head ); -} - -#define _On_Curve 1 -#define _X_Short 2 -#define _Y_Short 4 -#define _Repeat 8 -#define _X_Same 0x10 -#define _Y_Same 0x20 - -int SSAddPoints(SplineSet *ss,int ptcnt,BasePoint *bp, char *flags) { - SplinePoint *sp, *first, *nextsp; - int startcnt = ptcnt; - - if ( ss->first->prev!=NULL && - ss->first->prev->from->nextcpindex==startcnt ) { - if ( flags!=NULL ) flags[ptcnt] = 0; - bp[ptcnt].x = rint(ss->first->prevcp.x); - bp[ptcnt++].y = rint(ss->first->prevcp.y); - } else if ( ss->first->ttfindex!=ptcnt && ss->first->ttfindex!=0xfffe ) - IError("Unexpected point count in SSAddPoints" ); - - first = NULL; - for ( sp=ss->first; sp!=first ; ) { - if ( sp->ttfindex!=0xffff ) { - if ( flags!=NULL ) flags[ptcnt] = _On_Curve; - bp[ptcnt].x = rint(sp->me.x); - bp[ptcnt].y = rint(sp->me.y); - sp->ttfindex = ptcnt++; - } else if ( !SPInterpolate( sp ) ) { - /* If an on curve point is midway between two off curve points*/ - /* it may be omitted and will be interpolated on read in */ - if ( flags!=NULL ) flags[ptcnt] = _On_Curve; - bp[ptcnt].x = rint(sp->me.x); - bp[ptcnt].y = rint(sp->me.y); - sp->ttfindex = ptcnt++; - } - nextsp = sp->next!=NULL ? sp->next->to : NULL; - if ( sp->nextcpindex == startcnt ) - /* This control point is actually our first point, not our last */ - break; - if ( (sp->nextcpindex !=0xffff && sp->nextcpindex!=0xfffe ) || - !sp->nonextcp ) { - if ( flags!=NULL ) flags[ptcnt] = 0; - bp[ptcnt].x = rint(sp->nextcp.x); - bp[ptcnt++].y = rint(sp->nextcp.y); - } - if ( nextsp==NULL ) - break; - if ( first==NULL ) first = sp; - sp = nextsp; - } -return( ptcnt ); -} - -static void dumppointarrays(struct glyphinfo *gi,BasePoint *bp, char *fs, int pc) { - BasePoint last; - int i,flags; - int lastflag, flagcnt; - - if ( gi->maxp->maxPoints<pc ) - gi->maxp->maxPoints = pc; - - /* flags */ - last.x = last.y = 0; - lastflag = -1; flagcnt = 0; - for ( i=0; i<pc; ++i ) { - flags = 0; - if ( fs==NULL || fs[i] ) - flags = _On_Curve; /* points are on curve */ - if ( last.x==bp[i].x ) - flags |= _X_Same; - else if ( bp[i].x-last.x>-256 && bp[i].x-last.x<255 ) { - flags |= _X_Short; - if ( bp[i].x>=last.x ) - flags |= _X_Same; /* In this context it means positive */ - } - if ( last.y==bp[i].y ) - flags |= _Y_Same; - else if ( bp[i].y-last.y>-256 && bp[i].y-last.y<255 ) { - flags |= _Y_Short; - if ( bp[i].y>=last.y ) - flags |= _Y_Same; /* In this context it means positive */ - } - last = bp[i]; - if ( lastflag==-1 ) { - lastflag = flags; - flagcnt = 0; - } else if ( flags!=lastflag ) { - if ( flagcnt!=0 ) - lastflag |= _Repeat; - putc(lastflag,gi->glyphs); - if ( flagcnt!=0 ) - putc(flagcnt,gi->glyphs); - lastflag = flags; - flagcnt = 0; - } else { - if ( ++flagcnt == 255 ) { - putc(lastflag|_Repeat,gi->glyphs); - putc(255,gi->glyphs); - lastflag = -1; - flagcnt = 0; - } - } - } - if ( lastflag!=-1 ) { - if ( flagcnt!=0 ) - lastflag |= _Repeat; - putc(lastflag,gi->glyphs); - if ( flagcnt!=0 ) - putc(flagcnt,gi->glyphs); - } - - /* xcoords */ - last.x = 0; - for ( i=0; i<pc; ++i ) { - if ( last.x==bp[i].x ) - /* Do Nothing */; - else if ( bp[i].x-last.x>-256 && bp[i].x-last.x<255 ) { - if ( bp[i].x>=last.x ) - putc(bp[i].x-last.x,gi->glyphs); - else - putc(last.x-bp[i].x,gi->glyphs); - } else - putshort(gi->glyphs,bp[i].x-last.x); - last.x = bp[i].x; - } - /* ycoords */ - last.y = 0; - for ( i=0; i<pc; ++i ) { - if ( last.y==bp[i].y ) - /* Do Nothing */; - else if ( bp[i].y-last.y>-256 && bp[i].y-last.y<255 ) { - if ( bp[i].y>=last.y ) - putc(bp[i].y-last.y,gi->glyphs); - else - putc(last.y-bp[i].y,gi->glyphs); - } else - putshort(gi->glyphs,bp[i].y-last.y); - last.y = bp[i].y; - } - if ( ftell(gi->glyphs)&1 ) /* Pad the file so that the next glyph */ - putc('\0',gi->glyphs); /* on a word boundary */ -} - -static void dumpinstrs(struct glyphinfo *gi,uint8 *instrs,int cnt) { - int i; - - if ( (gi->flags&ttf_flag_nohints) ) { - putshort(gi->glyphs,0); -return; - } - /* Do we ever want to call AutoHint and AutoInst here? I think not. */ - - if ( gi->maxp->maxglyphInstr<cnt ) gi->maxp->maxglyphInstr=cnt; - putshort(gi->glyphs,cnt); - for ( i=0; i<cnt; ++i ) - putc( instrs[i],gi->glyphs ); -} - -static void dumpmissingglyph(SplineFont *sf,struct glyphinfo *gi,int fixedwidth) { - /* Or .notdef */ - struct glyphhead gh; - BasePoint bp[10]; - uint8 instrs[50]; - int stemcvt, stem; - char *stempt; - - stem = 0; - if ( sf->private!=NULL && (stempt=PSDictHasEntry(sf->private,"StdVW"))!=NULL ) - stem = strtod(stempt,NULL); - else if ( sf->private!=NULL && (stempt=PSDictHasEntry(sf->private,"StdHW"))!=NULL ) - stem = strtod(stempt,NULL); - if ( stem<=0 ) - stem = (sf->ascent+sf->descent)/30; - - gi->pointcounts[gi->next_glyph] = 8; - gi->loca[gi->next_glyph++] = ftell(gi->glyphs); - gi->maxp->maxContours = 2; - - gh.numContours = 2; - gh.ymin = 0; - gh.ymax = 2*(sf->ascent+sf->descent)/3; - gh.xmax = 5*stem+(sf->ascent+sf->descent)/10; - gh.xmin = stem; - gh.xmax += stem; - if ( gh.ymax>sf->ascent ) gh.ymax = sf->ascent; - dumpghstruct(gi,&gh); - - bp[0].x = stem; bp[0].y = 0; - bp[1].x = stem; bp[1].y = gh.ymax; - bp[2].x = gh.xmax; bp[2].y = gh.ymax; - bp[3].x = gh.xmax; bp[3].y = 0; - - bp[4].x = 2*stem; bp[4].y = stem; - bp[5].x = gh.xmax-stem; bp[5].y = stem; - bp[6].x = gh.xmax-stem; bp[6].y = gh.ymax-stem; - bp[7].x = 2*stem; bp[7].y = gh.ymax-stem; - - if ( !gi->ttc_composite_font ) { - stemcvt = TTF_getcvtval(gi->sf,stem); - - instrs[0] = 0xb1; /* Pushb, 2byte */ - instrs[1] = 1; /* Point 1 */ - instrs[2] = 0; /* Point 0 */ - instrs[3] = 0x2f; /* MDAP, rounded (pt0) */ - instrs[4] = 0x3c; /* ALIGNRP, (pt1 same pos as pt0)*/ - instrs[5] = 0xb2; /* Pushb, 3byte */ - instrs[6] = 7; /* Point 7 */ - instrs[7] = 4; /* Point 4 */ - instrs[8] = stemcvt; /* CVT entry for our stem width */ - instrs[9] = 0xe0+0x0d; /* MIRP, don't set rp0, minimum, rounded, black */ - instrs[10] = 0x32; /* SHP[rp2] (pt7 same pos as pt4) */ - instrs[11] = 0xb1; /* Pushb, 2byte */ - instrs[12] = 6; /* Point 6 */ - instrs[13] = 5; /* Point 5 */ - instrs[14] = 0xc0+0x1c; /* MDRP, set rp0, minimum, rounded, grey */ - instrs[15] = 0x3c; /* ALIGNRP, (pt6 same pos as pt5)*/ - instrs[16] = 0xb2; /* Pushb, 3byte */ - instrs[17] = 3; /* Point 3 */ - instrs[18] = 2; /* Point 2 */ - instrs[19] = stemcvt; /* CVT entry for our stem width */ - instrs[20] = 0xe0+0x0d; /* MIRP, dont set rp0, minimum, rounded, black */ - instrs[21] = 0x32; /* SHP[rp2] (pt3 same pos as pt2) */ - - instrs[22] = 0x00; /* SVTCA, y axis */ - - instrs[23] = 0xb1; /* Pushb, 2byte */ - instrs[24] = 3; /* Point 3 */ - instrs[25] = 0; /* Point 0 */ - instrs[26] = 0x2f; /* MDAP, rounded */ - instrs[27] = 0x3c; /* ALIGNRP, (pt3 same height as pt0)*/ - instrs[28] = 0xb2; /* Pushb, 3byte */ - instrs[29] = 5; /* Point 5 */ - instrs[30] = 4; /* Point 4 */ - instrs[31] = stemcvt; /* CVT entry for our stem width */ - instrs[32] = 0xe0+0x0d; /* MIRP, don't set rp0, minimum, rounded, black */ - instrs[33] = 0x32; /* SHP[rp2] (pt5 same height as pt4) */ - instrs[34] = 0xb2; /* Pushb, 3byte */ - instrs[35] = 7; /* Point 7 */ - instrs[36] = 6; /* Point 6 */ - instrs[37] = TTF_getcvtval(gi->sf,bp[6].y); /* CVT entry for top height */ - instrs[38] = 0xe0+0x1c; /* MIRP, set rp0, minimum, rounded, grey */ - instrs[39] = 0x3c; /* ALIGNRP (pt7 same height as pt6) */ - instrs[40] = 0xb2; /* Pushb, 3byte */ - instrs[41] = 1; /* Point 1 */ - instrs[42] = 2; /* Point 2 */ - instrs[43] = stemcvt; /* CVT entry for our stem width */ - instrs[44] = 0xe0+0x0d; /* MIRP, dont set rp0, minimum, rounded, black */ - instrs[45] = 0x32; /* SHP[rp2] (pt1 same height as pt2) */ - - /* We've touched all points in all dimensions */ - /* Don't need any IUP */ - } - - /* end contours array */ - putshort(gi->glyphs,4-1); - putshort(gi->glyphs,8-1); - /* instruction length&instructions */ - if ( !gi->ttc_composite_font ) - dumpinstrs(gi,instrs,46); - else - dumpinstrs(gi,NULL,0); - - dumppointarrays(gi,bp,NULL,8); - - if ( fixedwidth<=0 ) - putshort(gi->hmtx,gh.xmax + 2*stem); - else - putshort(gi->hmtx,fixedwidth); - putshort(gi->hmtx,stem); - if ( sf->hasvmetrics ) { - putshort(gi->vmtx,sf->ascent+sf->descent); - putshort(gi->vmtx,/*sf->vertical_origin-*/gh.ymax); - } -} - -static void dumpblankglyph(struct glyphinfo *gi,SplineFont *sf,int fixedwidth) { - int advance = gi->next_glyph==1?0:fixedwidth<=0?(sf->ascent+sf->descent)/3: - fixedwidth; - /* For reasons quite obscure to me, glyph 1 has an advance width of 0 */ - /* even in a mono-spaced font like CourierNew.ttf */ - - /* These don't get a glyph header, because there are no contours */ - gi->pointcounts[gi->next_glyph] = 0; - gi->loca[gi->next_glyph++] = ftell(gi->glyphs); - putshort(gi->hmtx,advance); - putshort(gi->hmtx,0); - if ( sf->hasvmetrics ) { - putshort(gi->vmtx,gi->next_glyph==2?0:(sf->ascent+sf->descent)); - putshort(gi->vmtx,0); - } -} - -static void dumpspace(SplineChar *sc, struct glyphinfo *gi) { - /* These don't get a glyph header, because there are no contours */ - DBounds b; - gi->pointcounts[gi->next_glyph] = 0; - gi->loca[gi->next_glyph++] = ftell(gi->glyphs); - memset(&b,0,sizeof(b)); - ttfdumpmetrics(sc,gi,&b); -} - -static int IsTTFRefable(SplineChar *sc,int layer) { - RefChar *ref; - - if ( sc->layers[layer].refs==NULL || sc->layers[layer].splines!=NULL ) -return( false ); - - for ( ref=sc->layers[layer].refs; ref!=NULL; ref=ref->next ) { - if ( ref->transform[0]<-2 || ref->transform[0]>1.999939 || - ref->transform[1]<-2 || ref->transform[1]>1.999939 || - ref->transform[2]<-2 || ref->transform[2]>1.999939 || - ref->transform[3]<-2 || ref->transform[3]>1.999939 ) -return( false ); - } -return( true ); -} - -int RefDepth(RefChar *ref,int layer) { - int rd, temp; - SplineChar *sc = ref->sc; - - if ( sc->layers[layer].refs==NULL || sc->layers[layer].splines!=NULL ) -return( 1 ); - rd = 0; - for ( ref = sc->layers[layer].refs; ref!=NULL; ref=ref->next ) { - if ( ref->transform[0]>=-2 || ref->transform[0]<=1.999939 || - ref->transform[1]>=-2 || ref->transform[1]<=1.999939 || - ref->transform[2]>=-2 || ref->transform[2]<=1.999939 || - ref->transform[3]>=-2 || ref->transform[3]<=1.999939 ) { - temp = RefDepth(ref,layer); - if ( temp>rd ) rd = temp; - } - } -return( rd+1 ); -} - -static void CountCompositeMaxPts(SplineChar *sc,struct glyphinfo *gi) { - RefChar *ref; - int ptcnt = 0, index; - - for ( ref=sc->layers[gi->layer].refs; ref!=NULL; ref=ref->next ) { - if ( ref->sc->ttf_glyph==-1 ) - continue; - index = ref->sc->ttf_glyph; - if ( gi->pointcounts[index]==-1 ) - CountCompositeMaxPts(ref->sc,gi); - ptcnt += gi->pointcounts[index]; - } - gi->pointcounts[sc->ttf_glyph] = ptcnt; - if ( gi->maxp->maxCompositPts<ptcnt ) gi->maxp->maxCompositPts=ptcnt; -} - -/* In order3 fonts we figure out the composite point counts at the end */ -/* when we know how many points are in each sub-glyph */ -static void RefigureCompositeMaxPts(SplineFont *sf,struct glyphinfo *gi) { - int i; - - for ( i=0; i<gi->gcnt; ++i ) if ( gi->bygid[i]!=-1 && sf->glyphs[gi->bygid[i]]->ttf_glyph!=-1 ) { - if ( sf->glyphs[gi->bygid[i]]->layers[gi->layer].splines==NULL && - sf->glyphs[gi->bygid[i]]->layers[gi->layer].refs!=NULL && - gi->pointcounts[i]== -1 ) - CountCompositeMaxPts(sf->glyphs[gi->bygid[i]],gi); - } -} - -static void dumpcomposite(SplineChar *sc, struct glyphinfo *gi) { - struct glyphhead gh; - DBounds bb; - int i, ptcnt, ctcnt, flags, sptcnt, rd; - SplineSet *ss; - RefChar *ref; - SplineChar *isc = sc->ttf_instrs==NULL && sc->parent->mm!=NULL && sc->parent->mm->apple ? - sc->parent->mm->normal->glyphs[sc->orig_pos] : sc; - int arg1, arg2; - - if ( gi->next_glyph!=sc->ttf_glyph ) - IError("Glyph count wrong in ttf output"); - if ( gi->next_glyph>=gi->maxp->numGlyphs ) - IError("max glyph count wrong in ttf output"); - gi->loca[gi->next_glyph] = ftell(gi->glyphs); - - SplineCharLayerQuickBounds(sc,gi->layer,&bb); - gh.numContours = -1; - gh.xmin = floor(bb.minx); gh.ymin = floor(bb.miny); - gh.xmax = ceil(bb.maxx); gh.ymax = ceil(bb.maxy); - dumpghstruct(gi,&gh); - - i=ptcnt=ctcnt=0; - for ( ref=sc->layers[gi->layer].refs; ref!=NULL; ref=ref->next, ++i ) { - if ( ref->sc->ttf_glyph==-1 ) { - /*if ( sc->layers[gi->layer].refs->next==NULL || any )*/ - continue; - } - flags = 0; - if ( ref->round_translation_to_grid ) - flags |= _ROUND; - if ( ref->use_my_metrics ) - flags |= _USE_MY_METRICS; - if ( ref->next!=NULL ) - flags |= _MORE; /* More components */ - else if ( isc->ttf_instrs_len!=0 ) /* Composits also inherit instructions */ - flags |= _INSTR; /* Instructions appear after last ref */ - if ( ref->transform[1]!=0 || ref->transform[2]!=0 ) - flags |= _MATRIX; /* Need a full matrix */ - else if ( ref->transform[0]!=ref->transform[3] ) - flags |= _XY_SCALE; /* different xy scales */ - else if ( ref->transform[0]!=1. ) - flags |= _SCALE; /* xy scale is same */ - if ( ref->point_match ) { - arg1 = ref->match_pt_base; - arg2 = ref->match_pt_ref; - } else { - arg1 = rint(ref->transform[4]); - arg2 = rint(ref->transform[5]); - flags |= _ARGS_ARE_XY|_UNSCALED_OFFSETS; - /* The values I output are the values I want to see */ - /* There is some very strange stuff wrongly-documented on the apple*/ - /* site about how these should be interpretted when there are */ - /* scale factors, or rotations */ - /* That description does not match the behavior of their rasterizer*/ - /* I've reverse engineered something else (see parsettf.c) */ - /* http://fonts.apple.com/TTRefMan/RM06/Chap6glyf.html */ - /* Adobe says that setting bit 12 means that this will not happen */ - /* Apple doesn't mention bit 12 though...(but they do support it) */ - } - if ( arg1<-128 || arg1>127 || - arg2<-128 || arg2>127 ) - flags |= _ARGS_ARE_WORDS; - putshort(gi->glyphs,flags); - putshort(gi->glyphs,ref->sc->ttf_glyph==-1?0:ref->sc->ttf_glyph); - if ( flags&_ARGS_ARE_WORDS ) { - putshort(gi->glyphs,(short)arg1); - putshort(gi->glyphs,(short)arg2); - } else { - putc((char) arg1,gi->glyphs); - putc((char) arg2,gi->glyphs); - } - if ( flags&_MATRIX ) { - put2d14(gi->glyphs,ref->transform[0]); - put2d14(gi->glyphs,ref->transform[1]); - put2d14(gi->glyphs,ref->transform[2]); - put2d14(gi->glyphs,ref->transform[3]); - } else if ( flags&_XY_SCALE ) { - put2d14(gi->glyphs,ref->transform[0]); - put2d14(gi->glyphs,ref->transform[3]); - } else if ( flags&_SCALE ) { - put2d14(gi->glyphs,ref->transform[0]); - } - sptcnt = SSTtfNumberPoints(ref->layers[0].splines); - for ( ss=ref->layers[0].splines; ss!=NULL ; ss=ss->next ) { - ++ctcnt; - } - if ( sc->layers[gi->layer].order2 ) - ptcnt += sptcnt; - else if ( ptcnt>=0 && gi->pointcounts[ref->sc->ttf_glyph==-1?0:ref->sc->ttf_glyph]>=0 ) - ptcnt += gi->pointcounts[ref->sc->ttf_glyph==-1?0:ref->sc->ttf_glyph]; - else - ptcnt = -1; - rd = RefDepth(ref,gi->layer); - if ( rd>gi->maxp->maxcomponentdepth ) - gi->maxp->maxcomponentdepth = rd; - } - - if ( isc->ttf_instrs_len!=0 ) - dumpinstrs(gi,isc->ttf_instrs,isc->ttf_instrs_len); - - gi->pointcounts[gi->next_glyph++] = ptcnt; - if ( gi->maxp->maxnumcomponents<i ) gi->maxp->maxnumcomponents = i; - if ( gi->maxp->maxCompositPts<ptcnt ) gi->maxp->maxCompositPts=ptcnt; - if ( gi->maxp->maxCompositCtrs<ctcnt ) gi->maxp->maxCompositCtrs=ctcnt; - - ttfdumpmetrics(sc,gi,&bb); - if ( ftell(gi->glyphs)&1 ) /* Pad the file so that the next glyph */ - putc('\0',gi->glyphs); /* on a word boundary, can only happen if odd number of instrs */ -} - -static void dumpglyph(SplineChar *sc, struct glyphinfo *gi) { - struct glyphhead gh; - DBounds bb; - SplineSet *ss, *ttfss; - int contourcnt, ptcnt, origptcnt; - BasePoint *bp; - char *fs; - SplineChar *isc = sc->ttf_instrs==NULL && sc->parent->mm!=NULL && sc->parent->mm->apple ? - sc->parent->mm->normal->glyphs[sc->orig_pos] : sc; - - /* This must have been an error on my part, can't just remove points */ - /* they might be matched to anchors or something */ -/* I haven't seen this documented, but ttf rasterizers are unhappy with a */ -/* glyph that consists of a single point. Glyphs containing two single points*/ -/* are ok, glyphs with a single point and anything else are ok, glyphs with */ -/* a line are ok. But a single point is not ok. Dunno why */ - if ( sc->layers[gi->layer].splines==NULL && sc->layers[gi->layer].refs==NULL ) { - dumpspace(sc,gi); -return; - } - - if ( gi->next_glyph!=sc->ttf_glyph ) - IError("Glyph count wrong in ttf output"); - if ( gi->next_glyph>=gi->maxp->numGlyphs ) - IError("max glyph count wrong in ttf output"); - gi->loca[gi->next_glyph] = ftell(gi->glyphs); - - ttfss = SCttfApprox(sc,gi->layer); - ptcnt = SSTtfNumberPoints(ttfss); - for ( ss=ttfss, contourcnt=0; ss!=NULL; ss=ss->next ) { - ++contourcnt; - } - origptcnt = ptcnt; - - SplineSetQuickBounds(ttfss,&bb); - gh.numContours = contourcnt; - gh.xmin = floor(bb.minx); gh.ymin = floor(bb.miny); - gh.xmax = ceil(bb.maxx); gh.ymax = ceil(bb.maxy); - dumpghstruct(gi,&gh); - if ( contourcnt>gi->maxp->maxContours ) gi->maxp->maxContours = contourcnt; - if ( ptcnt>gi->maxp->maxPoints ) gi->maxp->maxPoints = ptcnt; - - bp = malloc(ptcnt*sizeof(BasePoint)); - fs = malloc(ptcnt); - ptcnt = contourcnt = 0; - for ( ss=ttfss; ss!=NULL; ss=ss->next ) { - ptcnt = SSAddPoints(ss,ptcnt,bp,fs); - putshort(gi->glyphs,ptcnt-1); - } - if ( ptcnt!=origptcnt ) - IError( "Point count wrong calculated=%d, actual=%d in %.20s", origptcnt, ptcnt, sc->name ); - gi->pointcounts[gi->next_glyph++] = ptcnt; - - dumpinstrs(gi,isc->ttf_instrs,isc->ttf_instrs_len); - - dumppointarrays(gi,bp,fs,ptcnt); - SplinePointListsFree(ttfss); - free(bp); - free(fs); - - ttfdumpmetrics(sc,gi,&bb); -} - -void SFDummyUpCIDs(struct glyphinfo *gi,SplineFont *sf) { - int i,j,k,max; - int *bygid; - - max = 0; - for ( k=0; k<sf->subfontcnt; ++k ) - if ( sf->subfonts[k]->glyphcnt>max ) max = sf->subfonts[k]->glyphcnt; - if ( max == 0 ) -return; - - sf->glyphs = calloc(max,sizeof(SplineChar *)); - sf->glyphcnt = sf->glyphmax = max; - for ( k=0; k<sf->subfontcnt; ++k ) - for ( i=0; i<sf->subfonts[k]->glyphcnt; ++i ) if ( sf->subfonts[k]->glyphs[i]!=NULL ) - sf->glyphs[i] = sf->subfonts[k]->glyphs[i]; - - if ( gi==NULL ) -return; - - bygid = malloc((sf->glyphcnt+3)*sizeof(int)); - memset(bygid,0xff, (sf->glyphcnt+3)*sizeof(int)); - - j=1; - for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) { - if ( bygid[0]== -1 && strcmp(sf->glyphs[i]->name,".notdef")==0 ) { - sf->glyphs[i]->ttf_glyph = 0; - bygid[0] = i; - } else if ( SCWorthOutputting(sf->glyphs[i])) { - sf->glyphs[i]->ttf_glyph = j; - bygid[j++] = i; - } - } - gi->bygid = bygid; - gi->gcnt = j; -} - -static void AssignNotdefNull(SplineFont *sf,int *bygid, int iscff) { - int i; - - /* The first three glyphs are magic, glyph 0 is .notdef */ - /* glyph 1 is .null and glyph 2 is nonmarking return */ - /* We may generate them automagically */ - for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) { - if ( bygid[0]== -1 && strcmp(sf->glyphs[i]->name,".notdef")==0 ) { - sf->glyphs[i]->ttf_glyph = 0; - bygid[0] = i; - } else if ( !iscff && bygid[1]== -1 && - (strcmp(sf->glyphs[i]->name,".null")==0 || - strcmp(sf->glyphs[i]->name,"uni0000")==0 || - (i==1 && strcmp(sf->glyphs[1]->name,"glyph1")==0)) ) { - sf->glyphs[i]->ttf_glyph = 1; - bygid[1] = i; - } else if ( !iscff && bygid[2]== -1 && - (strcmp(sf->glyphs[i]->name,"nonmarkingreturn")==0 || - strcmp(sf->glyphs[i]->name,"uni000D")==0 || - (i==2 && strcmp(sf->glyphs[2]->name,"glyph2")==0)) ) { - sf->glyphs[i]->ttf_glyph = 2; - bygid[2] = i; - } - } -} - -static int AssignTTFGlyph(struct glyphinfo *gi,SplineFont *sf,EncMap *map,int iscff) { - int *bygid = malloc((sf->glyphcnt+3)*sizeof(int)); - int i,j; - - memset(bygid,0xff, (sf->glyphcnt+3)*sizeof(int)); - - AssignNotdefNull(sf,bygid,iscff); - - j = iscff ? 1 : 3; - for ( i=0; i<map->enccount; ++i ) if ( map->map[i]!=-1 ) { - SplineChar *sc = sf->glyphs[map->map[i]]; - if ( SCWorthOutputting(sc) && sc->ttf_glyph==-1 -#if HANYANG - && (!iscff || !sc->compositionunit) -#endif - ) { - sc->ttf_glyph = j; - bygid[j++] = sc->orig_pos; - } - } - - for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) { - SplineChar *sc = sf->glyphs[i]; - if ( SCWorthOutputting(sc) && sc->ttf_glyph==-1 -#if HANYANG - && (!iscff || !sc->compositionunit) -#endif - ) { - sc->ttf_glyph = j; - bygid[j++] = i; - } - } - gi->bygid = bygid; - gi->gcnt = j; -return j; -} - -static int dumpglyphs(SplineFont *sf,struct glyphinfo *gi) { - int i; - int fixed = gi->fixed_width; - - ff_progress_change_stages(2+gi->strikecnt); - QuickBlues(sf,gi->layer,&gi->bd); - /*FindBlues(sf,gi->blues,NULL);*/ - ff_progress_next_stage(); - - if ( !gi->onlybitmaps ) { - if ( sf->layers[gi->layer].order2 ) - for ( i=0; i<sf->glyphcnt; ++i ) { - SplineChar *sc = sf->glyphs[i]; - if ( SCWorthOutputting(sc) ) - if ( !SCPointsNumberedProperly(sc,gi->layer)) { - free(sc->ttf_instrs); sc->ttf_instrs = NULL; - sc->ttf_instrs_len = 0; - SCNumberPoints(sc,gi->layer); - } - } - } - - gi->maxp->numGlyphs = gi->gcnt; - gi->loca = malloc((gi->maxp->numGlyphs+1)*sizeof(uint32)); - gi->pointcounts = malloc((gi->maxp->numGlyphs+1)*sizeof(int32)); - memset(gi->pointcounts,-1,(gi->maxp->numGlyphs+1)*sizeof(int32)); - gi->next_glyph = 0; - gi->glyphs = tmpfile2(); - gi->hmtx = tmpfile2(); - if ( sf->hasvmetrics ) - gi->vmtx = tmpfile2(); - FigureFullMetricsEnd(sf,gi,true); - - if ( fixed>0 ) { - gi->lasthwidth = 3; - gi->hfullcnt = 3; - } - for ( i=0; i<gi->gcnt; ++i ) { - if ( i==0 ) { - if ( gi->bygid[0]!=-1 && (fixed<=0 || sf->glyphs[gi->bygid[0]]->width==fixed)) - dumpglyph(sf->glyphs[gi->bygid[0]],gi); - else - dumpmissingglyph(sf,gi,fixed); - } else if ( i<=2 && gi->bygid[i]==-1 ) - dumpblankglyph(gi,sf,fixed); - else if ( gi->onlybitmaps ) { - if ( gi->bygid[i]!=-1 && sf->glyphs[gi->bygid[i]]->ttf_glyph>0 ) - dumpspace(sf->glyphs[gi->bygid[i]],gi); - } else { - if ( gi->bygid[i]!=-1 && sf->glyphs[gi->bygid[i]]->ttf_glyph>0 ) { - if ( IsTTFRefable(sf->glyphs[gi->bygid[i]],gi->layer) ) - dumpcomposite(sf->glyphs[gi->bygid[i]],gi); - else - dumpglyph(sf->glyphs[gi->bygid[i]],gi); - } - } - if ( (ftell(gi->glyphs)&3) != 0 ) { - /* Apple says glyphs must be 16bit aligned */ - if ( ftell(gi->glyphs)&1 ) - putc('\0',gi->glyphs); - /* MS says glyphs should be 32bit aligned */ - if ( ftell(gi->glyphs)&2 ) - putshort(gi->glyphs,0); - } - if ( !ff_progress_next()) -return( false ); - } - - /* extra location entry points to end of last glyph */ - gi->loca[gi->next_glyph] = ftell(gi->glyphs); - /* Microsoft's Font Validator wants the last loca entry to point into the */ - /* glyph table. I think that's an error on their part, but it's so easy */ - /* to fix, I might as well (instead of pointing to right after the table)*/ - /* Sigh. But if I do that, it complains that there's extra stuff in the */ - /* glyph table. There's just no pleasing them */ - /* putlong(gi->glyphs,0);*/ - gi->glyph_len = ftell(gi->glyphs); - gi->hmtxlen = ftell(gi->hmtx); - /* pad out to four bytes */ - if ( gi->hmtxlen&2 ) putshort(gi->hmtx,0); - if ( gi->loca[gi->next_glyph]&3 ) { - for ( i=4-(gi->loca[gi->next_glyph]&3); i>0; --i ) - putc('\0',gi->glyphs); - } - if ( sf->hasvmetrics ) { - gi->vmtxlen = ftell(gi->vmtx); - if ( gi->vmtxlen&2 ) putshort(gi->vmtx,0); - } - if ( !sf->layers[gi->layer].order2 ) - RefigureCompositeMaxPts(sf,gi); - free(gi->pointcounts); - -return( true ); -} - -static int storesid(struct alltabs *at,const char *str) { - int i; - FILE *news; - const char *pt; - long pos; - - if ( str!=NULL ) { /* NULL is the magic string at end of array */ - for ( i=0; cffnames[i]!=NULL; ++i ) { - if ( strcmp(cffnames[i],str)==0 ) -return( i ); - } - } - - pos = ftell(at->sidf)+1; - if ( pos>=65536 && !at->sidlongoffset ) { - at->sidlongoffset = true; - news = tmpfile2(); - rewind(at->sidh); - for ( i=0; i<at->sidcnt; ++i ) - putlong(news,getushort(at->sidh)); - fclose(at->sidh); - at->sidh = news; - } - if ( at->sidlongoffset ) - putlong(at->sidh,pos); - else - putshort(at->sidh,pos); - - if ( str!=NULL ) { - for ( pt=str; *pt; ++pt ) - putc(*pt,at->sidf); - } -return( at->sidcnt++ + nStdStrings ); -} - -static void dumpint(FILE *cfff,int num) { - - if ( num>=-107 && num<=107 ) - putc(num+139,cfff); - else if ( num>=108 && num<=1131 ) { - num -= 108; - putc((num>>8)+247,cfff); - putc(num&0xff,cfff); - } else if ( num>=-1131 && num<=-108 ) { - num = -num; - num -= 108; - putc((num>>8)+251,cfff); - putc(num&0xff,cfff); - } else if ( num>=-32768 && num<32768 ) { - putc(28,cfff); - putc(num>>8,cfff); - putc(num&0xff,cfff); - } else { /* In dict data we have 4 byte ints, in type2 strings we don't */ - putc(29,cfff); - putc((num>>24)&0xff,cfff); - putc((num>>16)&0xff,cfff); - putc((num>>8)&0xff,cfff); - putc(num&0xff,cfff); - } -} - -static void dumpdbl(FILE *cfff,double d) { - if ( d-rint(d)>-.00001 && d-rint(d)<.00001 ) - dumpint(cfff,(int) d); - else { - /* The type2 strings have a fixed format, but the dict data does not */ - char buffer[20], *pt; - int sofar,n,odd; - sprintf( buffer, "%g", d); - sofar = 0; odd=true; - putc(30,cfff); /* Start a double */ - for ( pt=buffer; *pt; ++pt ) { - if ( isdigit(*pt) ) - n = *pt-'0'; - else if ( *pt=='.' ) - n = 0xa; - else if ( *pt=='-' ) - n = 0xe; - else if (( *pt=='E' || *pt=='e') && pt[1]=='-' ) { - n = 0xc; - ++pt; - } else if ( *pt=='E' || *pt=='e') - n = 0xb; - else - n = 0; /* Should never happen */ - if ( odd ) { - sofar = n<<4; - odd = false; - } else { - putc(sofar|n,cfff); - sofar=0; - odd = true; - } - } - if ( sofar==0 ) - putc(0xff,cfff); - else - putc(sofar|0xf,cfff); - } -} - -static void dumpoper(FILE *cfff,int oper ) { - if ( oper!=-1 ) { - if ( oper>=256 ) - putc(oper>>8,cfff); - putc(oper&0xff,cfff); - } -} - -static void dumpdbloper(FILE *cfff,double d, int oper ) { - dumpdbl(cfff,d); - dumpoper(cfff,oper); -} - -static void dumpintoper(FILE *cfff,int v, int oper ) { - dumpint(cfff,v); - dumpoper(cfff,oper); -} - -static void dumpsizedint(FILE *cfff,int big,int num, int oper ) { - if ( big ) { - putc(29,cfff); - putc((num>>24)&0xff,cfff); - putc((num>>16)&0xff,cfff); - putc((num>>8)&0xff,cfff); - putc(num&0xff,cfff); - } else { - putc(28,cfff); - putc(num>>8,cfff); - putc(num&0xff,cfff); - } - dumpoper(cfff,oper); -} - -static void dumpsid(FILE *cfff,struct alltabs *at,char *str,int oper) { - if ( str==NULL ) -return; - dumpint(cfff,storesid(at,str)); - dumpoper(cfff,oper); -} - -static void DumpStrDouble(char *pt,FILE *cfff,int oper) { - real d; - if ( *pt=='[' ) ++pt; /* For StdHW, StdVW */ - d = strtod(pt,NULL); - dumpdbloper(cfff,d,oper); -} - -static void DumpDblArray(real *arr,int n,FILE *cfff, int oper) { - int mi,i; - - for ( mi=n-1; mi>=0 && arr[mi]==0; --mi ); - if ( mi<0 ) -return; - dumpdbl(cfff,arr[0]); - for ( i=1; i<=mi; ++i ) - dumpdbl(cfff,arr[i]-arr[i-1]); - dumpoper(cfff,oper); -} - -static void DumpStrArray(char *pt,FILE *cfff,int oper) { - real d, last=0; - char *end; - - while ( *pt==' ' ) ++pt; - if ( *pt=='\0' ) -return; - if ( *pt=='[' ) ++pt; - while ( *pt==' ' ) ++pt; - while ( *pt!=']' && *pt!='\0' ) { - d = strtod(pt,&end); - if ( pt==end ) /* User screwed up. Should be a number */ - break; - dumpdbl(cfff,d-last); - last = d; - pt = end; - while ( *pt==' ' ) ++pt; - } - dumpoper(cfff,oper); -} - -static void dumpcffheader(FILE *cfff) { - putc('\1',cfff); /* Major version: 1 */ - putc('\0',cfff); /* Minor version: 0 */ - putc('\4',cfff); /* Header size in bytes */ - putc('\4',cfff); /* Absolute Offset size. */ - /* I don't think there are any absolute offsets that aren't encoded */ - /* in a dict as numbers (ie. inherently variable sized items) */ -} - -static void dumpcffnames(SplineFont *sf,FILE *cfff) { - char *pt; - - putshort(cfff,1); /* One font name */ - putc('\1',cfff); /* Offset size */ - putc('\1',cfff); /* Offset to first name */ - putc('\1'+strlen(sf->fontname),cfff); - for ( pt=sf->fontname; *pt; ++pt ) - putc(*pt,cfff); -} - -static void dumpcffcharset(SplineFont *sf,struct alltabs *at) { - int i; - - at->gn_sid = calloc(at->gi.gcnt,sizeof(uint32)); - putc(0,at->charset); - /* I always use a format 0 charset. ie. an array of SIDs in random order */ - - /* First element must be ".notdef" and is omitted */ - - for ( i=1; i<at->gi.gcnt; ++i ) - if ( at->gi.bygid[i]!=-1 && SCWorthOutputting(sf->glyphs[at->gi.bygid[i]])) { - at->gn_sid[i] = storesid(at,sf->glyphs[at->gi.bygid[i]]->name); - putshort(at->charset,at->gn_sid[i]); - } -} - -static void dumpcffcidset(struct alltabs *at) { - int gid, start; - - putc(2,at->charset); - - start = -1; /* Glyph 0 always maps to CID 0, and is omitted */ - for ( gid = 1; gid<at->gi.gcnt; ++gid ) { - if ( start==-1 ) - start = gid; - else if ( at->gi.bygid[gid]-at->gi.bygid[start]!=gid-start ) { - putshort(at->charset,at->gi.bygid[start]); - putshort(at->charset,at->gi.bygid[gid-1]-at->gi.bygid[start]); - start = gid; - } - } - if ( start!=-1 ) { - putshort(at->charset,at->gi.bygid[start]); - putshort(at->charset,at->gi.bygid[gid-1]-at->gi.bygid[start]); - } -} - -static void dumpcfffdselect(SplineFont *sf,struct alltabs *at) { - int cid, k, lastfd, cnt; - int gid; - - putc(3,at->fdselect); - putshort(at->fdselect,0); /* number of ranges, fill in later */ - - for ( k=0; k<sf->subfontcnt; ++k ) - if ( SCWorthOutputting(sf->subfonts[k]->glyphs[0])) - break; - if ( k==sf->subfontcnt ) --k; /* If CID 0 not defined, put it in last font */ - putshort(at->fdselect,0); - putc(k,at->fdselect); - lastfd = k; - cnt = 1; - for ( gid = 1; gid<at->gi.gcnt; ++gid ) { - cid = at->gi.bygid[gid]; - for ( k=0; k<sf->subfontcnt; ++k ) { - if ( cid<sf->subfonts[k]->glyphcnt && - SCWorthOutputting(sf->subfonts[k]->glyphs[cid]) ) - break; - } - if ( k==sf->subfontcnt ) - /* Doesn't map to a glyph, irrelevant */; - else { - if ( k!=lastfd ) { - putshort(at->fdselect,gid); - putc(k,at->fdselect); - lastfd = k; - ++cnt; - } - } - } - putshort(at->fdselect,gid); - fseek(at->fdselect,1,SEEK_SET); - putshort(at->fdselect,cnt); - fseek(at->fdselect,0,SEEK_END); -} - -static void dumpcffencoding(SplineFont *sf,struct alltabs *at) { - int i, cnt, anydups; - uint32 start_pos = ftell(at->encoding); - SplineChar *sc; - EncMap *map = at->map; - - putc(0,at->encoding); - /* I always use a format 0 encoding. ie. an array of glyph indexes */ - putc(0xff,at->encoding); /* fixup later */ - - for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) - sf->glyphs[i]->ticked = false; - - cnt = 0; - anydups = 0; - for ( i=0; i<256 && i<map->enccount; ++i ) if ( map->map[i]!=-1 && (sc=sf->glyphs[map->map[i]])!=NULL ) { - if ( sc->ttf_glyph>255 ) - continue; - if ( sc->ticked ) { - ++anydups; - } else if ( sc->ttf_glyph>0 ) { - if ( cnt>=255 ) - break; - putc(i,at->encoding); - ++cnt; - sc->ticked = true; - } - } - if ( anydups ) { - fseek(at->encoding,start_pos,SEEK_SET); - putc(0x80,at->encoding); - putc(cnt,at->encoding); - fseek(at->encoding,0,SEEK_END); - putc(anydups,at->encoding); - - for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) - sf->glyphs[i]->ticked = false; - for ( i=0; i<256 && i<map->enccount; ++i ) if ( map->map[i]!=-1 && (sc=sf->glyphs[map->map[i]])!=NULL ) { - if ( sc->ttf_glyph>255 ) - continue; - if ( sc->ticked ) { - putc(i,at->encoding); - putshort(at->encoding,at->gn_sid[sc->ttf_glyph]); - } - sc->ticked = true; - } - } else { - fseek(at->encoding,start_pos+1,SEEK_SET); - putc(cnt,at->encoding); - fseek(at->encoding,0,SEEK_END); - } - free( at->gn_sid ); - at->gn_sid = NULL; -} - -static void _dumpcffstrings(FILE *file, struct pschars *strs) { - int i, len, offsize; - - /* First figure out the offset size */ - len = 1; - for ( i=0; i<strs->next; ++i ) - len += strs->lens[i]; - - /* Then output the index size and offsets */ - putshort( file, strs->next ); - if ( strs->next!=0 ) { - /* presumably offsets are unsigned. But the docs don't state this in the obvious place */ - offsize = len<=255?1:len<=65535?2:len<=0xffffff?3:4; - putc(offsize,file); - len = 1; - for ( i=0; i<strs->next; ++i ) { - dumpoffset(file,offsize,len); - len += strs->lens[i]; - } - dumpoffset(file,offsize,len); - - /* last of all the strings */ - for ( i=0; i<strs->next; ++i ) { - uint8 *pt = strs->values[i], *end = pt+strs->lens[i]; - while ( pt<end ) { - putc( *pt++, file ); - } - } - } -} - -static FILE *dumpcffstrings(struct pschars *strs) { - FILE *file = tmpfile2(); - _dumpcffstrings(file,strs); - PSCharsFree(strs); -return( file ); -} - -int SFFigureDefWidth(SplineFont *sf, int *_nomwid) { - uint16 *widths; uint32 *cumwid; - int nomwid, defwid, i, j, sameval=(int) 0x80000000, maxw=0, allsame=true; - unsigned cnt; - - for ( i=0; i<sf->glyphcnt; ++i ) - if ( SCWorthOutputting(sf->glyphs[i]) ) { - if ( maxw<sf->glyphs[i]->width ) maxw = sf->glyphs[i]->width; - if ( sameval == 0x8000000 ) - sameval = sf->glyphs[i]->width; - else if ( sameval!=sf->glyphs[i]->width ) - allsame = false; - } - if ( allsame ) { - nomwid = defwid = sameval; - } else { - ++maxw; - if ( maxw>65535 ) maxw = 3*(sf->ascent+sf->descent); - widths = calloc(maxw,sizeof(uint16)); - cumwid = calloc(maxw,sizeof(uint32)); - defwid = 0; cnt=0; - for ( i=0; i<sf->glyphcnt; ++i ) - if ( SCWorthOutputting(sf->glyphs[i]) && - sf->glyphs[i]->width>=0 && - sf->glyphs[i]->width<maxw ) - if ( ++widths[sf->glyphs[i]->width] > cnt ) { - defwid = sf->glyphs[i]->width; - cnt = widths[defwid]; - } - widths[defwid] = 0; - for ( i=0; i<maxw; ++i ) - for ( j=-107; j<=107; ++j ) - if ( i+j>=0 && i+j<maxw ) - cumwid[i] += widths[i+j]; - cnt = 0; nomwid = 0; - for ( i=0; i<maxw; ++i ) - if ( cnt<cumwid[i] ) { - cnt = cumwid[i]; - nomwid = i; - } - free(widths); free(cumwid); - } - if ( _nomwid!=NULL ) - *_nomwid = nomwid; -return( defwid ); -} - -static void ATFigureDefWidth(SplineFont *sf, struct alltabs *at, int subfont) { - int nomwid, defwid; - - defwid = SFFigureDefWidth(sf,&nomwid); - if ( subfont==-1 ) - at->defwid = defwid; - else - at->fds[subfont].defwid = defwid; - if ( subfont==-1 ) - at->nomwid = nomwid; - else - at->fds[subfont].nomwid = nomwid; -} - -static void dumpcffprivate(SplineFont *sf,struct alltabs *at,int subfont, - int subrcnt) { - char *pt; - FILE *private = subfont==-1?at->private:at->fds[subfont].private; - int mi,i; - real bluevalues[14], otherblues[10]; - real snapcnt[12]; - real stemsnaph[12], stemsnapv[12]; - real stdhw[1], stdvw[1]; - int hasblue=0, hash=0, hasv=0, bs; - int nomwid, defwid; - EncMap *map = at->map; - double bluescale; - - /* The private dict is not in an index, so no index header. Just the data */ - - if ( subfont==-1 ) - defwid = at->defwid; - else - defwid = at->fds[subfont].defwid; - dumpintoper(private,defwid,20); /* Default Width */ - if ( subfont==-1 ) - nomwid = at->nomwid; - else - nomwid = at->fds[subfont].nomwid; - dumpintoper(private,nomwid,21); /* Nominative Width */ - - bs = SplineFontIsFlexible(sf,at->gi.layer,at->gi.flags); - hasblue = PSDictHasEntry(sf->private,"BlueValues")!=NULL; - hash = PSDictHasEntry(sf->private,"StdHW")!=NULL; - hasv = PSDictHasEntry(sf->private,"StdVW")!=NULL; - ff_progress_change_stages(2+autohint_before_generate+!hasblue); - if ( autohint_before_generate ) { - ff_progress_change_line1(_("Auto Hinting Font...")); - SplineFontAutoHint(sf,at->gi.layer); - ff_progress_next_stage(); - } - - otherblues[0] = otherblues[1] = bluevalues[0] = bluevalues[1] = 0; - if ( !hasblue ) { - FindBlues(sf,at->gi.layer,bluevalues,otherblues); - ff_progress_next_stage(); - } - - stdhw[0] = stdvw[0] = 0; - if ( !hash ) { - FindHStems(sf,stemsnaph,snapcnt); - mi = -1; - for ( i=0; i<12 && stemsnaph[i]!=0; ++i ) - if ( mi==-1 ) mi = i; - else if ( snapcnt[i]>snapcnt[mi] ) mi = i; - if ( mi!=-1 ) stdhw[0] = stemsnaph[mi]; - } - - if ( !hasv ) { - FindVStems(sf,stemsnapv,snapcnt); - mi = -1; - for ( i=0; i<12 && stemsnapv[i]!=0; ++i ) - if ( mi==-1 ) mi = i; - else if ( snapcnt[i]>snapcnt[mi] ) mi = i; - if ( mi!=-1 ) stdvw[0] = stemsnapv[mi]; - } - ff_progress_change_line1(_("Saving OpenType Font")); - - if ( hasblue ) - DumpStrArray(PSDictHasEntry(sf->private,"BlueValues"),private,6); - else - DumpDblArray(bluevalues,sizeof(bluevalues)/sizeof(bluevalues[0]),private,6); - if ( (pt=PSDictHasEntry(sf->private,"OtherBlues"))!=NULL ) - DumpStrArray(pt,private,7); - else if ( !hasblue ) - DumpDblArray(otherblues,sizeof(otherblues)/sizeof(otherblues[0]),private,7); - if ( (pt=PSDictHasEntry(sf->private,"FamilyBlues"))!=NULL ) - DumpStrArray(pt,private,8); - bluescale = BlueScaleFigure(sf->private,bluevalues,otherblues); - if ( (pt=PSDictHasEntry(sf->private,"FamilyOtherBlues"))!=NULL ) - DumpStrArray(pt,private,9); - if ( (pt=PSDictHasEntry(sf->private,"BlueScale"))!=NULL ) - DumpStrDouble(pt,private,(12<<8)+9); - else if ( bluescale!=-1 ) - dumpdbloper(private,bluescale,(12<<8)+9); - if ( (pt=PSDictHasEntry(sf->private,"BlueShift"))!=NULL ) - DumpStrDouble(pt,private,(12<<8)+10); - else - dumpintoper(private,bs,(12<<8)+10); - if ( (pt=PSDictHasEntry(sf->private,"BlueFuzz"))!=NULL ) - DumpStrDouble(pt,private,(12<<8)+11); - if ( hash ) { - DumpStrDouble(PSDictHasEntry(sf->private,"StdHW"),private,10); - if ( (pt=PSDictHasEntry(sf->private,"StemSnapH"))!=NULL ) - DumpStrArray(pt,private,(12<<8)|12); - } else { - if ( stdhw[0]!=0 ) - dumpdbloper(private,stdhw[0],10); - DumpDblArray(stemsnaph,sizeof(stemsnaph)/sizeof(stemsnaph[0]),private,(12<<8)|12); - } - if ( hasv ) { - DumpStrDouble(PSDictHasEntry(sf->private,"StdVW"),private,11); - if ( (pt=PSDictHasEntry(sf->private,"StemSnapV"))!=NULL ) - DumpStrArray(pt,private,(12<<8)|13); - } else { - if ( stdvw[0]!=0 ) - dumpdbloper(private,stdvw[0],11); - DumpDblArray(stemsnapv,sizeof(stemsnapv)/sizeof(stemsnapv[0]),private,(12<<8)|13); - } - if ( (pt=PSDictHasEntry(sf->private,"ForceBold"))!=NULL ) { - dumpintoper(private,*pt=='t'||*pt=='T',(12<<8)|14); - } else if ( sf->weight!=NULL && - (strstrmatch(sf->weight,"Bold")!=NULL || - strstrmatch(sf->weight,"Demi")!=NULL || - strstrmatch(sf->weight,"Fett")!=NULL || - strstrmatch(sf->weight,"Gras")!=NULL || - strstrmatch(sf->weight,"Heavy")!=NULL || - strstrmatch(sf->weight,"Black")!=NULL)) - dumpintoper(private,1,(12<<8)|14); - if ( (pt=PSDictHasEntry(sf->private,"LanguageGroup"))!=NULL ) - DumpStrDouble(pt,private,(12<<8)+17); - else if ( map==NULL ) - /* Do Nothing */; - else if ( map->enc->is_japanese || - map->enc->is_korean || - map->enc->is_tradchinese || - map->enc->is_simplechinese ) - dumpintoper(private,1,(12<<8)|17); - if ( (pt=PSDictHasEntry(sf->private,"ExpansionFactor"))!=NULL ) - DumpStrDouble(pt,private,(12<<8)+18); - if ( subrcnt!=0 ) - dumpsizedint(private,false,ftell(private)+3+1,19); /* Subrs */ - - if ( subfont==-1 ) - at->privatelen = ftell(private); - else - at->fds[subfont].privatelen = ftell(private); -} - -/* When we exit this the topdict is not complete, we still need to fill in */ -/* values for charset,encoding,charstrings and private. Then we need to go */ -/* back and fill in the table length (at lenpos) */ -static void dumpcfftopdict(SplineFont *sf,struct alltabs *at) { - char *pt, *end; - FILE *cfff = at->cfff; - DBounds b; - - putshort(cfff,1); /* One top dict */ - putc('\2',cfff); /* Offset size */ - putshort(cfff,1); /* Offset to topdict */ - at->lenpos = ftell(cfff); - putshort(cfff,0); /* placeholder for final position (final offset in index points beyond last element) */ - dumpsid(cfff,at,sf->version,0); - dumpsid(cfff,at,sf->copyright,1); - dumpsid(cfff,at,sf->fullname?sf->fullname:sf->fontname,2); - dumpsid(cfff,at,sf->familyname,3); - dumpsid(cfff,at,sf->weight,4); - if ( at->gi.fixed_width>0 ) dumpintoper(cfff,1,(12<<8)|1); - if ( sf->italicangle!=0 ) dumpdbloper(cfff,sf->italicangle,(12<<8)|2); - if ( sf->upos!=-100 ) dumpdbloper(cfff,sf->upos,(12<<8)|3); - if ( sf->uwidth!=50 ) dumpdbloper(cfff,sf->uwidth,(12<<8)|4); - if ( sf->strokedfont ) { - dumpintoper(cfff,2,(12<<8)|5); - dumpdbloper(cfff,sf->strokewidth,(12<<8)|8); - } - /* We'll never set CharstringType */ - if ( sf->ascent+sf->descent!=1000 ) { - dumpdbl(cfff,1.0/(sf->ascent+sf->descent)); - dumpint(cfff,0); - dumpint(cfff,0); - dumpdbl(cfff,1.0/(sf->ascent+sf->descent)); - dumpint(cfff,0); - dumpintoper(cfff,0,(12<<8)|7); - } - if ( sf->uniqueid!=-1 && sf->use_uniqueid ) - dumpintoper(cfff, sf->uniqueid?sf->uniqueid:4000000 + (rand()&0x3ffff), 13 ); - SplineFontLayerFindBounds(sf,at->gi.layer,&b); - at->gi.xmin = b.minx; - at->gi.ymin = b.miny; - at->gi.xmax = b.maxx; - at->gi.ymax = b.maxy; - dumpdbl(cfff,floor(b.minx)); - dumpdbl(cfff,floor(b.miny)); - dumpdbl(cfff,ceil(b.maxx)); - dumpdbloper(cfff,ceil(b.maxy),5); - /* We'll never set StrokeWidth */ - if ( sf->xuid!=NULL && sf->use_xuid ) { - pt = sf->xuid; if ( *pt=='[' ) ++pt; - while ( *pt && *pt!=']' ) { - dumpint(cfff,strtol(pt,&end,10)); - if ( pt==end ) /* garbage in XUID */ - break; - for ( pt = end; *pt==' '; ++pt ); - } - putc(14,cfff); - if ( sf->changed_since_xuidchanged ) - SFIncrementXUID(sf); - } - /* Offset to charset (oper=15) needed here */ - /* Offset to encoding (oper=16) needed here (not for CID )*/ - /* Offset to charstrings (oper=17) needed here */ - /* Length of, and Offset to private (oper=18) needed here (not for CID )*/ -} - -static int dumpcffdict(SplineFont *sf,struct alltabs *at) { - FILE *fdarray = at->fdarray; - int pstart; - /* according to the PSRef Man v3, only fontname, fontmatrix and private */ - /* appear in this dictionary */ - - dumpsid(fdarray,at,sf->fontname,(12<<8)|38); - if ( sf->ascent+sf->descent!=1000 ) { - dumpdbl(fdarray,1.0/(sf->ascent+sf->descent)); - dumpint(fdarray,0); - dumpint(fdarray,0); - dumpdbl(fdarray,1.0/(sf->ascent+sf->descent)); - dumpint(fdarray,0); - dumpintoper(fdarray,0,(12<<8)|7); - } - pstart = ftell(fdarray); - dumpsizedint(fdarray,false,0,-1); /* private length */ - dumpsizedint(fdarray,true,0,18); /* private offset */ -return( pstart ); -} - -static void dumpcffdictindex(SplineFont *sf,struct alltabs *at) { - int i; - int pos; - - putshort(at->fdarray,sf->subfontcnt); - putc('\2',at->fdarray); /* DICTs aren't very big, and there are at most 255 */ - putshort(at->fdarray,1); /* Offset to first dict */ - for ( i=0; i<sf->subfontcnt; ++i ) - putshort(at->fdarray,0); /* Dump offset placeholders (note there's one extra to mark the end) */ - pos = ftell(at->fdarray)-1; - for ( i=0; i<sf->subfontcnt; ++i ) { - at->fds[i].fillindictmark = dumpcffdict(sf->subfonts[i],at); - at->fds[i].eodictmark = ftell(at->fdarray); - if ( at->fds[i].eodictmark>65536 ) - IError("The DICT INDEX got too big, result won't work"); - } - fseek(at->fdarray,2*sizeof(short)+sizeof(char),SEEK_SET); - for ( i=0; i<sf->subfontcnt; ++i ) - putshort(at->fdarray,at->fds[i].eodictmark-pos); - fseek(at->fdarray,0,SEEK_END); -} - -static void dumpcffcidtopdict(SplineFont *sf,struct alltabs *at) { - char *pt, *end; - FILE *cfff = at->cfff; - DBounds b; - int cidcnt=0, k; - - for ( k=0; k<sf->subfontcnt; ++k ) - if ( sf->subfonts[k]->glyphcnt>cidcnt ) cidcnt = sf->subfonts[k]->glyphcnt; - - putshort(cfff,1); /* One top dict */ - putc('\2',cfff); /* Offset size */ - putshort(cfff,1); /* Offset to topdict */ - at->lenpos = ftell(cfff); - putshort(cfff,0); /* placeholder for final position */ - dumpsid(cfff,at,sf->cidregistry,-1); - dumpsid(cfff,at,sf->ordering,-1); - dumpintoper(cfff,sf->supplement,(12<<8)|30); /* ROS operator must be first */ - dumpdbloper(cfff,sf->cidversion,(12<<8)|31); - dumpintoper(cfff,cidcnt,(12<<8)|34); - if ( sf->use_uniqueid ) - dumpintoper(cfff, sf->uniqueid?sf->uniqueid:4000000 + (rand()&0x3ffff), (12<<8)|35 ); - - dumpsid(cfff,at,sf->copyright,1); - dumpsid(cfff,at,sf->fullname?sf->fullname:sf->fontname,2); - dumpsid(cfff,at,sf->familyname,3); - dumpsid(cfff,at,sf->weight,4); - /* FontMatrix (identity here, real ones in sub fonts)*/ - /* Actually there is no fontmatrix in the adobe cid font I'm looking at */ - /* which means it should default to [.001...] but it doesn't so the */ - /* docs aren't completely accurate */ - /* I now see I've no idea what the FontMatrix means in a CID keyed font */ - /* it seems to be ignored everywhere, so we omit it */ - - CIDLayerFindBounds(sf,at->gi.layer,&b); - at->gi.xmin = b.minx; - at->gi.ymin = b.miny; - at->gi.xmax = b.maxx; - at->gi.ymax = b.maxy; - dumpdbl(cfff,floor(b.minx)); - dumpdbl(cfff,floor(b.miny)); - dumpdbl(cfff,ceil(b.maxx)); - dumpdbloper(cfff,ceil(b.maxy),5); - /* We'll never set StrokeWidth */ - if ( sf->xuid!=NULL && sf->use_xuid ) { - pt = sf->xuid; if ( *pt=='[' ) ++pt; - while ( *pt && *pt!=']' ) { - dumpint(cfff,strtol(pt,&end,10)); - for ( pt = end; *pt==' '; ++pt ); - } - putc(14,cfff); - if ( sf->changed_since_xuidchanged ) - SFIncrementXUID(sf); - } - /* Acrobat doesn't seem to care about a private dict here. Ghostscript */ - /* dies. Tech Note: 5176.CFF.PDF, top of page 23 says: */ - /* A Private DICT is required, but may be specified as having */ - /* a length of 0 if there are no non-default values to be stored*/ - /* No indication >where< it is required. I assumed everywhere. Perhaps */ - /* just in basefonts? */ - /* Omit it. */ - - /* Offset to charset (oper=15) needed here */ - /* Offset to charstrings (oper=17) needed here */ - /* Offset to FDArray (oper=12,36) needed here */ - /* Offset to FDSelect (oper=12,37) needed here */ -} - -static int isStdEncoding(SplineFont *sf,EncMap *map) { - int i; - - for ( i=0; i<256 && i<map->enccount; ++i ) if ( map->map[i]!=-1 && sf->glyphs[map->map[i]]!=NULL ) - if ( sf->glyphs[map->map[i]]->unicodeenc!=-1 ) - if ( sf->glyphs[map->map[i]]->unicodeenc!=unicode_from_adobestd[i] ) -return( 0 ); - -return( 1 ); -} - -static void finishup(SplineFont *sf,struct alltabs *at) { - int strlen, shlen, glen,enclen,csetlen,cstrlen,prvlen; - int base, eotop, strhead; - int output_enc = ( at->format==ff_cff && !isStdEncoding(sf,at->map)); - - storesid(at,NULL); /* end the strings index */ - strlen = ftell(at->sidf) + (shlen = ftell(at->sidh)); - glen = sizeof(short); /* Single entry: 0, no globals */ - enclen = ftell(at->encoding); - csetlen = ftell(at->charset); - cstrlen = ftell(at->charstrings); - prvlen = ftell(at->private); - base = ftell(at->cfff); - if ( base+6*3+strlen+glen+enclen+csetlen+cstrlen+prvlen > 32767 ) { - at->cfflongoffset = true; - base += 5*5+4; - } else - base += 5*3+4; - strhead = 2+(at->sidcnt>1); - base += strhead; - - dumpsizedint(at->cfff,at->cfflongoffset,base+strlen+glen,15); /* Charset */ - if ( output_enc ) /* encoding offset */ - dumpsizedint(at->cfff,at->cfflongoffset,base+strlen+glen+csetlen,16); /* encoding offset */ - else { - dumpsizedint(at->cfff,at->cfflongoffset,0,16); - enclen = 0; - } - dumpsizedint(at->cfff,at->cfflongoffset,base+strlen+glen+csetlen+enclen,17);/* charstrings */ - dumpsizedint(at->cfff,at->cfflongoffset,at->privatelen,-1); - dumpsizedint(at->cfff,at->cfflongoffset,base+strlen+glen+csetlen+enclen+cstrlen,18); /* private size */ - eotop = base-strhead-at->lenpos-1; - if ( at->cfflongoffset ) { - fseek(at->cfff,3,SEEK_SET); - putc(4,at->cfff); - } - fseek(at->cfff,at->lenpos,SEEK_SET); - putshort(at->cfff,eotop); - fseek(at->cfff,0,SEEK_END); - - /* String Index */ - putshort(at->cfff,at->sidcnt-1); - if ( at->sidcnt!=1 ) { /* Everybody gets an added NULL */ - putc(at->sidlongoffset?4:2,at->cfff); - if ( !ttfcopyfile(at->cfff,at->sidh,base,"CFF-StringBase")) at->error = true; - if ( !ttfcopyfile(at->cfff,at->sidf,base+shlen,"CFF-StringData")) at->error = true; - } - - /* Global Subrs */ - putshort(at->cfff,0); - - /* Charset */ - if ( !ttfcopyfile(at->cfff,at->charset,base+strlen+glen,"CFF-Charset")) at->error = true; - - /* Encoding */ - if ( !ttfcopyfile(at->cfff,at->encoding,base+strlen+glen+csetlen,"CFF-Encoding")) at->error = true; - - /* Char Strings */ - if ( !ttfcopyfile(at->cfff,at->charstrings,base+strlen+glen+csetlen+enclen,"CFF-CharStrings")) at->error = true; - - /* Private & Subrs */ - if ( !ttfcopyfile(at->cfff,at->private,base+strlen+glen+csetlen+enclen+cstrlen,"CFF-Private")) at->error = true; -} - -static void finishupcid(SplineFont *sf,struct alltabs *at) { - int strlen, shlen, glen,csetlen,cstrlen,fdsellen,fdarrlen,prvlen; - int base, eotop, strhead; - int i; - - storesid(at,NULL); /* end the strings index */ - strlen = ftell(at->sidf) + (shlen = ftell(at->sidh)); - glen = ftell(at->globalsubrs); - /* No encodings */ - csetlen = ftell(at->charset); - fdsellen = ftell(at->fdselect); - cstrlen = ftell(at->charstrings); - fdarrlen = ftell(at->fdarray); - base = ftell(at->cfff); - - at->cfflongoffset = true; - base += 5*4+4+2; /* two of the opers below are two byte opers */ - strhead = 2+(at->sidcnt>1); - base += strhead; - - prvlen = 0; - for ( i=0; i<sf->subfontcnt; ++i ) { - fseek(at->fdarray,at->fds[i].fillindictmark,SEEK_SET); - dumpsizedint(at->fdarray,false,at->fds[i].privatelen,-1); /* Private len */ - dumpsizedint(at->fdarray,true,base+strlen+glen+csetlen+fdsellen+cstrlen+fdarrlen+prvlen,18); /* Private offset */ - prvlen += ftell(at->fds[i].private); /* private & subrs */ - } - - dumpsizedint(at->cfff,at->cfflongoffset,base+strlen+glen,15); /* charset */ - dumpsizedint(at->cfff,at->cfflongoffset,base+strlen+glen+csetlen,(12<<8)|37); /* fdselect */ - dumpsizedint(at->cfff,at->cfflongoffset,base+strlen+glen+csetlen+fdsellen,17); /* charstrings */ - dumpsizedint(at->cfff,at->cfflongoffset,base+strlen+glen+csetlen+fdsellen+cstrlen,(12<<8)|36); /* fdarray */ - eotop = base-strhead-at->lenpos-1; - fseek(at->cfff,at->lenpos,SEEK_SET); - putshort(at->cfff,eotop); - fseek(at->cfff,0,SEEK_END); - - /* String Index */ - putshort(at->cfff,at->sidcnt-1); - if ( at->sidcnt!=1 ) { /* Everybody gets an added NULL */ - putc(at->sidlongoffset?4:2,at->cfff); - if ( !ttfcopyfile(at->cfff,at->sidh,base,"CFF-StringBase")) at->error = true; - if ( !ttfcopyfile(at->cfff,at->sidf,base+shlen,"CFF-StringData")) at->error = true; - } - - /* Global Subrs */ - if ( !ttfcopyfile(at->cfff,at->globalsubrs,base+strlen,"CFF-GlobalSubrs")) at->error = true; - - /* Charset */ - if ( !ttfcopyfile(at->cfff,at->charset,base+strlen+glen,"CFF-Charset")) at->error = true; - - /* FDSelect */ - if ( !ttfcopyfile(at->cfff,at->fdselect,base+strlen+glen+csetlen,"CFF-FDSelect")) at->error = true; - - /* Char Strings */ - if ( !ttfcopyfile(at->cfff,at->charstrings,base+strlen+glen+csetlen+fdsellen,"CFF-CharStrings")) at->error = true; - - /* FDArray (DICT Index) */ - if ( !ttfcopyfile(at->cfff,at->fdarray,base+strlen+glen+csetlen+fdsellen+cstrlen,"CFF-FDArray")) at->error = true; - - /* Private & Subrs */ - prvlen = 0; - for ( i=0; i<sf->subfontcnt; ++i ) { - int temp = ftell(at->fds[i].private); - if ( !ttfcopyfile(at->cfff,at->fds[i].private, - base+strlen+glen+csetlen+fdsellen+cstrlen+fdarrlen+prvlen,"CFF-PrivateSubrs")) at->error = true; - prvlen += temp; - } - - free(at->fds); -} - -static int dumpcffhmtx(struct alltabs *at,SplineFont *sf,int bitmaps) { - DBounds b; - SplineChar *sc; - int i,cnt; - int dovmetrics = sf->hasvmetrics; - int width = at->gi.fixed_width; - - at->gi.hmtx = tmpfile2(); - if ( dovmetrics ) - at->gi.vmtx = tmpfile2(); - FigureFullMetricsEnd(sf,&at->gi,bitmaps); /* Bitmap fonts use ttf convention of 3 magic glyphs */ - if ( at->gi.bygid[0]!=-1 && (sf->glyphs[at->gi.bygid[0]]->width==width || width<=0 )) { - putshort(at->gi.hmtx,sf->glyphs[at->gi.bygid[0]]->width); - SplineCharLayerFindBounds(sf->glyphs[at->gi.bygid[0]],at->gi.layer,&b); - putshort(at->gi.hmtx,b.minx); - if ( dovmetrics ) { - putshort(at->gi.vmtx,sf->glyphs[at->gi.bygid[0]]->vwidth); - putshort(at->gi.vmtx,/*sf->vertical_origin-*/b.miny); - } - } else { - putshort(at->gi.hmtx,width<=0?(sf->ascent+sf->descent)/2:width); - putshort(at->gi.hmtx,0); - if ( dovmetrics ) { - putshort(at->gi.vmtx,sf->ascent+sf->descent); - putshort(at->gi.vmtx,0); - } - } - cnt = 1; - if ( bitmaps ) { - if ( width<=0 ) width = (sf->ascent+sf->descent)/3; - putshort(at->gi.hmtx,width); - putshort(at->gi.hmtx,0); - if ( dovmetrics ) { - putshort(at->gi.vmtx,sf->ascent+sf->descent); - putshort(at->gi.vmtx,0); - } - putshort(at->gi.hmtx,width); - putshort(at->gi.hmtx,0); - if ( dovmetrics ) { - putshort(at->gi.vmtx,sf->ascent+sf->descent); - putshort(at->gi.vmtx,0); - } - cnt = 3; - } - - for ( i=cnt; i<at->gi.gcnt; ++i ) if ( at->gi.bygid[i]!=-1 ) { - sc = sf->glyphs[at->gi.bygid[i]]; - if ( SCWorthOutputting(sc) ) { - if ( i<=at->gi.lasthwidth ) - putshort(at->gi.hmtx,sc->width); - SplineCharLayerFindBounds(sc,at->gi.layer,&b); - putshort(at->gi.hmtx,b.minx); - if ( dovmetrics ) { - if ( i<=at->gi.lastvwidth ) - putshort(at->gi.vmtx,sc->vwidth); - putshort(at->gi.vmtx,/*sf->vertical_origin-*/b.maxy); - } - ++cnt; - if ( i==at->gi.lasthwidth ) - at->gi.hfullcnt = cnt; - if ( i==at->gi.lastvwidth ) - at->gi.vfullcnt = cnt; - } - } - at->gi.hmtxlen = ftell(at->gi.hmtx); - if ( at->gi.hmtxlen&2 ) putshort(at->gi.hmtx,0); - if ( dovmetrics ) { - at->gi.vmtxlen = ftell(at->gi.vmtx); - if ( at->gi.vmtxlen&2 ) putshort(at->gi.vmtx,0); - } - - at->gi.maxp->numGlyphs = cnt; -return( true ); -} - -static void dumpcffcidhmtx(struct alltabs *at,SplineFont *_sf) { - DBounds b; - SplineChar *sc; - int cid,i,cnt=0,max; - SplineFont *sf; - int dovmetrics = _sf->hasvmetrics; - - at->gi.hmtx = tmpfile2(); - if ( dovmetrics ) - at->gi.vmtx = tmpfile2(); - FigureFullMetricsEnd(_sf,&at->gi,false); - - max = 0; - for ( i=0; i<_sf->subfontcnt; ++i ) - if ( max<_sf->subfonts[i]->glyphcnt ) - max = _sf->subfonts[i]->glyphcnt; - for ( cid = 0; cid<max; ++cid ) { - for ( i=0; i<_sf->subfontcnt; ++i ) { - sf = _sf->subfonts[i]; - if ( cid<sf->glyphcnt && SCWorthOutputting(sf->glyphs[cid])) - break; - } - if ( i!=_sf->subfontcnt ) { - sc = sf->glyphs[cid]; - if ( sc->ttf_glyph<=at->gi.lasthwidth ) - putshort(at->gi.hmtx,sc->width); - SplineCharLayerFindBounds(sc,at->gi.layer,&b); - putshort(at->gi.hmtx,b.minx); - if ( dovmetrics ) { - if ( sc->ttf_glyph<=at->gi.lastvwidth ) - putshort(at->gi.vmtx,sc->vwidth); - putshort(at->gi.vmtx,/*sf->vertical_origin-*/b.maxy); - } - ++cnt; - if ( sc->ttf_glyph==at->gi.lasthwidth ) - at->gi.hfullcnt = cnt; - if ( sc->ttf_glyph==at->gi.lastvwidth ) - at->gi.vfullcnt = cnt; - } else if ( cid==0 ) { - /* Create a dummy entry for .notdef */ - sf = _sf->subfonts[0]; - putshort(at->gi.hmtx,sf->ascent+sf->descent); - putshort(at->gi.hmtx,0); - ++cnt; - if ( dovmetrics ) { - putshort(at->gi.vmtx,sf->ascent+sf->descent); - putshort(at->gi.vmtx,0); - } - } - } - at->gi.hmtxlen = ftell(at->gi.hmtx); - if ( at->gi.hmtxlen&2 ) putshort(at->gi.hmtx,0); - if ( dovmetrics ) { - at->gi.vmtxlen = ftell(at->gi.vmtx); - if ( at->gi.vmtxlen&2 ) putshort(at->gi.vmtx,0); - } - - at->gi.maxp->numGlyphs = cnt; -} - -static int dumptype2glyphs(SplineFont *sf,struct alltabs *at) { - int i; - struct pschars *subrs, *chrs; - - at->cfff = tmpfile2(); - at->sidf = tmpfile2(); - at->sidh = tmpfile2(); - at->charset = tmpfile2(); - at->encoding = tmpfile2(); - at->private = tmpfile2(); - - dumpcffheader(at->cfff); - dumpcffnames(sf,at->cfff); - dumpcffcharset(sf,at); - ff_progress_change_stages(2+at->gi.strikecnt); - - ATFigureDefWidth(sf,at,-1); - if ((chrs =SplineFont2ChrsSubrs2(sf,at->nomwid,at->defwid,at->gi.bygid,at->gi.gcnt,at->gi.flags,&subrs,at->gi.layer))==NULL ) -return( false ); - dumpcffprivate(sf,at,-1,subrs->next); - if ( subrs->next!=0 ) - _dumpcffstrings(at->private,subrs); - ff_progress_next_stage(); - at->charstrings = dumpcffstrings(chrs); - PSCharsFree(subrs); - if ( at->charstrings == NULL ) -return( false ); - if ( at->format==ff_cff && !isStdEncoding(sf,at->map)) - dumpcffencoding(sf,at); /* Do this after we've assigned glyph ids */ - dumpcfftopdict(sf,at); - finishup(sf,at); - - at->cfflen = ftell(at->cfff); - if ( at->cfflen&3 ) { - for ( i=4-(at->cfflen&3); i>0; --i ) - putc('\0',at->cfff); - } - - if ( at->format!=ff_cff ) - dumpcffhmtx(at,sf,false); - free(at->gn_sid); at->gn_sid=NULL; -return( true ); -} - -static int dumpcidglyphs(SplineFont *sf,struct alltabs *at) { - int i; - struct pschars *glbls = NULL, *chrs; - - at->cfff = tmpfile2(); - at->sidf = tmpfile2(); - at->sidh = tmpfile2(); - at->charset = tmpfile2(); - at->fdselect = tmpfile2(); - at->fdarray = tmpfile2(); - at->globalsubrs = tmpfile2(); - - at->fds = calloc(sf->subfontcnt,sizeof(struct fd2data)); - for ( i=0; i<sf->subfontcnt; ++i ) { - at->fds[i].private = tmpfile2(); - ATFigureDefWidth(sf->subfonts[i],at,i); - } - if ( (chrs = CID2ChrsSubrs2(sf,at->fds,at->gi.flags,&glbls,at->gi.layer))==NULL ) -return( false ); - for ( i=0; i<sf->subfontcnt; ++i ) { - dumpcffprivate(sf->subfonts[i],at,i,at->fds[i].subrs->next); - if ( at->fds[i].subrs->next!=0 ) - _dumpcffstrings(at->fds[i].private,at->fds[i].subrs); - PSCharsFree(at->fds[i].subrs); - } - _dumpcffstrings(at->globalsubrs,glbls); - PSCharsFree(glbls); - - dumpcffheader(at->cfff); - dumpcffnames(sf,at->cfff); - dumpcffcidset(at); - dumpcfffdselect(sf,at); - dumpcffdictindex(sf,at); - if ( (at->charstrings = dumpcffstrings(chrs))==NULL ) -return( false ); - dumpcffcidtopdict(sf,at); - finishupcid(sf,at); - - at->cfflen = ftell(at->cfff); - if ( at->cfflen&3 ) { - for ( i=4-(at->cfflen&3); i>0; --i ) - putc('\0',at->cfff); - } - - if ( at->format!=ff_cffcid ) - dumpcffcidhmtx(at,sf); -return( true ); -} - -static int AnyInstructions(SplineFont *sf) { - int i; - - if ( sf->subfontcnt!=0 ) { - for ( i=0; i<sf->subfontcnt; ++i ) - if ( AnyInstructions(sf->subfonts[i])) -return( true ); - } else { - for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) { - if ( sf->glyphs[i]->ttf_instrs_len!=0 ) -return( true ); - } - } -return( false ); -} - -void cvt_unix_to_1904( long long time, int32 result[2]) { - uint32 date1970[4], tm[4]; - uint32 year[2]; - int i; - - tm[0] = time &0xffff; - tm[1] = (time>>16)&0xffff; - tm[2] = (time>>32)&0xffff; - tm[3] = (time>>48)&0xffff; - memset(date1970,0,sizeof(date1970)); - year[0] = (60*60*24*365L)&0xffff; - year[1] = (60*60*24*365L)>>16; - for ( i=1904; i<1970; ++i ) { - date1970[0] += year[0]; - date1970[1] += year[1]; - if ( (i&3)==0 && (i%100!=0 || i%400==0)) - date1970[0] += 24*60*60L; /* Leap year */ - date1970[1] += (date1970[0]>>16); - date1970[0] &= 0xffff; - date1970[2] += date1970[1]>>16; - date1970[1] &= 0xffff; - date1970[3] += date1970[2]>>16; - date1970[2] &= 0xffff; - } - - for ( i=0; i<3; ++i ) { - tm[i] += date1970[i]; - tm[i+1] += tm[i]>>16; - tm[i] &= 0xffff; - } - tm[3] -= date1970[3]; - - result[0] = (tm[1]<<16) | tm[0]; - result[1] = (tm[3]<<16) | tm[2]; -} - -static void sethead(struct head *head,SplineFont *sf,struct alltabs *at, - enum fontformat format, int32 *bsizes) { - int i, lr, rl, indic_rearrange, arabic; - ASM *sm; - struct ttflangname *useng; - float vn; - - if ( at->gi.xmin==15000 ) at->gi.xmin = 0; - if ( at->gi.ymin==15000 ) at->gi.ymin = 0; - if ( bsizes!=NULL && format==ff_none ) { - if ( sf->ascent >at->gi.ymax ) at->gi.ymax = sf->ascent; - if ( -sf->descent<at->gi.ymin ) at->gi.ymin = -sf->descent; - } - head->xmin = at->gi.xmin; - head->ymin = at->gi.ymin; - head->xmax = at->gi.xmax; - head->ymax = at->gi.ymax; - - lr = rl = arabic = 0; - for ( i=0; i<at->gi.gcnt; ++i ) if ( at->gi.bygid[i]!=-1 ) { - SplineChar *sc = sf->glyphs[at->gi.bygid[i]]; - int uni = sc->unicodeenc ; - if ( SCRightToLeft(sc) ) - rl = 1; - else if (( uni!=-1 && uni<0x10000 && islefttoright(uni)) || - (uni>=0x10300 && uni<0x107ff)) - lr = 1; - if ( SCScriptFromUnicode(sc)==CHR('a','r','a','b') ) - arabic = 1; - } - - head->version = 0x00010000; - head->revision = sf->sfntRevision; - if ( sf->sfntRevision==sfntRevisionUnset ) { - head->revision = 0x00010000; - for ( useng=sf->names; useng!=NULL; useng=useng->next ) - if ( useng->lang==0x409 ) - break; - if ( useng!=NULL && useng->names[ttf_version]!=NULL && - sscanf(useng->names[ttf_version], "Version %f", &vn)==1 ) { - head->revision = vn*65536; - } else if ( sf->subfontcnt!=0 ) { - int val, mant; - val = floor(sf->cidversion); - mant = floor(65536.*((double)sf->cidversion-val)); - head->revision = (val<<16) | mant; - } else if ( sf->version!=NULL ) { - char *pt=sf->version; - double dval; - int val, mant; - while ( *pt && !isdigit(*pt) && *pt!='.' ) ++pt; - if ( *pt ) { - dval = strtod(pt,NULL); - val = floor(dval); - mant = floor(65536.*(dval-val)); - head->revision = (val<<16) | mant; - } - } - } - head->checksumAdj = 0; - head->magicNum = 0x5f0f3cf5; - head->flags = 8|2|1; /* baseline at 0, lsbline at 0, round ppem */ - if ( format>=ff_ttf && format<=ff_ttfdfont ) { - if ( AnyInstructions(sf) ) - head->flags = 0x10|8|4|2|1; /* baseline at 0, lsbline at 0, round ppem, instructions may depend on point size, instructions change metrics */ - } - /* If a font contains embedded bitmaps, and if some of those bitmaps have */ - /* a different advance width from that expected by scaling, then windows */ - /* will only notice the fact if the 0x10 bit is set (even though this has*/ - /* nothing to do with instructions) */ -/* Apple flags */ - if ( sf->hasvmetrics ) - head->flags |= (1<<5); /* designed to be layed out vertically */ - /* Bit 6 must be zero */ - if ( arabic ) - head->flags |= (1<<7); - if ( sf->sm ) - head->flags |= (1<<8); /* has metamorphesis effects */ - if ( rl ) - head->flags |= (1<<9); - indic_rearrange = 0; - for ( sm = sf->sm; sm!=NULL; sm=sm->next ) - if ( sm->type == asm_indic ) - indic_rearrange = true; - if ( indic_rearrange ) - head->flags |= (1<<10); -/* End apple flags */ - if ( sf->head_optimized_for_cleartype ) - head->flags |= (1<<13); - head->emunits = sf->ascent+sf->descent; - head->macstyle = MacStyleCode(sf,NULL); - head->lowestreadable = 8; - head->locais32 = 1; - if ( at->gi.glyph_len<0x20000 ) - head->locais32 = 0; - - /* I assume we've always got some neutrals (spaces, punctuation) */ - if ( lr && rl ) - head->dirhint = 0; - else if ( rl ) - head->dirhint = -2; - else - head->dirhint = 2; - if ( rl ) - head->flags |= (1<<9); /* Apple documents this */ - /* if there are any indic characters, set bit 10 */ - - cvt_unix_to_1904(sf->creationtime,head->createtime); - cvt_unix_to_1904(sf->modificationtime,head->modtime); -} - -static void sethhead(struct hhead *hhead,struct hhead *vhead,struct alltabs *at, SplineFont *sf) { - int i, width, rbearing, height, bbearing; - int ymax, ymin, xmax, xmin, off; - DBounds bb; - /* Might as well fill in the vhead even if we don't use it */ - /* we just won't dump it out if we don't want it */ - - width = 0x80000000; rbearing = 0x7fffffff; height = 0x80000000; bbearing=0x7fffffff; - xmax = ymax = 0x80000000; xmin = ymin = 0x7fffffff; - for ( i=0; i<at->gi.gcnt; ++i ) if ( at->gi.bygid[i]!=-1 ) { - SplineChar *sc = sf->glyphs[at->gi.bygid[i]]; - SplineCharLayerFindBounds(sc,at->gi.layer,&bb); - if ( sc->width>width ) width = sc->width; - if ( sc->vwidth>height ) height = sc->vwidth; - if ( sc->width-bb.maxx < rbearing ) rbearing = sc->width-bb.maxx; - if ( sc->vwidth-bb.maxy < bbearing ) bbearing = sc->vwidth-bb.maxy; - if ( bb.maxy > ymax ) ymax = bb.maxy; - if ( bb.miny < ymin ) ymin = bb.miny; - if ( bb.maxx > xmax ) xmax = bb.maxx; - if ( bb.minx < xmin ) xmin = bb.minx; - } - - if ( at->head.ymax>ymax ) ymax = at->head.ymax; /* If generated .notdef glyph is bigger than real glyphs */ - if ( at->head.ymin<ymin ) ymin = at->head.ymin; - - if ( ymax==0 && ymin==0 ) { - /* this can happen in a bitmap only font */ - ymax = sf->ascent; - ymin = -sf->descent; - } - hhead->version = 0x00010000; - if ( sf->pfminfo.hheadascent_add ) - hhead->ascender = ymax + sf->pfminfo.hhead_ascent; - else - hhead->ascender = sf->pfminfo.hhead_ascent; - if ( sf->pfminfo.hheaddescent_add ) - hhead->descender = ymin + sf->pfminfo.hhead_descent; - else - hhead->descender = sf->pfminfo.hhead_descent; - hhead->linegap = sf->pfminfo.linegap; - - vhead->version = 0x00011000; - off = (sf->ascent+sf->descent)/2; - vhead->ascender = xmax-off; - vhead->descender = xmin-off; - vhead->linegap = sf->pfminfo.linegap; - - at->isfixed = at->gi.fixed_width>0; - hhead->maxwidth = width; - hhead->minlsb = at->head.xmin; - hhead->minrsb = rbearing; - /* Apple's ftxvalidator says the min sidebearing should be 0 even if it isn't */ - if ( hhead->minlsb>0 ) hhead->minlsb = 0; - if ( hhead->minrsb>0 ) hhead->minrsb = 0; - hhead->maxextent = at->head.xmax; - if ( sf->italicangle==0 ) - hhead->caretSlopeRise = 1; - else { - hhead->caretSlopeRise = 100; - hhead->caretSlopeRun = (int) rint(100*tan(-sf->italicangle*3.1415926535897/180.)); - } - - vhead->maxwidth = height; - vhead->minlsb = at->head.ymin; - vhead->minrsb = bbearing; - vhead->maxextent = at->head.ymax; - vhead->caretSlopeRise = 0; - vhead->caretSlopeRun = 1; - /* Are there vertical oblique fonts? */ - - hhead->numMetrics = at->gi.hfullcnt; - vhead->numMetrics = at->gi.vfullcnt; -} - -static void OS2WeightCheck(struct pfminfo *pfminfo,char *weight) { - if ( weight==NULL ) { - /* default it */ - } else if ( strstrmatch(weight,"medi")!=NULL ) { - pfminfo->weight = 500; - pfminfo->panose[2] = 6; - } else if ( strstrmatch(weight,"demi")!=NULL || - strstrmatch(weight,"halb")!=NULL || - (strstrmatch(weight,"semi")!=NULL && - strstrmatch(weight,"bold")!=NULL) ) { - pfminfo->weight = 600; - pfminfo->panose[2] = 7; - } else if ( strstrmatch(weight,"bold")!=NULL || - strstrmatch(weight,"fett")!=NULL || - strstrmatch(weight,"gras")!=NULL ) { - pfminfo->weight = 700; - pfminfo->panose[2] = 8; - } else if ( strstrmatch(weight,"heavy")!=NULL ) { - pfminfo->weight = 800; - pfminfo->panose[2] = 9; - } else if ( strstrmatch(weight,"black")!=NULL ) { - pfminfo->weight = 900; - pfminfo->panose[2] = 10; - } else if ( strstrmatch(weight,"nord")!=NULL ) { - pfminfo->weight = 950; - pfminfo->panose[2] = 11; - } else if ( strstrmatch(weight,"thin")!=NULL ) { - pfminfo->weight = 100; - pfminfo->panose[2] = 2; - } else if ( strstrmatch(weight,"extra")!=NULL || - strstrmatch(weight,"light")!=NULL ) { - pfminfo->weight = 200; - pfminfo->panose[2] = 3; - } else if ( strstrmatch(weight,"light")!=NULL ) { - pfminfo->weight = 300; - pfminfo->panose[2] = 4; - } -} - -void SFDefaultOS2Simple(struct pfminfo *pfminfo,SplineFont *sf) { - pfminfo->pfmfamily = 0x11; - pfminfo->panose[0] = 2; - pfminfo->weight = 400; - pfminfo->panose[2] = 5; - pfminfo->width = 5; - pfminfo->panose[3] = 3; - pfminfo->winascent_add = pfminfo->windescent_add = true; - pfminfo->hheadascent_add = pfminfo->hheaddescent_add = true; - pfminfo->typoascent_add = pfminfo->typodescent_add = true; - pfminfo->os2_winascent = pfminfo->os2_windescent = 0; - - if ( sf->subfonts!=NULL ) sf = sf->subfonts[0]; - pfminfo->linegap = pfminfo->vlinegap = pfminfo->os2_typolinegap = - rint(.09*(sf->ascent+sf->descent)); -} - -void SFDefaultOS2SubSuper(struct pfminfo *pfminfo,int emsize,double italic_angle) { - double s = sin(italic_angle*3.1415926535897932/180.0); - pfminfo->os2_supysize = pfminfo->os2_subysize = .7*emsize; - pfminfo->os2_supxsize = pfminfo->os2_subxsize = .65*emsize; - pfminfo->os2_subyoff = .14*emsize; - pfminfo->os2_supyoff = .48*emsize; - pfminfo->os2_supxoff = s*pfminfo->os2_supyoff; - pfminfo->os2_subxoff = -s*pfminfo->os2_subyoff; - pfminfo->os2_strikeysize = 102*emsize/2048; - pfminfo->os2_strikeypos = 530*emsize/2048; -} - -void SFDefaultOS2Info(struct pfminfo *pfminfo,SplineFont *sf,char *fontname) { - int samewid= -1; - char *weight = sf->cidmaster==NULL ? sf->weight : sf->cidmaster->weight; - - if ( sf->pfminfo.pfmset ) { - if ( pfminfo!=&sf->pfminfo ) - *pfminfo = sf->pfminfo; - if ( !pfminfo->panose_set ) { - struct pfminfo info; - memset(&info,0,sizeof(info)); - sf->pfminfo.pfmset = false; - SFDefaultOS2Info(&info,sf,fontname); - sf->pfminfo.pfmset = true; - memcpy(pfminfo->panose,info.panose,sizeof(info.panose)); - } - } else { - struct pfminfo hold; - if ( pfminfo->hheadset || pfminfo->vheadset ) - hold = *pfminfo; - else - hold.hheadset = hold.vheadset = false; - memset(pfminfo,'\0',sizeof(*pfminfo)); - SFDefaultOS2Simple(pfminfo,sf); - samewid = CIDOneWidth(sf); - - pfminfo->pfmfamily = 0x10; - if ( samewid>0 ) { - pfminfo->pfmfamily = 0x30; - /* pfminfo->panose[3] = 9; */ /* This is done later */ - } else if ( strstrmatch(fontname,"sans")!=NULL ) - pfminfo->pfmfamily = 0x20; - else if ( strstrmatch(fontname,"script")!=NULL ) { - pfminfo->pfmfamily = 0x40; - pfminfo->panose[0] = 3; - } - if ( samewid==-1 ) - pfminfo->pfmfamily |= 0x1; /* Else it assumes monospace */ - -/* urw uses 4 character abreviations */ - if ( weight!=NULL ) - OS2WeightCheck(pfminfo,weight); - OS2WeightCheck(pfminfo,fontname); - - if ( strstrmatch(fontname,"ultra")!=NULL && - strstrmatch(fontname,"condensed")!=NULL ) { - pfminfo->width = 1; - pfminfo->panose[3] = 8; - } else if ( strstrmatch(fontname,"extra")!=NULL && - strstrmatch(fontname,"condensed")!=NULL ) { - pfminfo->width = 2; - pfminfo->panose[3] = 8; - } else if ( strstrmatch(fontname,"semi")!=NULL && - strstrmatch(fontname,"condensed")!=NULL ) { - pfminfo->width = 4; - pfminfo->panose[3] = 6; - } else if ( strstrmatch(fontname,"condensed")!=NULL || - strstrmatch(fontname,"narrow")!=NULL ) { - pfminfo->width = 3; - pfminfo->panose[3] = 6; - } else if ( strstrmatch(fontname,"ultra")!=NULL && - strstrmatch(fontname,"expanded")!=NULL ) { - pfminfo->width = 9; - pfminfo->panose[3] = 7; - } else if ( strstrmatch(fontname,"extra")!=NULL && - strstrmatch(fontname,"expanded")!=NULL ) { - pfminfo->width = 8; - pfminfo->panose[3] = 7; - } else if ( strstrmatch(fontname,"semi")!=NULL && - strstrmatch(fontname,"expanded")!=NULL ) { - pfminfo->width = 6; - pfminfo->panose[3] = 5; - } else if ( strstrmatch(fontname,"expanded")!=NULL ) { - pfminfo->width = 7; - pfminfo->panose[3] = 5; - } - if ( samewid>0 ) - pfminfo->panose[3] = 9; - if ( hold.hheadset ) { - pfminfo->hheadset = true; - pfminfo->hheadascent_add = hold.hheadascent_add; - pfminfo->hheaddescent_add = hold.hheaddescent_add; - pfminfo->hhead_ascent = hold.hhead_ascent; - pfminfo->hhead_descent = hold.hhead_descent; - pfminfo->linegap = hold.linegap; - } - if ( hold.vheadset ) { - pfminfo->vheadset = true; - pfminfo->vlinegap = hold.vlinegap; - } - } - if ( !pfminfo->subsuper_set ) - SFDefaultOS2SubSuper(pfminfo,sf->ascent+sf->descent,sf->italicangle); -} - -int AlreadyMSSymbolArea(SplineFont *sf,EncMap *map) { - int i; - int acnt=0, pcnt=0; - - for ( i=0; i<map->enccount && i<0xffff; ++i ) { - if ( map->map[i]!=-1 && sf->glyphs[map->map[i]]!=NULL && - sf->glyphs[map->map[i]]->ttf_glyph!=-1 ) { - if ( i>=0xf000 && i<=0xf0ff ) - ++pcnt; - else if ( i>=0x20 && i<=0xff ) - ++acnt; - } - } -return( pcnt>acnt ); -} - -void OS2FigureCodePages(SplineFont *sf, uint32 CodePage[2]) { - int i; - uint32 latin1[8]; - int has_ascii, has_lineart=0, has_radical=0, has_summation=0; - int cp852=0, cp775=0, cp861=0, cp860=0, cp857=0, cp855=0, cp862=0, cp863=0; - int cp864=0, cp865=0, cp866=0, cp869=0, cp737=0, cp708=0, mac=0; - int k; - SplineChar *sc; - SplineFont *sub; - - memset(latin1,0,sizeof(latin1)); - k=0; - do { - sub = k<sf->subfontcnt? sf->subfonts[k] : sf; - for ( i=0; i<sub->glyphcnt; ++i ) if ( (sc = sub->glyphs[i])!=NULL ) { - if ( sc->unicodeenc<256 && sc->unicodeenc>=0 ) - latin1[(sc->unicodeenc>>5)] |= 1<<(sc->unicodeenc&31); - } - ++k; - } while ( k<sf->subfontcnt ); - - has_ascii = latin1[1]==0xffffffff && latin1[2]==0xffffffff && - (latin1[3]&0x7fffffff)==0x7fffffff; /* DEL is not a char */ - CodePage[0] = CodePage[1] = 0; - - k=0; - do { - sub = k<sf->subfontcnt? sf->subfonts[k] : sf; - for ( i=0; i<sub->glyphcnt; ++i ) if ( (sc = sub->glyphs[i])!=NULL ) { - int uni = sc->unicodeenc; - if ( uni==0xde && has_ascii ) - CodePage[0] |= 1<<0; /* (ANSI) Latin1 */ - else if ( uni==0x255a && has_ascii ) { - CodePage[1] |= 1U<<30; /* WE/latin1 */ /* Not latin1 at all */ - CodePage[1] |= 1U<<31; /* US */ - } else if ( uni==0x13d && has_ascii ) { - CodePage[0] |= 1<<1; /* latin2 */ - ++cp852; - } else if ( uni==0x411 ) { - CodePage[0] |= 1<<2; /* cyrillic */ - ++cp866; - ++cp855; - } else if ( uni==0x405 ) { - ++cp855; - } else if ( uni==0x386 ) { - CodePage[0] |= 1<<3; /* greek */ - ++cp869; - ++cp737; - } else if ( uni==0x130 && has_ascii ) { - CodePage[0] |= 1<<4; /* turkish */ - ++cp857; - } else if ( uni==0x5d0 ) { - CodePage[0] |= 1<<5; /* hebrew */ - ++cp862; - } else if ( uni==0x631 ) { - CodePage[0] |= 1<<6; /* arabic */ - ++cp864; - ++cp708; - } else if ( uni==0x157 && has_ascii ) { - CodePage[0] |= 1<<7; /* baltic */ - ++cp775; - } else if ( uni==0x20AB && has_ascii ) { - CodePage[0] |= 1<<8; /* vietnamese */ - } else if ( uni==0xe45 ) - CodePage[0] |= 1<<16; /* thai */ - else if ( uni==0x30a8 ) - CodePage[0] |= 1<<17; /* japanese */ - else if ( uni==0x3105 ) - CodePage[0] |= 1<<18; /* simplified chinese */ - else if ( uni==0x3131 ) - CodePage[0] |= 1<<19; /* korean wansung */ - else if ( uni==0x592E ) - CodePage[0] |= 1<<20; /* traditional chinese */ - else if ( uni==0xacf4 ) - CodePage[0] |= 1<<21; /* korean Johab */ - else if ( uni==0x2030 && has_ascii ) - ++mac; - else if ( uni==0x2665 && has_ascii ) - CodePage[0] |= 1U<<30; /* OEM */ - /* the symbol bit doesn't mean it contains the glyphs in symbol */ - /* rather that one is using a symbol encoding. Or that there are */ - /* glyphs with unicode encoding between 0xf000 and 0xf0ff, in which */ - /* case those guys should be given a symbol encoding */ - /* There's a bug in the way otf fonts handle this (but not ttf) and */ - /* they only seem to list the symbol glyphs. */ - /* Hence we don't test uni==0x21d4 */ - /* This doesn't work well either. In ttf fonts the bit is ignored */ - /* in otf fonts the bit means "ignore all other bits" */ - else if ( uni>=0xf000 && uni<=0xf0ff ) - CodePage[0] |= 1U<<31; /* symbol */ - else if ( uni==0xc5 && has_ascii ) - ++cp865; - else if ( uni==0xe9 && has_ascii ) - ++cp863; - else if ( uni==0xf5 && has_ascii ) - ++cp860; - else if ( uni==0xfe && has_ascii ) - ++cp861; - else if ( uni==0x2524 ) - ++has_lineart; - else if ( uni==0x255c ) - ++cp866; - else if ( uni==0xbd ) - ++cp869; - else if ( uni==0x221A ) - has_radical=true; - else if ( uni==0x2211 ) - has_summation=true; - } - ++k; - } while ( k<sf->subfontcnt ); - if ( cp852 && has_lineart ) - CodePage[1] |= 1<<26; /* latin2 */ - if ( cp775 && has_lineart ) - CodePage[1] |= 1<<27; /* baltic */ - if ( cp861 && has_lineart ) - CodePage[1] |= 1<<22; /* MS-DOS Icelandic */ - if ( cp866==2 && has_lineart ) - CodePage[1] |= 1<<17; /* MS DOS Russian */ - if ( cp855==2 && has_lineart ) - CodePage[1] |= 1<<25; /* IBM Cyrillic */ - if ( cp869==2 && has_lineart ) - CodePage[1] |= 1<<16; /* IBM Greek */ - if ( cp737 && has_lineart && has_radical ) - CodePage[1] |= 1<<28; /* Greek, former 437 G */ - if ( cp857 && has_lineart ) - CodePage[1] |= 1<<24; /* IBM turkish */ - if ( cp862 && has_lineart && has_radical ) - CodePage[1] |= 1<<21; /* hebrew */ - if ( cp864 && has_radical ) - CodePage[1] |= 1<<19; /* arabic */ - if ( cp708 && has_lineart) - CodePage[1] |= 1<<29; /* arabic; ASMO 708 */ - if ( cp863 && has_lineart && has_radical ) - CodePage[1] |= 1<<20; /* MS-DOS Canadian French */ - if ( cp865 && has_lineart && has_radical ) - CodePage[1] |= 1<<18; /* MS-DOS Nordic */ - if ( cp860 && has_lineart && has_radical ) - CodePage[1] |= 1<<23; /* MS-DOS Portuguese */ - if ( mac && has_summation ) - CodePage[0] |= 1U<<29; /* mac roman */ -} - -void OS2FigureUnicodeRanges(SplineFont *sf, uint32 Ranges[4]) { - int i, k; - unsigned j; - SplineChar *sc; - SplineFont *sub; - - memset(Ranges,0,4*sizeof(uint32)); - k=0; - do { - sub = k<sf->subfontcnt? sf->subfonts[k] : sf; - for ( i=0; i<sub->glyphcnt; ++i ) if ( (sc = sub->glyphs[i])!=NULL ) { - if ( SCWorthOutputting(sc) && sc->unicodeenc!=-1 ) { - if ( sc->unicodeenc > 0xffff ) - Ranges[57>>5] |= (1<<(57&31)); - for ( j=0; j<sizeof(uniranges)/sizeof(uniranges[0]); ++j ) - if ( sc->unicodeenc>=uniranges[j][0] && - sc->unicodeenc<=uniranges[j][1] ) { - int bit = uniranges[j][2]; - Ranges[bit>>5] |= (1<<(bit&31)); - break; - } - } - } - ++k; - } while ( k<sf->subfontcnt ); -} - -static void WinBB(SplineFont *sf,uint16 *winascent,uint16 *windescent,struct alltabs *at) { - /* The windows ascent/descent is calculated on the ymin/max of the */ - /* glyphs in the so called ANSI character set. I'm going to pretend */ - /* that's Latin1 with a few additions */ - /* Well, that's what is documented, but the documentation says contradictory */ - /* things. I believe that winAscent should be the same as hhea.ascent */ - - *winascent = at->head.ymax; - *windescent = -at->head.ymin; /* Should be positive */ - if ( sf->cidmaster!=NULL ) - sf = sf->cidmaster; - - if ( sf->pfminfo.winascent_add ) - *winascent += sf->pfminfo.os2_winascent; - else - *winascent = sf->pfminfo.os2_winascent; - if ( sf->pfminfo.windescent_add ) - *windescent += sf->pfminfo.os2_windescent; - else - *windescent = sf->pfminfo.os2_windescent; -} - -static void redohead(struct alltabs *at); - -static void setos2(struct os2 *os2,struct alltabs *at, SplineFont *sf, - enum fontformat format) { - int i,cnt1,cnt2,first,last,avg1,avg2,gid; - char *pt; - static int const weightFactors[26] = { 64, 14, 27, 35, 100, 20, 14, 42, 63, - 3, 6, 35, 20, 56, 56, 17, 4, 49, 56, 71, 31, 10, 18, 3, 18, 2 }; - EncMap *map; - SplineChar *sc; - int modformat = format; - - os2->version = 1; - if ( format==ff_otf || format==ff_otfcid ) - os2->version = 3; - if ( sf->use_typo_metrics || sf->weight_width_slope_only ) - os2->version = 4; - if ( sf->os2_version > os2->version ) - os2->version = sf->os2_version; - if (( format>=ff_ttf && format<=ff_otfdfont) && (at->gi.flags&ttf_flag_symbol)) - modformat = ff_ttfsym; - - os2->weightClass = sf->pfminfo.weight; - os2->widthClass = sf->pfminfo.width; - os2->fstype = 0x8; - if ( sf->pfminfo.fstype!=-1 ) - os2->fstype = sf->pfminfo.fstype; - if ( !sf->pfminfo.subsuper_set ) - SFDefaultOS2SubSuper(&sf->pfminfo,sf->ascent+sf->descent,sf->italicangle); - os2->ysupYSize = sf->pfminfo.os2_supysize; - os2->ysubXSize = sf->pfminfo.os2_subxsize; - os2->ysubYSize = sf->pfminfo.os2_subysize; - os2->ysupXSize = sf->pfminfo.os2_supxsize; - os2->ysubYOff = sf->pfminfo.os2_subyoff; - os2->ysubXOff = sf->pfminfo.os2_subxoff; - os2->ysupXOff = sf->pfminfo.os2_supxoff; - os2->ysupYOff = sf->pfminfo.os2_supyoff; - os2->yStrikeoutSize = sf->pfminfo.os2_strikeysize; - os2->yStrikeoutPos = sf->pfminfo.os2_strikeypos; - if ( sf->pfminfo.stylemap!=-1 ) { - int changed = 0; - os2->fsSel = sf->pfminfo.stylemap; - /* Make sure fsSel and macStyle don't contradict */ - if (at->head.macstyle&1 && !(os2->fsSel&32)) {at->head.macstyle &= 0x7E; changed=1;} - if (at->head.macstyle&2 && !(os2->fsSel&1)) {at->head.macstyle &= 0x7D; changed=1;} - if (changed) redohead(at); - } else { - os2->fsSel = (at->head.macstyle&1?32:0)|(at->head.macstyle&2?1:0); - if ( os2->fsSel==0 && sf->pfminfo.weight==400 ) - os2->fsSel = 64; /* Regular */ - } - if ( sf->fullname!=NULL && strstrmatch(sf->fullname,"outline")!=NULL ) - os2->fsSel |= 8; - if ( os2->version>=4 ) { - if ( strstrmatch(sf->fontname,"Obli")!=NULL ) { - os2->fsSel &= ~1; /* Turn off Italic */ - os2->fsSel |= 512; /* Turn on Oblique */ - } - if ( sf->use_typo_metrics ) - os2->fsSel |= 128; /* Don't use win ascent/descent for line spacing */ - if ( sf->weight_width_slope_only ) - os2->fsSel |= 256; - } -/* David Lemon @Adobe.COM -1) The sTypoAscender and sTypoDescender values should sum to 2048 in -a 2048-unit font. They indicate the position of the em square -relative to the baseline. -GWW: Almost, sTypoAscender-sTypoDescender == EmSize - -2) The usWinAscent and usWinDescent values represent the maximum -height and depth of specific glyphs within the font, and some -applications will treat them as the top and bottom of the font -bounding box. (the "ANSI" glyphs) -GWW: That's what's documented. But it means non-ANSI glyphs get clipped. So the -docs are wrong. -*/ - if ( sf->pfminfo.typoascent_add ) - os2->ascender = sf->ascent + sf->pfminfo.os2_typoascent; - else - os2->ascender = sf->pfminfo.os2_typoascent; - if ( sf->pfminfo.typodescent_add ) - os2->descender = -sf->descent + sf->pfminfo.os2_typodescent; /* Should be neg */ - else - os2->descender = sf->pfminfo.os2_typodescent; - WinBB(sf,&os2->winascent,&os2->windescent,at); - os2->linegap = sf->pfminfo.os2_typolinegap; - os2->sFamilyClass = sf->pfminfo.os2_family_class; - - avg1 = avg2 = last = 0; first = 0xffff; - cnt1 = cnt2 = 0; - for ( i=0; i<sf->glyphcnt; ++i ) if ( (sc = sf->glyphs[i])!=NULL ) { - if ( SCWorthOutputting(sc) && sc->unicodeenc!=-1 ) { - /* Don't include the dummy glyphs (.notdef, .null, etc.) they aren't */ - /* really encoded. Don't include glyphs out of BMP, OS/2 uses shorts */ - /* for the first/last char and can't represent them. */ - /* If no BMP glyphs, then first should be 0xffff. If any outside */ - /* BMP then last is 0xffff */ - /* sc->ttf_glyph>2 is to skip the first few truetype glyphs but */ - /* that doesn't work for cff files which only have .notdef to ignore */ - if ( ( format>=ff_ttf && format<=ff_otfdfont && sc->ttf_glyph>2) || - ( format>=ff_ttf && format<=ff_otfdfont && sc->ttf_glyph>0) ) { - if ( sc->unicodeenc<=0xffff ) { - if ( sc->unicodeenc<first ) first = sc->unicodeenc; - if ( sc->unicodeenc>last ) last = sc->unicodeenc; - } else { - last = 0xffff; - } - } - if ( sc->width!=0 ) { - avg2 += sc->width; ++cnt2; - } - if ( sc->unicodeenc==' ') { - avg1 += sc->width * 166; ++cnt1; - } else if (sc->unicodeenc>='a' && sc->unicodeenc<='z') { - avg1 += sc->width * weightFactors[sc->unicodeenc-'a']; ++cnt1; - } - } - } - if ( sf->pfminfo.hasunicoderanges ) - memcpy(os2->unicoderange,sf->pfminfo.unicoderanges,sizeof(os2->unicoderange)); - else - OS2FigureUnicodeRanges(sf,os2->unicoderange); - if ( modformat==ff_ttfsym ) /* MS Symbol font has this set to zero. Does it matter? */ - memset(os2->unicoderange,0,sizeof(os2->unicoderange)); - - if ( sf->pfminfo.pfmset ) - strncpy(os2->achVendID,sf->pfminfo.os2_vendor,4); - else if ( TTFFoundry!=NULL ) - strncpy(os2->achVendID,TTFFoundry,4); - else - memcpy(os2->achVendID,"PfEd",4); - for ( pt=os2->achVendID; pt<os2->achVendID && *pt!='\0'; ++pt ); - while ( pt<os2->achVendID ) *pt++ = ' '; /* Pad with spaces not NUL */ - - /* v1,2 & v3,4 have different ways of calculating avgCharWid. */ - /* but I'm told that using the v3 way breaks display of CJK fonts in windows */ - os2->avgCharWid = 500; - os2->v1_avgCharWid = os2->v3_avgCharWid = 0; - if ( cnt1==27 ) - os2->v1_avgCharWid = avg1/1000; - if ( cnt2!=0 ) - os2->v3_avgCharWid = avg2/cnt2; - memcpy(os2->panose,sf->pfminfo.panose,sizeof(os2->panose)); - map = at->map; - if ( modformat==ff_ttfsym ) { - if ( sf->pfminfo.hascodepages ) - memcpy(os2->ulCodePage,sf->pfminfo.codepages,sizeof(os2->ulCodePage)); - else { - os2->ulCodePage[0] = 0x80000000; - os2->ulCodePage[1] = 0; - } - if ( AlreadyMSSymbolArea(sf,map)) { - first = 0xf0ff; last = 0; - for ( i=0xf020; i<map->enccount && i<=0xf0ff; ++i ) - if ( (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL && - sf->glyphs[gid]->ttf_glyph!=-1 ) { - if ( i<first ) first = i; - if ( i>last ) last = i; - } - for ( i=0; i<map->enccount && i<=255; ++i ) - if ( (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL && - sf->glyphs[gid]->ttf_glyph!=-1 ) { - if ( i+0xf000<first ) first = i+0xf000; - if ( i+0xf000>last ) last = i+0xf000; - } - os2->firstcharindex = first; /* This gets mapped to space */ - os2->lastcharindex = last; - } else { - first = 255; last = 0; - for ( i=0; i<map->enccount && i<=255; ++i ) - if ( (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL && - sf->glyphs[gid]->ttf_glyph!=-1 ) { - if ( i<first ) first = i; - if ( i>last ) last = i; - } - for ( i=0xf020; i<map->enccount && i<=0xf0ff; ++i ) - if ( (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL && - sf->glyphs[gid]->ttf_glyph!=-1 ) { - if ( i-0xf000<first ) first = i-0xf000; - if ( i-0xf000>last ) last = i-0xf000; - } - if ( first<' ' ) first = ' '; - os2->firstcharindex = 0xf000 + first; /* This gets mapped to space */ - os2->lastcharindex = 0xf000 + last; - } - } else { - os2->firstcharindex = first; - os2->lastcharindex = last; - if ( sf->pfminfo.hascodepages ) - memcpy(os2->ulCodePage,sf->pfminfo.codepages,sizeof(os2->ulCodePage)); - else - OS2FigureCodePages(sf, os2->ulCodePage); - /* Herbert Duerr: */ - /* Some old versions of Windows do not provide access to all */ - /* glyphs in a font if the fonts contains non-PUA symbols */ - /* and thus only has sets the codepage flag for symbol */ - /* => a workaround for this problem on Windows legacy versions */ - /* is to use an OS2-table version without codepage flags */ - /* GWW: */ - /* This sounds to me like a windows bug rather than one in ff */ - /* and this is a work-around for windows. As far as I can tell */ - /* ff is setting the codepage field properly, it's just that */ - /* windows doesn't interpret that bit correctly */ - /* GWW: Things get worse. Windows no longer accepts a version 0 */ - /* for OS/2. FontLab simply lies and says we have a latin1 */ - /* code page when we don't. */ - if( !sf->pfminfo.hascodepages ) - if( (os2->ulCodePage[0]&~(1U<<31))==0 && os2->ulCodePage[1]==0 ) - os2->ulCodePage[0] |= 1; - } - - if ( os2->version>=2 ) { - if ( sf->pfminfo.os2_xheight!=0 ) - os2->xHeight = sf->pfminfo.os2_xheight; - else { - double xh = SFXHeight(sf,at->gi.layer,true); - os2->xHeight = (xh >= 0.0 ? xh : 0); - } - if ( sf->pfminfo.os2_capheight!=0 ) - os2->capHeight = sf->pfminfo.os2_capheight; - else { - double caph = SFCapHeight(sf,at->gi.layer,true); - os2->capHeight = (caph >= 0.0 ? caph : 0); - } - os2->defChar = 0; - if ( format==ff_otf || format==ff_otfcid ) - os2->defChar = ' '; - os2->breakChar = ' '; - os2->maxContext = 1; /* Kerning will set this to 2, ligature to whatever */ - } - - if ( os2->version>=3 && os2->v3_avgCharWid!=0 ) - os2->avgCharWid = os2->v3_avgCharWid; - else if ( os2->v1_avgCharWid!=0 ) - os2->avgCharWid = os2->v1_avgCharWid; - else if ( os2->v3_avgCharWid!=0 ) - os2->avgCharWid = os2->v3_avgCharWid; -} - -static void redoloca(struct alltabs *at) { - int i; - - at->loca = tmpfile2(); - if ( at->head.locais32 ) { - for ( i=0; i<=at->maxp.numGlyphs; ++i ) - putlong(at->loca,at->gi.loca[i]); - at->localen = sizeof(int32)*(at->maxp.numGlyphs+1); - } else { - for ( i=0; i<=at->maxp.numGlyphs; ++i ) - putshort(at->loca,at->gi.loca[i]/2); - at->localen = sizeof(int16)*(at->maxp.numGlyphs+1); - if ( ftell(at->loca)&2 ) - putshort(at->loca,0); - } - if ( at->format!=ff_type42 && at->format!=ff_type42cid ) { - free(at->gi.loca); - at->gi.loca = NULL; - } -} - -static void dummyloca(struct alltabs *at) { - - at->loca = tmpfile2(); - if ( at->head.locais32 ) { - putlong(at->loca,0); - at->localen = sizeof(int32); - } else { - putshort(at->loca,0); - at->localen = sizeof(int16); - putshort(at->loca,0); /* pad it */ - } -} - -static void redohead(struct alltabs *at) { - at->headf = tmpfile2(); - - putlong(at->headf,at->head.version); - putlong(at->headf,at->head.revision); - putlong(at->headf,at->head.checksumAdj); - putlong(at->headf,at->head.magicNum); - putshort(at->headf,at->head.flags); - putshort(at->headf,at->head.emunits); - putlong(at->headf,at->head.createtime[1]); - putlong(at->headf,at->head.createtime[0]); - putlong(at->headf,at->head.modtime[1]); - putlong(at->headf,at->head.modtime[0]); - putshort(at->headf,at->head.xmin); - putshort(at->headf,at->head.ymin); - putshort(at->headf,at->head.xmax); - putshort(at->headf,at->head.ymax); - putshort(at->headf,at->head.macstyle); - putshort(at->headf,at->head.lowestreadable); - putshort(at->headf,at->head.dirhint); - putshort(at->headf,at->head.locais32); - putshort(at->headf,at->head.glyphformat); - - at->headlen = ftell(at->headf); - if ( (at->headlen&2)!=0 ) - putshort(at->headf,0); -} - -static void redohhead(struct alltabs *at,int isv) { - int i; - struct hhead *head; - FILE *f; - - if ( !isv ) { - f = at->hheadf = tmpfile2(); - head = &at->hhead; - } else { - f = at->vheadf = tmpfile2(); - head = &at->vhead; - } - - putlong(f,head->version); - putshort(f,head->ascender); - putshort(f,head->descender); - putshort(f,head->linegap); - putshort(f,head->maxwidth); - putshort(f,head->minlsb); - putshort(f,head->minrsb); - putshort(f,head->maxextent); - putshort(f,head->caretSlopeRise); - putshort(f,head->caretSlopeRun); - for ( i=0; i<5; ++i ) - putshort(f,head->mbz[i]); - putshort(f,head->metricformat); - putshort(f,head->numMetrics); - - if ( !isv ) { - at->hheadlen = ftell(f); - if ( (at->hheadlen&2)!=0 ) - putshort(f,0); - } else { - at->vheadlen = ftell(f); - if ( (at->vheadlen&2)!=0 ) - putshort(f,0); - } -} - -static void redomaxp(struct alltabs *at,enum fontformat format) { - at->maxpf = tmpfile2(); - - putlong(at->maxpf,at->maxp.version); - putshort(at->maxpf,at->maxp.numGlyphs); - if ( format!=ff_otf && format!=ff_otfcid ) { - putshort(at->maxpf,at->maxp.maxPoints); - putshort(at->maxpf,at->maxp.maxContours); - putshort(at->maxpf,at->maxp.maxCompositPts); - putshort(at->maxpf,at->maxp.maxCompositCtrs); - putshort(at->maxpf,at->maxp.maxZones); - putshort(at->maxpf,at->maxp.maxTwilightPts); - putshort(at->maxpf,at->maxp.maxStorage); - putshort(at->maxpf,at->maxp.maxFDEFs); - putshort(at->maxpf,at->maxp.maxIDEFs); - putshort(at->maxpf,at->maxp.maxStack); - putshort(at->maxpf,at->maxp.maxglyphInstr); - putshort(at->maxpf,at->maxp.maxnumcomponents); - putshort(at->maxpf,at->maxp.maxcomponentdepth); - } - - at->maxplen = ftell(at->maxpf); - if ( (at->maxplen&2)!=0 ) - putshort(at->maxpf,0); -} - -static void redoos2(struct alltabs *at) { - int i; - at->os2f = tmpfile2(); - - putshort(at->os2f,at->os2.version); - putshort(at->os2f,at->os2.avgCharWid); - putshort(at->os2f,at->os2.weightClass); - putshort(at->os2f,at->os2.widthClass); - putshort(at->os2f,at->os2.fstype); - putshort(at->os2f,at->os2.ysubXSize); - putshort(at->os2f,at->os2.ysubYSize); - putshort(at->os2f,at->os2.ysubXOff); - putshort(at->os2f,at->os2.ysubYOff); - putshort(at->os2f,at->os2.ysupXSize); - putshort(at->os2f,at->os2.ysupYSize); - putshort(at->os2f,at->os2.ysupXOff); - putshort(at->os2f,at->os2.ysupYOff); - putshort(at->os2f,at->os2.yStrikeoutSize); - putshort(at->os2f,at->os2.yStrikeoutPos); - putshort(at->os2f,at->os2.sFamilyClass); - for ( i=0; i<10; ++i ) - putc(at->os2.panose[i],at->os2f); - for ( i=0; i<4; ++i ) - putlong(at->os2f,at->os2.unicoderange[i]); - for ( i=0; i<4; ++i ) - putc(at->os2.achVendID[i],at->os2f); - putshort(at->os2f,at->os2.fsSel); - putshort(at->os2f,at->os2.firstcharindex); - putshort(at->os2f,at->os2.lastcharindex); - putshort(at->os2f,at->os2.ascender); - putshort(at->os2f,at->os2.descender); - putshort(at->os2f,at->os2.linegap); - putshort(at->os2f,at->os2.winascent); - putshort(at->os2f,at->os2.windescent); - if ( at->os2.version>=1 ) { - putlong(at->os2f,at->os2.ulCodePage[0]); - putlong(at->os2f,at->os2.ulCodePage[1]); - } - - if ( at->os2.version>=2 ) { - putshort(at->os2f,at->os2.xHeight); - putshort(at->os2f,at->os2.capHeight); - putshort(at->os2f,at->os2.defChar); - putshort(at->os2f,at->os2.breakChar); - putshort(at->os2f,at->os2.maxContext); - } - - at->os2len = ftell(at->os2f); - if ( (at->os2len&2)!=0 ) - putshort(at->os2f,0); -} - -static void dumpgasp(struct alltabs *at, SplineFont *sf) { - int i; - - at->gaspf = tmpfile2(); - if ( sf->gasp_cnt==0 ) { - putshort(at->gaspf,0); /* Old version number */ - /* For fonts with no instructions always dump a gasp table which */ - /* asks for grey and no grid fit */ - putshort(at->gaspf,1); - putshort(at->gaspf,0xffff); /* Upper bound on pixels/em for this range */ - putshort(at->gaspf,0x2); /* Grey scale, no gridfitting */ - /* No hints, so no grids to fit */ - } else { - putshort(at->gaspf,sf->gasp_version); /* New version number, with clear type info */ - putshort(at->gaspf,sf->gasp_cnt); - for ( i=0; i<sf->gasp_cnt; ++i ) { - putshort(at->gaspf,sf->gasp[i].ppem); - putshort(at->gaspf,sf->gasp[i].flags); - } - } - at->gasplen = ftell(at->gaspf); - /* This table is always 32 bit aligned */ -} - -static void dumpstr(FILE *file,char *str) { - do { - putc(*str,file); - } while ( *str++!='\0' ); -} - -static void dumpustr(FILE *file,char *utf8_str) { - unichar_t *ustr = utf82u_copy(utf8_str), *pt=ustr; - do { - putc(*pt>>8,file); - putc(*pt&0xff,file); - } while ( *pt++!='\0' ); - free(ustr); -} - -static void dumppstr(FILE *file,const char *str) { - putc(strlen(str),file); - fwrite(str,sizeof(char),strlen(str),file); -} - -char *utf8_verify_copy(const char *str) { - /* When given a postscript string it SHOULD be in ASCII. But it will often*/ - /* contain a copyright symbol (sometimes in latin1, sometimes in macroman)*/ - /* unfortunately both encodings use 0xa9 for copyright so we can't distinguish */ - /* guess that it's latin1 (or that copyright is the only odd char which */ - /* means a latin1 conversion will work for macs too). */ - - if ( str==NULL ) -return( NULL ); - - if ( utf8_valid(str)) -return( copy(str)); /* Either in ASCII (good) or appears to be utf8*/ -return( latin1_2_utf8_copy(str)); -} - -/* Oh. If the encoding is symbol (platform=3, specific=0) then Windows won't */ -/* accept the font unless the name table also has entries for (3,0). I'm not */ -/* sure if this is the case for the CJK encodings (docs don't mention that) */ -/* but let's do it just in case */ -void DefaultTTFEnglishNames(struct ttflangname *dummy, SplineFont *sf) { - time_t now; - struct tm *tm; - char buffer[200]; - - if ( dummy->names[ttf_copyright]==NULL || *dummy->names[ttf_copyright]=='\0' ) - dummy->names[ttf_copyright] = utf8_verify_copy(sf->copyright); - if ( dummy->names[ttf_family]==NULL || *dummy->names[ttf_family]=='\0' ) - dummy->names[ttf_family] = utf8_verify_copy(sf->familyname); - if ( dummy->names[ttf_subfamily]==NULL || *dummy->names[ttf_subfamily]=='\0' ) - dummy->names[ttf_subfamily] = utf8_verify_copy(SFGetModifiers(sf)); - if ( dummy->names[ttf_uniqueid]==NULL || *dummy->names[ttf_uniqueid]=='\0' ) { - time(&now); - tm = localtime(&now); - sprintf( buffer, "%s : %s : %d-%d-%d", - TTFFoundry?TTFFoundry:"FontForge 2.0", - sf->fullname!=NULL?sf->fullname:sf->fontname, - tm->tm_mday, tm->tm_mon+1, tm->tm_year+1900 ); - dummy->names[ttf_uniqueid] = copy(buffer); - } - if ( dummy->names[ttf_fullname]==NULL || *dummy->names[ttf_fullname]=='\0' ) - dummy->names[ttf_fullname] = utf8_verify_copy(sf->fullname); - if ( dummy->names[ttf_version]==NULL || *dummy->names[ttf_version]=='\0' ) { - if ( sf->subfontcnt!=0 ) - sprintf( buffer, "Version %f ", (double)sf->cidversion ); - else if ( sf->version!=NULL ) - sprintf(buffer,"Version %.20s ", sf->version); - else - strcpy(buffer,"Version 1.0" ); - dummy->names[ttf_version] = copy(buffer); - } - if ( dummy->names[ttf_postscriptname]==NULL || *dummy->names[ttf_postscriptname]=='\0' ) - dummy->names[ttf_postscriptname] = utf8_verify_copy(sf->fontname); -} - -typedef struct { - uint16 platform; - uint16 specific; - uint16 lang; - uint16 strid; - uint16 len; - uint16 offset; -} NameEntry; - -typedef struct { - FILE *strings; - int cur, max; - enum fontformat format; - Encoding *encoding_name; - NameEntry *entries; - int applemode; -} NamTab; - -static int compare_entry(const void *_mn1, const void *_mn2) { - const NameEntry *mn1 = _mn1, *mn2 = _mn2; - - if ( mn1->platform!=mn2->platform ) -return( mn1->platform - mn2->platform ); - if ( mn1->specific!=mn2->specific ) -return( mn1->specific - mn2->specific ); - if ( mn1->lang!=mn2->lang ) -return( mn1->lang - mn2->lang ); - -return( mn1->strid-mn2->strid ); -} - -static void AddEncodedName(NamTab *nt,char *utf8name,uint16 lang,uint16 strid) { - NameEntry *ne; - int maclang, macenc= -1, specific; - char *macname = NULL; - - if ( strid==ttf_postscriptname && lang!=0x409 ) -return; /* Should not happen, but it did */ - - if ( nt->cur+6>=nt->max ) { - if ( nt->cur==0 ) - nt->entries = malloc((nt->max=100)*sizeof(NameEntry)); - else - nt->entries = realloc(nt->entries,(nt->max+=100)*sizeof(NameEntry)); - } - - ne = nt->entries + nt->cur; - - ne->platform = 3; /* Windows */ - ne->specific = 1; /* unicode */ - ne->lang = lang; - ne->strid = strid; - ne->offset = ftell(nt->strings); - ne->len = 2*utf82u_strlen(utf8name); - dumpustr(nt->strings,utf8name); - ++ne; - - if ( nt->format==ff_ttfsym ) { - *ne = ne[-1]; - ne->specific = 0; /* Windows "symbol" */ - ++ne; - } - - maclang = WinLangToMac(lang); - if ( !nt->applemode && lang!=0x409 ) - maclang = 0xffff; - if ( maclang!=0xffff ) { -#ifdef FONTFORGE_CONFIG_APPLE_UNICODE_NAMES - if ( strid!=ttf_postscriptname ) { - *ne = ne[-1]; - ne->platform = 0; /* Mac unicode */ - ne->specific = 0; /* 3 => Unicode 2.0 semantics */ /* 0 ("default") is also a reasonable value */ - ne->lang = maclang; - ++ne; - } -#endif - - macenc = MacEncFromMacLang(maclang); - macname = Utf8ToMacStr(utf8name,macenc,maclang); - if ( macname!=NULL ) { - ne->platform = 1; /* apple non-unicode encoding */ - ne->specific = macenc; /* whatever */ - ne->lang = maclang; - ne->strid = strid; - ne->offset = ftell(nt->strings); - ne->len = strlen(macname); - dumpstr(nt->strings,macname); - ++ne; - free(macname); - } - } - - specific = nt->encoding_name->is_korean ? 5 : /* Wansung, korean */ - nt->encoding_name->is_japanese ? 2 : /* SJIS */ - nt->encoding_name->is_simplechinese ? 3 :/* packed gb2312, don't know the real name */ - strmatch(nt->encoding_name->enc_name,"EUC-GB12345")==0 ? 3 :/* Lie */ - nt->encoding_name->is_tradchinese ? 4 : /* Big5, traditional Chinese */ - -1; - if ( specific != -1 ) { - ne->platform = 3; /* windows */ - ne->specific = specific; /* whatever */ - ne->lang = lang; - ne->strid = strid; - if ( macname!=NULL && - (( specific== 2 && macenc==1 ) || /* Japanese */ - ( specific== 3 && macenc==25 ) || /* simplified chinese */ - ( specific== 4 && macenc==2 ) || /* traditional chinese */ - ( specific== 5 && macenc==3 )) ) { /* wansung korean */ - ne->offset = ne[-1].offset; - ne->len = ne[-1].len; - } else { - char *space, *out; - const char *encname; - ICONV_CONST char *in; - Encoding *enc; - size_t inlen, outlen; - ne->offset = ftell(nt->strings); - encname = nt->encoding_name->is_japanese ? "SJIS" : - strmatch(nt->encoding_name->enc_name,"JOHAB")==0 ? "JOHAB" : - nt->encoding_name->is_korean ? "EUC-KR" : - nt->encoding_name->is_simplechinese ? "EUC-CN" : - nt->encoding_name->enc_name; - enc = FindOrMakeEncoding(encname); - if ( enc==NULL ) - --ne; - else { - unichar_t *uin = utf82u_copy(utf8name); - outlen = 3*strlen(utf8name)+10; - out = space = malloc(outlen+2); - in = (char *) uin; inlen = 2*u_strlen(uin); - iconv(enc->fromunicode,NULL,NULL,NULL,NULL); /* should not be needed, but just in case */ - iconv(enc->fromunicode,&in,&inlen,&out,&outlen); - out[0] = '\0'; out[1] = '\0'; - ne->offset = ftell(nt->strings); - ne->len = strlen(space); - dumpstr(nt->strings,space); - free(space); free(uin); - } - } - ++ne; - } - nt->cur = ne - nt->entries; -} - -static void AddMacName(NamTab *nt,struct macname *mn, int strid) { - NameEntry *ne; - - if ( nt->cur+1>=nt->max ) { - if ( nt->cur==0 ) - nt->entries = malloc((nt->max=100)*sizeof(NameEntry)); - else - nt->entries = realloc(nt->entries,(nt->max+=100)*sizeof(NameEntry)); - } - - ne = nt->entries + nt->cur; - - ne->platform = 1; /* apple non-unicode encoding */ - ne->specific = mn->enc; /* whatever */ - ne->lang = mn->lang; - ne->strid = strid; - ne->offset = ftell(nt->strings); - ne->len = strlen(mn->name); - dumpstr(nt->strings,mn->name); - - ++nt->cur; -} - -/* There's an inconsistancy here. Apple's docs say there most be only one */ -/* nameid==6 and that name must be ascii (presumably plat=1, spec=0, lang=0) */ -/* The opentype docs say there must be two (psl=1,0,0 & psl=3,1,0x409) any */ -/* others are to be ignored */ -/* A representative from Apple says they will change their spec to accept */ -/* the opentype version, and tells me that they don't currently care */ -/* So ignore this */ -/* Undocumented fact: Windows insists on having a UniqueID string 3,1 */ -static void dumpnames(struct alltabs *at, SplineFont *sf,enum fontformat format) { - int i,j; - struct ttflangname dummy, *cur, *useng = NULL; - struct macname *mn; - struct other_names *on, *onn; - NamTab nt; - struct otfname *otfn; - struct otffeatname *fn; - - memset(&nt,0,sizeof(nt)); - nt.encoding_name = at->map->enc; - nt.format = format; - nt.applemode = at->applemode; - nt.strings = tmpfile2(); - if (( format>=ff_ttf && format<=ff_otfdfont) && (at->gi.flags&ttf_flag_symbol)) - nt.format = ff_ttfsym; - - memset(&dummy,0,sizeof(dummy)); - for ( cur=sf->names; cur!=NULL; cur=cur->next ) { - if ( cur->lang==0x409 ) { - dummy = *cur; - useng = cur; - break; - } - } - DefaultTTFEnglishNames(&dummy, sf); - - for ( i=0; i<ttf_namemax; ++i ) if ( dummy.names[i]!=NULL ) - AddEncodedName(&nt,dummy.names[i],0x409,i); - for ( cur=sf->names; cur!=NULL; cur=cur->next ) { - if ( cur->lang!=0x409 ) - for ( i=0; i<ttf_namemax; ++i ) - if ( cur->names[i]!=NULL ) - AddEncodedName(&nt,cur->names[i],cur->lang,i); - } - - /* The examples I've seen of the feature table only contain platform==mac */ - /* so I'm not including apple unicode */ - if ( at->feat_name!=NULL ) { - for ( i=0; at->feat_name[i].strid!=0; ++i ) { - for ( mn=at->feat_name[i].mn; mn!=NULL; mn=mn->next ) - AddMacName(&nt,mn,at->feat_name[i].strid); - /* I'm not sure why I keep track of these alternates (feat_name[i].smn) */ - /* Dumping them out is a bad idea. It might be worth */ - /* something if we searched through the alternate sets for languages */ - /* not found in the main set, but at the moment I don't think so */ - /* What happens now if I do it is that I get duplicate names output. */ - } - } - /* And the names used by the fvar table aren't mac unicode either */ - for ( on = at->other_names; on!=NULL; on=onn ) { - for ( mn = on->mn; mn!=NULL ; mn = mn->next ) - AddMacName(&nt,mn,on->strid); - onn = on->next; - chunkfree(on,sizeof(*on)); - } - /* Wow, the GPOS 'size' feature uses the name table in a very mac-like way*/ - if ( at->fontstyle_name_strid!=0 && sf->fontstyle_name!=NULL ) { - for ( otfn = sf->fontstyle_name; otfn!=NULL; otfn = otfn->next ) - AddEncodedName(&nt,otfn->name,otfn->lang,at->fontstyle_name_strid); - } - /* As do some other features now */ - for ( fn = sf->feat_names; fn!=NULL; fn=fn->next ) { - for ( otfn = fn->names; otfn!=NULL; otfn = otfn->next ) - AddEncodedName(&nt,otfn->name,otfn->lang,fn->nid); - } - - qsort(nt.entries,nt.cur,sizeof(NameEntry),compare_entry); - - at->name = tmpfile2(); - putshort(at->name,0); /* format */ - putshort(at->name,nt.cur); /* numrec */ - putshort(at->name,(3+nt.cur*6)*sizeof(int16)); /* offset to strings */ - - for ( i=0; i<nt.cur; ++i ) { - putshort(at->name,nt.entries[i].platform); - putshort(at->name,nt.entries[i].specific); - putshort(at->name,nt.entries[i].lang); - putshort(at->name,nt.entries[i].strid); - putshort(at->name,nt.entries[i].len); - putshort(at->name,nt.entries[i].offset); - } - if ( !ttfcopyfile(at->name,nt.strings,(3+nt.cur*6)*sizeof(int16),"name-data")) - at->error = true; - - at->namelen = ftell(at->name); - if ( (at->namelen&3)!=0 ) - for ( j= 4-(at->namelen&3); j>0; --j ) - putc('\0',at->name); - - for ( i=0; i<ttf_namemax; ++i ) - if ( useng==NULL || dummy.names[i]!=useng->names[i] ) - free( dummy.names[i]); - free( nt.entries ); - free( at->feat_name ); - - /* Windows at one point refused to load fonts with 'name' tables bigger than 5K (decided they were insecure). */ -} - -static void dumppost(struct alltabs *at, SplineFont *sf, enum fontformat format) { - int pos, i,j, shouldbe; - int shorttable = (format==ff_otf || format==ff_otfcid || - (at->gi.flags&ttf_flag_shortps)); - uint32 here; - - at->post = tmpfile2(); - - putlong(at->post,shorttable?0x00030000:0x00020000); /* formattype */ - putfixed(at->post,sf->italicangle); - putshort(at->post,sf->upos-sf->uwidth/2); /* 'post' defn says top of rect, while FontInfo def says center of rect */ - putshort(at->post,sf->uwidth); - putlong(at->post,at->isfixed); - putlong(at->post,0); /* no idea about memory */ - putlong(at->post,0); /* no idea about memory */ - putlong(at->post,0); /* no idea about memory */ - putlong(at->post,0); /* no idea about memory */ - if ( !shorttable ) { - here = ftell(at->post); - putshort(at->post,at->maxp.numGlyphs); - - shouldbe = 0; - for ( i=0, pos=0; i<at->maxp.numGlyphs; ++i ) { - if ( at->gi.bygid[i]!=-1 && sf->glyphs[at->gi.bygid[i]]!=NULL ) { - SplineChar *sc = sf->glyphs[at->gi.bygid[i]]; - while ( i>shouldbe ) { - if ( shouldbe==0 ) - putshort(at->post,0); /* glyph 0 is named .notdef */ - else if ( shouldbe==1 ) - putshort(at->post,1); /* glyphs 1&2 are .null and cr */ - else if ( shouldbe==2 ) - putshort(at->post,2); /* or something */ - else - putshort(at->post,0); - ++shouldbe; - } - if ( strcmp(sc->name,".notdef")==0 ) - putshort(at->post,0); - else { - for ( j=0; j<258; ++j ) - if ( strcmp(sc->name,ttfstandardnames[j])==0 ) - break; - if ( j!=258 ) - putshort(at->post,j); - else { - putshort(at->post,pos+258); - ++pos; - } - } - ++shouldbe; - } - } - - if ( shouldbe!=at->maxp.numGlyphs ) { - fseek(at->post,here,SEEK_SET); - putshort(at->post,shouldbe); - fseek(at->post,0,SEEK_END); - } - if ( pos!=0 ) { - for ( i=0; i<at->maxp.numGlyphs; ++i ) if ( at->gi.bygid[i]!=-1 ) { - SplineChar *sc = sf->glyphs[at->gi.bygid[i]]; - if ( strcmp(sc->name,".notdef")==0 ) - /* Do Nothing */; - else { - for ( j=0; j<258; ++j ) - if ( strcmp(sc->name,ttfstandardnames[j])==0 ) - break; - if ( j!=258 ) - /* Do Nothing */; - else - dumppstr(at->post,sc->name); - } - } - } - } - at->postlen = ftell(at->post); - if ( (at->postlen&3)!=0 ) - for ( j= 4-(at->postlen&3); j>0; --j ) - putc('\0',at->post); -} - -static FILE *_Gen816Enc(SplineFont *sf,int *tlen,EncMap *map) { - int i, j, complained, pos, k, subheadindex, jj, isbig5=false; - uint16 table[256]; - struct subhead subheads[128]; - uint16 *glyphs; - uint16 tempglyphs[256]; - int base, lbase, basebound, subheadcnt, planesize, plane0size; - int base2, base2bound; - FILE *sub; - const char *encname = map->enc->iconv_name!=NULL ? map->enc->iconv_name : map->enc->enc_name; - - *tlen = 0; - - base2 = -1; base2bound = -2; - if ( map->enc->is_tradchinese && strstrmatch(encname,"hkscs")!=NULL ) { - base = 0x81; - basebound = 0xfe; - subheadcnt = basebound-base+1; - lbase = 0x40; - planesize = 191; - } else if ( map->enc->is_tradchinese || sf->uni_interp==ui_trad_chinese) { - base = 0xa1; - basebound = 0xf9; /* wcl-02.ttf's cmap claims to go up to fc, but everything after f9 is invalid (according to what I know of big5, f9 should be the end) */ - subheadcnt = basebound-base+1; - lbase = 0x40; - planesize = 191; - isbig5 = true; - } else if ( strstrmatch(encname,"euc")!=NULL ) { - base = 0xa1; - basebound = 0xfd; - lbase = 0xa1; - subheadcnt = basebound-base+1; - planesize = 0xfe - lbase +1; - } else if ( strstrmatch(encname,"johab")!=NULL ) { - base = 0x84; - basebound = 0xf9; - lbase = 0x31; - subheadcnt = basebound-base+1; - planesize = 0xfe -0x31+1; /* Stupid gcc bug, thinks 0xfe- is ambiguous (exponant) */ - } else if ( strstrmatch(encname,"sjis")!=NULL || strstrmatch(encname,"cp932")!=NULL ) { - base = 129; - basebound = 159; - lbase = 64; - planesize = 252 - lbase +1; - base2 = 0xe0; - /* SJIS supports "user defined characters" between 0xf040 and 0xfcfc */ - /* there probably won't be any, but allow space for them if there are*/ - for ( base2bound=0xfc00; base2bound>0xefff; --base2bound ) - if ( base2bound<map->enccount && map->map[base2bound]!=-1 && - SCWorthOutputting(sf->glyphs[map->map[base2bound]])) - break; - base2bound >>= 8; - subheadcnt = basebound-base + 1 + base2bound-base2 + 1; - } else { - IError( "Unsupported 8/16 encoding %s\n", map->enc->enc_name ); -return( NULL ); - } - plane0size = base2==-1? base : base2; - i=0; - if ( base2!=-1 ) { - for ( i=basebound; i<base2 && i<map->enccount; ++i ) - if ( map->map[i]==-1 ) - continue; - else if ( SCWorthOutputting(sf->glyphs[map->map[i]])) - break; - if ( i==base2 || i==map->enccount ) - i = 0; - } - if ( i==0 ) { - for ( i=0; i<base && i<map->enccount; ++i ) - if ( map->map[i]==-1 ) - continue; - else if ( SCWorthOutputting(sf->glyphs[map->map[i]])) - break; - } - if ( base2!=-1 ) { - for ( i=base; i<=basebound && i<map->enccount; ++i ) - if ( map->map[i]!=-1 && SCWorthOutputting(sf->glyphs[map->map[i]])) { - ff_post_error(_("Bad Encoding"),_("There is a single byte character (%d) using one of the slots needed for double byte characters"),i); - break; - } - if ( i==basebound+1 ) - for ( i=base2; i<256 && i<map->enccount; ++i ) - if ( map->map[i]!=-1 && SCWorthOutputting(sf->glyphs[map->map[i]])) { - ff_post_error(_("Bad Encoding"),_("There is a single byte character (%d) using one of the slots needed for double byte characters"),i); - break; - } - } else { - for ( i=base; i<=256 && i<map->enccount; ++i ) - if ( map->map[i]!=-1 && SCWorthOutputting(sf->glyphs[map->map[i]])) { - ff_post_error(_("Bad Encoding"),_("There is a single byte character (%d) using one of the slots needed for double byte characters"),i); - break; - } - } - for ( i=256; i<(base<<8) && i<map->enccount; ++i ) - if ( map->map[i]!=-1 && SCWorthOutputting(sf->glyphs[map->map[i]])) { - ff_post_error(_("Bad Encoding"),_("There is a character (%d) which cannot be encoded"),i); - break; - } - if ( i==(base<<8) && base2==-1 ) - for ( i=((basebound+1)<<8); i<0x10000 && i<map->enccount; ++i ) - if ( map->map[i]!=-1 && SCWorthOutputting(sf->glyphs[map->map[i]])) { - ff_post_error(_("Bad Encoding"),_("There is a character (%d) which cannot be encoded"),i); - break; - } - - memset(table,'\0',sizeof(table)); - for ( i=base; i<=basebound; ++i ) - table[i] = 8*(i-base+1); - for ( i=base2; i<=base2bound; ++i ) - table[i] = 8*(i-base2+basebound-base+1+1); - memset(subheads,'\0',sizeof(subheads)); - subheads[0].first = 0; subheads[0].cnt = plane0size; - for ( i=1; i<subheadcnt+1; ++i ) { - subheads[i].first = lbase; - subheads[i].cnt = planesize; - } - glyphs = calloc(subheadcnt*planesize+plane0size,sizeof(uint16)); - subheads[0].rangeoff = 0; - for ( i=0; i<plane0size && i<map->enccount; ++i ) - if ( map->map[i]!=-1 && sf->glyphs[map->map[i]]!=NULL && - sf->glyphs[map->map[i]]->ttf_glyph!=-1 ) - glyphs[i] = sf->glyphs[map->map[i]]->ttf_glyph; - - pos = 1; - - complained = false; - subheadindex = 1; - for ( jj=0; jj<2 || (base2==-1 && jj<1); ++jj ) - for ( j=((jj==0?base:base2)<<8); j<=((jj==0?basebound:base2bound)<<8); j+= 0x100 ) { - for ( i=0; i<lbase; ++i ) - if ( !complained && map->map[i+j]!=-1 && - SCWorthOutputting(sf->glyphs[map->map[i+j]])) { - ff_post_error(_("Bad Encoding"),_("There is a character (%d) which is not normally in the encoding"),i+j); - complained = true; - } - if ( isbig5 ) { - /* big5 has a gap here. Does johab? */ - for ( i=0x7f; i<0xa1; ++i ) - if ( !complained && map->map[i+j]!=-1 && - SCWorthOutputting(sf->glyphs[map->map[i+j]])) { - ff_post_error(_("Bad Encoding"),_("There is a character (%d) which is not normally in the encoding"),i+j); - complained = true; - } - } - memset(tempglyphs,0,sizeof(tempglyphs)); - for ( i=0; i<planesize; ++i ) - if ( map->map[j+lbase+i]!=-1 && sf->glyphs[map->map[j+lbase+i]]!=NULL && - sf->glyphs[map->map[j+lbase+i]]->ttf_glyph!=-1 ) - tempglyphs[i] = sf->glyphs[map->map[j+lbase+i]]->ttf_glyph; - for ( i=1; i<pos; ++i ) { - int delta = 0; - for ( k=0; k<planesize; ++k ) - if ( tempglyphs[k]==0 && glyphs[plane0size+(i-1)*planesize+k]==0 ) - /* Still matches */; - else if ( tempglyphs[k]==0 || glyphs[plane0size+(i-1)*planesize+k]==0 ) - break; /* Doesn't match */ - else if ( delta==0 ) - delta = (uint16) (tempglyphs[k]-glyphs[plane0size+(i-1)*planesize+k]); - else if ( tempglyphs[k]==(uint16) (glyphs[plane0size+(i-1)*planesize+k]+delta) ) - /* Still matches */; - else - break; - if ( k==planesize ) { - subheads[subheadindex].delta = delta; - subheads[subheadindex].rangeoff = plane0size+(i-1)*planesize; - break; - } - } - if ( subheads[subheadindex].rangeoff==0 ) { - memcpy(glyphs+(pos-1)*planesize+plane0size,tempglyphs,planesize*sizeof(uint16)); - subheads[subheadindex].rangeoff = plane0size+(pos++-1)*planesize ; - } - ++subheadindex; - } - - /* fixup offsets */ - /* my rangeoffsets are indexes into the glyph array. That's nice and */ - /* simple. Unfortunately ttf says they are offsets from the current */ - /* location in the file (sort of) so we now fix them up. */ - for ( i=0; i<subheadcnt+1; ++i ) - subheads[i].rangeoff = subheads[i].rangeoff*sizeof(uint16) + - (subheadcnt-i)*sizeof(struct subhead) + sizeof(uint16); - - sub = tmpfile2(); - if ( sub==NULL ) -return( NULL ); - - putshort(sub,2); /* 8/16 format */ - putshort(sub,0); /* Subtable length, we'll come back and fix this */ - putshort(sub,0); /* version/language, not meaningful in ms systems */ - for ( i=0; i<256; ++i ) - putshort(sub,table[i]); - for ( i=0; i<subheadcnt+1; ++i ) { - putshort(sub,subheads[i].first); - putshort(sub,subheads[i].cnt); - putshort(sub,subheads[i].delta); - putshort(sub,subheads[i].rangeoff); - } - for ( i=0; i<(pos-1)*planesize+plane0size; ++i ) - putshort(sub,glyphs[i]); - free(glyphs); - - *tlen = ftell(sub); - fseek(sub,2,SEEK_SET); - putshort(sub,*tlen); /* Length, I said we'd come back to it */ - rewind( sub ); -return( sub ); -} - -static FILE *Needs816Enc(SplineFont *sf,int *tlen,EncMap *map, FILE **apple, int *appletlen) { - FILE *sub; - const char *encname = map->enc->iconv_name!=NULL ? map->enc->iconv_name : map->enc->enc_name; - EncMap *oldmap = map; - EncMap *applemap = NULL; - Encoding *enc; - - *tlen = 0; - if ( apple!=NULL ) { - *apple = NULL; - *appletlen = 0; - } - if ( sf->cidmaster!=NULL || sf->subfontcnt!=0 ) -return( NULL ); - if ( (strstrmatch(encname,"big")!=NULL && strchr(encname,'5')!=NULL) || - strstrmatch(encname,"johab")!=NULL || - strstrmatch(encname,"sjis")!=NULL || - strstrmatch(encname,"cp932")!=NULL || - strstrmatch(encname,"euc-kr")!=NULL || - strstrmatch(encname,"euc-cn")!=NULL ) - /* Already properly encoded */; - else if ( strstrmatch(encname,"2022")!=NULL && - (strstrmatch(encname,"JP2")!=NULL || - strstrmatch(encname,"JP-2")!=NULL || - strstrmatch(encname,"JP-3")!=NULL )) -return( NULL ); /* No 8/16 encoding for JP2 nor JP3 */ - else if ( sf->uni_interp>=ui_japanese && sf->uni_interp<=ui_korean ) { - enc = FindOrMakeEncoding( - sf->uni_interp==ui_japanese ? "sjis" : - sf->uni_interp==ui_trad_chinese ? "big5" : - sf->uni_interp==ui_simp_chinese ? "euc-cn" : - "euc-kr"); - if ( map->enc!=enc ) { - map = EncMapFromEncoding(sf,enc); - encname = map->enc->iconv_name!=NULL ? map->enc->iconv_name : map->enc->enc_name; - } - } else -return( NULL ); - - /* Both MS and Apple extend sjis. I don't know how to get iconv to give me*/ - /* apple's encoding though. So I generate one 8/16 table for MS based on */ - /* their extension (cp932), and another table based on plain sjis for Apple*/ - /* Don't know if this is true of other cjk encodings... for the moment I */ - /* will just use standard encodings for them */ - if ( strstrmatch(encname,"sjis")!=NULL ) { - enc = FindOrMakeEncoding("cp932"); - if ( enc!=NULL ) { - applemap = map; - map = EncMapFromEncoding(sf,enc); - } - } else if ( strstrmatch(encname,"cp932")!=NULL ) - applemap = EncMapFromEncoding(sf,FindOrMakeEncoding("sjis")); - - if ( applemap!=NULL ) - *apple = _Gen816Enc(sf,appletlen,applemap); - sub = _Gen816Enc(sf,tlen,map); - - if ( applemap!=NULL && applemap!=oldmap ) - EncMapFree(applemap); - if ( map!=oldmap ) - EncMapFree(map); -return( sub ); -} - -static FILE *NeedsUCS4Table(SplineFont *sf,int *ucs4len,EncMap *map) { - int i=0,j,group; - FILE *format12; - SplineChar *sc; - EncMap *freeme = NULL; - struct altuni *altuni; - - if ( map->enc->is_unicodefull ) - i=0x10000; - else if ( map->enc->is_custom ) - i = 0; - else - i = map->enc->char_cnt; - for ( ; i<map->enccount; ++i ) { - if ( map->map[i]!=-1 && SCWorthOutputting(sf->glyphs[map->map[i]]) ) { - if ( sf->glyphs[map->map[i]]->unicodeenc>=0x10000 ) - break; - for ( altuni=sf->glyphs[map->map[i]]->altuni; altuni!=NULL && (altuni->unienc<0x10000 || altuni->vs!=-1 || altuni->fid!=0); - altuni=altuni->next ); - if ( altuni!=NULL ) - break; - } - } - - if ( i>=map->enccount ) -return(NULL); - - if ( !map->enc->is_unicodefull ) - map = freeme = EncMapFromEncoding(sf,FindOrMakeEncoding("ucs4")); - - format12 = tmpfile2(); - if ( format12==NULL ) -return( NULL ); - - putshort(format12,12); /* Subtable format */ - putshort(format12,0); /* padding */ - putlong(format12,0); /* Length, we'll come back to this */ - putlong(format12,0); /* language */ - putlong(format12,0); /* Number of groups, we'll come back to this */ - - group = 0; - for ( i=0; i<map->enccount; ++i ) if ( map->map[i]!=-1 && SCWorthOutputting(sf->glyphs[map->map[i]]) && sf->glyphs[map->map[i]]->unicodeenc!=-1 ) { - sc = sf->glyphs[map->map[i]]; - for ( j=i+1; j<map->enccount && map->map[j]!=-1 && - SCWorthOutputting(sf->glyphs[map->map[j]]) && - sf->glyphs[map->map[j]]->unicodeenc!=-1 && - sf->glyphs[map->map[j]]->ttf_glyph==sc->ttf_glyph+j-i; ++j ); - --j; - putlong(format12,i); /* start char code */ - putlong(format12,j); /* end char code */ - putlong(format12,sc->ttf_glyph); - ++group; - i=j; /* move to the start of the next group */ - } - *ucs4len = ftell(format12); - fseek(format12,4,SEEK_SET); - putlong(format12,*ucs4len); /* Length, I said we'd come back to it */ - putlong(format12,0); /* language */ - putlong(format12,group); /* Number of groups */ - rewind( format12 ); - - if ( freeme!=NULL ) - EncMapFree(freeme); -return( format12 ); -} - -static FILE *NeedsUCS2Table(SplineFont *sf,int *ucs2len,EncMap *map,int issymbol) { - /* We always want a format 4 2byte unicode encoding map */ - /* But if it's symbol, only include encodings 0xff20 - 0xffff */ - uint32 *avail = malloc(65536*sizeof(uint32)); - int i,j,l; - int segcnt, cnt=0, delta, rpos; - struct cmapseg { uint16 start, end; uint16 delta; uint16 rangeoff; } *cmapseg; - uint16 *ranges; - SplineChar *sc; - FILE *format4 = tmpfile2(); - - memset(avail,0xff,65536*sizeof(uint32)); - if ( map->enc->is_unicodebmp || map->enc->is_unicodefull ) { int gid; - for ( i=0; i<65536 && i<map->enccount; ++i ) if ( (gid=map->map[i])!=-1 && sf->glyphs[gid]!=NULL && sf->glyphs[gid]->ttf_glyph!=-1 ) { - avail[i] = gid; - ++cnt; - } - } else { - struct altuni *altuni; - for ( i=0; i<sf->glyphcnt; ++i ) { - if ( (sc=sf->glyphs[i])!=NULL && sc->ttf_glyph!=-1 ) { - if ( sc->unicodeenc>=0 && sc->unicodeenc<=0xffff ) { - avail[sc->unicodeenc] = i; - ++cnt; - } - for ( altuni=sc->altuni; altuni!=NULL; altuni = altuni->next ) { - if ( altuni->unienc<=0xffff && altuni->vs==-1 && altuni->fid==0 ) { - avail[altuni->unienc] = i; - ++cnt; - } - } - } - } - } - if ( issymbol ) { - /* Clear out all entries we don't want */ - memset(avail ,0xff,0xf020*sizeof(uint32)); - memset(avail+0xf100,0xff,0x0eff*sizeof(uint32)); - } - - j = -1; - for ( i=segcnt=0; i<65536; ++i ) { - if ( avail[i]!=0xffffffff && j==-1 ) { - j=i; - ++segcnt; - } else if ( j!=-1 && avail[i]==0xffffffff ) - j = -1; - } - cmapseg = calloc(segcnt+1,sizeof(struct cmapseg)); - ranges = malloc(cnt*sizeof(int16)); - j = -1; - for ( i=segcnt=0; i<65536; ++i ) { - if ( avail[i]!=0xffffffff && j==-1 ) { - j=i; - cmapseg[segcnt].start = j; - ++segcnt; - } else if ( j!=-1 && avail[i]==0xffffffff ) { - cmapseg[segcnt-1].end = i-1; - j = -1; - } - } - if ( j!=-1 ) - cmapseg[segcnt-1].end = i-1; - /* create a dummy segment to mark the end of the table */ - cmapseg[segcnt].start = cmapseg[segcnt].end = 0xffff; - cmapseg[segcnt++].delta = 1; - rpos = 0; - for ( i=0; i<segcnt-1; ++i ) { - l = avail[cmapseg[i].start]; - sc = sf->glyphs[l]; - delta = sc->ttf_glyph-cmapseg[i].start; - for ( j=cmapseg[i].start; j<=cmapseg[i].end; ++j ) { - l = avail[j]; - sc = sf->glyphs[l]; - if ( delta != sc->ttf_glyph-j ) - break; - } - if ( j>cmapseg[i].end ) - cmapseg[i].delta = delta; - else { - cmapseg[i].rangeoff = (rpos + (segcnt-i)) * sizeof(int16); - for ( j=cmapseg[i].start; j<=cmapseg[i].end; ++j ) { - l = avail[j]; - sc = sf->glyphs[l]; - ranges[rpos++] = sc->ttf_glyph; - } - } - } - free(avail); - - - putshort(format4,4); /* format */ - putshort(format4,(8+4*segcnt+rpos)*sizeof(int16)); - putshort(format4,0); /* language/version */ - putshort(format4,2*segcnt); /* segcnt */ - for ( j=0,i=1; i<=segcnt; i<<=1, ++j ); - putshort(format4,i); /* 2*2^floor(log2(segcnt)) */ - putshort(format4,j-1); - putshort(format4,2*segcnt-i); - for ( i=0; i<segcnt; ++i ) - putshort(format4,cmapseg[i].end); - putshort(format4,0); - for ( i=0; i<segcnt; ++i ) - putshort(format4,cmapseg[i].start); - for ( i=0; i<segcnt; ++i ) - putshort(format4,cmapseg[i].delta); - for ( i=0; i<segcnt; ++i ) - putshort(format4,cmapseg[i].rangeoff); - for ( i=0; i<rpos; ++i ) - putshort(format4,ranges[i]); - free(ranges); - free(cmapseg); - *ucs2len = ftell(format4); -return( format4 ); -} - -static FILE *NeedsVariationSequenceTable(SplineFont *sf,int *vslen) { - /* Do we need a format 14 (unicode variation sequence) subtable? */ - int gid, vs_cnt=0, vs_max=512, i, j, k, cnt, mingid, maxgid; - struct altuni *altuni, *au; - int32 vsbuf[512], *vses = vsbuf; - FILE *format14; - uint32 *avail = NULL; - enum vs_type {vs_default=(1<<24), vs_nondefault=(2<<24) }; - SplineChar *sc; - uint32 here; - int any; - - mingid = maxgid = -1; - for ( gid=0; gid<sf->glyphcnt; ++gid ) if ( (sc = sf->glyphs[gid])!=NULL ) { - for ( altuni = sc->altuni; altuni!=NULL; altuni=altuni->next ) { - if ( altuni->unienc!=-1 && (uint32)altuni->unienc<unicode4_size && - altuni->vs!=-1 && altuni->fid==0 ) { - for ( i=0; i<vs_cnt; ++i ) - if ( vses[i]==altuni->vs ) - break; - if ( i>=vs_cnt ) { - if ( i>=vs_max ) { - if ( vses==vsbuf ) { - vses = malloc((vs_max*=2)*sizeof(uint32)); - memcpy(vses,vsbuf,sizeof(vsbuf)); - } else - vses = realloc(vses,(vs_max+=512)*sizeof(uint32)); - } - vses[vs_cnt++] = altuni->vs; - } - if ( mingid==-1 ) - mingid = maxgid = gid; - else - maxgid = gid; - } - } - } - if ( vs_cnt==0 ) { - *vslen = 0; -return( NULL ); /* No variation selectors */ - } - - /* Sort the variation selectors */ - for ( i=0; i<vs_cnt; ++i ) for ( j=i+1; j<vs_cnt; ++j ) { - if ( vses[i]>vses[j] ) { - int temp = vses[i]; - vses[i] = vses[j]; - vses[j] = temp; - } - } - - avail = malloc(unicode4_size*sizeof(uint32)); - - format14 = tmpfile2(); - putshort(format14,14); - putlong(format14,0); /* Length, fixup later */ - putlong(format14,vs_cnt); /* number of selectors */ - - /* Variation selector records */ - for ( i=0; i<vs_cnt; ++i ) { - putu24(format14,vses[i]); - putlong(format14,0); - putlong(format14,0); - } - - for ( i=0; i<vs_cnt; ++i ) { - memset(avail,0,unicode4_size*sizeof(uint32)); - any = 0; - for ( gid=mingid; gid<=maxgid; ++gid ) if ( (sc=sf->glyphs[gid])!=NULL ) { - for ( altuni = sc->altuni; altuni!=NULL; altuni=altuni->next ) { - if ( altuni->unienc!=-1 && altuni->unienc < (int)unicode4_size && - altuni->vs==vses[i] && altuni->fid==0 ) { - for ( au=sc->altuni; au!=NULL; au=au->next ) - if ( au->unienc==altuni->unienc && au->vs==-1 && au->fid==0 ) - break; - if ( altuni->unienc==sc->unicodeenc || au!=NULL ) { - avail[altuni->unienc] = gid | vs_default; - any |= vs_default; - } else { - avail[altuni->unienc] = gid | vs_nondefault; - any |= vs_nondefault; - } - } - } - } - if ( any&vs_default ) { - here = ftell(format14); - fseek(format14,10+ i*11 + 3, SEEK_SET); /* Seek to defaultUVSOffset */ - putlong(format14,here); - fseek(format14,0,SEEK_END); - cnt = 0; - for ( j=0; (unsigned)j<unicode4_size; ++j ) if ( avail[j]&vs_default ) { - for ( k=j+1; (unsigned)k<unicode4_size && (avail[k]&vs_default); ++k ); - if ( k-j>256 ) k=j+256; /* Each range is limited to 255 code points, as the count is a byte */ - ++cnt; - j = k-1; - } - putlong(format14,cnt); - for ( j=0; (unsigned)j<unicode4_size; ++j ) if ( avail[j]&vs_default ) { - for ( k=j+1; (unsigned)k<unicode4_size && (avail[k]&vs_default); ++k ); - if ( k-j>256 ) k=j+256; - putu24(format14,j); - putc(k-j-1,format14); - j = k-1; - } - } - if ( any&vs_nondefault ) { - here = ftell(format14); - fseek(format14,10+ i*11 + 7, SEEK_SET); /* Seek to nonDefaultUVSOffset */ - putlong(format14,here); - fseek(format14,0,SEEK_END); - cnt = 0; - for ( j=0; (unsigned)j<unicode4_size; ++j ) if ( avail[j]&vs_nondefault ) - ++cnt; - putlong(format14,cnt); - for ( j=0; (unsigned)j<unicode4_size; ++j ) if ( avail[j]&vs_nondefault ) { - putu24(format14,j); - putshort(format14,sf->glyphs[avail[j]&0xffff]->ttf_glyph); - } - } - } - - here = ftell(format14); - fseek(format14,2,SEEK_SET); - putlong(format14,here); - fseek(format14,0,SEEK_END); - if ( here&1 ) { - putc('\0',format14); - ++here; - } - if ( here&2 ) { - putshort(format14,0); - here += 2; - } - *vslen = here; - - free(avail); - if ( vses!=vsbuf ) - free(vses); - -return( format14 ); -} - -extern unichar_t MacRomanEnc[]; -static void dumpcmap(struct alltabs *at, SplineFont *sf,enum fontformat format) { - int i,enccnt, issmall, hasmac; - uint16 table[256]; - SplineChar *sc; - int alreadyprivate = false; - int wasotf = format==ff_otf || format==ff_otfcid; - EncMap *map = at->map; - int ucs4len=0, ucs2len=0, cjklen=0, applecjklen=0, vslen=0; - FILE *format12, *format4, *format2, *apple2, *format14; - int mspos, ucs4pos, cjkpos, applecjkpos, vspos, start_of_macroman; - int modformat = format; - - if (( format>=ff_ttf && format<=ff_otfdfont) && (at->gi.flags&ttf_flag_symbol)) - modformat = ff_ttfsym; - - at->cmap = tmpfile2(); - - /* MacRoman encoding table */ /* Not going to bother with making this work for cid fonts */ - /* I now see that Apple doesn't restrict us to format 0 sub-tables (as */ - /* the docs imply) but instead also uses format 6 tables. Wildly in- */ - /* appropriate as they are for 2byte encodings, but Apple uses them */ - /* for one byte ones too */ - memset(table,'\0',sizeof(table)); - if ( !wasotf ) { - table[29] = table[8] = table[0] = 1; - table[9] = table[13] = 2; - } - for ( i=0; i<256 ; ++i ) { - sc = SFGetChar(sf,MacRomanEnc[i],NULL); - if ( sc!=NULL && sc->ttf_glyph!=-1 ) - table[i] = sc->ttf_glyph; - } - if ( table[0]==0 ) table[0] = 1; - - if ( modformat==ff_ttfsym ) { - alreadyprivate = AlreadyMSSymbolArea(sf,map); - memset(table,'\0',sizeof(table)); - if ( !wasotf ) { - table[29] = table[8] = table[0] = 1; - table[9] = table[13] = 2; - } - if ( !alreadyprivate ) { - for ( i=0; i<map->enccount && i<256; ++i ) { - if ( map->map[i]!=-1 && (sc = sf->glyphs[map->map[i]])!=NULL && - sc->ttf_glyph!=-1 ) - table[i] = sc->ttf_glyph; - } - for ( i=0xf020; i<=0xf0ff && i<sf->glyphcnt; ++i ) { - if ( map->map[i]!=-1 && (sc = sf->glyphs[map->map[i]])!=NULL && - sc->ttf_glyph!=-1 && table[i-0xf000]==0 ) - table[i-0xf000] = sc->ttf_glyph; - } - } else { - for ( i=0xf020; i<=0xf0ff && i<sf->glyphcnt; ++i ) { - if ( map->map[i]!=-1 && (sc = sf->glyphs[map->map[i]])!=NULL && - sc->ttf_glyph!=-1 ) - table[i-0xf000] = sc->ttf_glyph; - } - for ( i=0; i<map->enccount && i<256; ++i ) { - if ( map->map[i]!=-1 && (sc = sf->glyphs[map->map[i]])!=NULL && - sc->ttf_glyph!=-1 && table[i]==0 ) - table[i] = sc->ttf_glyph; - } - } - /* if the user has read in a ttf symbol file then it will already have */ - /* the right private use encoding, and we don't want to mess it up. */ - /* The alreadyprivate flag should detect this case */ - if ( !alreadyprivate ) { - for ( i=0; i<map->enccount && i<256; ++i ) { - if ( map->map[i]!=-1 && (sc = sf->glyphs[map->map[i]])!=NULL ) { - sc->orig_pos = sc->unicodeenc; - sc->unicodeenc = 0xf000 + i; - } - } - for ( ; i<map->enccount; ++i ) { - if ( map->map[i]!=-1 && (sc = sf->glyphs[map->map[i]])!=NULL ) { - sc->orig_pos = sc->unicodeenc; - sc->unicodeenc = -1; - } - } - } - } - - format4 = NeedsUCS2Table(sf,&ucs2len,map,modformat==ff_ttfsym); - apple2 = NULL; - if ( modformat!=ff_ttfsym ) { - format12 = NeedsUCS4Table(sf,&ucs4len,map); - format2 = Needs816Enc(sf,&cjklen,map,&apple2,&applecjklen); - format14 = NeedsVariationSequenceTable(sf,&vslen); - } else - format12 = format2 = format14 = apple2 = NULL; - - /* Two/Three/Four encoding table pointers, one for ms, one for mac */ - /* usually one for mac big, just a copy of ms */ - /* plus we may have a format12 encoding for ucs4, mac doesn't support */ - /* plus we may have a format2 encoding for cjk, sometimes I know the codes for the mac... */ - /* sometimes the mac will have a slightly different cjk table */ - /* Sometimes we want a variation sequence subtable (format=14) for */ - /* unicode platform */ - if ( modformat==ff_ttfsym ) { - enccnt = 2; - hasmac = 0; - } else { - hasmac = 1; - enccnt = 3; - if ( format12!=NULL ) - enccnt = 5; - if ( format2!=NULL ) { - if ( strstrmatch(map->enc->enc_name,"johab")!=NULL ) { - ++enccnt; - } else { - enccnt+=2; - hasmac=3; - } - } - if ( format14!=NULL ) - ++enccnt; - } - - putshort(at->cmap,0); /* version */ - putshort(at->cmap,enccnt); /* num tables */ - - mspos = 2*sizeof(uint16)+enccnt*(2*sizeof(uint16)+sizeof(uint32)); - ucs4pos = mspos+ucs2len; - cjkpos = ucs4pos+ucs4len; - if ( apple2==NULL ) { - applecjkpos = cjkpos; - applecjklen = cjklen; - } else - applecjkpos = cjkpos + cjklen; - /* applecjklen set above */ - vspos = applecjkpos + applecjklen; - start_of_macroman = vspos + vslen; - - if ( hasmac&1 ) { - /* big mac table, just a copy of the ms table */ - putshort(at->cmap,0); /* mac unicode platform */ - putshort(at->cmap,3); /* Unicode 2.0 */ - putlong(at->cmap,mspos); - } - if ( format12!=NULL ) { - /* full unicode mac table, just a copy of the ms table */ - putshort(at->cmap,0); /* mac unicode platform */ - if( map->enc->is_unicodefull ) { - putshort(at->cmap,10); /* Unicode 2.0, unicode beyond BMP */ - } else { - putshort(at->cmap,4); /* Unicode 2.0, unicode BMP */ - } - putlong(at->cmap,ucs4pos); - } - if ( format14!=NULL ) { - /* variation sequence subtable. Only for platform 0. */ - putshort(at->cmap,0); /* mac unicode platform */ - putshort(at->cmap,5); /* Variation sequence table */ - putlong(at->cmap,vspos); - } - putshort(at->cmap,1); /* mac platform */ - putshort(at->cmap,0); /* plat specific enc, script=roman */ - /* Even the symbol font on the mac claims a mac roman encoding */ - /* although it actually contains a symbol encoding. There is an*/ - /* "RSymbol" language listed for Mac (specific=8) but it isn't used*/ - putlong(at->cmap,start_of_macroman); /* offset from tab start to sub tab start */ - if ( format2!=NULL && (hasmac&2) ) { - /* mac cjk table, often a copy of the ms table */ - putshort(at->cmap,1); /* mac platform */ - putshort(at->cmap, - map->enc->is_japanese || sf->uni_interp==ui_japanese ? 1 : /* SJIS */ - map->enc->is_korean || sf->uni_interp==ui_korean ? 3 : /* Korean */ - map->enc->is_simplechinese || sf->uni_interp==ui_simp_chinese ? 25 :/* Simplified Chinese */ - 2 ); /* Big5 */ - putlong(at->cmap,applecjkpos); - } - - putshort(at->cmap,3); /* ms platform */ - putshort(at->cmap, /* plat specific enc */ - modformat==ff_ttfsym ? 0 : /* Symbol */ - 1 ); /* Unicode */ - putlong(at->cmap,mspos); /* offset from tab start to sub tab start */ - - if ( format2!=NULL ) { - putshort(at->cmap,3); /* ms platform */ - putshort(at->cmap, /* plat specific enc */ - strstrmatch(map->enc->enc_name,"johab")!=NULL ? 6 : - map->enc->is_korean || sf->uni_interp==ui_korean ? 5 : - map->enc->is_japanese || sf->uni_interp==ui_japanese ? 2 : - map->enc->is_simplechinese || sf->uni_interp==ui_simp_chinese ? 3 : - 4); /* Big5 */ - putlong(at->cmap,cjkpos); /* offset from tab start to sub tab start */ - } - - if ( format12!=NULL ) { - putshort(at->cmap,3); /* ms platform */ - putshort(at->cmap,10); /* plat specific enc, ucs4 */ - putlong(at->cmap,ucs4pos); /* offset from tab start to sub tab start */ - } - if ( format4!=NULL ) { - if ( !ttfcopyfile(at->cmap,format4,mspos,"cmap-Unicode16")) at->error = true; - } - if ( format12!=NULL ) { - if ( !ttfcopyfile(at->cmap,format12,ucs4pos,"cmap-Unicode32")) at->error = true; - } - if ( format2!=NULL ) { - if ( !ttfcopyfile(at->cmap,format2,cjkpos,"cmap-cjk")) at->error = true; - } - if ( apple2!=NULL ) { - if ( !ttfcopyfile(at->cmap,apple2,applecjkpos,"cmap-applecjk")) at->error = true; - } - if ( format14!=NULL ) { - if ( !ttfcopyfile(at->cmap,format14,vspos,"cmap-uniVariations")) at->error = true; - } - - /* Mac table */ - issmall = true; - for ( i=0; i<256; ++i ) - if ( table[i]>=256 ) { - issmall = false; - break; - } - if ( issmall ) { - putshort(at->cmap,0); /* format */ - putshort(at->cmap,262); /* length = 256bytes + 6 header bytes */ - putshort(at->cmap,0); /* language = english */ - for ( i=0; i<256; ++i ) - putc(table[i],at->cmap); - } else { - putshort(at->cmap,6); /* format 6 */ - putshort(at->cmap,522); /* length = 256short +10 header bytes */ - putshort(at->cmap,0); /* language = english */ - putshort(at->cmap,0); /* first code */ - putshort(at->cmap,256); /* entry count */ - for ( i=0; i<256; ++i ) - putshort(at->cmap,table[i]); - } - - at->cmaplen = ftell(at->cmap); - if ( (at->cmaplen&2)!=0 ) - putshort(at->cmap,0); - - if ( modformat==ff_ttfsym ) { - if ( !alreadyprivate ) { - for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) { - sf->glyphs[i]->unicodeenc = sf->glyphs[i]->orig_pos; - sf->glyphs[i]->orig_pos = i; - } - } - } -} - -int32 filechecksum(FILE *file) { - uint32 sum = 0, chunk; - - rewind(file); - while ( 1 ) { - chunk = getuint32(file); - if ( feof(file) || ferror(file)) - break; - sum += chunk; - } -return( sum ); -} - -static void AbortTTF(struct alltabs *at, SplineFont *sf) { - int i; - - if ( at->loca!=NULL ) - fclose(at->loca); - if ( at->name!=NULL ) - fclose(at->name); - if ( at->post!=NULL ) - fclose(at->post); - if ( at->gpos!=NULL ) - fclose(at->gpos); - if ( at->gsub!=NULL ) - fclose(at->gsub); - if ( at->gdef!=NULL ) - fclose(at->gdef); - if ( at->kern!=NULL ) - fclose(at->kern); - if ( at->cmap!=NULL ) - fclose(at->cmap); - if ( at->headf!=NULL ) - fclose(at->headf); - if ( at->hheadf!=NULL ) - fclose(at->hheadf); - if ( at->maxpf!=NULL ) - fclose(at->maxpf); - if ( at->os2f!=NULL ) - fclose(at->os2f); - if ( at->cvtf!=NULL ) - fclose(at->cvtf); - if ( at->vheadf!=NULL ) - fclose(at->vheadf); - if ( at->vorgf!=NULL ) - fclose(at->vorgf); - if ( at->cfff!=NULL ) - fclose(at->cfff); - - if ( at->gi.glyphs!=NULL ) - fclose(at->gi.glyphs); - if ( at->gi.hmtx!=NULL ) - fclose(at->gi.hmtx); - if ( at->gi.vmtx!=NULL ) - fclose(at->gi.vmtx); - if ( at->fpgmf!=NULL ) - fclose(at->fpgmf); - if ( at->prepf!=NULL ) - fclose(at->prepf); - if ( at->gaspf!=NULL ) - fclose(at->gaspf); - - if ( at->sidf!=NULL ) - fclose(at->sidf); - if ( at->sidh!=NULL ) - fclose(at->sidh); - if ( at->charset!=NULL ) - fclose(at->charset); - if ( at->encoding!=NULL ) - fclose(at->encoding); - if ( at->private!=NULL ) - fclose(at->private); - if ( at->charstrings!=NULL ) - fclose(at->charstrings); - if ( at->fdselect!=NULL ) - fclose(at->fdselect); - if ( at->fdarray!=NULL ) - fclose(at->fdarray); - if ( at->bdat!=NULL ) - fclose(at->bdat); - if ( at->bloc!=NULL ) - fclose(at->bloc); - if ( at->ebsc!=NULL ) - fclose(at->ebsc); - - if ( at->prop!=NULL ) - fclose(at->prop); - if ( at->opbd!=NULL ) - fclose(at->opbd); - if ( at->acnt!=NULL ) - fclose(at->acnt); - if ( at->lcar!=NULL ) - fclose(at->lcar); - if ( at->feat!=NULL ) - fclose(at->feat); - if ( at->morx!=NULL ) - fclose(at->morx); - - if ( at->pfed!=NULL ) - fclose(at->pfed); - if ( at->tex!=NULL ) - fclose(at->tex); - - if ( at->gvar!=NULL ) - fclose(at->gvar); - if ( at->fvar!=NULL ) - fclose(at->fvar); - if ( at->cvar!=NULL ) - fclose(at->cvar); - if ( at->avar!=NULL ) - fclose(at->avar); - - for ( i=0; i<sf->subfontcnt; ++i ) { - if ( at->fds[i].private!=NULL ) - fclose(at->fds[i].private); - } - if ( sf->subfontcnt!=0 ) { - free(sf->glyphs); - sf->glyphs = NULL; - sf->glyphcnt = sf->glyphmax = 0; - } - free( at->fds ); - free( at->gi.bygid ); -} - -int SFHasInstructions(SplineFont *sf) { - int i; - - if ( sf->mm!=NULL && sf->mm->apple ) - sf = sf->mm->normal; - - if ( sf->subfontcnt!=0 ) -return( false ); /* Truetype doesn't support cid keyed fonts */ - - for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) { - if ( strcmp(sf->glyphs[i]->name,".notdef")==0 ) - continue; /* ff produces fonts with instructions in .notdef & not elsewhere. Ignore these */ - if ( sf->glyphs[i]->ttf_instrs!=NULL ) -return( true ); - } -return( false ); -} - -static void MaxpFromTable(struct alltabs *at,SplineFont *sf) { - struct ttf_table *maxp; - - maxp = SFFindTable(sf,CHR('m','a','x','p')); - if ( maxp==NULL && sf->mm!=NULL && sf->mm->apple ) - maxp = SFFindTable(sf->mm->normal,CHR('m','a','x','p')); - if ( maxp==NULL || maxp->len<13*sizeof(uint16) ) -return; - /* We can figure out the others ourselves, but these depend on the contents */ - /* of uninterpretted tables */ - at->maxp.maxZones = memushort(maxp->data,maxp->len, 7*sizeof(uint16)); - at->maxp.maxTwilightPts = memushort(maxp->data,maxp->len, 8*sizeof(uint16)); - at->maxp.maxStorage = memushort(maxp->data,maxp->len, 9*sizeof(uint16)); - at->maxp.maxFDEFs = memushort(maxp->data,maxp->len, 10*sizeof(uint16)); - at->maxp.maxIDEFs = memushort(maxp->data,maxp->len, 11*sizeof(uint16)); - at->maxp.maxStack = memushort(maxp->data,maxp->len, 12*sizeof(uint16)); -} - -static FILE *dumpstoredtable(SplineFont *sf,uint32 tag,int *len) { - struct ttf_table *tab = SFFindTable(sf,tag); - FILE *out; - - if ( tab==NULL && sf->mm!=NULL && sf->mm->apple ) - tab = SFFindTable(sf->mm->normal,tag); - if ( tab==NULL ) { - *len = 0; -return( NULL ); - } - - out = tmpfile2(); - fwrite(tab->data,1,tab->len,out); - if ( (tab->len&1)) - putc('\0',out); - if ( (tab->len+1)&2 ) - putshort(out,0); - *len = tab->len; -return( out ); -} - -static FILE *dumpsavedtable(struct ttf_table *tab) { - FILE *out; - - if ( tab==NULL ) -return( NULL ); - - out = tmpfile2(); - fwrite(tab->data,1,tab->len,out); - if ( (tab->len&1)) - putc('\0',out); - if ( (tab->len+1)&2 ) - putshort(out,0); -return( out ); -} - -static int tagcomp(const void *_t1, const void *_t2) { - struct taboff *t1 = *((struct taboff **) _t1), *t2 = *((struct taboff **) _t2); -return( (int) (t1->tag - t2->tag) ); -} - -static int tcomp(const void *_t1, const void *_t2) { - struct taboff *t1 = *((struct taboff **) _t1), *t2 = *((struct taboff **) _t2); -return( t1->orderingval - t2->orderingval ); -} - -static void ATmaxpInit(struct alltabs *at,SplineFont *sf, enum fontformat format) { - - at->maxp.version = 0x00010000; - if ( format==ff_otf || format==ff_otfcid || (format==ff_none && at->applemode) ) - at->maxp.version = 0x00005000; - at->maxp.maxnumcomponents = 0; - at->maxp.maxcomponentdepth = 0; - at->maxp.maxZones = 2; /* 1 would probably do, don't use twilight */ - at->maxp.maxFDEFs = 1; /* Not even 1 */ - at->maxp.maxStorage = 1; /* Not even 1 */ - at->maxp.maxStack = 64; /* A guess, it's probably more like 8 */ - if ( format==ff_otf || format==ff_otfcid || (format==ff_none && at->applemode) ) - at->maxp.version = 0x00005000; - else - MaxpFromTable(at,sf); - at->gi.maxp = &at->maxp; -} - -static void initATTables(struct alltabs *at, SplineFont *sf, enum fontformat format) { - setos2(&at->os2,at,sf,format); /* should precede kern/ligature output */ - if ( at->opentypemode ) { - SFFindUnusedLookups(sf); - otf_dumpgpos(at,sf); - otf_dumpgsub(at,sf); - otf_dumpgdef(at,sf); - otf_dumpjstf(at,sf); - otf_dumpbase(at,sf); - otf_dump_math(at,sf); /* Not strictly OpenType yet */ - if ( at->gi.flags & ttf_flag_dummyDSIG ) - otf_dump_dummydsig(at,sf); - } - if ( at->dovariations ) - ttf_dumpvariations(at,sf); - if ( at->applemode ) { - if ( !at->opentypemode ) - SFFindUnusedLookups(sf); - ttf_dumpkerns(at,sf); - aat_dumplcar(at,sf); - aat_dumpmorx(at,sf); /* Sets the feat table too */ - aat_dumpopbd(at,sf); - aat_dumpprop(at,sf); - aat_dumpbsln(at,sf); - } - if ( !at->applemode && (!at->opentypemode || (at->gi.flags&ttf_flag_oldkern)) ) - ttf_dumpkerns(at,sf); /* everybody supports a mimimal kern table */ - - dumpnames(at,sf,format); /* Must be after dumpmorx which may create extra names */ - /* GPOS 'size' can also create names (so must be after that too) */ - redoos2(at); -} - -static struct taboff *findtabindir(struct tabdir *td, uint32 tag ) { - int i; - - for ( i=0; i<td->numtab; ++i ) - if ( td->tabs[i].tag == tag ) -return( &td->tabs[i] ); - -return( NULL ); -} - -static void buildtablestructures(struct alltabs *at, SplineFont *sf, - enum fontformat format) { - int i; - int ebdtpos, eblcpos; - struct ttf_table *tab; - - if ( format==ff_otf || format==ff_otfcid ) { - at->tabdir.version = CHR('O','T','T','O'); -#ifdef FONTFORGE_CONFIG_APPLE_ONLY_TTF /* This means that Windows will reject the font. In general not a good idea */ - } else if ( at->applemode && !at->opentypemode ) { - at->tabdir.version = CHR('t','r','u','e'); -#endif - } else { - at->tabdir.version = 0x00010000; - } - - i = 0; - - if ( at->base!=NULL ) { - at->tabdir.tabs[i].tag = CHR('B','A','S','E'); - at->tabdir.tabs[i].data = at->base; - at->tabdir.tabs[i++].length = at->baselen; - } - - if ( at->bsln!=NULL ) { - at->tabdir.tabs[i].tag = CHR('b','s','l','n'); - at->tabdir.tabs[i].data = at->bsln; - at->tabdir.tabs[i++].length = at->bslnlen; - } - - if ( at->bdf!=NULL ) { - at->tabdir.tabs[i].tag = CHR('B','D','F',' '); - at->tabdir.tabs[i].data = at->bdf; - at->tabdir.tabs[i++].length = at->bdflen; - } - - if ( format==ff_otf || format==ff_otfcid ) { - at->tabdir.tabs[i].tag = CHR('C','F','F',' '); - at->tabdir.tabs[i].length = at->cfflen; - at->tabdir.tabs[i++].data = at->cfff; - } - - if ( at->dsigf!=NULL ) { - ebdtpos = i; - at->tabdir.tabs[i].tag = CHR('D','S','I','G'); - at->tabdir.tabs[i].length = at->dsiglen; - at->tabdir.tabs[i++].data = at->dsigf; - } - - if ( at->bdat!=NULL && (at->msbitmaps || at->otbbitmaps)) { - ebdtpos = i; - at->tabdir.tabs[i].tag = CHR('E','B','D','T'); - at->tabdir.tabs[i].length = at->bdatlen; - at->tabdir.tabs[i++].data = at->bdat; - } - - if ( at->bloc!=NULL && (at->msbitmaps || at->otbbitmaps)) { - eblcpos = i; - at->tabdir.tabs[i].tag = CHR('E','B','L','C'); - at->tabdir.tabs[i].data = at->bloc; - at->tabdir.tabs[i++].length = at->bloclen; - } - - if ( at->ebsc!=NULL ) { - at->tabdir.tabs[i].tag = CHR('E','B','S','C'); - at->tabdir.tabs[i].data = at->ebsc; - at->tabdir.tabs[i++].length = at->ebsclen; - } - - if ( at->fftmf!=NULL ) { - at->tabdir.tabs[i].tag = CHR('F','F','T','M'); - at->tabdir.tabs[i].data = at->fftmf; - at->tabdir.tabs[i++].length = at->fftmlen; - } - - if ( at->gdef!=NULL ) { - at->tabdir.tabs[i].tag = CHR('G','D','E','F'); - at->tabdir.tabs[i].data = at->gdef; - at->tabdir.tabs[i++].length = at->gdeflen; - } - - if ( at->gpos!=NULL ) { - at->tabdir.tabs[i].tag = CHR('G','P','O','S'); - at->tabdir.tabs[i].data = at->gpos; - at->tabdir.tabs[i++].length = at->gposlen; - } - - if ( at->gsub!=NULL ) { - at->tabdir.tabs[i].tag = CHR('G','S','U','B'); - at->tabdir.tabs[i].data = at->gsub; - at->tabdir.tabs[i++].length = at->gsublen; - } - - if ( at->jstf!=NULL ) { - at->tabdir.tabs[i].tag = CHR('J','S','T','F'); - at->tabdir.tabs[i].data = at->jstf; - at->tabdir.tabs[i++].length = at->jstflen; - } - - if ( at->os2f!=NULL ) { - at->tabdir.tabs[i].tag = CHR('O','S','/','2'); - at->tabdir.tabs[i].data = at->os2f; - at->tabdir.tabs[i++].length = at->os2len; - } - - if ( at->pfed!=NULL ) { - at->tabdir.tabs[i].tag = CHR('P','f','E','d'); - at->tabdir.tabs[i].data = at->pfed; - at->tabdir.tabs[i++].length = at->pfedlen; - } - - if ( at->tex!=NULL ) { - at->tabdir.tabs[i].tag = CHR('T','e','X',' '); - at->tabdir.tabs[i].data = at->tex; - at->tabdir.tabs[i++].length = at->texlen; - } - - if ( at->math!=NULL ) { - at->tabdir.tabs[i].tag = CHR('M','A','T','H'); - at->tabdir.tabs[i].data = at->math; - at->tabdir.tabs[i++].length = at->mathlen; - } - - if ( at->vorgf!=NULL ) { /* No longer generated */ - at->tabdir.tabs[i].tag = CHR('V','O','R','G'); - at->tabdir.tabs[i].data = at->vorgf; - at->tabdir.tabs[i++].length = at->vorglen; - } - - if ( at->acnt!=NULL ) { - at->tabdir.tabs[i].tag = CHR('a','c','n','t'); - at->tabdir.tabs[i].data = at->acnt; - at->tabdir.tabs[i++].length = at->acntlen; - } - - if ( at->bdat!=NULL && at->applebitmaps ) { - at->tabdir.tabs[i].tag = CHR('b','d','a','t'); - if ( !at->msbitmaps ) { - at->tabdir.tabs[i].data = at->bdat; - at->tabdir.tabs[i++].length = at->bdatlen; - } else { - at->tabdir.tabs[i].data = NULL; - at->tabdir.tabs[i].dup_of = ebdtpos; - at->tabdir.tabs[i++].length = at->tabdir.tabs[ebdtpos].length; - } - } - - if ( format==ff_none && at->applebitmaps ) { - /* Bitmap only fonts get a bhed table rather than a head */ - at->tabdir.tabs[i].tag = CHR('b','h','e','d'); - at->tabdir.tabs[i].data = at->headf; - at->tabdir.tabs[i++].length = at->headlen; - } - - if ( at->bloc!=NULL && at->applebitmaps ) { - at->tabdir.tabs[i].tag = CHR('b','l','o','c'); - if ( !at->msbitmaps ) { - at->tabdir.tabs[i].data = at->bloc; - at->tabdir.tabs[i++].length = at->bloclen; - } else { - at->tabdir.tabs[i].data = NULL; - at->tabdir.tabs[i].dup_of = eblcpos; - at->tabdir.tabs[i++].length = at->tabdir.tabs[eblcpos].length; - } - } - - if ( at->cmap!=NULL ) { - at->tabdir.tabs[i].tag = CHR('c','m','a','p'); - at->tabdir.tabs[i].data = at->cmap; - at->tabdir.tabs[i++].length = at->cmaplen; - } - - if ( format!=ff_otf && format!=ff_otfcid && format!=ff_none ) { - if ( at->cvtf!=NULL ) { - at->tabdir.tabs[i].tag = CHR('c','v','t',' '); - at->tabdir.tabs[i].data = at->cvtf; - at->tabdir.tabs[i++].length = at->cvtlen; - } - } - - if ( at->feat!=NULL ) { - at->tabdir.tabs[i].tag = CHR('f','e','a','t'); - at->tabdir.tabs[i].data = at->feat; - at->tabdir.tabs[i++].length = at->featlen; - } - - if ( at->fpgmf!=NULL ) { - at->tabdir.tabs[i].tag = CHR('f','p','g','m'); - at->tabdir.tabs[i].data = at->fpgmf; - at->tabdir.tabs[i++].length = at->fpgmlen; - } - - if ( at->gaspf!=NULL ) { - at->tabdir.tabs[i].tag = CHR('g','a','s','p'); - at->tabdir.tabs[i].data = at->gaspf; - at->tabdir.tabs[i++].length = at->gasplen; - } - - if ( at->gi.glyphs!=NULL ) { - at->tabdir.tabs[i].tag = CHR('g','l','y','f'); - at->tabdir.tabs[i].data = at->gi.glyphs; - at->tabdir.tabs[i++].length = at->gi.glyph_len; - } - - if ( at->hdmxf!=NULL ) { - at->tabdir.tabs[i].tag = CHR('h','d','m','x'); - at->tabdir.tabs[i].data = at->hdmxf; - at->tabdir.tabs[i++].length = at->hdmxlen; - } - - if ( format!=ff_none || !at->applebitmaps ) { - at->tabdir.tabs[i].tag = CHR('h','e','a','d'); - at->tabdir.tabs[i].data = at->headf; - at->tabdir.tabs[i++].length = at->headlen; - } - - if ( format!=ff_none || !at->applemode ) { - at->tabdir.tabs[i].tag = CHR('h','h','e','a'); - at->tabdir.tabs[i].data = at->hheadf; - at->tabdir.tabs[i++].length = at->hheadlen; - } else if ( at->hheadf!=NULL ) { - fclose(at->hheadf); - at->hheadf = NULL; - } - - if ( format!=ff_none || !at->applemode ) { - at->tabdir.tabs[i].tag = CHR('h','m','t','x'); - at->tabdir.tabs[i].data = at->gi.hmtx; - at->tabdir.tabs[i++].length = at->gi.hmtxlen; - } - - if ( at->kern!=NULL ) { - at->tabdir.tabs[i].tag = CHR('k','e','r','n'); - at->tabdir.tabs[i].data = at->kern; - at->tabdir.tabs[i++].length = at->kernlen; - } - - if ( at->lcar!=NULL ) { - at->tabdir.tabs[i].tag = CHR('l','c','a','r'); - at->tabdir.tabs[i].data = at->lcar; - at->tabdir.tabs[i++].length = at->lcarlen; - } - - if ( at->loca!=NULL ) { - at->tabdir.tabs[i].tag = CHR('l','o','c','a'); - at->tabdir.tabs[i].data = at->loca; - at->tabdir.tabs[i++].length = at->localen; - } - - at->tabdir.tabs[i].tag = CHR('m','a','x','p'); - at->tabdir.tabs[i].data = at->maxpf; - at->tabdir.tabs[i++].length = at->maxplen; - - if ( at->morx!=NULL ) { - at->tabdir.tabs[i].tag = CHR('m','o','r','x'); - at->tabdir.tabs[i].data = at->morx; - at->tabdir.tabs[i++].length = at->morxlen; - } - - if ( at->name!=NULL ) { - at->tabdir.tabs[i].tag = CHR('n','a','m','e'); - at->tabdir.tabs[i].data = at->name; - at->tabdir.tabs[i++].length = at->namelen; - } - - if ( at->opbd!=NULL ) { - at->tabdir.tabs[i].tag = CHR('o','p','b','d'); - at->tabdir.tabs[i].data = at->opbd; - at->tabdir.tabs[i++].length = at->opbdlen; - } - - if ( at->post!=NULL ) { - at->tabdir.tabs[i].tag = CHR('p','o','s','t'); - at->tabdir.tabs[i].data = at->post; - at->tabdir.tabs[i++].length = at->postlen; - } - - if ( format!=ff_otf && format!=ff_otfcid && format!=ff_none ) { - if ( at->prepf!=NULL ) { - at->tabdir.tabs[i].tag = CHR('p','r','e','p'); - at->tabdir.tabs[i].data = at->prepf; - at->tabdir.tabs[i++].length = at->preplen; - } - } - - if ( at->prop!=NULL ) { - at->tabdir.tabs[i].tag = CHR('p','r','o','p'); - at->tabdir.tabs[i].data = at->prop; - at->tabdir.tabs[i++].length = at->proplen; - } - - if ( at->vheadf!=NULL ) { - at->tabdir.tabs[i].tag = CHR('v','h','e','a'); - at->tabdir.tabs[i].data = at->vheadf; - at->tabdir.tabs[i++].length = at->vheadlen; - - at->tabdir.tabs[i].tag = CHR('v','m','t','x'); - at->tabdir.tabs[i].data = at->gi.vmtx; - at->tabdir.tabs[i++].length = at->gi.vmtxlen; - } - - if ( at->fvar!=NULL ) { - at->tabdir.tabs[i].tag = CHR('f','v','a','r'); - at->tabdir.tabs[i].data = at->fvar; - at->tabdir.tabs[i++].length = at->fvarlen; - } - if ( at->gvar!=NULL ) { - at->tabdir.tabs[i].tag = CHR('g','v','a','r'); - at->tabdir.tabs[i].data = at->gvar; - at->tabdir.tabs[i++].length = at->gvarlen; - } - if ( at->cvar!=NULL ) { - at->tabdir.tabs[i].tag = CHR('c','v','a','r'); - at->tabdir.tabs[i].data = at->cvar; - at->tabdir.tabs[i++].length = at->cvarlen; - } - if ( at->avar!=NULL ) { - at->tabdir.tabs[i].tag = CHR('a','v','a','r'); - at->tabdir.tabs[i].data = at->avar; - at->tabdir.tabs[i++].length = at->avarlen; - } - - if ( i>=MAX_TAB ) - IError("Miscalculation of number of tables needed. Up sizeof tabs array in struct tabdir in ttf.h" ); - - for ( tab=sf->ttf_tab_saved; tab!=NULL && i<MAX_TAB; tab=tab->next ) { - at->tabdir.tabs[i].tag = tab->tag; - at->tabdir.tabs[i].data = tab->temp; - at->tabdir.tabs[i++].length = tab->len; - } - if ( tab!=NULL ) - IError("Some user supplied tables omitted. Up sizeof tabs array in struct tabdir in ttf.h" ); - - at->tabdir.numtab = i; - at->tabdir.searchRange = (i<16?8:i<32?16:i<64?32:64)*16; - at->tabdir.entrySel = (i<16?3:i<32?4:i<64?5:6); - at->tabdir.rangeShift = at->tabdir.numtab*16-at->tabdir.searchRange; -} - -static int initTables(struct alltabs *at, SplineFont *sf, enum fontformat format, - int32 *bsizes, enum bitmapformat bf) { - int i, aborted, offset; - struct ttf_table *tab; - - if (strmatch(at->map->enc->enc_name, "symbol") == 0 && format == ff_ttf) - format = ff_ttfsym; - - tab = SFFindTable(sf, CHR('c', 'v', 't', ' ')); - if (tab != NULL) { - at->oldcvt = tab; - at->oldcvtlen = tab->len; - } - - SFDefaultOS2Info(&sf->pfminfo, sf, sf->fontname); - - at->gi.xmin = at->gi.ymin = 15000; - at->gi.sf = sf; - bsizes = NULL; - - if (sf->subfonts != NULL) { - SFDummyUpCIDs(&at->gi, sf); /* life is easier if we ignore the separate fonts of a cid keyed fonts and treat it as flat */ - } else if (format != ff_none) - AssignTTFGlyph(&at->gi, sf, at->map, format == ff_otf); - else { - if (bsizes == NULL) { - ff_post_error(_("No bitmap strikes"), _("No bitmap strikes")); - AbortTTF(at, sf); - return ( false); - } -// AssignTTFBitGlyph(&at->gi, sf, at->map, bsizes); - } - if (at->gi.gcnt > 65535) { - ff_post_error(_("Too many glyphs"), _("The 'sfnt' format is currently limited to 65535 glyphs, and your font has %d of them."), - at->gi.gcnt); - AbortTTF(at, sf); - return ( false); - } else if (at->gi.gcnt == 65535) { - /* GID 65535 is used as a "No Glyph" mark in many places (cmap tables, mac substitutions to delete a glyph */ - LogError(_("Your font has exactly 65535 glyphs. Encoding 65535 is the limit and is often used as a magic \ - value, so it may cause quirks.\n")); - } - - - ATmaxpInit(at,sf,format); - if ( format==ff_otf ) - aborted = !dumptype2glyphs(sf,at); - else if ( format==ff_otfcid ) - aborted = !dumpcidglyphs(sf,at); - else { - /* if format==ff_none the following will put out lots of space glyphs */ - aborted = !dumpglyphs(sf,&at->gi); - } - if ( aborted ) { - AbortTTF(at,sf); -return( false ); - } - - sethead(&at->head,sf,at,format,bsizes); - sethhead(&at->hhead,&at->vhead,at,sf); - if ( format==ff_none && at->otbbitmaps ) - dummyloca(at); - else if ( format!=ff_otf && format!=ff_otfcid && bf!=bf_sfnt_dfont && - (format!=ff_none || (bsizes!=NULL && !at->applemode && at->opentypemode)) ) - redoloca(at); - redohead(at); - if ( format!=ff_none || !at->applemode ) /* No 'hhea' table for apple bitmap-only fonts */ - redohhead(at,false); - if ( sf->hasvmetrics ) { - redohhead(at,true); - } - ttf_fftm_dump(sf,at); - - if ( format!=ff_type42 && format!=ff_type42cid && !sf->internal_temp ) { - initATTables(at, sf, format); - } - redomaxp(at,format); - if ( format!=ff_otf && format!=ff_otfcid && format!=ff_none ) { - if (( sf->gasp_cnt!=0 || !SFHasInstructions(sf)) - && format!=ff_type42 && format!=ff_type42cid ) - dumpgasp(at, sf); - at->fpgmf = dumpstoredtable(sf,CHR('f','p','g','m'),&at->fpgmlen); - at->prepf = dumpstoredtable(sf,CHR('p','r','e','p'),&at->preplen); - at->cvtf = dumpstoredtable(sf,CHR('c','v','t',' '),&at->cvtlen); - } - for ( tab=sf->ttf_tab_saved; tab!=NULL; tab=tab->next ) - tab->temp = dumpsavedtable(tab); - if ( format!=ff_type42 && format!=ff_type42cid ) { - dumppost(at,sf,format); - dumpcmap(at,sf,format); - - pfed_dump(at,sf); - tex_dump(at,sf); - } - if ( sf->subfonts!=NULL ) { - free(sf->glyphs); sf->glyphs = NULL; - sf->glyphcnt = sf->glyphmax = 0; - } - free( at->gi.bygid ); - at->gi.gcnt = 0; - - buildtablestructures(at,sf,format); - for ( i=0; i<at->tabdir.numtab; ++i ) { - struct taboff *tab = &at->tabdir.tabs[i]; - at->tabdir.ordered[i] = tab; - at->tabdir.alpha[i] = tab; -/* This is the ordering of tables in ARIAL. I've no idea why it makes a */ -/* difference to order them, time to do a seek seems likely to be small, but */ -/* other people make a big thing about ordering them so I'll do it. */ -/* I got bored after glyph. Adobe follows the same scheme for their otf fonts */ -/* so at least the world is consistant */ -/* On the other hand, MS Font validator has a different idea. Oh well */ -/* From: http://partners.adobe.com/asn/tech/type/opentype/recom.jsp */ -/* TrueType Ordering */ -/* head, hhea, maxp, OS/2, hmtx, LTSH, VDMX, hdmx, cmap, fpgm, prep, cvt, */ -/* loca, glyf, kern, name, post, gasp, PCLT, DSIG */ -/* CFF in OpenType Ordering */ -/* head, hhea, maxp, OS/2, name, cmap, post, CFF, (other tables, as convenient) */ - if ( format==ff_otf || format==ff_otfcid ) { - tab->orderingval = tab->tag==CHR('h','e','a','d')? 1 : - tab->tag==CHR('h','h','e','a')? 2 : - tab->tag==CHR('m','a','x','p')? 3 : - tab->tag==CHR('O','S','/','2')? 4 : - tab->tag==CHR('n','a','m','e')? 5 : - tab->tag==CHR('c','m','a','p')? 6 : - tab->tag==CHR('p','o','s','t')? 7 : - tab->tag==CHR('C','F','F',' ')? 8 : - tab->tag==CHR('G','D','E','F')? 17 : - tab->tag==CHR('G','S','U','B')? 18 : - tab->tag==CHR('G','P','O','S')? 19 : - 20; - } else { - tab->orderingval = tab->tag==CHR('h','e','a','d')? 1 : - tab->tag==CHR('h','h','e','a')? 2 : - tab->tag==CHR('m','a','x','p')? 3 : - tab->tag==CHR('O','S','/','2')? 4 : - tab->tag==CHR('h','m','t','x')? 5 : - tab->tag==CHR('L','T','S','H')? 6 : - tab->tag==CHR('V','D','M','X')? 7 : - tab->tag==CHR('h','d','m','x')? 8 : - tab->tag==CHR('c','m','a','p')? 9 : - tab->tag==CHR('f','p','g','m')? 10 : - tab->tag==CHR('p','r','e','p')? 11 : - tab->tag==CHR('c','v','t',' ')? 12 : - tab->tag==CHR('l','o','c','a')? 13 : - tab->tag==CHR('g','l','y','f')? 14 : - tab->tag==CHR('k','e','r','n')? 15 : - tab->tag==CHR('n','a','m','e')? 16 : - tab->tag==CHR('p','o','s','t')? 17 : - tab->tag==CHR('g','a','s','p')? 18 : - tab->tag==CHR('P','C','L','T')? 19 : - tab->tag==CHR('D','S','I','G')? 20 : - tab->tag==CHR('G','D','E','F')? 21 : - tab->tag==CHR('G','S','U','B')? 22 : - tab->tag==CHR('G','P','O','S')? 23 : - 24; - } - } - - qsort(at->tabdir.ordered,at->tabdir.numtab,sizeof(struct taboff *),tcomp); - qsort(at->tabdir.alpha,i,sizeof(struct taboff *),tagcomp); - - offset = sizeof(int32)+4*sizeof(int16) + at->tabdir.numtab*4*sizeof(int32); - for ( i=0; i<at->tabdir.numtab; ++i ) if ( at->tabdir.ordered[i]->data!=NULL ) { - at->tabdir.ordered[i]->offset = offset; - offset += ((at->tabdir.ordered[i]->length+3)>>2)<<2; - at->tabdir.ordered[i]->checksum = filechecksum(at->tabdir.ordered[i]->data); - } - for ( i=0; i<at->tabdir.numtab; ++i ) if ( at->tabdir.ordered[i]->data==NULL ) { - struct taboff *tab = &at->tabdir.tabs[at->tabdir.ordered[i]->dup_of]; - at->tabdir.ordered[i]->offset = tab->offset; - at->tabdir.ordered[i]->checksum = tab->checksum; - } - - tab = SFFindTable(sf,CHR('c','v','t',' ')); - if ( tab!=NULL ) { - if ( at->oldcvt!=NULL && at->oldcvtlen<tab->len ) - tab->len = at->oldcvtlen; - else if ( at->oldcvt==NULL ) { - /* We created a cvt table when we output the .notdef glyph */ - /* now that means AutoInstr thinks it no longer has a blank */ - /* slate to work with, and will complain, much to the user's */ - /* surprise. So get rid of it */ - struct ttf_table *prev = NULL; - for ( tab = sf->ttf_tables; tab!=NULL ; prev = tab, tab=tab->next ) - if ( tab->tag==CHR('c','v','t',' ') ) - break; - if ( tab!=NULL ) { - if ( prev==NULL ) - sf->ttf_tables = tab->next; - else - prev->next = tab->next; - tab->next = NULL; - TtfTablesFree(tab); - } - } - } -return( true ); -} - -static char *Tag2String(uint32 tag) { - static char buffer[8]; - - buffer[0] = tag>>24; - buffer[1] = tag>>16; - buffer[2] = tag>>8; - buffer[3] = tag; - buffer[4] = 0; -return( buffer ); -} - -static void dumpttf(FILE *ttf,struct alltabs *at) { - int32 checksum; - int i, head_index=-1; - /* I can't use fwrite because I (may) have to byte swap everything */ - - putlong(ttf,at->tabdir.version); - putshort(ttf,at->tabdir.numtab); - putshort(ttf,at->tabdir.searchRange); - putshort(ttf,at->tabdir.entrySel); - putshort(ttf,at->tabdir.rangeShift); - for ( i=0; i<at->tabdir.numtab; ++i ) { - if ( at->tabdir.alpha[i]->tag==CHR('h','e','a','d') || at->tabdir.alpha[i]->tag==CHR('b','h','e','d') ) - head_index = i; - putlong(ttf,at->tabdir.alpha[i]->tag); - putlong(ttf,at->tabdir.alpha[i]->checksum); - putlong(ttf,at->tabdir.alpha[i]->offset); - putlong(ttf,at->tabdir.alpha[i]->length); - } - - for ( i=0; i<at->tabdir.numtab; ++i ) if ( at->tabdir.ordered[i]->data!=NULL ) { - if ( !ttfcopyfile(ttf,at->tabdir.ordered[i]->data, - at->tabdir.ordered[i]->offset,Tag2String(at->tabdir.ordered[i]->tag))) - at->error = true; - } - - if ( head_index!=-1 ) { - checksum = filechecksum(ttf); - checksum = 0xb1b0afba-checksum; - fseek(ttf,at->tabdir.alpha[head_index]->offset+2*sizeof(int32),SEEK_SET); - putlong(ttf,checksum); - } - - /* ttfcopyfile closed all the files (except ttf) */ -} - -static void DumpGlyphToNameMap(char *fontname,SplineFont *sf) { - char *d, *e; - char *newname = malloc(strlen(fontname)+10); - FILE *file; - int i,k,max; - SplineChar *sc; - - strcpy(newname,fontname); - d = strrchr(newname,'/'); - if ( d==NULL ) d=newname; - e = strrchr(d,'.'); - if ( e==NULL ) e = newname+strlen(newname); - strcpy(e,".g2n"); - - file = fopen(newname,"wb"); - if ( file==NULL ) { - LogError( _("Failed to open glyph to name map file for writing: %s\n"), newname ); - free(newname); -return; - } - - if ( sf->subfontcnt==0 ) - max = sf->glyphcnt; - else { - for ( k=max=0; k<sf->subfontcnt; ++k ) - if ( sf->subfonts[k]->glyphcnt > max ) - max = sf->subfonts[k]->glyphcnt; - } - for ( i=0; i<max; ++i ) { - sc = NULL; - if ( sf->subfontcnt==0 ) - sc = sf->glyphs[i]; - else { - for ( k=0; k<sf->subfontcnt; ++k ) if ( i<sf->subfonts[k]->glyphcnt ) - if ( (sc=sf->subfonts[k]->glyphs[i])!=NULL ) - break; - } - if ( sc!=NULL && sc->ttf_glyph!=-1 ) { - fprintf( file, "GLYPHID %d\tPSNAME %s", sc->ttf_glyph, sc->name ); - if ( sc->unicodeenc!=-1 ) - fprintf( file, "\tUNICODE %04X", sc->unicodeenc ); - putc('\n',file); - } - } - fclose(file); - free(newname); -} - -static int dumpcff(struct alltabs *at,SplineFont *sf,enum fontformat format, - FILE *cff) { - int ret; - - if ( format==ff_cff ) { - AssignTTFGlyph(&at->gi,sf,at->map,true); - ret = dumptype2glyphs(sf,at); - } else { - SFDummyUpCIDs(&at->gi,sf); /* life is easier if we ignore the separate fonts of a cid keyed fonts and treat it as flat */ - ret = dumpcidglyphs(sf,at); - free(sf->glyphs); sf->glyphs = NULL; - sf->glyphcnt = sf->glyphmax = 0; - } - free( at->gi.bygid ); - - if ( !ret ) - at->error = true; - else if ( at->gi.flags & ps_flag_nocffsugar ) { - if ( !ttfcopyfile(cff,at->cfff,0,"CFF")) - at->error = true; - } else { - long len; - char buffer[80]; - fprintf(cff,"%%!PS-Adobe-3.0 Resource-FontSet\n"); - fprintf(cff,"%%%%DocumentNeedResources:ProcSet (FontSetInit)\n"); - fprintf(cff,"%%%%Title: (FontSet/%s)\n", sf->fontname); - fprintf(cff,"%%%%EndComments\n" ); - fprintf(cff,"%%%%IncludeResource: ProcSet(FontSetInit)\n" ); - fprintf(cff,"%%%%BeginResource: FontSet(%s)\n", sf->fontname ); - fprintf(cff,"/FontSetInit /ProcSet findresource begin\n" ); - fseek(at->cfff,0,SEEK_END); - len = ftell(at->cfff); - rewind(at->cfff); - sprintf( buffer, "/%s %ld StartData\n", sf->fontname, len ); - fprintf(cff,"%%%%BeginData: %ld Binary Bytes\n", (long) (len+strlen(buffer)) ); - fputs(buffer,cff); - if ( !ttfcopyfile(cff,at->cfff,ftell(cff),"CFF")) - at->error = true; - fprintf(cff,"\n%%%%EndData\n" ); - fprintf(cff,"%%%%EndResource\n" ); - fprintf(cff,"%%%%EOF\n" ); - } -return( !at->error ); -} - -static void ATinit(struct alltabs *at,SplineFont *sf,EncMap *map,int flags, int layer, - enum fontformat format, enum bitmapformat bf,int *bsizes) { - - at->gi.flags = flags; - at->gi.layer = layer; - at->gi.is_ttf = format == ff_ttf || format==ff_ttfsym || format==ff_ttfmacbin || format==ff_ttfdfont; - at->gi.sf = sf; - at->applemode = (flags&ttf_flag_applemode)?1:0; - at->opentypemode = (flags&ttf_flag_otmode)?1:0; - at->msbitmaps = bsizes!=NULL && at->opentypemode; - at->applebitmaps = bsizes!=NULL && at->applemode; - at->gi.onlybitmaps = format==ff_none; - - if ( bf==bf_sfnt_dfont ) { at->msbitmaps = false; at->applebitmaps=true; at->opentypemode=false; at->gi.onlybitmaps=true;} - if ( bf==bf_sfnt_ms ) { at->msbitmaps = true; at->applebitmaps=false; at->applemode=false; at->gi.onlybitmaps=true;} - if ( bf==bf_otb ) { at->otbbitmaps = true; at->applebitmaps=at->msbitmaps=false; at->applemode=false; at->gi.onlybitmaps=true;} - - if ( bsizes!=NULL && !at->applebitmaps && !at->otbbitmaps && !at->msbitmaps ) - at->msbitmaps = true; /* They asked for bitmaps, but no bitmap type selected */ - at->gi.bsizes = bsizes; - at->gi.fixed_width = CIDOneWidth(sf); - at->isotf = format==ff_otf || format==ff_otfcid; - at->format = format; - at->next_strid = 256; - if ( at->applemode && sf->mm!=NULL && sf->mm->apple && - (format==ff_ttf || format==ff_ttfsym || format==ff_ttfmacbin || - format==ff_ttfdfont) && - MMValid(sf->mm,false)) { - at->dovariations = true; - at->gi.dovariations = true; - sf = sf->mm->normal; - } - at->sf = sf; - at->map = map; -} - -int _WriteTTFFont(FILE *ttf,SplineFont *sf,enum fontformat format, - int32 *bsizes, enum bitmapformat bf,int flags,EncMap *map, int layer) { - struct alltabs at; - int i, anyglyphs; - - short_too_long_warned = 0; // This is a static variable defined for putshort. - /* TrueType probably doesn't need this, but OpenType does for floats in dictionaries */ - ff_locale_t tmplocale, oldlocale; // Declare temporary locale storage. - switch_to_c_locale(&tmplocale, &oldlocale); // Switch to the C locale temporarily and cache the old locale. - - if ( format==ff_otfcid || format== ff_cffcid ) { - if ( sf->cidmaster ) sf = sf->cidmaster; - } else { - if ( sf->subfontcnt!=0 ) sf = sf->subfonts[0]; - } - - if ( sf->subfontcnt==0 ) { - anyglyphs = false; - for ( i=sf->glyphcnt-1; i>=0 ; --i ) { - if ( SCWorthOutputting(sf->glyphs[i])) { - anyglyphs = true; - if ( sf->glyphs[i]->unicodeenc!=-1 ) - break; - } - } - if ( !anyglyphs && !sf->internal_temp ) { - ff_post_error(_("No Encoded Glyphs"),_("Warning: Font contained no glyphs")); - } - if ( format!=ff_ttfsym && !(flags&ttf_flag_symbol) && !sf->internal_temp ) { - if ( i<0 && anyglyphs ) { - if ( map->enccount<=256 ) { - char *buts[3]; - buts[0] = _("_Yes"); buts[1] = _("_No"); buts[2] = NULL; - if ( ff_ask(_("No Encoded Glyphs"),(const char **) buts,0,1,_("This font contains no glyphs with unicode encodings.\nWould you like to use a \"Symbol\" encoding instead of Unicode?"))==0 ) - flags |= ttf_flag_symbol; - } else - ff_post_error(_("No Encoded Glyphs"),_("This font contains no glyphs with unicode encodings.\nYou will probably not be able to use the output.")); - } - } - } - - for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) - sf->glyphs[i]->ttf_glyph = -1; - - memset(&at,'\0',sizeof(struct alltabs)); - ATinit(&at,sf,map,flags,layer,format,bf,bsizes); - - if ( format==ff_cff || format==ff_cffcid ) { - dumpcff(&at,sf,format,ttf); - } else { - if ( initTables(&at,sf,format,bsizes,bf)) - dumpttf(ttf,&at); - } - switch_to_old_locale(&tmplocale, &oldlocale); // Switch to the cached locale. - if ( at.error || ferror(ttf)) -return( 0 ); - -#ifdef __CygWin - /* Modern versions of windows want the execute bit set on a ttf file */ - /* I've no idea what this corresponds to in windows, nor any idea on */ - /* how to set it from the windows UI, but this seems to work */ - { - struct stat buf; - fstat(fileno(ttf),&buf); - fchmod(fileno(ttf),S_IXUSR | buf.st_mode ); - } -#endif - -return( 1 ); -} - -int WriteTTFFont(char *fontname,SplineFont *sf,enum fontformat format, - int32 *bsizes, enum bitmapformat bf,int flags,EncMap *map, int layer) { - FILE *ttf; - int ret; - - if ( strstr(fontname,"://")!=NULL ) { - if (( ttf = tmpfile2())==NULL ) -return( 0 ); - } else { - if (( ttf=fopen(fontname,"wb+"))==NULL ) -return( 0 ); - } - ret = _WriteTTFFont(ttf,sf,format,bsizes,bf,flags,map,layer); - if ( ret && (flags&ttf_flag_glyphmap) ) - DumpGlyphToNameMap(fontname,sf); - if ( fclose(ttf)==-1 ) -return( 0 ); -return( ret ); -} - -/* ************************************************************************** */ -/* ****************************** Type42 stuff ****************************** */ - -/* ************************************************************************** */ -/* ******************************* TTC stuff ******************************** */ -/* ************************************************************************** */ - -typedef struct splinecharlist *UHash[65536]; -typedef struct splinecharlist *NHash[257]; - -static unsigned int hashname(const char *name) { - unsigned int hash = 0; - - while ( *name ) { - unsigned int extra = (hash>>27); - hash<<=5; - hash += *name&0x1f; - hash ^= extra; - ++name; - } -return( hash % 257 ); -} - -static int glyphmatches(SplineChar *sc,SplineChar *sc2,int layer) { - RefChar *r, *r2; - SplineSet *ss, *ss2; - SplinePoint *sp, *sp2; - - if ( sc->width!=sc2->width ) -return( false ); - if ( sc->ttf_instrs_len != sc2->ttf_instrs_len ) -return( false ); - if ( sc->ttf_instrs_len!=0 && memcmp(sc->ttf_instrs,sc2->ttf_instrs,sc->ttf_instrs_len)!=0 ) -return( false ); - - for ( r=sc->layers[layer].refs, r2=sc2->layers[layer].refs; - r!=NULL && r2!=NULL; - r = r->next, r2 = r2->next ) { - if ( r->transform[0] != r2->transform[0] || - r->transform[1] != r2->transform[1] || - r->transform[2] != r2->transform[2] || - r->transform[3] != r2->transform[3] || - r->transform[4] != r2->transform[4] || - r->transform[5] != r2->transform[5] ) -return( false ); - if ( r->sc->unicodeenc!=r2->sc->unicodeenc ) -return( false ); - if ( r->sc->unicodeenc==-1 && strcmp(r->sc->name,r2->sc->name)!=0 ) -return( false ); - } - if ( r!=NULL || r2!=NULL ) -return( false ); - - for ( ss=sc->layers[layer].splines, ss2=sc2->layers[layer].splines; - ss!=NULL && ss2!=NULL; - ss = ss->next, ss2 = ss2->next ) { - for ( sp=ss->first, sp2=ss2->first; sp!=NULL && sp2!=NULL; ) { - if ( sp->me.x != sp2->me.x || - sp->me.y != sp2->me.y || - sp->nextcp.x != sp2->nextcp.x || - sp->nextcp.y != sp2->nextcp.y || - sp->prevcp.x != sp2->prevcp.x || - sp->prevcp.y != sp2->prevcp.y ) -return( false ); - sp = (sp->next ? sp->next->to : NULL); - sp2 = (sp2->next ? sp2->next->to : NULL); - if ( sp==ss->first ) { - if ( sp2==ss2->first ) - break; -return( false ); - } else if ( sp2==ss2->first ) -return( false ); - } - if (( sp==NULL && sp2!=NULL ) || ( sp!=NULL && sp2==NULL )) -return( false ); - } - if ( ss==NULL && ss2==NULL ) -return( true ); - -return( false ); -} - -static SplineChar *hashglyphfound(SplineChar *sc,UHash *uhash,NHash *nhash,int layer) { - int hash; - struct splinecharlist *test; - struct altuni *alt; - - /* the unicodeenc might be unset and we might still have altunis if the */ - /* glyph is controlled by a variant selector */ - if ( sc->unicodeenc==-1 && sc->altuni==NULL ) { - hash = hashname(sc->name); - for ( test=(*nhash)[hash]; test!=NULL; test=test->next ) - if ( strcmp(test->sc->name,sc->name)==0 && glyphmatches(sc,test->sc,layer)) -return( test->sc ); - } else if ( sc->unicodeenc!=-1 ) { - hash = sc->unicodeenc&0xffff; - for ( test=(*uhash)[hash]; test!=NULL; test=test->next ) - if ( glyphmatches(sc,test->sc,layer)) -return( test->sc ); - } - for ( alt=sc->altuni; alt!=NULL; alt=alt->next ) { - hash = alt->unienc&0xffff; - for ( test=(*uhash)[hash]; test!=NULL; test=test->next ) - if ( glyphmatches(sc,test->sc,layer)) -return( test->sc ); - } -return( NULL ); -} - -static void hashglyphadd(SplineChar *sc,UHash *uhash,NHash *nhash) { - int hash; - struct splinecharlist *test; - struct altuni *alt; - - if ( sc->unicodeenc==-1 && sc->altuni==NULL ) { - hash = hashname(sc->name); - test = chunkalloc(sizeof(struct splinecharlist)); - test->sc = sc; - test->next = (*nhash)[hash]; - (*nhash)[hash] = test; - } else if ( sc->unicodeenc!=-1 ) { - hash = sc->unicodeenc&0xffff; - test = chunkalloc(sizeof(struct splinecharlist)); - test->sc = sc; - test->next = (*uhash)[hash]; - (*uhash)[hash] = test; - } - for ( alt=sc->altuni; alt!=NULL; alt=alt->next ) { - hash = alt->unienc&0xffff; - test = chunkalloc(sizeof(struct splinecharlist)); - test->sc = sc; - test->next = (*uhash)[hash]; - (*uhash)[hash] = test; - } -} - -static struct alltabs *ttc_prep(struct sflist *sfs, enum fontformat format, - enum bitmapformat bf,int flags, int layer,SplineFont *dummysf) { - struct alltabs *ret; - int fcnt, cnt, gcnt=3; - struct sflist *sfitem; - int emsize = -1; - UHash *uhash; /* hash glyphs by unicode */ - NHash *nhash; /* hash glyphs by name if no unicode */ - int anyvmetrics = false; - int *bygid; - SplineFont *sf; - SplineChar *sc, *test; - int i, aborted; - - for ( sfitem= sfs, cnt=0; sfitem!=NULL; sfitem=sfitem->next, ++cnt ) { - sf = sfitem->sf; - /* to share the same 'head' table all must be the same emsize */ - if ( emsize==-1 ) - emsize = sf->ascent + sf->descent; - else if ( emsize != sf->ascent + sf->descent ) -return( NULL ); - if ( format==ff_otf && !PSDictSame(sf->private,sfs->sf->private)) -return( NULL ); - if ( sf->hasvmetrics ) anyvmetrics = true; - for ( i=0; i<sf->glyphcnt; ++i ) if ( (sc = sf->glyphs[i])!=NULL ) - sc->ttf_glyph = -1; - gcnt += sf->glyphcnt; - } - if ( cnt==0 ) -return( NULL ); - fcnt = cnt; - - uhash = calloc(1,sizeof(UHash)); - nhash = calloc(1,sizeof(NHash)); - - *dummysf = *sfs->sf; - dummysf->glyphmax = gcnt; - dummysf->glyphs = calloc(gcnt,sizeof(SplineChar *)); - dummysf->glyphcnt = 0; - dummysf->hasvmetrics = anyvmetrics; - - bygid = malloc((gcnt+3)*sizeof(int)); - memset(bygid,0xff, (gcnt+3)*sizeof(int)); - for ( sfitem= sfs; sfitem!=NULL; sfitem=sfitem->next ) { - AssignNotdefNull(sfitem->sf,bygid,false); - if ( bygid[0]!=-1 && dummysf->glyphs[0]==NULL ) { - dummysf->glyphs[0] = sfitem->sf->glyphs[bygid[0]]; - bygid[0]=0; - } - if ( format==ff_ttf ) { - if ( bygid[1]!=-1 && dummysf->glyphs[1]==NULL ) { - dummysf->glyphs[1] = sfitem->sf->glyphs[bygid[1]]; - bygid[1]=1; - } - if ( bygid[2]!=-1 && dummysf->glyphs[2]==NULL ) { - dummysf->glyphs[2] = sfitem->sf->glyphs[bygid[2]]; - bygid[2]=2; - } - if ( bygid[0]!=-1 && bygid[1]!=-1 && bygid[2]!=-1 ) - break; - } else { - if ( bygid[0]!=-1 ) - break; - } - } - dummysf->glyphcnt = format==ff_ttf ? 3 : 1; - - ret = calloc(fcnt+2,sizeof(struct alltabs)); - ATinit(&ret[fcnt],dummysf,sfs->map,flags&~ttf_flag_dummyDSIG, - layer,format,bf,NULL); - ret[fcnt].gi.ttc_composite_font = true; - ATmaxpInit(&ret[fcnt],dummysf,format); - - for ( sfitem= sfs, cnt=0; sfitem!=NULL; sfitem=sfitem->next, ++cnt ) { - sf = sfitem->sf; - ATinit(&ret[cnt],sf,sfitem->map,flags&~ttf_flag_dummyDSIG, - layer,format,bf,sfitem->sizes); - ret[cnt].gi.bygid = malloc((gcnt+3)*sizeof(int)); - memset(ret[cnt].gi.bygid,-1,(gcnt+3)*sizeof(int)); - for ( i=0; i<sf->glyphcnt; ++i ) { - if ( SCWorthOutputting(sc = sf->glyphs[i])) { - if ( sc->ttf_glyph==-1 ) { - if ( strcmp(sc->name,".notdef")==0 ) - sc->ttf_glyph = bygid[0]; - else if ( format==ff_ttf && - (strcmp(sf->glyphs[i]->name,".null")==0 || - strcmp(sf->glyphs[i]->name,"uni0000")==0 || - (i==1 && strcmp(sf->glyphs[1]->name,"glyph1")==0)) ) - sc->ttf_glyph = bygid[1]; - else if ( format==ff_ttf && - (strcmp(sf->glyphs[i]->name,"nonmarkingreturn")==0 || - strcmp(sf->glyphs[i]->name,"uni000D")==0 || - (i==2 && strcmp(sf->glyphs[2]->name,"glyph2")==0))) - sc->ttf_glyph = bygid[2]; - else { - test = hashglyphfound(sc,uhash,nhash,layer); - if ( test!=NULL ) - sc->ttf_glyph = test->ttf_glyph; - else { - sc->ttf_glyph = dummysf->glyphcnt++; - bygid[sc->ttf_glyph] = sc->ttf_glyph; - dummysf->glyphs[sc->ttf_glyph] = sc; - hashglyphadd(sc,uhash,nhash); - } - } - } - if ( sc->ttf_glyph!=-1 ) { - ret[cnt].gi.bygid[sc->ttf_glyph] = i; - if ( sc->ttf_glyph>=ret[cnt].gi.gcnt ) - ret[cnt].gi.gcnt = sc->ttf_glyph+1; - } - } - if ( sc!=NULL ) - sc->lsidebearing = 0x7fff; - } - - MaxpFromTable(&ret[cnt],sf); - - if ( ret[cnt].maxp.maxZones > ret[fcnt].maxp.maxZones ) - ret[fcnt].maxp.maxZones = ret[cnt].maxp.maxZones; - if ( ret[cnt].maxp.maxTwilightPts > ret[fcnt].maxp.maxTwilightPts ) - ret[fcnt].maxp.maxTwilightPts = ret[cnt].maxp.maxTwilightPts; - if ( ret[cnt].maxp.maxStorage > ret[fcnt].maxp.maxStorage ) - ret[fcnt].maxp.maxStorage = ret[cnt].maxp.maxStorage; - if ( ret[cnt].maxp.maxFDEFs > ret[fcnt].maxp.maxFDEFs ) - ret[fcnt].maxp.maxFDEFs = ret[cnt].maxp.maxFDEFs; - if ( ret[cnt].maxp.maxIDEFs > ret[fcnt].maxp.maxIDEFs ) - ret[fcnt].maxp.maxIDEFs = ret[cnt].maxp.maxIDEFs; - if ( ret[cnt].maxp.maxStack > ret[fcnt].maxp.maxStack ) - ret[fcnt].maxp.maxStack = ret[cnt].maxp.maxStack; - } - free(uhash); - free(nhash); - - if ( dummysf->glyphcnt>0xffff ) { - free(dummysf->glyphs); - free(bygid); - for ( sfitem= sfs, cnt=0; sfitem!=NULL; sfitem=sfitem->next, ++cnt ) - free(ret[cnt].gi.bygid); - free(ret); -return( NULL ); - } - - ret[fcnt].gi.fixed_width = CIDOneWidth(sf); - ret[fcnt].gi.bygid = bygid; - ret[fcnt].gi.gcnt = ret[fcnt].maxp.numGlyphs = dummysf->glyphcnt; - if ( format==ff_ttf ) - aborted = !dumpglyphs(dummysf,&ret[cnt].gi); - else - aborted = !dumptype2glyphs(dummysf,&ret[cnt]); - if ( aborted ) { - free(dummysf->glyphs); - free(bygid); - for ( sfitem= sfs, cnt=0; sfitem!=NULL; sfitem=sfitem->next, ++cnt ) - free(ret[cnt].gi.bygid); - free(ret); -return( NULL ); - } - sethhead(&ret[fcnt].hhead,&ret[fcnt].vhead,&ret[fcnt],dummysf); - for ( sfitem= sfs, cnt=0; sfitem!=NULL; sfitem=sfitem->next, ++cnt ) - ret[cnt].maxp = ret[fcnt].maxp; - - /* Just to get a timestamp for all other heads */ - /* and to figure out whether 'loca' is 4byte or 2 */ - sethead(&ret[fcnt].head,dummysf,&ret[fcnt],format,NULL); - if ( format==ff_ttf ) - redoloca(&ret[fcnt]); - redohhead(&ret[fcnt],false); - if ( dummysf->hasvmetrics ) - redohhead(&ret[fcnt],true); - ttf_fftm_dump(dummysf,&ret[fcnt]); - -return( ret ); -} - -static FILE *checkdupstoredtable(SplineFont *sf,uint32 tag,int *len, - struct alltabs *all, int me) { - int i; - struct ttf_table *tab = SFFindTable(sf,tag), *test; - - if ( tab==NULL ) { - *len = 0; -return( NULL ); - } - for ( i=0; i<me; ++i ) { - test = SFFindTable(all[i].sf,tag); - if ( test!=NULL && test->len==tab->len && - memcmp(test->data,tab->data,tab->len)==0 ) { - *len = i; -return( (FILE *) (intpt) -1 ); - } - } -return( dumpstoredtable(sf,tag,len)); -} - -static void ttc_perfonttables(struct alltabs *all, int me, int mainpos, - enum fontformat format ) { - struct alltabs *at = &all[me]; - struct alltabs *tabsmain = &all[mainpos]; - SplineFont *sf = at->sf; - struct ttf_table *tab; - - at->gi.xmin = tabsmain->gi.xmin; at->gi.xmax = tabsmain->gi.xmax; - at->gi.ymin = tabsmain->gi.ymin; at->gi.ymax = tabsmain->gi.ymax; - at->gi.glyph_len = tabsmain->gi.glyph_len; - at->gi.gcnt = tabsmain->maxp.numGlyphs; - sethead(&at->head,sf,at,format,NULL); - memcpy(at->head.modtime,tabsmain->head.modtime,sizeof(at->head.modtime)); - memcpy(at->head.createtime,at->head.modtime,sizeof(at->head.modtime)); - initATTables(at, sf, format); /* also name and OS/2 */ - - if ( format==ff_ttf ) { - if ( sf->gasp_cnt!=0 || !SFHasInstructions(sf) ) - dumpgasp(at, sf); - at->fpgmf = checkdupstoredtable(sf,CHR('f','p','g','m'),&at->fpgmlen, all, me); - at->prepf = checkdupstoredtable(sf,CHR('p','r','e','p'),&at->preplen, all, me); - at->cvtf = checkdupstoredtable(sf,CHR('c','v','t',' '),&at->cvtlen, all, me); - } - - for ( tab=sf->ttf_tab_saved; tab!=NULL; tab=tab->next ) - tab->temp = dumpsavedtable(tab); - { - /* post table is expected to have names for every glyph (or none) even*/ - /* those not used in this font. Now it might seem we could just share*/ - /* the post table, but it also contains a few font specific things */ - /* (italic angle, etc.) so dump one for each font and hope that we'll*/ - /* be able to coalesce them later when we check if any tables are the*/ - /* same across fonts */ - int cnt = sf->glyphcnt; - SplineChar **g = sf->glyphs; - int *bygid = at->gi.bygid; - sf->glyphcnt = tabsmain->sf->glyphcnt; - sf->glyphs = tabsmain->sf->glyphs; - at->gi.bygid = tabsmain->gi.bygid; - dumppost(at,sf,format); - sf->glyphcnt = cnt; - sf->glyphs = g; - at->gi.bygid = bygid; - } - dumpcmap(at,sf,format); - redohead(at); - - pfed_dump(at,sf); - tex_dump(at,sf); - - /* These tables are always to be shared and are found in the extra structure */ - /* called main */ - if ( format==ff_ttf ) { - at->loca = (void *) (intpt) -1; at->localen = mainpos; - at->gi.glyphs = (void *) (intpt) -1; at->gi.glyph_len = mainpos; - } else { - at->cfff = (void *) (intpt) -1; at->cfflen = mainpos; - } - at->fftmf = (void *) (intpt) -1; at->fftmlen = mainpos; - at->hheadf = (void *) (intpt) -1; at->hheadlen = mainpos; - at->gi.hmtx = (void *) (intpt) -1; at->gi.hmtxlen = mainpos; - at->maxpf = (void *) (intpt) -1; at->maxplen = mainpos; - if ( all[mainpos].vheadf!=NULL ) { - at->vheadf = (void *) (intpt) -1; at->vheadlen = mainpos; - at->gi.vmtx = (void *) (intpt) -1; at->gi.vmtxlen = mainpos; - } - - free(at->gi.bygid); -} - -static int tablefilematch(struct taboff *tab,FILE *ttc,struct alltabs *all,int pos) { - int i, ch1, ch2; - struct taboff *test; - unsigned len; - - /* See if this table (which lives in its own file) matches any tables */ - /* with the same tag in an earlier font */ - - for ( i=0; i<pos; ++i ) { - test = findtabindir(&all[i].tabdir,tab->tag); - if ( test==NULL || test->data==(void *) (intpt) -1 || - test->length!=tab->length ) - continue; - rewind(tab->data); - fseek(ttc,test->offset,SEEK_SET); - for ( len=0; len<tab->length && (ch1=getc(tab->data))!=EOF && (ch2=getc(ttc))!=EOF; ++len ) { - if ( ch1!=ch2 ) - break; - } - if ( len==tab->length ) { - rewind(tab->data); - fseek(ttc,0,SEEK_END); -return( i ); - } - } - rewind(tab->data); - fseek(ttc,0,SEEK_END); -return( -1 ); -} - -static void ttc_dump(FILE *ttc,struct alltabs *all, enum fontformat format, - int flags, enum ttc_flags ttc_flags ) { - int i,j,cnt,tot,ch,dup; - int offset, startoffset; - struct taboff *tab; - - for ( cnt=0; all[cnt].sf!=NULL; ++cnt ); - --cnt; /* Last one is dummysf */ - - putlong(ttc,CHR('t','t','c','f')); - if ( flags&ttf_flag_dummyDSIG ) { - putlong(ttc,0x00020000); - startoffset = 4*(3+cnt+4); - } else { - putlong(ttc,0x00010000); - startoffset = 4*(3+cnt); - } - putlong(ttc,cnt); - offset = startoffset; - for ( i=0; i<cnt; ++i ) { - putlong(ttc,offset); /* Pointer to font header */ - offset += (8+16*MAX_TAB); /* Explained below */ - } - if ( flags&ttf_flag_dummyDSIG ) { - putlong(ttc,CHR('D','S','I','G')); - putlong(ttc,8); /* Length of dummy DSIG table */ - putlong(ttc,0x00000001); /* Standard DSIG version */ - putlong(ttc,0); /* No Signatures, no flags */ - } - - /* Now a font header contains 8 bytes of header and 16 bytes/table */ - /* Reserve space for cnt fonts. Don't know how many tables they'll */ - /* have, so reserve MAX_TAB */ - tot = cnt*(8+16*MAX_TAB); - for ( i=0; i<tot; ++i ) - putc('\0', ttc); - - /* Build, but don't output. This is so we can lookup tables by tag later */ - buildtablestructures(&all[cnt],all[cnt].sf,format); - - /* Output some of the smaller tables now, near the head of the file */ - /* I have my doubts about this being a significant savings... but */ - /* it doesn't hurt */ - tab = findtabindir(&all[cnt].tabdir,CHR('h','h','e','a')); - tab->offset = ftell(ttc); - tab->checksum = filechecksum(tab->data); - if ( !ttfcopyfile(ttc,tab->data, tab->offset,Tag2String(tab->tag))) - all[cnt].error = true; - tab = findtabindir(&all[cnt].tabdir,CHR('v','h','e','a')); - if ( tab!=NULL ) { - tab->offset = ftell(ttc); - tab->checksum = filechecksum(tab->data); - if ( !ttfcopyfile(ttc,tab->data, tab->offset,Tag2String(tab->tag))) - all[cnt].error = true; - } - tab = findtabindir(&all[cnt].tabdir,CHR('m','a','x','p')); - tab->offset = ftell(ttc); - for ( i=0; i<64; ++i ) /* maxp table is 64 bytes, fill in later */ - putc('\0', ttc); - tab = findtabindir(&all[cnt].tabdir,CHR('F','F','T','M')); - tab->offset = ftell(ttc); - tab->checksum = filechecksum(tab->data); - if ( !ttfcopyfile(ttc,tab->data, tab->offset,Tag2String(tab->tag))) - all[cnt].error = true; - - for ( i=0; i<cnt; ++i ) { - /* Now generate all tables unique to this font */ - ttc_perfonttables(all, i, cnt, format ); - buildtablestructures(&all[i],all[i].sf,format); - /* Check for any tables which match those of a previous font */ - for ( j=0 ; j<all[i].tabdir.numtab; ++j ) { - if ( all[i].tabdir.tabs[j].data!=(void *) (intpt) -1 && - (dup = tablefilematch(&all[i].tabdir.tabs[j],ttc,all,i))!=-1 ) { - fclose(all[i].tabdir.tabs[j].data); - all[i].tabdir.tabs[j].data = (void *) (intpt) -1; - all[i].tabdir.tabs[j].length = dup; - } - } - - /* And now dump those tables into the file. I don't see how I could */ - /* order them meaningfully */ - for ( j=0 ; j<all[i].tabdir.numtab; ++j ) { - if ( all[i].tabdir.tabs[j].data!=(void *) (intpt) -1 ) { - all[i].tabdir.tabs[j].offset = ftell(ttc); - all[i].tabdir.tabs[j].checksum = filechecksum(all[i].tabdir.tabs[j].data); - if ( !ttfcopyfile(ttc,all[i].tabdir.tabs[j].data, all[i].tabdir.tabs[j].offset,Tag2String(all[i].tabdir.tabs[j].tag))) - all[cnt].error = true; - } - } - } - - free(all[cnt].sf->glyphs); - free(all[cnt].gi.bygid); - - /* Now dump the big shared tables */ - tab = findtabindir(&all[cnt].tabdir,CHR('h','m','t','x')); - tab->offset = ftell(ttc); - tab->checksum = filechecksum(tab->data); - if ( !ttfcopyfile(ttc,tab->data, tab->offset,Tag2String(tab->tag))) - all[cnt].error = true; - tab = findtabindir(&all[cnt].tabdir,CHR('v','m','t','x')); - if ( tab!=NULL ) { - tab->offset = ftell(ttc); - tab->checksum = filechecksum(tab->data); - if ( !ttfcopyfile(ttc,tab->data, tab->offset,Tag2String(tab->tag))) - all[cnt].error = true; - } - if ( format==ff_ttf ) { - tab = findtabindir(&all[cnt].tabdir,CHR('l','o','c','a')); - tab->offset = ftell(ttc); - tab->checksum = filechecksum(tab->data); - if ( !ttfcopyfile(ttc,tab->data, tab->offset,Tag2String(tab->tag))) - all[cnt].error = true; - tab = findtabindir(&all[cnt].tabdir,CHR('g','l','y','f')); - tab->offset = ftell(ttc); - tab->checksum = filechecksum(tab->data); - if ( !ttfcopyfile(ttc,tab->data, tab->offset,Tag2String(tab->tag))) - all[cnt].error = true; - } else { - tab = findtabindir(&all[cnt].tabdir,CHR('C','F','F',' ')); - tab->offset = ftell(ttc); - tab->checksum = filechecksum(tab->data); - if ( !ttfcopyfile(ttc,tab->data, tab->offset,Tag2String(tab->tag))) - all[cnt].error = true; - } - - /* Do maxp last, in case generating other tables changed it */ - redomaxp(&all[cnt],format); - tab = findtabindir(&all[cnt].tabdir,CHR('m','a','x','p')); - fseek(ttc,tab->offset,SEEK_SET); - tab->checksum = filechecksum(all[cnt].maxpf); - tab->length = all[cnt].maxplen; - rewind(all[cnt].maxpf); - while ( (ch=getc(all[cnt].maxpf))!=EOF ) - putc(ch,ttc); - - /* Now output the font headers */ - for ( offset=startoffset, i=0; i<cnt; ++i, offset += (8+16*MAX_TAB)) { - struct alltabs *at = &all[i]; - /* Find the location of any shared tables */ - for ( j=0; j<at->tabdir.numtab; ++j ) { - struct taboff *curtab = &at->tabdir.tabs[j]; - if ( curtab->data == (void *) (intpt) -1 ) { - tab = findtabindir(&all[curtab->length].tabdir,curtab->tag); - if ( tab==NULL ) { - IError("Failed to find tab"); - curtab->length = 0; - curtab->offset = 0; - curtab->checksum = 0; - } else { - curtab->offset = tab->offset; - curtab->length = tab->length; - curtab->checksum = tab->checksum; - } - } - } - fseek(ttc,offset,SEEK_SET); - - /* Put in alphabetic order */ - for ( j=0; j<at->tabdir.numtab; ++j ) - at->tabdir.alpha[j] = &at->tabdir.tabs[j]; - qsort(at->tabdir.alpha,at->tabdir.numtab,sizeof(struct taboff *),tagcomp); - - putlong(ttc,at->tabdir.version); - putshort(ttc,at->tabdir.numtab); - putshort(ttc,at->tabdir.searchRange); - putshort(ttc,at->tabdir.entrySel); - putshort(ttc,at->tabdir.rangeShift); - for ( j=0; j<at->tabdir.numtab; ++j ) { - putlong(ttc,at->tabdir.alpha[j]->tag); - putlong(ttc,at->tabdir.alpha[j]->checksum); - putlong(ttc,at->tabdir.alpha[j]->offset); - putlong(ttc,at->tabdir.alpha[j]->length); - } - } - - tab = findtabindir(&all[0].tabdir,CHR('h','e','a','d')); - if ( tab!=NULL ) { - /* As far as I can tell the file checksum is ignored */ - int checksum; - checksum = filechecksum(ttc); - checksum = 0xb1b0afba-checksum; - fseek(ttc,tab->offset+2*sizeof(int32),SEEK_SET); - putlong(ttc,checksum); - } -} - -static void CopySFNTAndFixup(FILE *ttc,FILE *ttf) { - /* ttf contains a truetype file which we want to copy into ttc */ - /* Mostly this is just a dump copy, but the offset table at the */ - /* start of the file must be adjusted to reflect the absolute */ - /* locations of the tables in the ttc */ - int offset = ftell(ttc); - int val, table_cnt, i; - - fseek(ttf,0,SEEK_SET); - val = getlong(ttf); - putlong(ttc,val); /* sfnt version */ - table_cnt = getushort(ttf); - putshort(ttc,table_cnt); - val = getushort(ttf); - putshort(ttc,val); - val = getushort(ttf); - putshort(ttc,val); - val = getushort(ttf); - putshort(ttc,val); - - for ( i=0; i<table_cnt; ++i ) { - val = getlong(ttf); - putlong(ttc,val); /* tag */ - val = getlong(ttf); - putlong(ttc,val); /* checkSum */ - val = getlong(ttf); - putlong(ttc,val+offset); /* offset */ - val = getlong(ttf); - putlong(ttc,val); /* length */ - } - - while ( (val=getc(ttf))!=EOF ) - putc(val,ttc); - - fclose(ttf); - - if ( ftell(ttc)&1 ) - putc('\0',ttc); - if ( ftell(ttc)&2 ) - putshort(ttc,0); -} - -int WriteTTC(const char *filename,struct sflist *sfs,enum fontformat format, - enum bitmapformat bf,int flags, int layer, enum ttc_flags ttcflags) { - struct sflist *sfitem, *sfi2; - int ok=1; - FILE *ttc; - int cnt, offset; - int dobruteforce; - struct alltabs *ret; - SplineFont dummysf; - - if ( strstr(filename,"://")!=NULL ) { - if (( ttc = tmpfile2())==NULL ) -return( 0 ); - } else { - if (( ttc=fopen(filename,"wb+"))==NULL ) -return( 0 ); - } - - format = (ttcflags & ttc_flag_cff) ? ff_otf : ff_ttf; - - dobruteforce = true; - if ( (ttcflags & ttc_flag_trymerge) && bf==bf_none ) { - dobruteforce = false; - ret = ttc_prep(sfs,format,bf,flags,layer,&dummysf); - if ( ret==NULL ) - dobruteforce = true; - else - ttc_dump(ttc,ret,format,flags,ttcflags); - free(ret); - } - if ( dobruteforce ) { - /* Create a trivial ttc where each font is its own entity and there */ - /* are no common tables */ - /* Generate all the fonts (don't generate DSIGs, there's one DSIG for */ - /* the ttc as a whole) */ - for ( sfitem= sfs, cnt=0; sfitem!=NULL; sfitem=sfitem->next, ++cnt ) { - sfitem->tempttf = tmpfile2(); - if ( sfitem->tempttf==NULL ) - ok=0; - else - ok = _WriteTTFFont(sfitem->tempttf,sfitem->sf,format,sfitem->sizes, - bf,flags&~ttf_flag_dummyDSIG,sfitem->map,layer); - if ( !ok ) { - for ( sfi2=sfs; sfi2!=NULL; sfi2 = sfi2->next ) - if ( sfi2->tempttf!=NULL ) - fclose(sfi2->tempttf ); - fclose(ttc); -return( true ); - } - fseek(sfitem->tempttf,0,SEEK_END); - sfitem->len = ftell(sfitem->tempttf); - } - - putlong(ttc,CHR('t','t','c','f')); - if ( flags&ttf_flag_dummyDSIG ) { - putlong(ttc,0x00020000); - offset = 4*(3+cnt+4); - } else { - putlong(ttc,0x00010000); - offset = 4*(3+cnt); - } - putlong(ttc,cnt); - for ( sfitem= sfs; sfitem!=NULL; sfitem=sfitem->next ) { - putlong(ttc,offset); - offset += ((sfitem->len+3)>>2)<<2; /* Align on 4 byte boundary */ - } - if ( flags&ttf_flag_dummyDSIG ) { - putlong(ttc,CHR('D','S','I','G')); - putlong(ttc,8); /* Length of dummy DSIG table */ - putlong(ttc,0x00000001); /* Standard DSIG version */ - putlong(ttc,0); /* No Signatures, no flags */ - } - for ( sfitem= sfs; sfitem!=NULL; sfitem=sfitem->next ) - CopySFNTAndFixup(ttc,sfitem->tempttf); - if ( ftell(ttc)!=offset ) - IError("Miscalculated offsets in ttc"); - } else - - if ( ferror(ttc)) - ok = false; - if ( fclose(ttc)==-1 ) - ok = false; - if ( !ok ) - LogError(_("Something went wrong")); -return( ok ); -} |