Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

7016 lines (6406 sloc) 225.424 kB
/* 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 <unistd.h>
#include <time.h>
#include <locale.h>
#include <utype.h>
#include <ustring.h>
#include <chardata.h>
#include <gwidget.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 AssignTTFBitGlyph(struct glyphinfo *gi,SplineFont *sf,EncMap *map,int32 *bsizes) {
int i, j;
BDFFont *bdf;
int *bygid = malloc((sf->glyphcnt+3)*sizeof(int));
memset(bygid,0xff, (sf->glyphcnt+3)*sizeof(int));
AssignNotdefNull(sf,bygid,false);
for ( bdf = sf->bitmaps; bdf!=NULL; bdf=bdf->next ) {
for ( j=0; bsizes[j]!=0 && ((bsizes[j]&0xffff)!=bdf->pixelsize || (bsizes[j]>>16)!=BDFDepth(bdf)); ++j );
if ( bsizes[j]==0 )
continue;
for ( i=0; i<bdf->glyphcnt; ++i ) if ( !IsntBDFChar(bdf->glyphs[i]) )
sf->glyphs[i]->ttf_glyph = -2;
}
j = 3;
for ( i=0; i<map->enccount; ++i ) if ( map->map[i]!=-1 ) {
SplineChar *sc = sf->glyphs[map->map[i]];
if ( sc->ttf_glyph==-2 ) {
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 ( sc->ttf_glyph==-2 ) {
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;
int answer, answered=-1;
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)) {
if ( answered==-1 && sc->ttf_instrs_len!=0 ) {
char *buts[5];
buts[0] = _("_Yes");
buts[1] = _("Yes to _All");
buts[2] = _("No _to All");
buts[3] = _("_No");
buts[4] = NULL;
ff_progress_pause_timer();
answer = ff_ask(_("Bad Point Numbering"),(const char **) buts,0,3,_("The points in %s are not numbered properly. This means that any instructions will probably move the wrong points and do the wrong thing.\nWould you like me to remove the instructions?"),sc->name);
if ( answer==1 || answer==2 )
answered = answer;
} else
answer=answered;
if ( answer==0 ) {
free(sc->ttf_instrs); sc->ttf_instrs = NULL;
sc->ttf_instrs_len = 0;
SCMarkInstrDlgAsChanged(sc);
}
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 = tmpfile();
gi->hmtx = tmpfile();
if ( sf->hasvmetrics )
gi->vmtx = tmpfile();
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 );
}
/* Generate a null glyph and loca table for X opentype bitmaps */
static int dumpnoglyphs(struct glyphinfo *gi) {
gi->glyphs = tmpfile();
gi->glyph_len = 0;
/* loca gets built in dummyloca */
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 = tmpfile();
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 = tmpfile();
_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 = tmpfile();
if ( dovmetrics )
at->gi.vmtx = tmpfile();
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 = tmpfile();
if ( dovmetrics )
at->gi.vmtx = tmpfile();
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 = tmpfile();
at->sidf = tmpfile();
at->sidh = tmpfile();
at->charset = tmpfile();
at->encoding = tmpfile();
at->private = tmpfile();
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 = tmpfile();
at->sidf = tmpfile();
at->sidh = tmpfile();
at->charset = tmpfile();
at->fdselect = tmpfile();
at->fdarray = tmpfile();
at->globalsubrs = tmpfile();
at->fds = calloc(sf->subfontcnt,sizeof(struct fd2data));
for ( i=0; i<sf->subfontcnt; ++i ) {
at->fds[i].private = tmpfile();
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 );
}
static int AnyMisleadingBitmapAdvances(SplineFont *sf, int32 *bsizes) {
int strike, gid;
double em = sf->ascent+sf->descent;
BDFFont *bdf;
/* Are there any bitmap glyphs whose advance width differs from the */
/* expected value from scaling the outline's advance width? */
if ( bsizes==NULL )
return( false );
for ( strike = 0; bsizes[strike]!=0; ++strike ) {
for ( bdf=sf->bitmaps; bdf!=NULL && (bdf->pixelsize!=(bsizes[strike]&0xffff) || BDFDepth(bdf)!=(bsizes[strike]>>16)); bdf=bdf->next );
if ( bdf==NULL )
continue;
for ( gid=0; gid<sf->glyphcnt && gid<bdf->glyphcnt; ++gid ) {
SplineChar *sc = sf->glyphs[gid];
BDFChar *bc = bdf->glyphs[gid];
if ( sc==NULL || bc==NULL )
continue;
if ( (int) rint( (sc->width*bdf->pixelsize)/em ) != bc->width )
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) {
time_t now;
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 */
else if ( AnyMisleadingBitmapAdvances(sf,bsizes))
head->flags = 0x10|8|2|1; /* baseline at 0, lsbline at 0, round ppem, 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 */
time(&now); /* seconds since 1970, need to convert to seconds since 1904 */
cvt_unix_to_1904(now,head->modtime);
memcpy(head->createtime,head->modtime,sizeof(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 &= 1111110; changed=1;}
if (at->head.macstyle&2 && !(os2->fsSel&1)) {at->head.macstyle &= 1111101; 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 = tmpfile();
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 = tmpfile();
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 = tmpfile();
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 = tmpfile();
head = &at->hhead;
} else {
f = at->vheadf = tmpfile();
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 = tmpfile();
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 = tmpfile();
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 = tmpfile();
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