1 /* Copyright (C) 2000-2012 by George Williams */
2 /*
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions are met:
5 
6  * Redistributions of source code must retain the above copyright notice, this
7  * list of conditions and the following disclaimer.
8 
9  * Redistributions in binary form must reproduce the above copyright notice,
10  * this list of conditions and the following disclaimer in the documentation
11  * and/or other materials provided with the distribution.
12 
13  * The name of the author may not be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15 
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <fontforge-config.h>
29 
30 #include "tottfgpos.h"
31 
32 #include "asmfpst.h"
33 #include "fontforgevw.h"
34 #include "fvfonts.h"
35 #include "gfile.h"
36 #include "lookups.h"
37 #include "mathconstants.h"
38 #include "mem.h"
39 #include "namelist.h"
40 #include "splinesaveafm.h"
41 #include "splineutil.h"
42 #include "tottf.h"
43 #include "ustring.h"
44 #include "utype.h"
45 
46 int coverageformatsallowed=3;
47 int use_second_indic_scripts = true;
48 
49 #include "ttf.h"
50 
51 /* This file contains routines to create the otf gpos and gsub tables and their */
52 /*  attendant subtables */
53 
54 /* Undocumented fact: ATM (which does kerning for otf fonts in Word) can't handle features with multiple lookups */
55 
56 /* Undocumented fact: Only one feature with a given tag allowed per script/lang */
57 /*  So if we have multiple lookups with the same tag they must be merged into */
58 /*  one feature with many lookups */
59 
60 /* scripts (for opentype) that I understand */
61     /* see also list in lookups.c mapping script tags to friendly names */
62 
63 static uint32 scripts[][61] = {
64 /* Adlam */	{ CHR('a','d','l','m'), 0x1e900, 0x1e95f },
65 /* Ahom */	{ CHR('a','h','o','m'), 0x11700, 0x1173f },
66 /* Anatolian */	{ CHR('h','l','u','w'), 0x14400, 0x1467f },
67 /* Arabic */	{ CHR('a','r','a','b'), 0x0600, 0x06ff, 0x0750, 0x077f, 0xfb50, 0xfdff, 0xfe70, 0xfefe },
68 /* Aramaic */	{ CHR('s','a','m','r'), 0x0820, 0x083f },
69 /* Armenian */	{ CHR('a','r','m','n'), 0x0530, 0x058f, 0xfb13, 0xfb17 },
70 /* Avestan */	{ CHR('a','v','s','t'), 0x10b00, 0x10b3f },
71 /* Balinese */	{ CHR('b','a','l','i'), 0x1b00, 0x1b7f },
72 /* Bamum */	{ CHR('b','a','m','u'), 0xa6a0, 0xa6ff, 0x16800, 0x16a3f },
73 /* Bassa Vah */	{ CHR('b','a','s','s'), 0x16ad0, 0x16aff },
74 /* Batak */	{ CHR('b','a','t','k'), 0x1bc0, 0x1bff },
75 /* Bengali */	{ CHR('b','e','n','g'), 0x0980, 0x09ff },
76 /* Bhaiksuki */	{ CHR('b','h','k','s'), 0x11c00, 0x11c6f },
77 /* Bopomofo */	{ CHR('b','o','p','o'), 0x3100, 0x312f, 0x02ea, 0x02eb, 0x31a0, 0x31bf },
78 /* Brahmi */	{ CHR('b','r','a','h'), 0x11000, 0x1107f },
79 /* Braille */	{ CHR('b','r','a','i'), 0x2800, 0x28ff },
80 /* Buginese */	{ CHR('b','u','g','i'), 0x1a00, 0x1a1f },
81 /* Buhid */	{ CHR('b','u','h','d'), 0x1740, 0x175f },
82 /* Byzantine M*/{ CHR('b','y','z','m'), 0x1d000, 0x1d0ff },
83 /* Canadian Syl*/{CHR('c','a','n','s'), 0x1400, 0x167f, 0x18b0, 0x18ff },
84 /* Carian */	{ CHR('c','a','r','i'), 0x102a0, 0x102df },
85 /* Caucasian Albanian */
86 		{ CHR('a','g','h','b'), 0x10530, 0x1056f },
87 /* Chakma */	{ CHR('c','a','k','m'), 0x11100, 0x1114f },
88 /* Cham */	{ CHR('c','h','a','m'), 0xaa00, 0xaa5f },
89 /* Cherokee */	{ CHR('c','h','e','r'), 0x13a0, 0x13ff, 0xab70, 0xabbf },
90 /* CJKIdeogra */{ CHR('h','a','n','i'), 0x3400, 0x4dbf, 0x2e80, 0x2fdf, 0x3005, 0x3005, 0x3007, 0x3007,
91 	0x3021, 0x3029, 0x3038, 0x303B, 0x4e00, 0x9fff, 0xf900, 0xfaff, 0x020000, 0x02ffff },
92 /* Coptic */	{ CHR('c','o','p','t'), 0x03e2, 0x03ef, 0x2c80, 0x2cff },
93 /* Cypriot */	{ CHR('c','p','r','t'), 0x10800, 0x1083f },
94 /* Cyrillic */	{ CHR('c','y','r','l'), 0x0400, 0x052f, 0x1c80, 0x1c8f, 0x1d2b, 0x1d2b, 0x1d78, 0x1d78,
95 	0x2de0, 0x2dff, 0xa640, 0xa6ff },
96 /* Deseret */	{ CHR('d','s','r','t'), 0x10400, 0x1044f },
97 /* Devanagari */{ CHR('d','e','v','a'), 0x0900, 0x097f, 0xa8e0, 0xa8ff },
98 /* Dogra */	{ CHR('d','o','g','r'), 0x11800, 0x1184f },
99 /* Duployan */	{ CHR('d','u','p','l'), 0x1bc00, 0x1bc9f },
100 /* Egyptian */	{ CHR('e','g','y','p'), 0x13000, 0x1343f },
101 /* Elbasan */	{ CHR('e','l','b','a'), 0x10500, 0x1052f },
102 /* Ethiopic */	{ CHR('e','t','h','i'), 0x1200, 0x139f, 0x2d80, 0x2ddf, 0xab00, 0xab2f },
103 /* Georgian */	{ CHR('g','e','o','r'), 0x10a0, 0x10ff, 0x1c90, 0x1cbf, 0x2d00, 0x2d2f },
104 /* Glagolitic */{ CHR('g','l','a','g'), 0x2c00, 0x2c5f, 0x1e000, 0x1e02f },
105 /* Gothic */	{ CHR('g','o','t','h'), 0x10330, 0x1034a },
106 /* Grantha */	{ CHR('g','r','a','n'), 0x11300, 0x1137f },
107 /* Greek */	{ CHR('g','r','e','k'), 0x0370, 0x03e1, 0x03f0, 0x03ff, 0x1d26, 0x1d2a, 0x1d5d, 0x1d61,
108 	0x1d66, 0x1d6a, 0x1dbf, 0x1dbf, 0x1f00, 0x1fff, 0x2126, 0x2126, 0xab65, 0xab65, 0x10140, 0x1018f,
109 	0x101a0, 0x101a0, 0x1d200, 0x1d24f },
110 /* Gujarati */	{ CHR('g','u','j','r'), 0x0a80, 0x0aff },
111 /* Gunjala Gondi */
112 		{ CHR('g','o','n','g'), 0x11d60, 0x11daf },
113 /* Gurmukhi */	{ CHR('g','u','r','u'), 0x0a00, 0x0a7f },
114 /* Hangul */	{ CHR('h','a','n','g'), 0xac00, 0xd7af, 0x3130, 0x319f, 0xffa0, 0xffdf },
115  /* I'm not sure what the difference is between the 'hang' tag and the 'jamo' */
116  /*  tag. 'Jamo' is said to be the precomposed forms, but what's 'hang'? */
117 /* Hanifi Rohingya */
118 		{ CHR('r','o','h','g'), 0x10d00, 0x10d3f },
119 /* Hanunoo */	{ CHR('h','a','n','o'), 0x1720, 0x1734 },
120 /* Hatran */	{ CHR('h','a','t','r'), 0x108e0, 0x108ff },
121 /* Hebrew */	{ CHR('h','e','b','r'), 0x0590, 0x05ff, 0xfb1d, 0xfb4f },
122 /* Hiragana used to have its own tag 'hira', but has since been merged with katakana */
123 /* Hangul Jamo*/{ CHR('j','a','m','o'), 0x1100, 0x11ff, 0x3130, 0x319f, 0xffa0, 0xffdf },
124 /* Imperial Aramaic */
125 		{ CHR('a','r','m','i'), 0x10840, 0x1085f },
126 /* Inscriptional Pahlavi */
127 		{ CHR('p','h','l','i'), 0x10b60, 0x10b7f },
128 /* Inscriptional Parthian */
129 		{ CHR('p','r','t','i'), 0x10b40, 0x10b5f },
130 /* Javanese */	{ CHR('j','a','v','a'), 0xa980, 0xa9df },
131 /* Katakana */	{ CHR('k','a','n','a'), 0x3040, 0x30ff, 0x31f0, 0x31ff, 0x32d0, 0x32fe, 0x3300, 0x3357,
132 	0xff66, 0xff9f },
133 /* Kaithi */	{ CHR('k','t','h','i'), 0x11080, 0x110cf },
134 /* Kayah Li */	{ CHR('k','a','l','i'), 0xa900, 0xa92f },
135 /* Kannada */	{ CHR('k','n','d','a'), 0x0c80, 0x0cff },
136 /* Kharosthi */	{ CHR('k','h','a','r'), 0x10a00, 0x10a5f },
137 /* Khmer */	{ CHR('k','h','m','r'), 0x1780, 0x17ff, 0x19e0, 0x19ff },
138 /* Khojki */	{ CHR('k','h','o','j'), 0x11200, 0x1124f },
139 /* Khudawadi */	{ CHR('s','i','n','d'), 0x112b0, 0x112ff },
140 /* Lao */	{ CHR('l','a','o',' '), 0x0e80, 0x0eff },
141 /* Latin */	{ CHR('l','a','t','n'), 0x0041, 0x005a, 0x0061, 0x007a, 0x00aa, 0x00aa, 0x00ba, 0x00ba,
142 	0x00c0, 0x00d6, 0x00d8, 0x00f6, 0x00f8, 0x02b8, 0x02e0, 0x02e4, 0x1d00, 0x1d25, 0x1d2c, 0x1d5c,
143 	0x1d62, 0x1d65, 0x1d6b, 0x1d77, 0x1d79, 0x1dbe, 0x1e00, 0x1eff, 0x2071, 0x2071, 0x207f, 0x207f,
144 	0x2090, 0x209c, 0x212a, 0x212b, 0x2132, 0x2132, 0x214e, 0x214e, 0x2160, 0x2188, 0x2c60, 0x2c7f,
145 	0xa722, 0xa7ff, 0xab30, 0xab5a, 0xab5c, 0xab64, 0xab66, 0xab67, 0xfb00, 0xfb0f, 0xff21, 0xff3a,
146 	0xff41, 0xff5a },
147 /* Lepcha */	{ CHR('l','e','p','c'), 0x1c00, 0x1c4f },
148 /* Limbu */	{ CHR('l','i','m','b'), 0x1900, 0x194f },
149 /* Linear A */	{ CHR('l','i','n','a'), 0x10600, 0x1077f },
150 /* Linear B */	{ CHR('l','i','n','b'), 0x10000, 0x100ff },
151 /* Lisu */	{ CHR('l','i','s','u'), 0xa4d0, 0xa4ff },
152 /* Lycian */	{ CHR('l','y','c','i'), 0x10280, 0x1029f },
153 /* Lydian */	{ CHR('l','y','d','i'), 0x10920, 0x1093f },
154 /* Mahajani */	{ CHR('m','a','h','j'), 0x11150, 0x1117f },
155 /* Makasar */	{ CHR('m','a','k','a'), 0x11ee0, 0x11eff },
156 /* Malayalam */	{ CHR('m','l','y','m'), 0x0d00, 0x0d7f },
157 /* Mandaic */	{ CHR('m','a','n','d'), 0x0840, 0x085f },
158 /* Manichaean */{ CHR('m','a','n','i'), 0x10ac0, 0x10aff },
159 /* Marchen */	{ CHR('m','a','r','c'), 0x11c70, 0x11cbf },
160 /* Masaram Gondi*/{CHR('g','o','n','m'), 0x11d00, 0x11d5f },
161 /* Mathematical Alphanumeric Symbols */
162 		{ CHR('m','a','t','h'), 0x1d400, 0x1d7ff },
163 /* Medefaidrin */{CHR('m','e','d','f'), 0x16e40, 0x16e9f },
164 /* Meetei Mayek*/{CHR('m','t','e','i'), 0xabc0, 0xabff, 0xaae0, 0xaaff },
165 /* Mende Kikakui */
166 		{ CHR('m','e','n','d'), 0x1e800, 0x1e8df },
167 /* Meroitic Cursive */
168 		{ CHR('m','e','r','c'), 0x109a0, 0x109ff },
169 /* Meroitic Hieroglyphs */
170 		{ CHR('m','e','r','o'), 0x10980, 0x1099f },
171 /* Miao */	{ CHR('p','l','r','d'), 0x16f00, 0x16f9f },
172 /* Modi */	{ CHR('m','o','d','i'), 0x11600, 0x1165f },
173 /* Mongolian */	{ CHR('m','o','n','g'), 0x1800, 0x18af, 0x11660, 0x1167f },
174 /* Mro */	{ CHR('m','r','o','o'), 0x16a40, 0x16a6f },
175 /* Multani */	{ CHR('m','u','l','t'), 0x11280, 0x112af },
176 /* Musical */	{ CHR('m','u','s','c'), 0x1d100, 0x1d1ff },
177 /* Myanmar */	{ CHR('m','y','m','2'), 0x1000, 0x109f, 0xa9e0, 0xa9ff, 0xaa60, 0xaa7f },
178 /* Nabataean */	{ CHR('n','b','a','t'), 0x10880, 0x108af },
179 /* Newa */	{ CHR('n','e','w','a'), 0x11400, 0x1147f },
180 /* New Tai Lue*/{ CHR('t','a','l','u'), 0x1980, 0x19df },
181 /* N'Ko */	{ CHR('n','k','o',' '), 0x07c0, 0x07ff },
182 /* Nushu */	{ CHR('n','s','h','u'), 0x1b170, 0x1b2ff, 0x16fe1, 0x16fe1 },
183 /* Ogham */	{ CHR('o','g','a','m'), 0x1680, 0x169f },
184 /* Ol Chiki */	{ CHR('o','l','c','k'), 0x1c50, 0x1c7f },
185 /* Old Italic */{ CHR('i','t','a','l'), 0x10300, 0x1032f },
186 /* Old Hungarian */
187 		{ CHR('h','u','n','g'), 0x10c80, 0x10cff },
188 /* Old North Arabian */
189 		{ CHR('n','a','r','b'), 0x10a80, 0x10a9f },
190 /* Old Permic */{ CHR('p','e','r','m'), 0x10350, 0x1037f },
191 /* Old Persian cuneiform */
192 		{ CHR('x','p','e','o'), 0x103a0, 0x103df },
193 /* Old Sogdian*/{ CHR('s','o','g','o'), 0x10f00, 0x10f2f },
194 /* Old South Arabian */
195 		{ CHR('s','a','r','b'), 0x10a60, 0x10a7f },
196 /* Old Turkic */{ CHR('o','r','k','h'), 0x10c00, 0x10c4f },
197 /* Oriya */	{ CHR('o','r','y','a'), 0x0b00, 0x0b7f },
198 /* Osage */	{ CHR('o','s','g','e'), 0x104b0, 0x104ff },
199 /* Osmanya */	{ CHR('o','s','m','a'), 0x10480, 0x104af },
200 /* Pahawh Hmong*/{CHR('h','m','n','g'), 0x16b00, 0x16b8f },
201 /* Palmyrene */	{ CHR('p','a','l','m'), 0x10860, 0x1087f },
202 /* Pau Cin Hau*/{ CHR('p','a','u','c'), 0x11ac0, 0x11aff },
203 /* Phags-pa */	{ CHR('p','h','a','g'), 0xa840, 0xa87f },
204 /* Phoenician */{ CHR('p','h','n','x'), 0x10900, 0x1091f },
205 /* Psalter Pahlavi */
206 		{ CHR('p','h','l','p'), 0x10b80, 0x10baf },
207 /* Rejang */    { CHR('r','j','n','g'), 0xa930, 0xa95f },
208 /* Runic */	{ CHR('r','u','n','r'), 0x16a0, 0x16ff },
209 /* Saurashtra*/ { CHR('s','a','u','r'), 0xa880, 0xa8df },
210 /* Sharada */	{ CHR('s','h','r','d'), 0x11180, 0x111df },
211 /* Shavian */	{ CHR('s','h','a','w'), 0x10450, 0x1047f },
212 /* Siddham */	{ CHR('s','i','d','d'), 0x11580, 0x115ff },
213 /* Sinhala */	{ CHR('s','i','n','h'), 0x0d80, 0x0dff },
214 /* SignWriting*/{ CHR('s','g','n','w'), 0x1d800, 0x1daaf },
215 /* Sogdian */	{ CHR('s','o','g','d'), 0x10f30, 0x10f6f },
216 /* Sora Sompeng*/{ CHR('s','o','r','a'), 0x110d0, 0x110ff },
217 /* Soyombo */	{ CHR('s','o','y','o'), 0x11a50, 0x11aaf },
218 /* Sumero-Akkadian Cuneiform */
219 		{ CHR('x','s','u','x'), 0x12000, 0x1254f },
220 /* Sundanese */ { CHR('s','u','n','d'), 0x1b80, 0x1bbf, 0x1cc0, 0x1ccf },
221 /* Syloti Nagri */
222 		{ CHR('s','y','l','o'), 0xa800, 0xa82f },
223 /* Syriac */	{ CHR('s','y','r','c'), 0x0700, 0x074f, 0x0860, 0x086f },
224 /* Tagalog */	{ CHR('t','a','g','l'), 0x1700, 0x171f },
225 /* Tagbanwa */	{ CHR('t','a','g','b'), 0x1760, 0x177f },
226 /* Tai Le */	{ CHR('t','a','l','e'), 0x1950, 0x197f },
227 /* Tai Tham */	{ CHR('l','a','n','a'), 0x1a20, 0x1aaf },
228 /* Tai Viet */	{ CHR('t','a','v','t'), 0xaa80, 0xaadf },
229 /* Takri */	{ CHR('t','a','k','r'), 0x11680, 0x116cf },
230 /* Tamil */	{ CHR('t','a','m','l'), 0x0b80, 0x0bff, 0x11fc0, 0x11fff },
231 /* Tangut */	{ CHR('t','a','n','g'), 0x17000, 0x18aff, 0x16fe0, 0x16fe0 },
232 /* Telugu */	{ CHR('t','e','l','u'), 0x0c00, 0x0c7f },
233 /* Thaana */	{ CHR('t','h','a','a'), 0x0780, 0x07bf },
234 /* Thai */	{ CHR('t','h','a','i'), 0x0e00, 0x0e7f },
235 /* Tibetan */	{ CHR('t','i','b','t'), 0x0f00, 0x0fff },
236 /* Tifinagh */	{ CHR('t','f','n','g'), 0x2d30, 0x2d7f },
237 /* Tirhuta */	{ CHR('t','i','r','h'), 0x11480, 0x114df },
238 /* Ugaritic */	{ CHR('u','g','a','r'), 0x10380, 0x1039f },
239 /* Vai */	{ CHR('v','a','i',' '), 0xa500, 0xa63f },
240 /* Warang Citi*/{ CHR('v','a','i',' '), 0x118a0, 0x118ff },
241 /* Yi */	{ CHR('y','i',' ',' '), 0xa000, 0xa48f },
242 /* Zanabazar Square */
243 		{ CHR('z','a','n','b'), 0x11a00, 0x11a4f },
244 		{ 0 }
245 };
246 
247 static SplineChar **SFOrderedGlyphs(SplineChar **glyphs);
248 
ScriptMainRange(uint32 script,int * start,int * end)249 void ScriptMainRange(uint32 script, int *start, int *end) {
250     int i;
251 
252     for ( i=0; scripts[i][0]!=0; ++i ) {
253 	if ( scripts[i][0] == script ) {
254 	    *start = scripts[i][1];
255 	    *end   = scripts[i][2];
256 return;
257 	}
258     }
259     *start = *end = -1;
260 }
261 
ScriptIsRightToLeft(uint32 script)262 int ScriptIsRightToLeft(uint32 script) {
263     switch ( script ) {
264       case CHR('a','d','l','m'):
265       case CHR('a','r','a','b'):
266       case CHR('a','r','m','i'):
267       case CHR('a','v','s','t'):
268       case CHR('c','p','r','t'):
269       case CHR('h','a','t','r'):
270       case CHR('h','e','b','r'):
271       case CHR('h','u','n','g'):
272       case CHR('k','h','a','r'):
273       case CHR('l','y','d','i'):
274       case CHR('m','a','n','d'):
275       case CHR('m','a','n','i'):
276       case CHR('m','e','n','d'):
277       case CHR('m','e','r','c'):
278       case CHR('m','e','r','o'):
279       case CHR('n','a','r','b'):
280       case CHR('n','b','a','t'):
281       case CHR('n','k','o',' '):
282       case CHR('o','r','k','h'):
283       case CHR('p','a','l','m'):
284       case CHR('p','h','l','i'):
285       case CHR('p','h','l','p'):
286       case CHR('p','h','n','x'):
287       case CHR('p','r','t','i'):
288       case CHR('r','o','h','g'):
289       case CHR('s','a','m','r'):
290       case CHR('s','a','r','b'):
291       case CHR('s','o','g','d'):
292       case CHR('s','o','g','o'):
293       case CHR('s','y','r','c'):
294       case CHR('t','h','a','a'):
295 	return true;
296       default:
297 	return false;
298     }
299 }
300 
ScriptFromUnicode(uint32 u,SplineFont * sf)301 uint32 ScriptFromUnicode(uint32 u,SplineFont *sf) {
302     int s, k;
303 
304     if ( (int32)u!=-1 ) {
305 	for ( s=0; scripts[s][0]!=0; ++s ) {
306 	    for ( k=1; scripts[s][k+1]!=0; k += 2 )
307 		if ( u>=scripts[s][k] && u<=scripts[s][k+1] )
308 	    break;
309 	    if ( scripts[s][k+1]!=0 )
310 	break;
311 	}
312 	if ( scripts[s][0]!=0 ) {
313 	    uint32 script = scripts[s][0];
314 	    if ( use_second_indic_scripts ) {
315 		/* MS has a parallel set of script tags for their new */
316 		/*  Indic font shaper */
317 		if ( script == CHR('b','e','n','g' )) script = CHR('b','n','g','2');
318 		else if ( script == CHR('d','e','v','a' )) script = CHR('d','e','v','2');
319 		else if ( script == CHR('g','u','j','r' )) script = CHR('g','j','r','2');
320 		else if ( script == CHR('g','u','r','u' )) script = CHR('g','u','r','2');
321 		else if ( script == CHR('k','n','d','a' )) script = CHR('k','n','d','2');
322 		else if ( script == CHR('m','l','y','m' )) script = CHR('m','l','m','2');
323 		else if ( script == CHR('o','r','y','a' )) script = CHR('o','r','y','2');
324 		else if ( script == CHR('t','a','m','l' )) script = CHR('t','m','l','2');
325 		else if ( script == CHR('t','e','l','u' )) script = CHR('t','e','l','2');
326 	    }
327 return( script );
328 	}
329     } else if ( sf!=NULL ) {
330 	if ( sf->cidmaster!=NULL || sf->subfontcnt!=0 ) {
331 	    if ( sf->cidmaster!=NULL ) sf = sf->cidmaster;
332 	    if ( strmatch(sf->ordering,"Identity")==0 )
333 return( DEFAULT_SCRIPT );
334 	    else if ( strmatch(sf->ordering,"Korean")==0 )
335 return( CHR('h','a','n','g'));
336 	    else
337 return( CHR('h','a','n','i') );
338 	}
339     }
340 
341 return( DEFAULT_SCRIPT );
342 }
343 
SCScriptFromUnicode(SplineChar * sc)344 uint32 SCScriptFromUnicode(SplineChar *sc) {
345     const char *pt;
346     PST *pst;
347     SplineFont *sf;
348     int i; unsigned uni;
349     FeatureScriptLangList *features;
350 
351     if ( sc==NULL )
352 return( DEFAULT_SCRIPT );
353 
354     sf = sc->parent;
355     if ( sc->unicodeenc!=-1 &&
356 	    !(sc->unicodeenc>=0xe000 && sc->unicodeenc<0xf8ff) &&
357 	    !(sc->unicodeenc>=0xf0000 && sc->unicodeenc<0x10ffff))
358 return( ScriptFromUnicode( sc->unicodeenc,sf ));
359 
360     pt = sc->name;
361     if ( *pt ) for ( ++pt; *pt!='\0' && *pt!='_' && *pt!='.'; ++pt );
362     if ( *pt!='\0' ) {
363 	char *str = copyn(sc->name,pt-sc->name);
364 	int uni = sf==NULL || sf->fv==NULL ? UniFromName(str,ui_none,&custom) :
365 			    UniFromName(str,sf->uni_interp,sf->fv->map->enc);
366 	free(str);
367 	if ( uni!=-1 )
368 return( ScriptFromUnicode( uni,sf ));
369     }
370     /* Adobe ligature uniXXXXXXXX */
371     if ( strncmp(sc->name,"uni",3)==0 && sscanf(sc->name+3,"%4x", &uni)==1 )
372 return( ScriptFromUnicode( uni,sf ));
373 
374     if ( sf==NULL )
375 return( DEFAULT_SCRIPT );
376 
377     if ( sf->cidmaster ) sf=sf->cidmaster;
378     else if ( sf->mm!=NULL ) sf=sf->mm->normal;
379     for ( i=0; i<2; ++i ) {
380 	for ( pst=sc->possub; pst!=NULL; pst=pst->next ) {
381 	    if ( pst->type == pst_lcaret )
382 	continue;
383 	    for ( features = pst->subtable->lookup->features; features!=NULL; features=features->next ) {
384 		if ( features->scripts!=NULL )
385 return( features->scripts->script );
386 	    }
387 	}
388     }
389 return( ScriptFromUnicode( sc->unicodeenc,sf ));
390 }
391 
SCRightToLeft(SplineChar * sc)392 int SCRightToLeft(SplineChar *sc) {
393 
394     if ( sc->unicodeenc>=0x10800 && sc->unicodeenc<=0x10fff ||
395 	    sc->unicodeenc>=0x1e800 && sc->unicodeenc<=0x1efff )
396 return( true );		/* Supplemental Multilingual Plane, RTL scripts */
397     if ( sc->unicodeenc!=-1 && sc->unicodeenc<0x10000 )
398 return( isrighttoleft(sc->unicodeenc ));
399 
400 return( ScriptIsRightToLeft(SCScriptFromUnicode(sc)));
401 }
402 
GlyphMapFree(SplineChar *** map)403 static void GlyphMapFree(SplineChar ***map) {
404     int i;
405 
406     if ( map==NULL )
407 		return;
408     for ( i=0; map[i]!=NULL; ++i )
409 	free(map[i]);
410     free(map);
411 }
412 
FindSubs(SplineChar * sc,struct lookup_subtable * sub)413 static SplineChar **FindSubs(SplineChar *sc,struct lookup_subtable *sub) {
414     SplineChar *spc[30], **space = spc;
415     int max = sizeof(spc)/sizeof(spc[0]);
416     int cnt=0;
417     char *pt, *start;
418     SplineChar *subssc, **ret;
419     PST *pst;
420 
421     for ( pst=sc->possub; pst!=NULL; pst=pst->next ) {
422 		if ( pst->subtable==sub ) {
423 			pt = pst->u.subs.variant;
424 			while ( 1 ) {
425 				while ( *pt==' ' ) ++pt; // Burn leading spaces.
426 				// Start tokenizing the space-delimited list of references.
427 				start = pt; // Note the beginning of the current item.
428 				pt = strchr(start,' '); // Find the end of the current item.
429 				if ( pt!=NULL )
430 					*pt = '\0'; // Temporarily terminate the item.
431 				subssc = SFGetChar(sc->parent,-1,start); // Find the corresponding SplineChar.
432 				if ( subssc!=NULL && subssc->ttf_glyph!=-1 ) {
433 					// Extend the list if necessary.
434 					if ( cnt>=max ) {
435 						if ( spc==space ) {
436 							space = malloc((max+=30)*sizeof(SplineChar *));
437 							memcpy(space,spc,(max-30)*sizeof(SplineChar *));
438 						} else
439 							space = realloc(space,(max+=30)*sizeof(SplineChar *));
440 					}
441 					// Write the SplineChar to the list.
442 					space[cnt++] = subssc;
443 				}
444 				if ( pt==NULL )
445 					break; // No more items.
446 				*pt=' '; // Repair the string from the tokenization process.
447 			}
448 		}
449     }
450 	// Returning NULL causes problems and seems to be unnecessary for now.
451     ret = malloc((cnt+1)*sizeof(SplineChar *));
452     memcpy(ret,space,cnt*sizeof(SplineChar *));
453     ret[cnt] = NULL;
454     if ( space!=spc )
455 		free(space); // Free the temp space only if it is dynamically allocated.
456 	return( ret );
457 }
458 
generateMapList(SplineChar ** glyphs,struct lookup_subtable * sub)459 static SplineChar ***generateMapList(SplineChar **glyphs, struct lookup_subtable *sub) {
460     int cnt;
461     SplineChar *sc;
462     int i;
463     SplineChar ***maps=NULL;
464 
465     for ( cnt=0; glyphs[cnt]!=NULL; ++cnt );
466     maps = malloc((cnt+1)*sizeof(SplineChar **));
467     for ( i=0; i<cnt; ++i ) {
468 		sc = glyphs[i];
469 		maps[i] = FindSubs(sc,sub);
470 		if (maps[i] == NULL) {
471 			fprintf( stderr, "maps[%d] is null; glyphs[%d] is \"%s\"; lookup name is \"%s\".\n" , i , i , (glyphs[i]->name ? glyphs[i]->name : ""), sub->subtable_name) ;
472 		}
473     }
474     maps[cnt] = NULL;
475 return( maps );
476 }
477 
AnchorClassDecompose(SplineFont * sf,AnchorClass * _ac,int classcnt,int * subcnts,SplineChar *** marks,SplineChar *** base,SplineChar *** lig,SplineChar *** mkmk,struct glyphinfo * gi)478 void AnchorClassDecompose(SplineFont *sf,AnchorClass *_ac, int classcnt, int *subcnts,
479 	SplineChar ***marks,SplineChar ***base,
480 	SplineChar ***lig,SplineChar ***mkmk,
481 	struct glyphinfo *gi) {
482     /* Run through the font finding all characters with this anchor class */
483     /*  (and the cnt-1 classes after it) */
484     /*  and distributing in the four possible anchor types */
485     int i,j,k,gid, gmax;
486     struct sclist { int cnt; SplineChar **glyphs; } heads[at_max];
487     AnchorPoint *test;
488     AnchorClass *ac;
489 
490     memset(heads,0,sizeof(heads));
491     memset(subcnts,0,classcnt*sizeof(int));
492     memset(marks,0,classcnt*sizeof(SplineChar **));
493     gmax = gi==NULL ? sf->glyphcnt : gi->gcnt;
494     for ( j=0; j<2; ++j ) {
495 	for ( i=0; i<gmax; ++i ) if ( (gid = gi==NULL ? i : gi->bygid[i])!=-1 && gid < sf->glyphcnt && sf->glyphs[gid]!=NULL ) {
496 	    for ( ac = _ac, k=0; k<classcnt; ac=ac->next ) if ( ac->matches ) {
497 		for ( test=sf->glyphs[gid]->anchor; test!=NULL ; test=test->next ) {
498 		    if ( test->anchor==ac ) {
499 			if ( test->type==at_mark ) {
500 			    if ( j )
501 				marks[k][subcnts[k]] = sf->glyphs[gid];
502 			    ++subcnts[k];
503 			    if ( ac->type!=act_mkmk )
504 		break;
505 			} else if ( test->type!=at_centry && test->type!=at_cexit ) {
506 			    if ( heads[test->type].glyphs!=NULL ) {
507 			    /* If we have multiple mark classes, we may use the same base glyph */
508 			    /* with more than one mark class. But it should only appear once in */
509 			    /* the output */
510 				if ( heads[test->type].cnt==0 ||
511 					 heads[test->type].glyphs[heads[test->type].cnt-1]!=sf->glyphs[gid] ) {
512 				    heads[test->type].glyphs[heads[test->type].cnt] = sf->glyphs[gid];
513 				    ++heads[test->type].cnt;
514 				}
515 			    } else
516 				++heads[test->type].cnt;
517 			    if ( ac->type!=act_mkmk )
518 		break;
519 			}
520 		    }
521 		}
522 		++k;
523 	    }
524 	}
525 	if ( j==1 )
526     break;
527 	for ( i=0; i<4; ++i )
528 	    if ( heads[i].cnt!=0 ) {
529 		heads[i].glyphs = malloc((heads[i].cnt+1)*sizeof(SplineChar *));
530 		/* I used to set glyphs[cnt] to NULL here. But it turns out */
531 		/*  cnt may be an overestimate on the first pass. So we can */
532 		/*  only set it at the end of the second pass */
533 		heads[i].cnt = 0;
534 	    }
535 	for ( k=0; k<classcnt; ++k ) if ( subcnts[k]!=0 ) {
536 	    marks[k] = malloc((subcnts[k]+1)*sizeof(SplineChar *));
537 	    marks[k][subcnts[k]] = NULL;
538 	    subcnts[k] = 0;
539 	}
540     }
541     for ( i=0; i<4; ++i ) {
542 	if ( heads[i].glyphs!=NULL )
543 	    heads[i].glyphs[heads[i].cnt] = NULL;
544     }
545     for ( i=0; i<classcnt; ++i ) {
546         if ( subcnts[i]!=0 )
547             SFOrderedGlyphs(marks[i]);
548     }
549 
550     *base = SFOrderedGlyphs(heads[at_basechar].glyphs);
551     *lig  = SFOrderedGlyphs(heads[at_baselig].glyphs);
552     *mkmk = SFOrderedGlyphs(heads[at_basemark].glyphs);
553 }
554 
EntryExitDecompose(SplineFont * sf,AnchorClass * ac,struct glyphinfo * gi)555 SplineChar **EntryExitDecompose(SplineFont *sf,AnchorClass *ac,struct glyphinfo *gi) {
556     /* Run through the font finding all characters with this anchor class */
557     int i,j, cnt, gmax, gid;
558     SplineChar **array;
559     AnchorPoint *test;
560 
561     array=NULL;
562     gmax = gi==NULL ? sf->glyphcnt : gi->gcnt;
563     for ( j=0; j<2; ++j ) {
564 	cnt = 0;
565 	for ( i=0; i<gmax; ++i ) if ( (gid = gi==NULL ? i : gi->bygid[i])!=-1 && sf->glyphs[gid]!=NULL ) {
566 	    for ( test=sf->glyphs[gid]->anchor; test!=NULL && test->anchor!=ac; test=test->next );
567 	    if ( test!=NULL && (test->type==at_centry || test->type==at_cexit )) {
568 		if ( array!=NULL )
569 		    array[cnt] = sf->glyphs[gid];
570 		++cnt;
571 	    }
572 	}
573 	if ( cnt==0 )
574 return( NULL );
575 	if ( j==1 )
576     break;
577 	array = malloc((cnt+1)*sizeof(SplineChar *));
578 	array[cnt] = NULL;
579     }
580 return( array );
581 }
582 
AnchorGuessContext(SplineFont * sf,struct alltabs * at)583 static void AnchorGuessContext(SplineFont *sf,struct alltabs *at) {
584     int i;
585     int maxbase=0, maxmark=0, basec, markc;
586     AnchorPoint *ap;
587     int hascursive = 0;
588 
589     /* the order in which we examine the glyphs does not matter here, so */
590     /*  we needn't add the complexity running though in gid order */
591     for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i] ) {
592 	basec = markc = 0;
593 	for ( ap = sf->glyphs[i]->anchor; ap!=NULL; ap=ap->next )
594 	    if ( ap->type==at_basemark )
595 		++markc;
596 	    else if ( ap->type==at_basechar || ap->type==at_baselig )
597 		++basec;
598 	    else if ( ap->type==at_centry )
599 		hascursive = true;
600 	if ( basec>maxbase ) maxbase = basec;
601 	if ( markc>maxmark ) maxmark = markc;
602     }
603 
604     if ( maxbase*(maxmark+1)>at->os2.maxContext )
605 	at->os2.maxContext = maxbase*(maxmark+1);
606     if ( hascursive && at->os2.maxContext<2 )
607 	at->os2.maxContext=2;
608 }
609 
dumpcoveragetable(FILE * gpos,SplineChar ** glyphs)610 static void dumpcoveragetable(FILE *gpos,SplineChar **glyphs) {
611     int i, last = -2, range_cnt=0, start, r;
612     /* the glyph list should already be sorted */
613     /* figure out whether it is better (smaller) to use an array of glyph ids */
614     /*  or a set of glyph id ranges */
615 
616 	// We will not emit glyphs with -1 identifiers.
617 	// We count the valid glyphs and the ranges.
618 	int glyph_cnt = 0;
619 	for (i=0; glyphs[i]!=NULL; i++) {
620 		if (i > 0 && glyphs[i]->ttf_glyph <= glyphs[i-1]->ttf_glyph) {
621 			LogError(_("Glyphs must be ordered when creating coverage table"));
622 		}
623 		if (glyphs[i]->ttf_glyph < 0) {
624 			LogError(_("-1 glyph index in dumpcoveragetable.\n"));
625 		} else {
626 			glyph_cnt++;
627 			// On the first validly TrueType-indexed glyph or at the start of any discontinuity, start a new range.
628 			if (range_cnt == 0 || glyphs[i]->ttf_glyph > last + 1)
629 				range_cnt++;
630 			last = glyphs[i]->ttf_glyph;
631 		}
632 	}
633 
634     /* I think Windows will only accept format 2 coverage tables? */
635     if ( !(coverageformatsallowed&2) || ((coverageformatsallowed&1) && i<=3*range_cnt )) {
636 	/* We use less space with a list of glyphs than with a set of ranges */
637 	putshort(gpos,1);		/* Coverage format=1 => glyph list */
638 	putshort(gpos,i);		/* count of glyphs */
639 	for ( i=0; glyphs[i]!=NULL; ++i )
640 	    putshort(gpos,glyphs[i]->ttf_glyph);	/* array of glyph IDs */
641     } else {
642 	putshort(gpos,2);		/* Coverage format=2 => range list */
643 	putshort(gpos,range_cnt);	/* count of ranges */
644 	last = -2; start = -2;		/* start is a index in our glyph array, last is ttf_glyph */
645 	// start is the index in the glyph array of the starting glyph. last is the ttf_glyph of the ending glyph.
646 	r = 0; // r keeps count of the emitted ranges.
647 	// We follow the chain of glyphs, ending and emitting a range whenever there is a discontinuity.
648 	for (i=0; glyphs[i]!=NULL; i++) {
649 		if (i > 0 && glyphs[i]->ttf_glyph <= glyphs[i-1]->ttf_glyph) {
650 			// LogError(_("Glyphs must be ordered when creating coverage table"));
651 		}
652 		if (glyphs[i]->ttf_glyph < 0) {
653 			// LogError(_("-1 glyph index in dumpcoveragetable."));
654 		} else {
655 			// At the start of any discontinuity, dump the previous range.
656 			if (r > 0 && glyphs[i]->ttf_glyph > last + 1) {
657 				putshort(gpos,glyphs[start]->ttf_glyph);	/* start glyph ID */
658 				putshort(gpos,last);			/* end glyph ID */
659 				putshort(gpos,start);			/* coverage index of start glyph */
660 			}
661 			// On the first validly TrueType-indexed glyph or at the start of any discontinuity, start a new range.
662 			if (r == 0 || glyphs[i]->ttf_glyph > last + 1) {
663 				start = i;
664 				r++;
665 			}
666 			last = glyphs[i]->ttf_glyph;
667 		}
668 	}
669 	// If there were any valid glyphs, there will be one more range to be emitted.
670 	if (r > 0) {
671 		putshort(gpos,glyphs[start]->ttf_glyph);	/* start glyph ID */
672 		putshort(gpos,last);			/* end glyph ID */
673 		putshort(gpos,start);			/* coverage index of start glyph */
674 	}
675 	if ( r!=range_cnt )
676 	    IError("Miscounted ranges in format 2 coverage table output");
677     }
678 }
679 
sc_ttf_order(const void * _sc1,const void * _sc2)680 static int sc_ttf_order( const void *_sc1, const void *_sc2) {
681     const SplineChar *sc1 = *(const SplineChar **) _sc1, *sc2 = *(const SplineChar **) _sc2;
682 return( sc1->ttf_glyph - sc2->ttf_glyph );
683 }
684 
SFOrderedGlyphs(SplineChar ** glyphs)685 static SplineChar **SFOrderedGlyphs(SplineChar **glyphs) {
686     int cnt, i, k;
687     if ( glyphs==NULL )
688 return( NULL );
689     for ( cnt=0; glyphs[cnt]!=NULL; ++cnt);
690     qsort(glyphs,cnt,sizeof(SplineChar *),sc_ttf_order);
691 	// We want to eliminate invalid glyphs.
692     if ( cnt > 0 && glyphs[0]->ttf_glyph < 0 ) {
693 	/* Not sure if this can happen, but it's easy to fix */
694 	// We count the invalid glyphs.
695 	for ( k=0; k<cnt && glyphs[k]->ttf_glyph < 0; ++k);
696 	// Then we move the valid glyphs down to the base of the range.
697 	for ( i=0; i<=cnt-k; ++i )
698 	    glyphs[i] = glyphs[i+k];
699 	cnt -= k;
700 	// fprintf(stderr, "Eliminated %d invalid glyphs.\n", k);
701 	// And we null-terminate.
702 	glyphs[i] = NULL;
703     }
704     for ( i=0; i<cnt-1; ++i )
705         if (glyphs[i]->ttf_glyph==glyphs[i+1]->ttf_glyph) {
706 						// fprintf(stderr, "Duplicate glyph.\n");
707             memmove(glyphs+i, glyphs+i+1, (cnt-i)*sizeof(SplineChar *));
708             --cnt;
709         }
710 	glyphs[cnt] = NULL;
711 return( glyphs );
712 }
713 
SFOrderedGlyphsWithPSTinSubtable(SplineFont * sf,struct lookup_subtable * sub)714 static SplineChar **SFOrderedGlyphsWithPSTinSubtable(SplineFont *sf,struct lookup_subtable *sub) {
715     SplineChar **glyphs = SFGlyphsWithPSTinSubtable(sf,sub);
716     return SFOrderedGlyphs(glyphs);
717 }
718 
SFGlyphsFromNames(SplineFont * sf,char * names)719 SplineChar **SFGlyphsFromNames(SplineFont *sf,char *names) {
720     int cnt, ch;
721     char *pt, *end;
722     SplineChar *sc, **glyphs;
723 
724     // If names is NULL, return a null-terminated zero-length list.
725     if ( names==NULL )
726 return( calloc(1,sizeof(SplineChar *)) );
727 
728     // Find the number of tokens in the name list.
729     cnt = 0;
730     for ( pt = names; *pt; pt = end+1 ) {
731 	++cnt;
732 	end = strchr(pt,' ');
733 	if ( end==NULL )
734     break;
735     }
736 
737     // Allocate space for all tokens in the name list.
738     // We may not use all of them if some of the references are invalid.
739     glyphs = malloc((cnt+1)*sizeof(SplineChar *));
740     cnt = 0;
741     for ( pt = names; *pt; pt = end+1 ) {
742 	end = strchr(pt,' ');
743 	if ( end==NULL )
744 	    end = pt+strlen(pt);
745 	ch = *end;
746 	*end = '\0';
747 	sc = SFGetChar(sf,-1,pt);
748 	if ( sc!=NULL && sc->ttf_glyph!=-1 )
749 	    glyphs[cnt++] = sc;
750 	*end = ch;
751 	if ( ch=='\0' )
752     break;
753     }
754     glyphs[cnt] = NULL;
755 return( glyphs );
756 }
757 
TTFGlyphsFromNames(SplineFont * sf,char * names)758 static SplineChar **TTFGlyphsFromNames(SplineFont *sf,char *names) {
759 		// This returns only the named glyphs that also have valid TrueType indices.
760     SplineChar **glyphs = SFGlyphsFromNames(sf,names);
761 		if (glyphs == NULL) IError("Glyph-finding error.");
762 		int i, j;
763 		// Count the valid glyphs.
764 		for (i=0, j=0; glyphs[i] != NULL; i++)
765 			if (glyphs[i]->ttf_glyph >= 0) j++;
766 		SplineChar **output = calloc(j+1,sizeof(SplineChar *));
767 		if (output == NULL) IError("Memory error.");
768 		for (i=0, j=0; glyphs[i] != NULL; i++)
769 			if (glyphs[i]->ttf_glyph >= 0) {
770 				output[j] = glyphs[i];
771 				j++;
772 			}
773 		// fprintf(stderr, "Using %d of %d glyphs.\n", j, i);
774 		free(glyphs);
775 		return output;
776 }
777 
OrderedGlyphsFromNames(SplineFont * sf,char * names)778 static SplineChar **OrderedGlyphsFromNames(SplineFont *sf,char *names) {
779     SplineChar **glyphs = SFGlyphsFromNames(sf,names);
780     int i,j;
781 
782     if ( glyphs==NULL || glyphs[0]==NULL )
783 return( glyphs );
784 
785 #if 0
786 
787     for ( i=0; glyphs[i] != NULL && glyphs[i+1]!=NULL; ++i ) for ( j=i+1; glyphs[j]!=NULL; ++j ) {
788 	if ( glyphs[i]->ttf_glyph > glyphs[j]->ttf_glyph ) {
789 	    SplineChar *sc = glyphs[i];
790 	    glyphs[i] = glyphs[j];
791 	    glyphs[j] = sc;
792 	}
793     }
794     if ( glyphs[0]!=NULL ) {		/* Glyphs should not appear twice in the name list, just just in case they do... */
795 	for ( i=0; glyphs[i+1]!=NULL; ++i ) {
796 	    if ( glyphs[i]==glyphs[i+1] ) {
797 		for ( j=i+1; glyphs[j]!=NULL; ++j )
798 		    glyphs[j] = glyphs[j+1];
799 	    }
800 	}
801     }
802 
803 return( glyphs );
804 #endif // 0
805 
806 // We are going to try using SFOrderedGlyphs here.
807 	return SFOrderedGlyphs(glyphs);
808 }
809 
gposvrmaskeddump(FILE * gpos,int vf1,int mask,int offset)810 static void gposvrmaskeddump(FILE *gpos,int vf1,int mask,int offset) {
811     if ( vf1&1 ) putshort(gpos,mask&1 ? offset : 0 );
812     if ( vf1&2 ) putshort(gpos,mask&2 ? offset : 0 );
813     if ( vf1&4 ) putshort(gpos,mask&4 ? offset : 0 );
814     if ( vf1&8 ) putshort(gpos,mask&8 ? offset : 0 );
815 }
816 
devtaboffsetsize(DeviceTable * dt)817 static int devtaboffsetsize(DeviceTable *dt) {
818     int type = 1, i;
819 
820     for ( i=dt->last_pixel_size-dt->first_pixel_size; i>=0; --i ) {
821 	if ( dt->corrections[i]>=8 || dt->corrections[i]<-8 )
822 return( 3 );
823 	else if ( dt->corrections[i]>=2 || dt->corrections[i]<-2 )
824 	    type = 2;
825     }
826 return( type );
827 }
828 
dumpgposdevicetable(FILE * gpos,DeviceTable * dt)829 static void dumpgposdevicetable(FILE *gpos,DeviceTable *dt) {
830     int type;
831     int i,cnt,b;
832 
833     if ( dt==NULL || dt->corrections==NULL )
834 return;
835     type = devtaboffsetsize(dt);
836     putshort(gpos,dt->first_pixel_size);
837     putshort(gpos,dt->last_pixel_size );
838     putshort(gpos,type);
839     cnt = dt->last_pixel_size - dt->first_pixel_size + 1;
840     if ( type==3 ) {
841 	for ( i=0; i<cnt; ++i )
842 	    putc(dt->corrections[i],gpos);
843 	if ( cnt&1 )
844 	    putc(0,gpos);
845     } else if ( type==2 ) {
846 	for ( i=0; i<cnt; i+=4 ) {
847 	    int val = 0;
848 	    for ( b=0; b<4 && i+b<cnt; ++b )
849 		val |= (dt->corrections[i+b]&0x000f)<<(12-b*4);
850 	    putshort(gpos,val);
851 	}
852     } else {
853 	for ( i=0; i<cnt; i+=8 ) {
854 	    int val = 0;
855 	    for ( b=0; b<8 && i+b<cnt; ++b )
856 		val |= (dt->corrections[i+b]&0x0003)<<(14-b*2);
857 	    putshort(gpos,val);
858 	}
859     }
860 }
861 
DevTabLen(DeviceTable * dt)862 static int DevTabLen(DeviceTable *dt) {
863     int type;
864     int cnt;
865 
866     if ( dt==NULL || dt->corrections==NULL )
867 return( 0 );
868     cnt = dt->last_pixel_size - dt->first_pixel_size + 1;
869     type = devtaboffsetsize(dt);
870     if ( type==3 )
871 	cnt = (cnt+1)/2;
872     else if ( type==2 )
873 	cnt = (cnt+3)/4;
874     else
875 	cnt = (cnt+7)/8;
876     cnt += 3;		/* first, last, type */
877 return( sizeof(uint16)*cnt );
878 }
879 
ValDevTabLen(ValDevTab * vdt)880 static int ValDevTabLen(ValDevTab *vdt) {
881 
882     if ( vdt==NULL )
883 return( 0 );
884 
885 return( DevTabLen(&vdt->xadjust) + DevTabLen(&vdt->yadjust) +
886 	DevTabLen(&vdt->xadv) + DevTabLen(&vdt->yadv) );
887 }
888 
gposdumpvaldevtab(FILE * gpos,ValDevTab * vdt,int bits,int next_dev_tab)889 static int gposdumpvaldevtab(FILE *gpos,ValDevTab *vdt,int bits,int next_dev_tab ) {
890 
891     if ( bits&0x10 ) {
892 	if ( vdt==NULL || vdt->xadjust.corrections==NULL )
893 	    putshort(gpos,0);
894 	else {
895 	    putshort(gpos,next_dev_tab);
896 	    next_dev_tab += DevTabLen(&vdt->xadjust);
897 	}
898     }
899     if ( bits&0x20 ) {
900 	if ( vdt==NULL || vdt->yadjust.corrections==NULL )
901 	    putshort(gpos,0);
902 	else {
903 	    putshort(gpos,next_dev_tab);
904 	    next_dev_tab += DevTabLen(&vdt->yadjust);
905 	}
906     }
907     if ( bits&0x40 ) {
908 	if ( vdt==NULL || vdt->xadv.corrections==NULL )
909 	    putshort(gpos,0);
910 	else {
911 	    putshort(gpos,next_dev_tab);
912 	    next_dev_tab += DevTabLen(&vdt->xadv);
913 	}
914     }
915     if ( bits&0x80 ) {
916 	if ( vdt==NULL || vdt->yadv.corrections==NULL )
917 	    putshort(gpos,0);
918 	else {
919 	    putshort(gpos,next_dev_tab);
920 	    next_dev_tab += DevTabLen(&vdt->yadv);
921 	}
922     }
923 return( next_dev_tab );
924 }
925 
gposmaskeddumpdevtab(FILE * gpos,DeviceTable * dt,int bits,int mask,int next_dev_tab)926 static int gposmaskeddumpdevtab(FILE *gpos,DeviceTable *dt,int bits,int mask,
927 	int next_dev_tab ) {
928 
929     if ( bits&0x10 ) {
930 	if ( !(mask&0x10) || dt==NULL )
931 	    putshort(gpos,0);
932 	else {
933 	    putshort(gpos,next_dev_tab);
934 	    next_dev_tab += DevTabLen(dt);
935 	}
936     }
937     if ( bits&0x20 ) {
938 	if ( !(mask&0x20) || dt==NULL )
939 	    putshort(gpos,0);
940 	else {
941 	    putshort(gpos,next_dev_tab);
942 	    next_dev_tab += DevTabLen(dt);
943 	}
944     }
945     if ( bits&0x40 ) {
946 	if ( !(mask&0x40) || dt==NULL )
947 	    putshort(gpos,0);
948 	else {
949 	    putshort(gpos,next_dev_tab);
950 	    next_dev_tab += DevTabLen(dt);
951 	}
952     }
953     if ( bits&0x80 ) {
954 	if ( !(mask&0x80) || dt==NULL )
955 	    putshort(gpos,0);
956 	else {
957 	    putshort(gpos,next_dev_tab);
958 	    next_dev_tab += DevTabLen(dt);
959 	}
960     }
961 return( next_dev_tab );
962 }
963 
DevTabsSame(DeviceTable * dt1,DeviceTable * dt2)964 static int DevTabsSame(DeviceTable *dt1, DeviceTable *dt2) {
965     DeviceTable _dt;
966     int i;
967 
968     if ( dt1==NULL && dt2==NULL )
969 return( true );
970     if ( dt1==NULL ) {
971 	memset(&_dt,0,sizeof(_dt));
972 	dt1 = &_dt;
973     }
974     if ( dt2==NULL ) {
975 	memset(&_dt,0,sizeof(_dt));
976 	dt2 = &_dt;
977     }
978     if ( dt1->corrections==NULL && dt2->corrections==NULL )
979 return( true );
980     if ( dt1->corrections==NULL || dt2->corrections==NULL )
981 return( false );
982     if ( dt1->first_pixel_size!=dt2->first_pixel_size ||
983 	    dt1->last_pixel_size!=dt2->last_pixel_size )
984 return( false );
985     for ( i=dt2->last_pixel_size-dt1->first_pixel_size; i>=0; --i )
986 	if ( dt1->corrections[i]!=dt2->corrections[i] )
987 return( false );
988 
989 return( true );
990 }
991 
ValDevTabsSame(ValDevTab * vdt1,ValDevTab * vdt2)992 static int ValDevTabsSame(ValDevTab *vdt1, ValDevTab *vdt2) {
993     ValDevTab _vdt;
994 
995     if ( vdt1==NULL && vdt2==NULL )
996 return( true );
997     if ( vdt1==NULL ) {
998 	memset(&_vdt,0,sizeof(_vdt));
999 	vdt1 = &_vdt;
1000     }
1001     if ( vdt2==NULL ) {
1002 	memset(&_vdt,0,sizeof(_vdt));
1003 	vdt2 = &_vdt;
1004     }
1005 return( DevTabsSame(&vdt1->xadjust,&vdt2->xadjust) &&
1006 	DevTabsSame(&vdt1->yadjust,&vdt2->yadjust) &&
1007 	DevTabsSame(&vdt1->xadv,&vdt2->xadv) &&
1008 	DevTabsSame(&vdt1->yadv,&vdt2->yadv) );
1009 }
1010 
dumpGPOSsimplepos(FILE * gpos,SplineFont * sf,struct lookup_subtable * sub)1011 static void dumpGPOSsimplepos(FILE *gpos,SplineFont *sf,struct lookup_subtable *sub ) {
1012     int cnt, cnt2;
1013     int32 coverage_pos, end;
1014     PST *pst, *first=NULL;
1015     int bits = 0, same=true;
1016     SplineChar **glyphs;
1017 
1018     glyphs = SFOrderedGlyphsWithPSTinSubtable(sf,sub);
1019     for ( cnt=cnt2=0; glyphs[cnt]!=NULL; ++cnt) {
1020 	for ( pst=glyphs[cnt]->possub; pst!=NULL; pst=pst->next ) {
1021 	    if ( pst->subtable==sub && pst->type==pst_position ) {
1022 		if ( first==NULL ) first = pst;
1023 		else if ( same && first && pst ) {
1024 		    if ( first->u.pos.xoff!=pst->u.pos.xoff ||
1025 			    first->u.pos.yoff!=pst->u.pos.yoff ||
1026 			    first->u.pos.h_adv_off!=pst->u.pos.h_adv_off ||
1027 			    first->u.pos.v_adv_off!=pst->u.pos.v_adv_off )
1028 			same = false;
1029 		    if ( !ValDevTabsSame(pst->u.pos.adjust,first->u.pos.adjust))
1030 			same = false;
1031 		}
1032 		if ( pst->u.pos.xoff!=0 ) bits |= 1;
1033 		if ( pst->u.pos.yoff!=0 ) bits |= 2;
1034 		if ( pst->u.pos.h_adv_off!=0 ) bits |= 4;
1035 		if ( pst->u.pos.v_adv_off!=0 ) bits |= 8;
1036 		if ( pst->u.pos.adjust!=NULL ) {
1037 		    if ( pst->u.pos.adjust->xadjust.corrections!=NULL ) bits |= 0x10;
1038 		    if ( pst->u.pos.adjust->yadjust.corrections!=NULL ) bits |= 0x20;
1039 		    if ( pst->u.pos.adjust->xadv.corrections!=NULL ) bits |= 0x40;
1040 		    if ( pst->u.pos.adjust->yadv.corrections!=NULL ) bits |= 0x80;
1041 		}
1042 		++cnt2;
1043 	break;
1044 	    }
1045 	}
1046     }
1047     if ( bits==0 ) bits=1;
1048     if ( cnt!=cnt2 )
1049 	IError( "Count mismatch in dumpGPOSsimplepos#1 %d vs %d\n", cnt, cnt2 );
1050 
1051     putshort(gpos,same?1:2);	/* 1 means all value records same */
1052     coverage_pos = ftell(gpos);
1053     putshort(gpos,0);		/* offset to coverage table */
1054     putshort(gpos,bits);
1055     if ( same && first ) {
1056 	if ( bits&1 ) putshort(gpos,first->u.pos.xoff);
1057 	if ( bits&2 ) putshort(gpos,first->u.pos.yoff);
1058 	if ( bits&4 ) putshort(gpos,first->u.pos.h_adv_off);
1059 	if ( bits&8 ) putshort(gpos,first->u.pos.v_adv_off);
1060 	if ( bits&0xf0 ) {
1061 	    int next_dev_tab = ftell(gpos)-coverage_pos+2+
1062 		sizeof(int16)*((bits&0x10?1:0) + (bits&0x20?1:0) + (bits&0x40?1:0) + (bits&0x80?1:0));
1063 	    if ( bits&0x10 ) { putshort(gpos,next_dev_tab); next_dev_tab += DevTabLen(&first->u.pos.adjust->xadjust); }
1064 	    if ( bits&0x20 ) { putshort(gpos,next_dev_tab); next_dev_tab += DevTabLen(&first->u.pos.adjust->yadjust); }
1065 	    if ( bits&0x40 ) { putshort(gpos,next_dev_tab); next_dev_tab += DevTabLen(&first->u.pos.adjust->xadv); }
1066 	    if ( bits&0x80 ) { putshort(gpos,next_dev_tab); next_dev_tab += DevTabLen(&first->u.pos.adjust->yadv); }
1067 	    if ( bits&0x10 ) dumpgposdevicetable(gpos,&first->u.pos.adjust->xadjust);
1068 	    if ( bits&0x20 ) dumpgposdevicetable(gpos,&first->u.pos.adjust->yadjust);
1069 	    if ( bits&0x40 ) dumpgposdevicetable(gpos,&first->u.pos.adjust->xadv);
1070 	    if ( bits&0x80 ) dumpgposdevicetable(gpos,&first->u.pos.adjust->yadv);
1071 	    if ( next_dev_tab!=ftell(gpos)-coverage_pos+2 )
1072 		IError( "Device Table offsets wrong in simple positioning 2");
1073 	}
1074     } else {
1075 	int vr_size =
1076 		sizeof(int16)*((bits&0x1?1:0) + (bits&0x2?1:0) + (bits&0x4?1:0) + (bits&0x8?1:0) +
1077 		    (bits&0x10?1:0) + (bits&0x20?1:0) + (bits&0x40?1:0) + (bits&0x80?1:0));
1078 	int next_dev_tab = ftell(gpos)-coverage_pos+2+2+vr_size*cnt;
1079 	putshort(gpos,cnt);
1080 	for ( cnt2 = 0; glyphs[cnt2]!=NULL; ++cnt2 ) {
1081 	    for ( pst=glyphs[cnt2]->possub; pst!=NULL; pst=pst->next ) {
1082 		if ( pst->subtable==sub && pst->type==pst_position ) {
1083 		    if ( bits&1 ) putshort(gpos,pst->u.pos.xoff);
1084 		    if ( bits&2 ) putshort(gpos,pst->u.pos.yoff);
1085 		    if ( bits&4 ) putshort(gpos,pst->u.pos.h_adv_off);
1086 		    if ( bits&8 ) putshort(gpos,pst->u.pos.v_adv_off);
1087 		    next_dev_tab = gposdumpvaldevtab(gpos,pst->u.pos.adjust,bits,
1088 			    next_dev_tab);
1089 	    break;
1090 		}
1091 	    }
1092 	}
1093 	if ( cnt!=cnt2 )
1094 	    IError( "Count mismatch in dumpGPOSsimplepos#3 %d vs %d\n", cnt, cnt2 );
1095 	if ( bits&0xf0 ) {
1096 	    for ( cnt2 = 0; glyphs[cnt2]!=NULL; ++cnt2 ) {
1097 		for ( pst=glyphs[cnt2]->possub; pst!=NULL; pst=pst->next ) {
1098 		    if ( pst->subtable==sub && pst->type==pst_position ) {
1099 			if ( bits&0x10 ) dumpgposdevicetable(gpos,&first->u.pos.adjust->xadjust);
1100 			if ( bits&0x20 ) dumpgposdevicetable(gpos,&first->u.pos.adjust->yadjust);
1101 			if ( bits&0x40 ) dumpgposdevicetable(gpos,&first->u.pos.adjust->xadv);
1102 			if ( bits&0x80 ) dumpgposdevicetable(gpos,&first->u.pos.adjust->yadv);
1103 		    }
1104 		}
1105 	    }
1106 	}
1107 	if ( next_dev_tab!=ftell(gpos)-coverage_pos+2 )
1108 	    IError( "Device Table offsets wrong in simple positioning 2");
1109     }
1110     end = ftell(gpos);
1111     fseek(gpos,coverage_pos,SEEK_SET);
1112     putshort(gpos,end-coverage_pos+2);
1113     fseek(gpos,end,SEEK_SET);
1114     dumpcoveragetable(gpos,glyphs);
1115     fseek(gpos,0,SEEK_END);
1116     free(glyphs);
1117 }
1118 
1119 struct sckppst {
1120     uint16 samewas;
1121     uint16 devtablen;
1122     uint16 tot;
1123     uint8 isv;
1124     uint8 subtable_too_big;
1125 /* The first few fields are only meaningful in the first structure in the array*/
1126 /*   and provide information about the entire rest of the array */
1127     uint16 other_gid;
1128     SplineChar *sc;
1129     KernPair *kp;
1130     PST *pst;
1131 };
1132 
cmp_gid(const void * _s1,const void * _s2)1133 static int cmp_gid( const void *_s1, const void *_s2 ) {
1134     const struct sckppst *s1 = _s1, *s2 = _s2;
1135 return( ((int) s1->other_gid) - ((int) s2->other_gid) );
1136 }
1137 
dumpGPOSpairpos(FILE * gpos,SplineFont * sf,struct lookup_subtable * sub)1138 static void dumpGPOSpairpos(FILE *gpos,SplineFont *sf,struct lookup_subtable *sub) {
1139     int cnt;
1140     int32 coverage_pos, offset_pos, end, start, pos;
1141     PST *pst;
1142     KernPair *kp;
1143     int vf1 = 0, vf2=0, i, j, k, tot, bit_cnt, v;
1144     int start_cnt, end_cnt;
1145     int chunk_cnt, chunk_max;
1146     SplineChar *sc, **glyphs, *gtemp;
1147     struct sckppst **seconds;
1148     int devtablen;
1149     int next_dev_tab;
1150 
1151     /* Figure out all the data we need. First the glyphs with kerning info */
1152     /*  then the glyphs to which they kern, and by how much */
1153     glyphs = SFOrderedGlyphsWithPSTinSubtable(sf,sub);
1154     for ( cnt=0; glyphs[cnt]!=NULL; ++cnt);
1155     seconds = malloc(cnt*sizeof(struct sckppst *));
1156     for ( cnt=0; glyphs[cnt]!=NULL; ++cnt) {
1157 	for ( k=0; k<2; ++k ) {
1158 	    devtablen = 0;
1159 	    tot = 0;
1160 	    for ( pst=glyphs[cnt]->possub; pst!=NULL; pst=pst->next ) {
1161 		if ( pst->subtable==sub && pst->type==pst_pair &&
1162 			(sc = SFGetChar(sf,-1,pst->u.pair.paired))!=NULL &&
1163 			sc->ttf_glyph!=-1 ) {
1164 		    if ( k ) {
1165 			seconds[cnt][tot].sc = sc;
1166 			seconds[cnt][tot].other_gid = sc->ttf_glyph;
1167 			seconds[cnt][tot].pst = pst;
1168 			devtablen += ValDevTabLen(pst->u.pair.vr[0].adjust) +
1169 				 ValDevTabLen(pst->u.pair.vr[1].adjust);
1170 
1171 		    }
1172 		    ++tot;
1173 		}
1174 	    }
1175 	    for ( v=0; v<2; ++v ) {
1176 		for ( kp = v ? glyphs[cnt]->vkerns : glyphs[cnt]->kerns; kp!=NULL; kp=kp->next ) {
1177 		    if( kp->subtable!=sub ) continue; // process only glyphs from the current subtable
1178 		    if ( kp->sc->ttf_glyph!=-1 ) {
1179 			if ( k ) {
1180 			    seconds[cnt][tot].other_gid = kp->sc->ttf_glyph;
1181 			    seconds[cnt][tot].sc = kp->sc;
1182 			    seconds[cnt][tot].kp = kp;
1183 			    seconds[cnt][tot].isv = v;
1184 			    devtablen += DevTabLen(kp->adjust);
1185 			}
1186 			++tot;
1187 		    }
1188 		}
1189 	    }
1190 	    if ( k==0 ) {
1191 		seconds[cnt] = calloc(tot+1,sizeof(struct sckppst));
1192 	    } else {
1193 		qsort(seconds[cnt],tot,sizeof(struct sckppst),cmp_gid);
1194 		seconds[cnt][0].tot = tot;
1195 		/* Devtablen is 0 unless we are configured for device tables */
1196 		seconds[cnt][0].devtablen = devtablen;
1197 		seconds[cnt][0].samewas = 0xffff;
1198 	    }
1199 	}
1200     }
1201 
1202     /* Some fonts do a primitive form of class based kerning, several glyphs */
1203     /*  can share the same list of second glyphs & offsets */
1204     for ( cnt=0; glyphs[cnt]!=NULL; ++cnt) {
1205 	struct sckppst *test = seconds[cnt], *test2;
1206 	for ( i=cnt-1; i>=0; --i ) {
1207 	    test2 = seconds[i];
1208 	    if ( test[0].tot != test2[0].tot || test2[0].samewas!=0xffff )
1209 	continue;
1210 	    for ( j=test[0].tot-1; j>=0; --j ) {
1211 		if ( test[j].other_gid != test2[j].other_gid )
1212 	    break;
1213 		if ( test[j].kp!=NULL && test2[j].kp!=NULL &&
1214 			test[j].kp->off == test2[j].kp->off
1215 			&& DevTabsSame(test[j].kp->adjust,test2[j].kp->adjust)
1216 			)
1217 		    /* So far, so good */;
1218 		else if ( test[j].pst!=NULL && test2[j].pst!=NULL &&
1219 			test[j].pst->u.pair.vr[0].xoff == test2[j].pst->u.pair.vr[0].xoff &&
1220 			test[j].pst->u.pair.vr[0].yoff == test2[j].pst->u.pair.vr[0].yoff &&
1221 			test[j].pst->u.pair.vr[0].h_adv_off == test2[j].pst->u.pair.vr[0].h_adv_off &&
1222 			test[j].pst->u.pair.vr[0].v_adv_off == test2[j].pst->u.pair.vr[0].v_adv_off &&
1223 			test[j].pst->u.pair.vr[1].xoff == test2[j].pst->u.pair.vr[1].xoff &&
1224 			test[j].pst->u.pair.vr[1].yoff == test2[j].pst->u.pair.vr[1].yoff &&
1225 			test[j].pst->u.pair.vr[1].h_adv_off == test2[j].pst->u.pair.vr[1].h_adv_off &&
1226 			test[j].pst->u.pair.vr[1].v_adv_off == test2[j].pst->u.pair.vr[1].v_adv_off
1227 			&& ValDevTabsSame(test[j].pst->u.pair.vr[0].adjust,test2[j].pst->u.pair.vr[0].adjust)
1228 			&& ValDevTabsSame(test[j].pst->u.pair.vr[1].adjust,test2[j].pst->u.pair.vr[1].adjust)
1229 			)
1230 		    /* That's ok too. */;
1231 		else
1232 	    break;
1233 	    }
1234 	    if ( j>=0 )
1235 	continue;
1236 	    test[0].samewas = i;
1237 	break;
1238 	}
1239     }
1240 
1241     /* Ok, how many offsets must we output? Normal kerning will just use */
1242     /*  one offset (with perhaps a device table), but the standard allows */
1243     /*  us to adjust 8 different values (with 8 different device tables) */
1244     /* Find out which we need */
1245     for ( cnt=0; glyphs[cnt]!=NULL; ++cnt) {
1246 	for ( tot=0 ; tot<seconds[cnt][0].tot; ++tot ) {
1247 	    if ( (pst=seconds[cnt][tot].pst)!=NULL ) {
1248 		if ( pst->subtable==sub && pst->type==pst_pair ) {
1249 		    if ( pst->u.pair.vr[0].xoff!=0 ) vf1 |= 1;
1250 		    if ( pst->u.pair.vr[0].yoff!=0 ) vf1 |= 2;
1251 		    if ( pst->u.pair.vr[0].h_adv_off!=0 ) vf1 |= 4;
1252 		    if ( pst->u.pair.vr[0].v_adv_off!=0 ) vf1 |= 8;
1253 		    if ( pst->u.pair.vr[0].adjust!=NULL ) {
1254 			if ( pst->u.pair.vr[0].adjust->xadjust.corrections!=NULL ) vf1 |= 0x10;
1255 			if ( pst->u.pair.vr[0].adjust->yadjust.corrections!=NULL ) vf1 |= 0x20;
1256 			if ( pst->u.pair.vr[0].adjust->xadv.corrections!=NULL ) vf1 |= 0x40;
1257 			if ( pst->u.pair.vr[0].adjust->yadv.corrections!=NULL ) vf1 |= 0x80;
1258 		    }
1259 		    if ( pst->u.pair.vr[1].xoff!=0 ) vf2 |= 1;
1260 		    if ( pst->u.pair.vr[1].yoff!=0 ) vf2 |= 2;
1261 		    if ( pst->u.pair.vr[1].h_adv_off!=0 ) vf2 |= 4;
1262 		    if ( pst->u.pair.vr[1].v_adv_off!=0 ) vf2 |= 8;
1263 		    if ( pst->u.pair.vr[1].adjust!=NULL ) {
1264 			if ( pst->u.pair.vr[1].adjust->xadjust.corrections!=NULL ) vf2 |= 0x10;
1265 			if ( pst->u.pair.vr[1].adjust->yadjust.corrections!=NULL ) vf2 |= 0x20;
1266 			if ( pst->u.pair.vr[1].adjust->xadv.corrections!=NULL ) vf2 |= 0x40;
1267 			if ( pst->u.pair.vr[1].adjust->yadv.corrections!=NULL ) vf2 |= 0x80;
1268 		    }
1269 		}
1270 	    }
1271 	    if ( (kp = seconds[cnt][tot].kp)!=NULL ) {
1272 		int mask = 0, mask2=0;
1273 		if ( seconds[cnt][tot].isv )
1274 		    mask = 0x0008;
1275 		else
1276 		    mask = 0x0004;
1277 		if ( kp->adjust!=NULL ) {
1278 		    mask  |= mask<<4;
1279 		    mask2 |= mask2<<4;
1280 		}
1281 		vf1 |= mask;
1282 		vf2 |= mask2;
1283 	    }
1284 	}
1285     }
1286     if ( vf1==0 && vf2==0 ) vf1=1;
1287     bit_cnt = 0;
1288     for ( i=0; i<8; ++i ) {
1289 	if ( vf1&(1<<i) ) ++bit_cnt;
1290 	if ( vf2&(1<<i) ) ++bit_cnt;
1291     }
1292 
1293     chunk_max = chunk_cnt = 0;
1294     for ( start_cnt=0; start_cnt<cnt; start_cnt=end_cnt ) {
1295 	int len = 5*2;		/* Subtable header */
1296 	for ( end_cnt=start_cnt; end_cnt<cnt; ++end_cnt ) {
1297 	    int glyph_len = 2;		/* For the glyph's offset */
1298 	    if ( seconds[end_cnt][0].samewas==0xffff || seconds[end_cnt][0].samewas<start_cnt )
1299 		glyph_len += (bit_cnt*2+2)*seconds[end_cnt][0].tot +
1300 				seconds[end_cnt][0].devtablen +
1301 			        2;	/* Number of secondary glyphs */
1302 	    if ( glyph_len>65535 && end_cnt==start_cnt ) {
1303 		LogError(_("Lookup subtable %s contains a glyph %s whose kerning information takes up more than 64k bytes\n"),
1304 			sub->subtable_name, glyphs[start_cnt]->name );
1305 		len += glyph_len;
1306 	    } else if ( len+glyph_len>65535 ) {
1307 		if( start_cnt==0 )
1308 		    LogError(_("Lookup subtable %s had to be split into several subtables\nbecause it was too big.\n"),
1309 			sub->subtable_name );
1310 	break;
1311 	    } else
1312 		len += glyph_len;
1313 	}
1314 	if ( start_cnt!=0 || end_cnt!=cnt ) {
1315 	    if ( chunk_cnt>=chunk_max )
1316 		sub->extra_subtables = realloc(sub->extra_subtables,((chunk_max+=10)+1)*sizeof(int32));
1317 	    sub->extra_subtables[chunk_cnt++] = ftell(gpos);
1318 	    sub->extra_subtables[chunk_cnt] = -1;
1319 	}
1320 
1321 	start = ftell(gpos);
1322 	putshort(gpos,1);		/* 1 means char pairs (ie. not classes) */
1323 	coverage_pos = ftell(gpos);
1324 	putshort(gpos,0);		/* offset to coverage table */
1325 	putshort(gpos,vf1);
1326 	putshort(gpos,vf2);
1327 	putshort(gpos,end_cnt-start_cnt);
1328 	offset_pos = ftell(gpos);
1329 	for ( i=start_cnt; i<end_cnt; ++i )
1330 	    putshort(gpos,0);	/* Fill in later */
1331 	for ( i=start_cnt; i<end_cnt; ++i ) {
1332 	    if ( seconds[i][0].samewas>= start_cnt && seconds[i][0].samewas!=0xffff ) {
1333 		/* It's the same as the glyph at samewas, so just copy the */
1334 		/*  offset from there. We don't need to do anything else */
1335 		int offset;
1336 		fseek(gpos,offset_pos+(seconds[i][0].samewas-start_cnt)*sizeof(uint16),SEEK_SET);
1337 		offset = getushort(gpos);
1338 		fseek(gpos,offset_pos+(i-start_cnt)*sizeof(uint16),SEEK_SET);
1339 		putshort(gpos,offset);
1340 		fseek(gpos,0,SEEK_END);
1341 	continue;
1342 	    }
1343 	    next_dev_tab = ftell(gpos)-start;
1344 	    if ( (vf1&0xf0) || (vf2&0xf0) ) {
1345 		for ( tot=0 ; tot<seconds[i][0].tot; ++tot ) {
1346 		    if ( (pst=seconds[i][tot].pst)!=NULL ) {
1347 			if ( pst->u.pair.vr[0].adjust!=NULL ) {
1348 			    dumpgposdevicetable(gpos,&pst->u.pair.vr[0].adjust->xadjust);
1349 			    dumpgposdevicetable(gpos,&pst->u.pair.vr[0].adjust->yadjust);
1350 			    dumpgposdevicetable(gpos,&pst->u.pair.vr[0].adjust->xadv);
1351 			    dumpgposdevicetable(gpos,&pst->u.pair.vr[0].adjust->yadv);
1352 			}
1353 			if ( pst->u.pair.vr[1].adjust!=NULL ) {
1354 			    dumpgposdevicetable(gpos,&pst->u.pair.vr[1].adjust->xadjust);
1355 			    dumpgposdevicetable(gpos,&pst->u.pair.vr[1].adjust->yadjust);
1356 			    dumpgposdevicetable(gpos,&pst->u.pair.vr[1].adjust->xadv);
1357 			    dumpgposdevicetable(gpos,&pst->u.pair.vr[1].adjust->yadv);
1358 			}
1359 		    }
1360 		    if ( (kp=seconds[i][tot].kp)!=NULL && kp->adjust!=NULL )
1361 			dumpgposdevicetable(gpos,kp->adjust);
1362 		}
1363 	    }
1364 	    pos = ftell(gpos);
1365 	    fseek(gpos,offset_pos+(i-start_cnt)*sizeof(uint16),SEEK_SET);
1366 	    putshort(gpos,pos-start);
1367 	    fseek(gpos,pos,SEEK_SET);
1368 
1369 	    putshort(gpos,seconds[i][0].tot);
1370 	    for ( tot=0 ; tot<seconds[i][0].tot; ++tot ) {
1371 		putshort(gpos,seconds[i][tot].other_gid);
1372 		if ( (pst=seconds[i][tot].pst)!=NULL ) {
1373 		    if ( vf1&1 ) putshort(gpos,pst->u.pair.vr[0].xoff);
1374 		    if ( vf1&2 ) putshort(gpos,pst->u.pair.vr[0].yoff);
1375 		    if ( vf1&4 ) putshort(gpos,pst->u.pair.vr[0].h_adv_off);
1376 		    if ( vf1&8 ) putshort(gpos,pst->u.pair.vr[0].v_adv_off);
1377 		    next_dev_tab = gposdumpvaldevtab(gpos,pst->u.pair.vr[0].adjust,vf1,
1378 			    next_dev_tab);
1379 		    if ( vf2&1 ) putshort(gpos,pst->u.pair.vr[1].xoff);
1380 		    if ( vf2&2 ) putshort(gpos,pst->u.pair.vr[1].yoff);
1381 		    if ( vf2&4 ) putshort(gpos,pst->u.pair.vr[1].h_adv_off);
1382 		    if ( vf2&8 ) putshort(gpos,pst->u.pair.vr[1].v_adv_off);
1383 		    next_dev_tab = gposdumpvaldevtab(gpos,pst->u.pair.vr[1].adjust,vf2,
1384 			    next_dev_tab);
1385 		} else if ( (kp=seconds[i][tot].kp)!=NULL ) {
1386 		    int mask=0, mask2=0;
1387 		    if ( seconds[i][tot].isv )
1388 			mask = 0x8;
1389 		    else
1390 			mask = 0x4;
1391 		    gposvrmaskeddump(gpos,vf1,mask,kp->off);
1392 		    next_dev_tab = gposmaskeddumpdevtab(gpos,kp->adjust,vf1,mask<<4,
1393 			    next_dev_tab);
1394 		    gposvrmaskeddump(gpos,vf2,mask2,kp->off);
1395 		    next_dev_tab = gposmaskeddumpdevtab(gpos,kp->adjust,vf2,mask2<<4,
1396 			    next_dev_tab);
1397 		}
1398 	    }
1399 	}
1400 	end = ftell(gpos);
1401 	fseek(gpos,coverage_pos,SEEK_SET);
1402 	if ( end-start>65535 )
1403 	    IError(_("I miscalculated the size of subtable %s, this means the kerning output is wrong."), sub->subtable_name );
1404 	putshort(gpos,end-start);
1405 	fseek(gpos,end,SEEK_SET);
1406 	gtemp = glyphs[end_cnt]; glyphs[end_cnt] = NULL;
1407 	dumpcoveragetable(gpos,glyphs+start_cnt);
1408 	glyphs[end_cnt] = gtemp;
1409     }
1410     for ( i=0; i<cnt; ++i )
1411 	free(seconds[i]);
1412     free(seconds);
1413     free(glyphs);
1414 }
1415 
ClassesFromNames(SplineFont * sf,char ** classnames,int class_cnt,int numGlyphs,SplineChar *** glyphs,int apple_kc)1416 uint16 *ClassesFromNames(SplineFont *sf,char **classnames,int class_cnt,
1417 	int numGlyphs, SplineChar ***glyphs, int apple_kc) {
1418     uint16 *class;
1419     int i;
1420     char *pt, *end, ch;
1421     SplineChar *sc, **gs=NULL;
1422     int offset = (apple_kc && classnames[0]!=NULL);
1423 
1424     class = calloc(numGlyphs,sizeof(uint16));
1425     if ( glyphs ) *glyphs = gs = calloc(numGlyphs,sizeof(SplineChar *));
1426     for ( i=0; i<class_cnt; ++i ) {
1427 	if ( i==0 && classnames[0]==NULL )
1428     continue;
1429 	for ( pt = classnames[i]; *pt; pt = end+1 ) {
1430 	    while ( *pt==' ' ) ++pt;
1431 	    if ( *pt=='\0' )
1432 	break;
1433 	    end = strchr(pt,' ');
1434 	    if ( end==NULL )
1435 		end = pt+strlen(pt);
1436 	    ch = *end;
1437 	    *end = '\0';
1438 	    sc = SFGetChar(sf,-1,pt);
1439 	    if ( sc!=NULL && sc->ttf_glyph!=-1 ) {
1440 		class[sc->ttf_glyph] = i+offset;
1441 		if ( gs!=NULL )
1442 		    gs[sc->ttf_glyph] = sc;
1443 	    }
1444 	    *end = ch;
1445 	    if ( ch=='\0' )
1446 	break;
1447 	}
1448     }
1449 return( class );
1450 }
1451 
GlyphsFromClasses(SplineChar ** gs,int numGlyphs)1452 static SplineChar **GlyphsFromClasses(SplineChar **gs, int numGlyphs) {
1453     int i, cnt;
1454     SplineChar **glyphs;
1455 
1456     for ( i=cnt=0; i<numGlyphs; ++i )
1457 	if ( gs[i]!=NULL ) ++cnt;
1458     glyphs = malloc((cnt+1)*sizeof(SplineChar *));
1459     for ( i=cnt=0; i<numGlyphs; ++i )
1460 	if ( gs[i]!=NULL )
1461 	    glyphs[cnt++] = gs[i];
1462     glyphs[cnt++] = NULL;
1463     free(gs);
1464 return( glyphs );
1465 }
1466 
GlyphsFromInitialClasses(SplineChar ** gs,int numGlyphs,uint16 * classes,uint16 * initial)1467 static SplineChar **GlyphsFromInitialClasses(SplineChar **gs, int numGlyphs, uint16 *classes, uint16 *initial) {
1468     int i, j, cnt;
1469     SplineChar **glyphs;
1470 
1471     for ( i=cnt=0; i<numGlyphs; ++i ) {
1472 	for ( j=0; initial[j]!=0xffff; ++j )
1473 	    if ( initial[j]==classes[i])
1474 	break;
1475 	if ( initial[j]!=0xffff && gs[i]!=NULL ) ++cnt;
1476     }
1477     glyphs = malloc((cnt+1)*sizeof(SplineChar *));
1478     for ( i=cnt=0; i<numGlyphs; ++i ) {
1479 	for ( j=0; initial[j]!=0xffff; ++j )
1480 	    if ( initial[j]==classes[i])
1481 	break;
1482 	if ( initial[j]!=0xffff && gs[i]!=NULL )
1483 	    glyphs[cnt++] = gs[i];
1484     }
1485     glyphs[cnt++] = NULL;
1486 return( glyphs );
1487 }
1488 
DumpClass(FILE * gpos,uint16 * class,int numGlyphs)1489 static void DumpClass(FILE *gpos,uint16 *class,int numGlyphs) {
1490     int ranges, i, cur, first= -1, last=-1, istart;
1491 
1492     for ( i=ranges=0; i<numGlyphs; ) {
1493 	istart = i;
1494 	cur = class[i];
1495 	while ( i<numGlyphs && class[i]==cur )
1496 	    ++i;
1497 	if ( cur!=0 ) {
1498 	    ++ranges;
1499 	    if ( first==-1 ) first = istart;
1500 	    last = i-1;
1501 	}
1502     }
1503     if ( ranges*3+1>last-first+1+2 || first==-1 ) {
1504 	if ( first==-1 ) first = last = 0;
1505 	putshort(gpos,1);		/* Format 1, list of all posibilities */
1506 	putshort(gpos,first);
1507 	putshort(gpos,last-first+1);
1508 	for ( i=first; i<=last ; ++i )
1509 	    putshort(gpos,class[i]);
1510     } else {
1511 	putshort(gpos,2);		/* Format 2, series of ranges */
1512 	putshort(gpos,ranges);
1513 	for ( i=0; i<numGlyphs; ) {
1514 	    istart = i;
1515 	    cur = class[i];
1516 	    while ( i<numGlyphs && class[i]==cur )
1517 		++i;
1518 	    if ( cur!=0 ) {
1519 		putshort(gpos,istart);
1520 		putshort(gpos,i-1);
1521 		putshort(gpos,cur);
1522 	    }
1523 	}
1524     }
1525 }
1526 
dumpgposkernclass(FILE * gpos,SplineFont * sf,struct lookup_subtable * sub,struct alltabs * at)1527 static void dumpgposkernclass(FILE *gpos,SplineFont *sf,
1528 	struct lookup_subtable *sub, struct alltabs *at) {
1529     uint32 begin_off = ftell(gpos), pos;
1530     uint16 *class1, *class2;
1531     KernClass *kc = sub->kc, *test;
1532     SplineChar **glyphs;
1533     int i, isv;
1534     int anydevtab = false;
1535     int next_devtab;
1536 
1537     putshort(gpos,2);		/* format 2 of the pair adjustment subtable */
1538     putshort(gpos,0);		/* offset to coverage table */
1539     for ( i=0; i<kc->first_cnt*kc->second_cnt; ++i ) {
1540 	if ( kc->adjusts[i].corrections!=NULL ) {
1541 	    anydevtab = true;
1542     break;
1543 	}
1544     }
1545 
1546     for ( test=sf->vkerns; test!=NULL && test!=kc; test=test->next );
1547     isv = test==kc;
1548 
1549     if ( isv ) {
1550 	/* As far as I know there is no "bottom to top" writing direction */
1551 	/*  Oh. There is. Ogham, Runic */
1552 	putshort(gpos,anydevtab?0x0088:0x0008);	/* Alter YAdvance of first character */
1553 	putshort(gpos,0x0000);			/* leave second char alone */
1554     } else {
1555 	putshort(gpos,anydevtab?0x0044:0x0004);	/* Alter XAdvance of first character */
1556 	putshort(gpos,0x0000);			/* leave second char alone */
1557     }
1558     class1 = ClassesFromNames(sf,kc->firsts,kc->first_cnt,at->maxp.numGlyphs,&glyphs,false);
1559     glyphs = GlyphsFromClasses(glyphs,at->maxp.numGlyphs);
1560     class2 = ClassesFromNames(sf,kc->seconds,kc->second_cnt,at->maxp.numGlyphs,NULL,false);
1561     putshort(gpos,0);		/* offset to first glyph classes */
1562     putshort(gpos,0);		/* offset to second glyph classes */
1563     putshort(gpos,kc->first_cnt);
1564     putshort(gpos,kc->second_cnt);
1565     next_devtab = ftell(gpos)-begin_off + kc->first_cnt*kc->second_cnt*2*sizeof(uint16);
1566     for ( i=0; i<kc->first_cnt*kc->second_cnt; ++i ) {
1567 	putshort(gpos,kc->offsets[i]);
1568 	if ( anydevtab && kc->adjusts[i].corrections!=NULL ) {
1569 	    putshort(gpos,next_devtab);
1570 	    next_devtab += DevTabLen(&kc->adjusts[i]);
1571 	} else if ( anydevtab )
1572 	    putshort(gpos,0);
1573     }
1574     if ( anydevtab ) {
1575 	for ( i=0; i<kc->first_cnt*kc->second_cnt; ++i ) {
1576 	    if ( kc->adjusts[i].corrections!=NULL )
1577 		dumpgposdevicetable(gpos,&kc->adjusts[i]);
1578 	}
1579 	if ( next_devtab!=ftell(gpos)-begin_off )
1580 	    IError("Device table offsets screwed up in kerning class");
1581     }
1582     pos = ftell(gpos);
1583     fseek(gpos,begin_off+4*sizeof(uint16),SEEK_SET);
1584     putshort(gpos,pos-begin_off);
1585     fseek(gpos,pos,SEEK_SET);
1586     DumpClass(gpos,class1,at->maxp.numGlyphs);
1587 
1588     pos = ftell(gpos);
1589     fseek(gpos,begin_off+5*sizeof(uint16),SEEK_SET);
1590     putshort(gpos,pos-begin_off);
1591     fseek(gpos,pos,SEEK_SET);
1592     DumpClass(gpos,class2,at->maxp.numGlyphs);
1593 
1594     pos = ftell(gpos);
1595     fseek(gpos,begin_off+sizeof(uint16),SEEK_SET);
1596     putshort(gpos,pos-begin_off);
1597     fseek(gpos,pos,SEEK_SET);
1598     dumpcoveragetable(gpos,glyphs);
1599 
1600     free(glyphs);
1601     free(class1);
1602     free(class2);
1603 }
1604 
dumpanchor(FILE * gpos,AnchorPoint * ap,int is_ttf)1605 static void dumpanchor(FILE *gpos,AnchorPoint *ap, int is_ttf ) {
1606     int base = ftell(gpos);
1607 
1608     if ( ap->xadjust.corrections!=NULL || ap->yadjust.corrections!=NULL )
1609 	putshort(gpos,3);	/* format 3 w/ device tables */
1610     else
1611     if ( ap->has_ttf_pt && is_ttf )
1612 	putshort(gpos,2);	/* format 2 w/ a matching ttf point index */
1613     else
1614 	putshort(gpos,1);	/* Anchor format 1 just location*/
1615     putshort(gpos,ap->me.x);	/* X coord of attachment */
1616     putshort(gpos,ap->me.y);	/* Y coord of attachment */
1617     if ( ap->xadjust.corrections!=NULL || ap->yadjust.corrections!=NULL ) {
1618 	putshort(gpos,ap->xadjust.corrections==NULL?0:
1619 		ftell(gpos)-base+4);
1620 	putshort(gpos,ap->yadjust.corrections==NULL?0:
1621 		ftell(gpos)-base+2+DevTabLen(&ap->xadjust));
1622 	dumpgposdevicetable(gpos,&ap->xadjust);
1623 	dumpgposdevicetable(gpos,&ap->yadjust);
1624     } else
1625     if ( ap->has_ttf_pt && is_ttf )
1626 	putshort(gpos,ap->ttf_pt_index);
1627 }
1628 
dumpgposCursiveAttach(FILE * gpos,SplineFont * sf,struct lookup_subtable * sub,struct glyphinfo * gi)1629 static void dumpgposCursiveAttach(FILE *gpos, SplineFont *sf,
1630 	struct lookup_subtable *sub,struct glyphinfo *gi) {
1631     AnchorClass *ac, *testac;
1632     SplineChar **entryexit;
1633     int cnt, offset,j;
1634     AnchorPoint *ap, *entry, *exit;
1635     uint32 coverage_offset, start;
1636 
1637     ac = NULL;
1638     for ( testac=sf->anchor; testac!=NULL; testac = testac->next ) {
1639 	if ( testac->subtable == sub ) {
1640 	    if ( ac==NULL )
1641 		ac = testac;
1642 	    else {
1643 		ff_post_error(_("Two cursive anchor classes"),_("Two cursive anchor classes in the same subtable, %s"),
1644 			sub->subtable_name);
1645     break;
1646 	    }
1647 	}
1648     }
1649     if ( ac==NULL ) {
1650 	IError( "Missing anchor class for %s", sub->subtable_name );
1651 return;
1652     }
1653     entryexit = EntryExitDecompose(sf,ac,gi);
1654     if ( entryexit==NULL )
1655 return;
1656 
1657     for ( cnt=0; entryexit[cnt]!=NULL; ++cnt );
1658 
1659     start = ftell(gpos);
1660     putshort(gpos,1);	/* format 1 for this subtable */
1661     putshort(gpos,0);	/* Fill in later, offset to coverage table */
1662     putshort(gpos,cnt);	/* number of glyphs */
1663 
1664     offset = 6+2*2*cnt;
1665     for ( j=0; j<cnt; ++j ) {
1666 	entry = exit = NULL;
1667 	for ( ap=entryexit[j]->anchor; ap!=NULL; ap=ap->next ) {
1668 	    if ( ap->anchor==ac && ap->type==at_centry ) entry = ap;
1669 	    if ( ap->anchor==ac && ap->type==at_cexit ) exit = ap;
1670 	}
1671 	if ( entry!=NULL ) {
1672 	    putshort(gpos,offset);
1673 	    offset += 6;
1674 	    if ( entry->xadjust.corrections!=NULL || entry->yadjust.corrections!=NULL )
1675 		offset += 4 + DevTabLen(&entry->xadjust) + DevTabLen(&entry->yadjust);
1676 	    if ( gi->is_ttf && entry->has_ttf_pt )
1677 		offset += 2;
1678 	} else
1679 	    putshort(gpos,0);
1680 	if ( exit!=NULL ) {
1681 	    putshort(gpos,offset);
1682 	    offset += 6;
1683 	    if ( exit->xadjust.corrections!=NULL || exit->yadjust.corrections!=NULL )
1684 		offset += 4 + DevTabLen(&exit->xadjust) + DevTabLen(&exit->yadjust);
1685 	    else
1686 	    if ( gi->is_ttf && exit->has_ttf_pt )
1687 		offset += 2;
1688 	} else
1689 	    putshort(gpos,0);
1690     }
1691     for ( j=0; j<cnt; ++j ) {
1692 	entry = exit = NULL;
1693 	for ( ap=entryexit[j]->anchor; ap!=NULL; ap=ap->next ) {
1694 	    if ( ap->anchor==ac && ap->type==at_centry ) entry = ap;
1695 	    if ( ap->anchor==ac && ap->type==at_cexit ) exit = ap;
1696 	}
1697 	if ( entry!=NULL )
1698 	    dumpanchor(gpos,entry,gi->is_ttf);
1699 	if ( exit!=NULL )
1700 	    dumpanchor(gpos,exit,gi->is_ttf);
1701     }
1702     coverage_offset = ftell(gpos);
1703     dumpcoveragetable(gpos,entryexit);
1704     fseek(gpos,start+2,SEEK_SET);
1705     putshort(gpos,coverage_offset-start);
1706     fseek(gpos,0,SEEK_END);
1707 
1708     free(entryexit);
1709 }
1710 
orderglyph(const void * _sc1,const void * _sc2)1711 static int orderglyph(const void *_sc1,const void *_sc2) {
1712     SplineChar * const *sc1 = _sc1, * const *sc2 = _sc2;
1713 
1714 return( (*sc1)->ttf_glyph - (*sc2)->ttf_glyph );
1715 }
1716 
allmarkglyphs(SplineChar *** glyphlist,int classcnt)1717 static SplineChar **allmarkglyphs(SplineChar ***glyphlist, int classcnt) {
1718     SplineChar **glyphs;
1719     int i, tot, k;
1720 
1721     if ( classcnt==1 )
1722 return( SFOrderedGlyphs(glyphlist[0]));
1723 
1724     for ( i=tot=0; i<classcnt; ++i ) {
1725 	for ( k=0; glyphlist[i][k]!=NULL; ++k );
1726 	tot += k;
1727     }
1728     glyphs = malloc((tot+1)*sizeof(SplineChar *));
1729     for ( i=tot=0; i<classcnt; ++i ) {
1730 	for ( k=0; glyphlist[i][k]!=NULL; ++k )
1731 	    glyphs[tot++] = glyphlist[i][k];
1732     }
1733     qsort(glyphs,tot,sizeof(SplineChar *),orderglyph);
1734     for ( i=k=0; i<tot; ++i ) {
1735 	while ( i+1<tot && glyphs[i]==glyphs[i+1]) ++i;
1736 	glyphs[k++] = glyphs[i];
1737     }
1738     glyphs[k] = NULL;
1739 return( glyphs );
1740 }
1741 
dumpgposAnchorData(FILE * gpos,AnchorClass * _ac,enum anchor_type at,SplineChar *** marks,SplineChar ** base,int classcnt,struct glyphinfo * gi)1742 static void dumpgposAnchorData(FILE *gpos,AnchorClass *_ac,
1743 	enum anchor_type at,
1744 	SplineChar ***marks,SplineChar **base,
1745 	int classcnt, struct glyphinfo *gi) {
1746     AnchorClass *ac=NULL;
1747     int j,cnt,k,l, pos, offset, tot, max;
1748     uint32 coverage_offset, markarray_offset, subtable_start;
1749     AnchorPoint *ap, **aps;
1750     SplineChar **markglyphs;
1751 
1752     for ( cnt=0; base[cnt]!=NULL; ++cnt );
1753 
1754     subtable_start = ftell(gpos);
1755     putshort(gpos,1);	/* format 1 for this subtable */
1756     putshort(gpos,0);	/* Fill in later, offset to mark coverage table */
1757     putshort(gpos,0);	/* Fill in later, offset to base coverage table */
1758     putshort(gpos,classcnt);
1759     putshort(gpos,0);	/* Fill in later, offset to mark array */
1760     putshort(gpos,12);	/* Offset to base array */
1761 	/* Base array */
1762     putshort(gpos,cnt);	/* Number of entries in array */
1763     if ( at==at_basechar || at==at_basemark ) {
1764 	offset = 2;
1765 	for ( l=0; l<3; ++l ) {
1766 	    for ( j=0; j<cnt; ++j ) {
1767 		for ( k=0, ac=_ac; k<classcnt; ac=ac->next ) if ( ac->matches ) {
1768 		    if ( !ac->has_mark || !ac->has_base )
1769 		continue;
1770 		    for ( ap=base[j]->anchor; ap!=NULL && (ap->anchor!=ac || ap->type!=at);
1771 			    ap=ap->next );
1772 		    switch ( l ) {
1773 		      case 0:
1774 			offset += 2;
1775 		      break;
1776 		      case 1:
1777 			if ( ap==NULL )
1778 			    putshort(gpos,0);
1779 			else {
1780 			    putshort(gpos,offset);
1781 			    offset += 6;
1782 			    if ( ap->xadjust.corrections!=NULL || ap->yadjust.corrections!=NULL )
1783 				offset += 4 + DevTabLen(&ap->xadjust) + DevTabLen(&ap->yadjust);
1784 			    else
1785 			    if ( gi->is_ttf && ap->has_ttf_pt )
1786 				offset += 2;
1787 			}
1788 		      break;
1789 		      case 2:
1790 			if ( ap!=NULL )
1791 			    dumpanchor(gpos,ap,gi->is_ttf);
1792 		      break;
1793 		    }
1794 		    ++k;
1795 		}
1796 	    }
1797 	}
1798     } else {
1799 	offset = 2+2*cnt;
1800 	max = 0;
1801 	for ( j=0; j<cnt; ++j ) {
1802 	    putshort(gpos,offset);
1803 	    pos = tot = 0;
1804 	    for ( ap=base[j]->anchor; ap!=NULL ; ap=ap->next )
1805 		for ( k=0, ac=_ac; k<classcnt; ac=ac->next ) if ( ac->matches ) {
1806 		    if ( ap->anchor==ac ) {
1807 			if ( ap->lig_index>pos ) pos = ap->lig_index;
1808 			++tot;
1809 		    }
1810 		    ++k;
1811 		}
1812 	    if ( pos>max ) max = pos;
1813 	    offset += 2+(pos+1)*classcnt*2+tot*6;
1814 		/* 2 for component count, for each component an offset to an offset to an anchor record */
1815 	}
1816 	++max;
1817         int special_ceiling = classcnt*max;
1818 	aps = malloc((classcnt*max+max)*sizeof(AnchorPoint *));
1819 	for ( j=0; j<cnt; ++j ) {
1820 	    memset(aps,0,(classcnt*max+max)*sizeof(AnchorPoint *));
1821 	    pos = 0;
1822 	    for ( ap=base[j]->anchor; ap!=NULL ; ap=ap->next )
1823 		for ( k=0, ac=_ac; k<classcnt; ac=ac->next ) if ( ac->matches ) {
1824 		    if ( ap->anchor==ac ) {
1825 			if ( ap->lig_index>pos ) pos = ap->lig_index;
1826 			if (k*max+ap->lig_index > special_ceiling || k*max+ap->lig_index < 0) {
1827 				fprintf(stderr, "A ligature index is invalid.\n");
1828 			} else {
1829 				aps[k*max+ap->lig_index] = ap;
1830 			}
1831 		    }
1832 		    ++k;
1833 		}
1834 	    ++pos;
1835 	    putshort(gpos,pos);
1836 	    offset = 2+2*pos*classcnt;
1837 	    for ( l=0; l<pos; ++l ) {
1838 		for ( k=0; k<classcnt; ++k ) {
1839 		    if ( aps[k*max+l]==NULL )
1840 			putshort(gpos,0);
1841 		    else {
1842 			putshort(gpos,offset);
1843 			offset += 6;
1844 			if ( aps[k*max+l]->xadjust.corrections!=NULL || aps[k*max+l]->yadjust.corrections!=NULL )
1845 			    offset += 4 + DevTabLen(&aps[k*max+l]->xadjust) +
1846 					DevTabLen(&aps[k*max+l]->yadjust);
1847 			else
1848 			if ( gi->is_ttf && aps[k*max+l]->has_ttf_pt )
1849 			    offset += 2;
1850 		    }
1851 		}
1852 	    }
1853 	    for ( l=0; l<pos; ++l ) {
1854 		for ( k=0; k<classcnt; ++k ) {
1855 		    if ( aps[k*max+l]!=NULL ) {
1856 			dumpanchor(gpos,aps[k*max+l],gi->is_ttf);
1857 		    }
1858 		}
1859 	    }
1860 	}
1861 	free(aps); aps = NULL;
1862     }
1863     coverage_offset = ftell(gpos);
1864     fseek(gpos,subtable_start+4,SEEK_SET);
1865     putshort(gpos,coverage_offset-subtable_start);
1866     fseek(gpos,0,SEEK_END);
1867     dumpcoveragetable(gpos,base);
1868 
1869     /* We tried sharing the mark table, (among all these sub-tables) but */
1870     /*  that doesn't work because we need to be able to reorder the sub-tables */
1871     markglyphs = allmarkglyphs(marks,classcnt);
1872     coverage_offset = ftell(gpos);
1873     dumpcoveragetable(gpos,markglyphs);
1874     markarray_offset = ftell(gpos);
1875     for ( cnt=0; markglyphs[cnt]!=NULL; ++cnt );
1876     putshort(gpos,cnt);
1877     offset = 2+4*cnt;
1878     for ( j=0; j<cnt; ++j ) {
1879 	if ( classcnt==0 ) {
1880 	    putshort(gpos,0);		/* Only one class */
1881 	    ap = NULL;
1882 	} else {
1883 	    for ( k=0, ac=_ac; k<classcnt; ac=ac->next ) {
1884 		if ( ac->matches ) {
1885 		    for ( ap = markglyphs[j]->anchor; ap!=NULL && (ap->anchor!=ac || ap->type!=at_mark);
1886 			    ap=ap->next );
1887 		    if ( ap!=NULL )
1888 	    break;
1889 		    ++k;
1890 		}
1891 	    }
1892 	    putshort(gpos,k);
1893 	}
1894 	putshort(gpos,offset);
1895 	offset += 6;
1896 	if ( ap!=NULL && (ap->xadjust.corrections!=NULL || ap->yadjust.corrections!=NULL ))
1897 	    offset += 4 + DevTabLen(&ap->xadjust) + DevTabLen(&ap->yadjust);
1898 	else
1899 	if ( gi->is_ttf && ap->has_ttf_pt )
1900 	    offset += 2;
1901     }
1902     for ( j=0; j<cnt; ++j ) {
1903 	for ( k=0, ac=_ac; k<classcnt; ac=ac->next ) {
1904 	    if ( ac->matches ) {
1905 		for ( ap = markglyphs[j]->anchor; ap!=NULL && (ap->anchor!=ac || ap->type!=at_mark);
1906 			ap=ap->next );
1907 		if ( ap!=NULL )
1908 	break;
1909 		++k;
1910 	    }
1911 	}
1912 	dumpanchor(gpos,ap,gi->is_ttf);
1913     }
1914     if ( markglyphs!=marks[0] )
1915 	free(markglyphs);
1916 
1917     fseek(gpos,subtable_start+2,SEEK_SET);	/* mark coverage table offset */
1918     putshort(gpos,coverage_offset-subtable_start);
1919     fseek(gpos,4,SEEK_CUR);
1920     putshort(gpos,markarray_offset-subtable_start);
1921 
1922     fseek(gpos,0,SEEK_END);
1923 }
1924 
dumpGSUBsimplesubs(FILE * gsub,SplineFont * sf,struct lookup_subtable * sub)1925 static void dumpGSUBsimplesubs(FILE *gsub,SplineFont *sf,struct lookup_subtable *sub) {
1926     int cnt, diff, ok = true;
1927     int32 coverage_pos, end;
1928     SplineChar **glyphs, ***maps;
1929 
1930     glyphs = SFOrderedGlyphsWithPSTinSubtable(sf,sub);
1931     maps = generateMapList(glyphs,sub);
1932 
1933     diff = (*maps[0])->ttf_glyph - glyphs[0]->ttf_glyph;
1934     for ( cnt=0; glyphs[cnt]!=NULL; ++cnt)
1935 	if ( diff!= maps[cnt][0]->ttf_glyph-glyphs[cnt]->ttf_glyph ) ok = false;
1936 
1937     if ( ok ) {
1938 	putshort(gsub,1);	/* delta format */
1939 	coverage_pos = ftell(gsub);
1940 	putshort(gsub,0);		/* offset to coverage table */
1941 	putshort(gsub,diff);
1942     } else {
1943 	putshort(gsub,2);		/* glyph list format */
1944 	coverage_pos = ftell(gsub);
1945 	putshort(gsub,0);		/* offset to coverage table */
1946 	putshort(gsub,cnt);
1947 	for ( cnt = 0; glyphs[cnt]!=NULL; ++cnt )
1948 	    putshort(gsub,(*maps[cnt])->ttf_glyph);
1949     }
1950     end = ftell(gsub);
1951     fseek(gsub,coverage_pos,SEEK_SET);
1952     putshort(gsub,end-coverage_pos+2);
1953     fseek(gsub,end,SEEK_SET);
1954     dumpcoveragetable(gsub,glyphs);
1955 
1956     free(glyphs);
1957     GlyphMapFree(maps);
1958 }
1959 
dumpGSUBmultiplesubs(FILE * gsub,SplineFont * sf,struct lookup_subtable * sub)1960 static void dumpGSUBmultiplesubs(FILE *gsub,SplineFont *sf,struct lookup_subtable *sub) {
1961     int cnt, offset;
1962     int32 coverage_pos, end;
1963     int gc;
1964     SplineChar **glyphs, ***maps;
1965 
1966     glyphs = SFOrderedGlyphsWithPSTinSubtable(sf,sub);
1967     maps = generateMapList(glyphs,sub);
1968     for ( cnt=0; glyphs[cnt]!=NULL; ++cnt);
1969 
1970     putshort(gsub,1);		/* glyph list format */
1971     coverage_pos = ftell(gsub);
1972     putshort(gsub,0);		/* offset to coverage table */
1973     putshort(gsub,cnt);
1974     offset = 6+2*cnt;
1975     for ( cnt = 0; glyphs[cnt]!=NULL; ++cnt ) {
1976 	putshort(gsub,offset);
1977 	if (maps[cnt] == NULL) {
1978 		fprintf( stderr, "maps[%d] is null; glyphs[%d] is \"%s\"; lookup name is \"%s\".\n" , cnt , cnt , (glyphs[cnt]->name ? glyphs[cnt]->name : ""), sub->subtable_name) ;
1979             gc = 0;
1980 	} else {
1981     	    for ( gc=0; maps[cnt][gc]!=NULL; ++gc );
1982         }
1983 	offset += 2+2*gc;
1984     }
1985     for ( cnt = 0; glyphs[cnt]!=NULL; ++cnt ) {
1986         if (maps[cnt] == NULL) {
1987             break;
1988         }
1989 	for ( gc=0; maps[cnt][gc]!=NULL; ++gc );
1990 	putshort(gsub,gc);
1991 	for ( gc=0; maps[cnt][gc]!=NULL; ++gc )
1992 	    putshort(gsub,maps[cnt][gc]->ttf_glyph);
1993     }
1994     end = ftell(gsub);
1995     fseek(gsub,coverage_pos,SEEK_SET);
1996     putshort(gsub,end-coverage_pos+2);
1997     fseek(gsub,end,SEEK_SET);
1998     dumpcoveragetable(gsub,glyphs);
1999 
2000     free(glyphs);
2001     GlyphMapFree(maps);
2002 }
2003 
AllToBeOutput(LigList * lig)2004 static int AllToBeOutput(LigList *lig) {
2005     struct splinecharlist *cmp;
2006 
2007     if ( lig->lig->u.lig.lig->ttf_glyph==-1 ||
2008 	    lig->first->ttf_glyph==-1 )
2009 return( 0 );
2010     for ( cmp=lig->components; cmp!=NULL; cmp=cmp->next )
2011 	if ( cmp->sc->ttf_glyph==-1 )
2012 return( 0 );
2013 return( true );
2014 }
2015 
dumpGSUBligdata(FILE * gsub,SplineFont * sf,struct lookup_subtable * sub,struct alltabs * at)2016 static void dumpGSUBligdata(FILE *gsub,SplineFont *sf,
2017 	struct lookup_subtable *sub, struct alltabs *at) {
2018     int32 coverage_pos, next_val_pos, here, lig_list_start;
2019     int cnt, i, pcnt, lcnt, max=100, j;
2020     uint16 *offsets=NULL, *ligoffsets=malloc(max*sizeof(uint16));
2021     SplineChar **glyphs;
2022     LigList *ll;
2023     struct splinecharlist *scl;
2024 
2025     glyphs = SFOrderedGlyphsWithPSTinSubtable(sf,sub);
2026     cnt=0;
2027     if ( glyphs!=NULL ) for ( ; glyphs[cnt]!=NULL; ++cnt );
2028 
2029     putshort(gsub,1);		/* only one format for ligatures */
2030     coverage_pos = ftell(gsub);
2031     putshort(gsub,0);		/* offset to coverage table */
2032     putshort(gsub,cnt);
2033     next_val_pos = ftell(gsub);
2034     if ( glyphs!=NULL )
2035 	offsets = malloc(cnt*sizeof(uint16));
2036     for ( i=0; i<cnt; ++i )
2037 	putshort(gsub,0);
2038     for ( i=0; i<cnt; ++i ) {
2039 	offsets[i] = ftell(gsub)-coverage_pos+2;
2040 	for ( pcnt = 0, ll = glyphs[i]->ligofme; ll!=NULL; ll=ll->next )
2041 	    if ( ll->lig->subtable==sub && AllToBeOutput(ll))
2042 		++pcnt;
2043 	putshort(gsub,pcnt);
2044 	if ( pcnt>=max ) {
2045 	    max = pcnt+100;
2046 	    ligoffsets = realloc(ligoffsets,max*sizeof(int));
2047 	}
2048 	lig_list_start = ftell(gsub);
2049 	for ( j=0; j<pcnt; ++j )
2050 	    putshort(gsub,0);			/* Place holders */
2051 	for ( pcnt=0, ll = glyphs[i]->ligofme; ll!=NULL; ll=ll->next ) {
2052 	    if ( ll->lig->subtable==sub && AllToBeOutput(ll)) {
2053 		ligoffsets[pcnt] = ftell(gsub)-lig_list_start+2;
2054 		putshort(gsub,ll->lig->u.lig.lig->ttf_glyph);
2055 		for ( lcnt=0, scl=ll->components; scl!=NULL; scl=scl->next ) ++lcnt;
2056 		putshort(gsub, lcnt+1);
2057 		if ( lcnt+1>at->os2.maxContext )
2058 		    at->os2.maxContext = lcnt+1;
2059 		for ( scl=ll->components; scl!=NULL; scl=scl->next )
2060 		    putshort(gsub, scl->sc->ttf_glyph );
2061 		++pcnt;
2062 	    }
2063 	}
2064 	fseek(gsub,lig_list_start,SEEK_SET);
2065 	for ( j=0; j<pcnt; ++j )
2066 	    putshort(gsub,ligoffsets[j]);
2067 	fseek(gsub,0,SEEK_END);
2068     }
2069     free(ligoffsets);
2070     if ( glyphs!=NULL ) {
2071 	here = ftell(gsub);
2072 	fseek(gsub,coverage_pos,SEEK_SET);
2073 	putshort(gsub,here-coverage_pos+2);
2074 	fseek(gsub,next_val_pos,SEEK_SET);
2075 	for ( i=0; i<cnt; ++i )
2076 	    putshort(gsub,offsets[i]);
2077 	fseek(gsub,here,SEEK_SET);
2078 	dumpcoveragetable(gsub,glyphs);
2079 	free(glyphs);
2080 	free(offsets);
2081     }
2082 }
2083 
ui16cmp(const void * _i1,const void * _i2)2084 static int ui16cmp(const void *_i1, const void *_i2) {
2085     if ( *(const uint16 *) _i1 > *(const uint16 *) _i2 )
2086 return( 1 );
2087     if ( *(const uint16 *) _i1 < *(const uint16 *) _i2 )
2088 return( -1 );
2089 
2090 return( 0 );
2091 }
2092 
FigureInitialClasses(FPST * fpst)2093 static uint16 *FigureInitialClasses(FPST *fpst) {
2094     uint16 *initial = malloc((fpst->nccnt+1)*sizeof(uint16));
2095     int i, cnt, j;
2096 
2097     initial[fpst->nccnt] = 0xffff;
2098     for ( i=cnt=0; i<fpst->rule_cnt; ++i ) {
2099 	for ( j=0; j<cnt ; ++j )
2100 	    if ( initial[j] == fpst->rules[i].u.class.nclasses[0] )
2101 	break;
2102 	if ( j==cnt )
2103 	    initial[cnt++] = fpst->rules[i].u.class.nclasses[0];
2104     }
2105     qsort(initial,cnt,sizeof(uint16),ui16cmp);
2106     initial[cnt] = 0xffff;
2107 return( initial );
2108 }
2109 
OrderedInitialGlyphs(SplineFont * sf,FPST * fpst)2110 static SplineChar **OrderedInitialGlyphs(SplineFont *sf,FPST *fpst) {
2111     SplineChar **glyphs, *sc;
2112     int i, j, cnt, ch;
2113     char *pt, *names;
2114 
2115     glyphs = malloc((fpst->rule_cnt+1)*sizeof(SplineChar *));
2116     for ( i=cnt=0; i<fpst->rule_cnt; ++i ) {
2117 	names = fpst->rules[i].u.glyph.names;
2118 	pt = strchr(names,' ');
2119 	if ( pt==NULL ) pt = names+strlen(names);
2120 	// Temporarily terminate the desired token.
2121 	ch = *pt; *pt = '\0';
2122 	sc = SFGetChar(sf,-1,names);
2123 	*pt = ch;
2124 	// Check for duplicates.
2125 	for ( j=0; j<cnt; ++j )
2126 	    if ( glyphs[j]==sc )
2127 	break;
2128 	// If there are no duplicates and sc is non-null, add it to the output collection.
2129 	if ( j==cnt && sc!=NULL )
2130 	    glyphs[cnt++] = sc;
2131     }
2132 		// Null-terminate the output collection.
2133     glyphs[cnt] = NULL;
2134     if ( cnt==0 )
2135 return( glyphs );
2136 
2137     // Sort the results.
2138     for ( i=0; glyphs[i] != NULL && glyphs[i+1]!=NULL; ++i ) for ( j=i+1; glyphs[j]!=NULL; ++j ) {
2139 	if ( glyphs[i]->ttf_glyph > glyphs[j]->ttf_glyph ) {
2140 	    sc = glyphs[i];
2141 	    glyphs[i] = glyphs[j];
2142 	    glyphs[j] = sc;
2143 	}
2144     }
2145 return( glyphs );
2146 }
2147 
OrderedInitialTTFGlyphs(SplineFont * sf,FPST * fpst)2148 static SplineChar **OrderedInitialTTFGlyphs(SplineFont *sf, FPST *fpst) {
2149 	SplineChar **glyphs = OrderedInitialGlyphs(sf, fpst);
2150 	int vcount = 0;
2151 	int i = 0;
2152 	for (i = 0; i < fpst->rule_cnt && glyphs[i] != NULL; i++) {
2153 		if (glyphs[i]->ttf_glyph >= 0) vcount ++;
2154 	}
2155 	// fprintf(stderr, "Killing %d of %d glyphs.\n", i - vcount, i);
2156 	SplineChar **vglyphs = malloc((vcount+1)*sizeof(SplineChar *));
2157 	int j = 0;
2158 	for (i = 0; i < fpst->rule_cnt && glyphs[i] != NULL; i++) {
2159 		if (glyphs[i]->ttf_glyph >= 0) vglyphs[j++] = glyphs[i];
2160 	}
2161 	vglyphs[j] = NULL;
2162 	free(glyphs);
2163 	return vglyphs;
2164 }
2165 
NamesStartWith(SplineChar * sc,char * names)2166 static int NamesStartWith(SplineChar *sc,char *names ) {
2167     char *pt;
2168 
2169     pt = strchr(names,' ');
2170     if ( pt==NULL ) pt = names+strlen(names);
2171     if ( pt-names!=strlen(sc->name))
2172 return( false );
2173 
2174 return( strncmp(sc->name,names,pt-names)==0 );
2175 }
2176 
CntRulesStartingWith(FPST * fpst,SplineChar * sc)2177 static int CntRulesStartingWith(FPST *fpst,SplineChar *sc) {
2178     int i, cnt;
2179 
2180     for ( i=cnt=0; i<fpst->rule_cnt; ++i ) {
2181 	if ( NamesStartWith(sc,fpst->rules[i].u.glyph.names))
2182 	    ++cnt;
2183     }
2184 return( cnt );
2185 }
2186 
CntRulesStartingWithClass(FPST * fpst,uint16 cval)2187 static int CntRulesStartingWithClass(FPST *fpst,uint16 cval) {
2188     int i, cnt;
2189 
2190     for ( i=cnt=0; i<fpst->rule_cnt; ++i ) {
2191 	if ( fpst->rules[i].u.class.nclasses[0]==cval )
2192 	    ++cnt;
2193     }
2194 return( cnt );
2195 }
2196 
dumpg___ContextChainGlyphs(FILE * lfile,SplineFont * sf,struct lookup_subtable * sub,struct alltabs * at)2197 static void dumpg___ContextChainGlyphs(FILE *lfile,SplineFont *sf,
2198 	struct lookup_subtable *sub, struct alltabs *at) {
2199     FPST *fpst = sub->fpst;
2200     int iscontext = fpst->type==pst_contextpos || fpst->type==pst_contextsub;
2201     uint32 base = ftell(lfile);
2202     int i,cnt, subcnt, j,k,l, maxcontext,curcontext;
2203     SplineChar **glyphs, **subglyphs;
2204     int lc;
2205 
2206     glyphs = OrderedInitialTTFGlyphs(sf,fpst);
2207     for ( cnt=0; glyphs[cnt]!=NULL; ++cnt );
2208 
2209     putshort(lfile,1);		/* Sub format 1 => glyph lists */
2210     putshort(lfile,(3+cnt)*sizeof(short));	/* offset to coverage */
2211     putshort(lfile,cnt);
2212     for ( i=0; i<cnt; ++i )
2213 	putshort(lfile,0);	/* Offset to rule */
2214     dumpcoveragetable(lfile,glyphs);
2215 
2216     maxcontext = 0;
2217 
2218     for ( i=0; i<cnt; ++i ) {
2219 	uint32 pos = ftell(lfile);
2220 	fseek(lfile,base+(3+i)*sizeof(short),SEEK_SET);
2221 	putshort(lfile,pos-base);
2222 	fseek(lfile,pos,SEEK_SET);
2223 	subcnt = CntRulesStartingWith(fpst,glyphs[i]);
2224 	putshort(lfile,subcnt);
2225 	for ( j=0; j<subcnt; ++j )
2226 	    putshort(lfile,0);
2227 	for ( j=k=0; k<fpst->rule_cnt; ++k ) if ( NamesStartWith(glyphs[i],fpst->rules[k].u.glyph.names )) {
2228 	    uint32 subpos = ftell(lfile);
2229 	    fseek(lfile,pos+(1+j)*sizeof(short),SEEK_SET);
2230 	    putshort(lfile,subpos-pos);
2231 	    fseek(lfile,subpos,SEEK_SET);
2232 
2233 	    for ( l=lc=0; l<fpst->rules[k].lookup_cnt; ++l )
2234 		if ( fpst->rules[k].lookups[l].lookup->lookup_index!=-1 )
2235 		    ++lc;
2236 	    if ( iscontext ) {
2237 		subglyphs = TTFGlyphsFromNames(sf,fpst->rules[k].u.glyph.names);
2238 		for ( l=0; subglyphs[l]!=NULL; ++l );
2239 		putshort(lfile,l);
2240 		curcontext = l;
2241 		putshort(lfile,lc);
2242 		if (subglyphs[0] != NULL)
2243 		for ( l=1; subglyphs[l]!=NULL; ++l )
2244 		    putshort(lfile,subglyphs[l]->ttf_glyph);
2245 		free(subglyphs);
2246 	    } else {
2247 		subglyphs = TTFGlyphsFromNames(sf,fpst->rules[k].u.glyph.back);
2248 		for ( l=0; subglyphs[l]!=NULL; ++l );
2249 		putshort(lfile,l);
2250 		curcontext = l;
2251 		for ( l=0; subglyphs[l]!=NULL; ++l )
2252 		    putshort(lfile,subglyphs[l]->ttf_glyph);
2253 		free(subglyphs);
2254 		subglyphs = TTFGlyphsFromNames(sf,fpst->rules[k].u.glyph.names);
2255 		for ( l=0; subglyphs[l]!=NULL; ++l );
2256 		putshort(lfile,l);
2257 		curcontext += l;
2258 		if (subglyphs[0] != NULL)
2259 		for ( l=1; subglyphs[l]!=NULL; ++l )
2260 		    putshort(lfile,subglyphs[l]->ttf_glyph);
2261 		free(subglyphs);
2262 		subglyphs = TTFGlyphsFromNames(sf,fpst->rules[k].u.glyph.fore);
2263 		for ( l=0; subglyphs[l]!=NULL; ++l );
2264 		putshort(lfile,l);
2265 		curcontext += l;
2266 		for ( l=0; subglyphs[l]!=NULL; ++l )
2267 		    putshort(lfile,subglyphs[l]->ttf_glyph);
2268 		free(subglyphs);
2269 		putshort(lfile,lc);
2270 	    }
2271 	    for ( l=0; l<fpst->rules[k].lookup_cnt; ++l )
2272 		if ( fpst->rules[k].lookups[l].lookup->lookup_index!=-1 ) {
2273 		    putshort(lfile,fpst->rules[k].lookups[l].seq);
2274 		    putshort(lfile,fpst->rules[k].lookups[l].lookup->lookup_index);
2275 		}
2276 	    ++j;
2277 	    if ( curcontext>maxcontext ) maxcontext = curcontext;
2278 	}
2279     }
2280     free(glyphs);
2281 
2282     if ( maxcontext>at->os2.maxContext )
2283 	at->os2.maxContext = maxcontext;
2284 }
2285 
dumpg___ContextChainClass(FILE * lfile,SplineFont * sf,struct lookup_subtable * sub,struct alltabs * at)2286 static void dumpg___ContextChainClass(FILE *lfile,SplineFont *sf,
2287 	struct lookup_subtable *sub, struct alltabs *at) {
2288     FPST *fpst = sub->fpst;
2289     int iscontext = fpst->type==pst_contextpos || fpst->type==pst_contextsub;
2290     uint32 base = ftell(lfile), rulebase, pos, subpos, npos;
2291     uint16 *initialclasses, *iclass, *bclass, *lclass;
2292     SplineChar **iglyphs, **bglyphs, **lglyphs, **glyphs;
2293     int i,ii,cnt, subcnt, j,k,l , maxcontext,curcontext;
2294     int lc;
2295 
2296     putshort(lfile,2);		/* Sub format 2 => class */
2297     putshort(lfile,0);		/* offset to coverage table */
2298     if ( iscontext )
2299 	putshort(lfile,0);	/* offset to input classdef */
2300     else {
2301 	putshort(lfile,0);	/* offset to backtrack classdef */
2302 	putshort(lfile,0);	/* offset to input classdef */
2303 	putshort(lfile,0);	/* offset to lookahead classdef */
2304     }
2305     initialclasses = FigureInitialClasses(fpst);
2306     putshort(lfile,fpst->nccnt);
2307     rulebase = ftell(lfile);
2308     for ( cnt=0; cnt<fpst->nccnt; ++cnt )
2309 	putshort(lfile,0);
2310 
2311     iclass = ClassesFromNames(sf,fpst->nclass,fpst->nccnt,at->maxp.numGlyphs,&iglyphs,false);
2312     lglyphs = bglyphs = NULL; bclass = lclass = NULL;
2313     if ( !iscontext ) {
2314 	bclass = ClassesFromNames(sf,fpst->bclass,fpst->bccnt,at->maxp.numGlyphs,&bglyphs,false);
2315 	lclass = ClassesFromNames(sf,fpst->fclass,fpst->fccnt,at->maxp.numGlyphs,&lglyphs,false);
2316     }
2317     pos = ftell(lfile);
2318     fseek(lfile,base+sizeof(uint16),SEEK_SET);
2319     putshort(lfile,pos-base);
2320     fseek(lfile,pos,SEEK_SET);
2321     glyphs = GlyphsFromInitialClasses(iglyphs,at->maxp.numGlyphs,iclass,initialclasses);
2322     dumpcoveragetable(lfile,glyphs);
2323     free(glyphs);
2324     free(iglyphs); free(bglyphs); free(lglyphs);
2325 
2326     if ( iscontext ) {
2327 	pos = ftell(lfile);
2328 	fseek(lfile,base+2*sizeof(uint16),SEEK_SET);
2329 	putshort(lfile,pos-base);
2330 	fseek(lfile,pos,SEEK_SET);
2331 	DumpClass(lfile,iclass,at->maxp.numGlyphs);
2332 	free(iclass);
2333     } else {
2334 	pos = ftell(lfile);
2335 	fseek(lfile,base+2*sizeof(uint16),SEEK_SET);
2336 	putshort(lfile,pos-base);
2337 	fseek(lfile,pos,SEEK_SET);
2338 	DumpClass(lfile,bclass,at->maxp.numGlyphs);
2339 	if ( ClassesMatch(fpst->bccnt,fpst->bclass,fpst->nccnt,fpst->nclass)) {
2340 	    npos = pos;
2341 	    fseek(lfile,base+3*sizeof(uint16),SEEK_SET);
2342 	    putshort(lfile,npos-base);
2343 	    fseek(lfile,0,SEEK_END);
2344 	} else {
2345 	    npos = ftell(lfile);
2346 	    fseek(lfile,base+3*sizeof(uint16),SEEK_SET);
2347 	    putshort(lfile,npos-base);
2348 	    fseek(lfile,npos,SEEK_SET);
2349 	    DumpClass(lfile,iclass,at->maxp.numGlyphs);
2350 	}
2351 	if ( ClassesMatch(fpst->fccnt,fpst->fclass,fpst->bccnt,fpst->bclass)) {
2352 	    fseek(lfile,base+4*sizeof(uint16),SEEK_SET);
2353 	    putshort(lfile,pos-base);
2354 	    fseek(lfile,0,SEEK_END);
2355 	} else if ( ClassesMatch(fpst->fccnt,fpst->fclass,fpst->nccnt,fpst->nclass)) {
2356 	    fseek(lfile,base+4*sizeof(uint16),SEEK_SET);
2357 	    putshort(lfile,npos-base);
2358 	    fseek(lfile,0,SEEK_END);
2359 	} else {
2360 	    pos = ftell(lfile);
2361 	    fseek(lfile,base+4*sizeof(uint16),SEEK_SET);
2362 	    putshort(lfile,pos-base);
2363 	    fseek(lfile,pos,SEEK_SET);
2364 	    DumpClass(lfile,lclass,at->maxp.numGlyphs);
2365 	}
2366 	free(iclass); free(bclass); free(lclass);
2367     }
2368 
2369     ii=0;
2370     for ( i=0; i<fpst->nccnt; ++i ) {
2371 	if ( initialclasses[ii]!=i ) {
2372 	    /* This class isn't an initial one, so leave it's rule pointer NULL */
2373 	} else {
2374 	    ++ii;
2375 	    pos = ftell(lfile);
2376 	    fseek(lfile,rulebase+i*sizeof(short),SEEK_SET);
2377 	    putshort(lfile,pos-base);
2378 	    fseek(lfile,pos,SEEK_SET);
2379 	    subcnt = CntRulesStartingWithClass(fpst,i);
2380 	    putshort(lfile,subcnt);
2381 	    for ( j=0; j<subcnt; ++j )
2382 		putshort(lfile,0);
2383 	    for ( j=k=0; k<fpst->rule_cnt; ++k ) if ( i==fpst->rules[k].u.class.nclasses[0] ) {
2384 		subpos = ftell(lfile);
2385 		fseek(lfile,pos+(1+j)*sizeof(short),SEEK_SET);
2386 		putshort(lfile,subpos-pos);
2387 		fseek(lfile,subpos,SEEK_SET);
2388 
2389 		for ( l=lc=0; l<fpst->rules[k].lookup_cnt; ++l )
2390 		    if ( fpst->rules[k].lookups[l].lookup->lookup_index!=-1 )
2391 			++lc;
2392 		if ( iscontext ) {
2393 		    putshort(lfile,fpst->rules[k].u.class.ncnt);
2394 		    putshort(lfile,lc);
2395 		    for ( l=1; l<fpst->rules[k].u.class.ncnt; ++l )
2396 			putshort(lfile,fpst->rules[k].u.class.nclasses[l]);
2397 		} else {
2398 		    putshort(lfile,fpst->rules[k].u.class.bcnt);
2399 		    for ( l=0; l<fpst->rules[k].u.class.bcnt; ++l )
2400 			putshort(lfile,fpst->rules[k].u.class.bclasses[l]);
2401 		    putshort(lfile,fpst->rules[k].u.class.ncnt);
2402 		    for ( l=1; l<fpst->rules[k].u.class.ncnt; ++l )
2403 			putshort(lfile,fpst->rules[k].u.class.nclasses[l]);
2404 		    putshort(lfile,fpst->rules[k].u.class.fcnt);
2405 		    for ( l=0; l<fpst->rules[k].u.class.fcnt; ++l )
2406 			putshort(lfile,fpst->rules[k].u.class.fclasses[l]);
2407 		    putshort(lfile,lc);
2408 		}
2409 		for ( l=0; l<fpst->rules[k].lookup_cnt; ++l )
2410 		    if ( fpst->rules[k].lookups[l].lookup->lookup_index!=-1 ) {
2411 			putshort(lfile,fpst->rules[k].lookups[l].seq);
2412 			putshort(lfile,fpst->rules[k].lookups[l].lookup->lookup_index);
2413 		    }
2414 		++j;
2415 	    }
2416 	}
2417     }
2418     free(initialclasses);
2419 
2420     maxcontext = 0;
2421     for ( i=0; i<fpst->rule_cnt; ++i ) {
2422 	curcontext = fpst->rules[i].u.class.ncnt+fpst->rules[i].u.class.bcnt+fpst->rules[i].u.class.fcnt;
2423 	if ( curcontext>maxcontext ) maxcontext = curcontext;
2424     }
2425     if ( maxcontext>at->os2.maxContext )
2426 	at->os2.maxContext = maxcontext;
2427 }
2428 
dumpg___ContextChainCoverage(FILE * lfile,SplineFont * sf,struct lookup_subtable * sub,struct alltabs * at)2429 static void dumpg___ContextChainCoverage(FILE *lfile,SplineFont *sf,
2430 	struct lookup_subtable *sub, struct alltabs *at) {
2431     FPST *fpst = sub->fpst;
2432     int iscontext = fpst->type==pst_contextpos || fpst->type==pst_contextsub;
2433     uint32 base = ftell(lfile), ibase, lbase, bbase;
2434     int i, l;
2435     SplineChar **glyphs;
2436     int curcontext;
2437     int lc;
2438 
2439     if ( fpst->rule_cnt!=1 )
2440 	IError("Bad rule cnt in coverage context lookup");
2441     if ( fpst->format==pst_reversecoverage && fpst->rules[0].u.rcoverage.always1!=1 )
2442 	IError("Bad input count in reverse coverage lookup" );
2443 
2444     if ( fpst->format==pst_reversecoverage )
2445 	putshort(lfile, 1);	/* reverse coverage is format 1 */
2446     else
2447 	putshort(lfile,3);	/* Sub format 3 => coverage */
2448     for ( l=lc=0; l<fpst->rules[0].lookup_cnt; ++l )
2449 	if ( fpst->rules[0].lookups[l].lookup->lookup_index!=-1 )
2450 	    ++lc;
2451     if ( iscontext ) {
2452 	putshort(lfile,fpst->rules[0].u.coverage.ncnt);
2453 	putshort(lfile,lc);
2454 	for ( i=0; i<fpst->rules[0].u.coverage.ncnt; ++i )
2455 	    putshort(lfile,0);
2456 	for ( i=0; i<fpst->rules[0].lookup_cnt; ++i )
2457 	    if ( fpst->rules[0].lookups[i].lookup->lookup_index!=-1 ) {
2458 		putshort(lfile,fpst->rules[0].lookups[i].seq);
2459 		putshort(lfile,fpst->rules[0].lookups[i].lookup->lookup_index);
2460 	    }
2461 	for ( i=0; i<fpst->rules[0].u.coverage.ncnt; ++i ) {
2462 	    uint32 pos = ftell(lfile);
2463 	    fseek(lfile,base+6+2*i,SEEK_SET);
2464 	    putshort(lfile,pos-base);
2465 	    fseek(lfile,pos,SEEK_SET);
2466 	    glyphs = OrderedGlyphsFromNames(sf,fpst->rules[0].u.coverage.ncovers[i]);
2467 	    dumpcoveragetable(lfile,glyphs);
2468 	    free(glyphs);
2469 	}
2470     } else {
2471 	if ( fpst->format==pst_reversecoverage ) {
2472 	    ibase = ftell(lfile);
2473 	    putshort(lfile,0);
2474 	}
2475 	putshort(lfile,fpst->rules[0].u.coverage.bcnt);
2476 	bbase = ftell(lfile);
2477 	for ( i=0; i<fpst->rules[0].u.coverage.bcnt; ++i )
2478 	    putshort(lfile,0);
2479 	if ( fpst->format==pst_coverage ) {
2480 	    putshort(lfile,fpst->rules[0].u.coverage.ncnt);
2481 	    ibase = ftell(lfile);
2482 	    for ( i=0; i<fpst->rules[0].u.coverage.ncnt; ++i )
2483 		putshort(lfile,0);
2484 	}
2485 	putshort(lfile,fpst->rules[0].u.coverage.fcnt);
2486 	lbase = ftell(lfile);
2487 	for ( i=0; i<fpst->rules[0].u.coverage.fcnt; ++i )
2488 	    putshort(lfile,0);
2489 	if ( fpst->format==pst_coverage ) {
2490 	    putshort(lfile,lc);
2491 	    for ( i=0; i<fpst->rules[0].lookup_cnt; ++i )
2492 		if ( fpst->rules[0].lookups[i].lookup->lookup_index!=-1 ) {
2493 		    putshort(lfile,fpst->rules[0].lookups[i].seq);
2494 		    putshort(lfile,fpst->rules[0].lookups[i].lookup->lookup_index);
2495 		}
2496 	}
2497 	if ( fpst->format==pst_reversecoverage ) {
2498 	    /* reverse coverage */
2499 	    glyphs = SFGlyphsFromNames(sf,fpst->rules[0].u.rcoverage.replacements);
2500 	    for ( i=0; glyphs[i]!=0; ++i );
2501 	    putshort(lfile,i);
2502 	    for ( i=0; glyphs[i]!=0; ++i )
2503 		putshort(lfile,glyphs[i]->ttf_glyph);
2504 	    free(glyphs);
2505 	}
2506 	for ( i=0; i<fpst->rules[0].u.coverage.ncnt; ++i ) {
2507 	    uint32 pos = ftell(lfile);
2508 	    fseek(lfile,ibase+2*i,SEEK_SET);
2509 	    putshort(lfile,pos-base);
2510 	    fseek(lfile,pos,SEEK_SET);
2511 	    glyphs = OrderedGlyphsFromNames(sf,fpst->rules[0].u.coverage.ncovers[i]);
2512 	    dumpcoveragetable(lfile,glyphs);
2513 	    free(glyphs);
2514 	}
2515 	for ( i=0; i<fpst->rules[0].u.coverage.bcnt; ++i ) {
2516 	    uint32 pos = ftell(lfile);
2517 	    fseek(lfile,bbase+2*i,SEEK_SET);
2518 	    putshort(lfile,pos-base);
2519 	    fseek(lfile,pos,SEEK_SET);
2520 	    glyphs = OrderedGlyphsFromNames(sf,fpst->rules[0].u.coverage.bcovers[i]);
2521 	    dumpcoveragetable(lfile,glyphs);
2522 	    free(glyphs);
2523 	}
2524 	for ( i=0; i<fpst->rules[0].u.coverage.fcnt; ++i ) {
2525 	    uint32 pos = ftell(lfile);
2526 	    fseek(lfile,lbase+2*i,SEEK_SET);
2527 	    putshort(lfile,pos-base);
2528 	    fseek(lfile,pos,SEEK_SET);
2529 	    glyphs = OrderedGlyphsFromNames(sf,fpst->rules[0].u.coverage.fcovers[i]);
2530 	    dumpcoveragetable(lfile,glyphs);
2531 	    free(glyphs);
2532 	}
2533     }
2534 
2535     curcontext = fpst->rules[0].u.coverage.ncnt+fpst->rules[0].u.coverage.bcnt+fpst->rules[0].u.coverage.fcnt;
2536     if ( curcontext>at->os2.maxContext )
2537 	at->os2.maxContext = curcontext;
2538 }
2539 
dumpg___ContextChain(FILE * lfile,SplineFont * sf,struct lookup_subtable * sub,struct alltabs * at)2540 static void dumpg___ContextChain(FILE *lfile,SplineFont *sf,
2541 	struct lookup_subtable *sub, struct alltabs *at) {
2542     FPST *fpst = sub->fpst;
2543 
2544     switch ( fpst->format ) {
2545       case pst_glyphs:
2546 	dumpg___ContextChainGlyphs(lfile,sf,sub,at);
2547       break;
2548       case pst_class:
2549 	dumpg___ContextChainClass(lfile,sf,sub,at);
2550       break;
2551       case pst_coverage:
2552       case pst_reversecoverage:
2553 	dumpg___ContextChainCoverage(lfile,sf,sub,at);
2554       break;
2555     }
2556 
2557     fseek(lfile,0,SEEK_END);
2558 
2559 }
2560 
AnchorsAway(FILE * lfile,SplineFont * sf,struct lookup_subtable * sub,struct glyphinfo * gi)2561 static void AnchorsAway(FILE *lfile,SplineFont *sf,
2562 	struct lookup_subtable *sub, struct glyphinfo *gi ) {
2563     SplineChar **base, **lig, **mkmk;
2564     AnchorClass *ac, *acfirst;
2565     SplineChar ***marks;
2566     int *subcnts;
2567     int cmax, classcnt;
2568     int i;
2569 
2570     marks = malloc((cmax=20)*sizeof(SplineChar **));
2571     subcnts = malloc(cmax*sizeof(int));
2572 
2573     classcnt = 0;
2574     acfirst = NULL;
2575     for ( ac=sf->anchor; ac!=NULL; ac = ac->next ) {
2576 	ac->matches = false;
2577 	if ( ac->subtable==sub && !ac->processed ) {
2578 	    if ( acfirst == NULL )
2579 		acfirst = ac;
2580 	    if ( ac->type==act_curs )
2581     continue;
2582 	    else if ( ac->has_mark && ac->has_base ) {
2583 		ac->matches = ac->processed = true;
2584 		++classcnt;
2585 	    }
2586 	}
2587     }
2588     if ( classcnt>cmax ) {
2589 	marks = realloc(marks,(cmax=classcnt+10)*sizeof(SplineChar **));
2590 	subcnts = realloc(subcnts,cmax*sizeof(int));
2591     }
2592     AnchorClassDecompose(sf,acfirst,classcnt,subcnts,marks,&base,&lig,&mkmk,gi);
2593     switch ( sub->lookup->lookup_type ) {
2594       case gpos_mark2base:
2595 	if ( marks[0]!=NULL && base!=NULL )
2596 	    dumpgposAnchorData(lfile,acfirst,at_basechar,marks,base,classcnt,gi);
2597       break;
2598       case gpos_mark2ligature:
2599 	if ( marks[0]!=NULL && lig!=NULL )
2600 	    dumpgposAnchorData(lfile,acfirst,at_baselig,marks,lig,classcnt,gi);
2601       break;
2602       case gpos_mark2mark:
2603 	if ( marks[0]!=NULL && mkmk!=NULL )
2604 	    dumpgposAnchorData(lfile,acfirst,at_basemark,marks,mkmk,classcnt,gi);
2605       break;
2606     }
2607     for ( i=0; i<classcnt; ++i )
2608 	free(marks[i]);
2609     free(base);
2610     free(lig);
2611     free(mkmk);
2612     free(marks);
2613     free(subcnts);
2614 }
2615 
lookup_size_cmp(const void * _l1,const void * _l2)2616 static int lookup_size_cmp(const void *_l1, const void *_l2) {
2617     const OTLookup *l1 = *(OTLookup **) _l1, *l2 = *(OTLookup **) _l2;
2618 return( l1->lookup_length-l2->lookup_length );
2619 }
2620 
FPSTRefersToOTL(FPST * fpst,OTLookup * otl)2621 static int FPSTRefersToOTL(FPST *fpst,OTLookup *otl) {
2622     int i, j;
2623 
2624     if ( fpst==NULL || fpst->type == pst_reversesub )
2625 return( false );
2626     for ( i=0; i<fpst->rule_cnt; ++i ) {
2627 	for ( j=0; j< fpst->rules[i].lookup_cnt; ++j )
2628 	    if ( fpst->rules[i].lookups[j].lookup == otl )
2629 return( true );
2630     }
2631 return( false );
2632 }
2633 
OnlyMac(OTLookup * otl,OTLookup * all)2634 static int OnlyMac(OTLookup *otl, OTLookup *all) {
2635     FeatureScriptLangList *features = otl->features;
2636     int anymac = 0;
2637     struct lookup_subtable *sub;
2638 
2639     switch ( otl->lookup_type ) {
2640     /* These two lookup types are mac only */
2641       case kern_statemachine: case morx_indic: case morx_context: case morx_insert:
2642 return( true );
2643     /* These lookup types are OpenType only */
2644       case gsub_multiple: case gsub_alternate: case gsub_context:
2645       case gsub_contextchain: case gsub_reversecchain:
2646       case gpos_single: case gpos_cursive: case gpos_mark2base:
2647       case gpos_mark2ligature: case gpos_mark2mark:
2648       case gpos_context: case gpos_contextchain:
2649 return( false );
2650     /* These two can be expressed in both, and might be either */
2651      case gpos_pair: case gsub_single: case gsub_ligature:
2652 	for ( features = otl->features; features!=NULL; features = features->next ) {
2653 	    if ( !features->ismac )
2654 return( false );
2655 	    else
2656 		anymac = true;
2657 	}
2658 	/* Either it has no features at all (nested), or all its features */
2659 	/*  are mac feature settings. Even if all are mac feature settings it */
2660 	/*  might still be used as under control of a contextual feature */
2661 	/*  so in both cases check for nested */
2662 	while ( all!=NULL ) {
2663 	    if ( all!=otl && !all->unused &&
2664 		    (all->lookup_type==gpos_context ||
2665 		     all->lookup_type==gpos_contextchain ||
2666 		     all->lookup_type==gsub_context ||
2667 		     all->lookup_type==gsub_contextchain /*||
2668 		     all->lookup_type==gsub_reversecchain*/ )) {
2669 		for ( sub=all->subtables; sub!=NULL; sub=sub->next ) if ( !sub->unused && sub->fpst!=NULL ) {
2670 		    if ( FPSTRefersToOTL(sub->fpst,otl) )
2671 return( false );
2672 		}
2673 	    }
2674 	    all = all->next;
2675 	}
2676 	if ( anymac )
2677 return( true );
2678 	/* As far as I can tell, this lookup isn't used at all */
2679 	/*  Let's output it anyway, just in case we ever support some other */
2680 	/*  table that uses GPOS/GSUB lookups (I think JUST) */
2681 return( false );
2682     }
2683     /* Should never get here, but gcc probably thinks we might */
2684 return( true );
2685 }
2686 
otf_dumpALookup(FILE * lfile,OTLookup * otl,SplineFont * sf,struct alltabs * at)2687 static void otf_dumpALookup(FILE *lfile, OTLookup *otl, SplineFont *sf,
2688 	struct alltabs *at) {
2689     struct lookup_subtable *sub;
2690     int lookup_sub_table_contains_no_data_count = 0;
2691     int lookup_sub_table_is_too_big_count = 0;
2692 
2693     otl->lookup_offset = ftell(lfile);
2694     for ( sub = otl->subtables; sub!=NULL; sub=sub->next ) {
2695 	sub->extra_subtables = NULL;
2696 	if ( sub->unused )
2697 	    sub->subtable_offset = -1;
2698 	else {
2699 	    sub->subtable_offset = ftell(lfile);
2700 	    switch ( otl->lookup_type ) {
2701 	    /* GPOS lookup types */
2702 	      case gpos_single:
2703 		dumpGPOSsimplepos(lfile,sf,sub);
2704 	      break;
2705 
2706 	      case gpos_pair:
2707 		if ( at->os2.maxContext<2 )
2708 		    at->os2.maxContext = 2;
2709 		if ( sub->kc!=NULL )
2710 		    dumpgposkernclass(lfile,sf,sub,at);
2711 		else
2712 		    dumpGPOSpairpos(lfile,sf,sub);
2713 	      break;
2714 
2715 	      case gpos_cursive:
2716 		dumpgposCursiveAttach(lfile,sf,sub,&at->gi);
2717 	      break;
2718 
2719 	      case gpos_mark2base:
2720 	      case gpos_mark2ligature:
2721 	      case gpos_mark2mark:
2722 		AnchorsAway(lfile,sf,sub,&at->gi);
2723 	      break;
2724 
2725 	      case gpos_contextchain:
2726 	      case gpos_context:
2727 		dumpg___ContextChain(lfile,sf,sub,at);
2728 	      break;
2729 
2730 	    /* GSUB lookup types */
2731 	      case gsub_single:
2732 		dumpGSUBsimplesubs(lfile,sf,sub);
2733 	      break;
2734 
2735 	      case gsub_multiple:
2736 	      case gsub_alternate:
2737 		dumpGSUBmultiplesubs(lfile,sf,sub);
2738 	      break;
2739 
2740 	      case gsub_ligature:
2741 		dumpGSUBligdata(lfile,sf,sub,at);
2742 	      break;
2743 
2744 	      case gsub_contextchain:
2745 	      case gsub_context:
2746 	      case gsub_reversecchain:
2747 		dumpg___ContextChain(lfile,sf,sub,at);
2748 	      break;
2749 	    }
2750 	    if ( ftell(lfile)-sub->subtable_offset==0 ) {
2751 		if ( lookup_sub_table_contains_no_data_count < 32 ) {
2752 		  IError( "Lookup sub table, %s in %s, contains no data.\n",
2753 		  	sub->subtable_name, sub->lookup->lookup_name );
2754 		  lookup_sub_table_contains_no_data_count ++;
2755 		}
2756 		sub->unused = true;
2757 		sub->subtable_offset = -1;
2758 	    } else if ( sub->extra_subtables==NULL &&
2759 		    ftell(lfile)-sub->subtable_offset>65535 )
2760 		if ( lookup_sub_table_is_too_big_count < 32 ) {
2761 		  IError( "Lookup sub table, %s in %s, is too big. Will not be useable.\n",
2762 		  	sub->subtable_name, sub->lookup->lookup_name );
2763 		  lookup_sub_table_is_too_big_count ++;
2764 		}
2765 	}
2766     }
2767     otl->lookup_length = ftell(lfile)-otl->lookup_offset;
2768 }
2769 
G___figureLookups(SplineFont * sf,int is_gpos,struct alltabs * at)2770 static FILE *G___figureLookups(SplineFont *sf,int is_gpos,
2771 	struct alltabs *at) {
2772     OTLookup *otl;
2773     struct lookup_subtable *sub;
2774     int index, i,j;
2775     FILE *final;
2776     FILE *lfile = GFileTmpfile();
2777     OTLookup **sizeordered;
2778     OTLookup *all = is_gpos ? sf->gpos_lookups : sf->gsub_lookups;
2779     char *buffer;
2780     int len;
2781 
2782     index = 0;
2783     for ( otl=all; otl!=NULL; otl=otl->next ) {
2784 	if ( otl->unused || OnlyMac(otl,all) || otl->only_jstf || otl->temporary_kern )
2785 	    otl->lookup_index = -1;
2786 	else
2787 	    otl->lookup_index = index++;
2788     }
2789     for ( otl=all; otl!=NULL; otl=otl->next ) {
2790 	if ( otl->lookup_index!=-1 ) {
2791 	    otf_dumpALookup(lfile, otl, sf, at );
2792 	}
2793     }
2794     if ( is_gpos )
2795 	AnchorGuessContext(sf,at);
2796 
2797     /* We don't need to reorder short files */
2798     if ( ftell(lfile)<65536 )
2799 return( lfile );
2800 
2801     /* Order the lookups so that the smallest ones come first */
2802     /*  thus we are less likely to need extension tables */
2803     /* I think it's better to order the entire lookup rather than ordering the*/
2804     /*  subtables -- since the extension subtable would be required for all */
2805     /*  subtables in the lookup, so might as well keep them all together */
2806     sizeordered = malloc(index*sizeof(OTLookup *));
2807     for ( otl=is_gpos ? sf->gpos_lookups : sf->gsub_lookups; otl!=NULL; otl=otl->next )
2808 	if ( otl->lookup_index!=-1 )
2809 	    sizeordered[ otl->lookup_index ] = otl;
2810     qsort(sizeordered,index,sizeof(OTLookup *),lookup_size_cmp);
2811 
2812     final = GFileTmpfile();
2813     buffer = malloc(32768);
2814     for ( i=0; i<index; ++i ) {
2815 	uint32 diff;
2816 	otl = sizeordered[i];
2817 	fseek(lfile,otl->lookup_offset,SEEK_SET);
2818 	diff = ftell(final) - otl->lookup_offset;
2819 	otl->lookup_offset = ftell(final);
2820 	len = otl->lookup_length;
2821 	while ( len>=32768 ) {
2822 	    int done = fread(buffer,1,32768,lfile);
2823 	    if ( done==0 )		/* fread returns 0 on error, not EOF */
2824 	break;
2825 	    fwrite(buffer,1,done,final);
2826 	    len -= done;
2827 	}
2828 	if ( len>0 && len<=32768 ) {
2829 	    int done = fread(buffer,1,len,lfile);
2830 	    if ( done==0 )
2831 	break;
2832 	    fwrite(buffer,1,done,final);
2833 	}
2834 	for ( sub = otl->subtables; sub!=NULL; sub=sub->next ) {
2835 	    if ( !sub->unused ) {
2836 		sub->subtable_offset += diff;
2837 		if ( sub->extra_subtables!=NULL ) {
2838 		    for ( j=0; sub->extra_subtables[j]!=-1; ++j )
2839 			sub->extra_subtables[j] += diff;
2840 		}
2841 	    }
2842 	}
2843     }
2844     free(buffer);
2845     free(sizeordered);
2846     fclose(lfile);
2847 return( final );
2848 }
2849 
2850 struct feat_lookups {
2851     uint32 tag;
2852     int lcnt;
2853     OTLookup **lookups;
2854     int feature_id;		/* Initially consecutive, but may be rearranged by sorting */
2855     uint32 name_param_ptr;
2856 };
2857 
2858 struct langsys {
2859     uint32 lang;
2860     int fc;
2861     int *feature_id;
2862     int same_as;
2863     int32 offset;
2864 };
2865 
2866 struct scriptset {
2867     uint32 script;
2868     int lc;
2869     struct langsys *langsys;
2870 };
2871 
2872 struct ginfo {
2873     int fmax, fcnt;
2874     struct feat_lookups *feat_lookups;
2875     int sc;
2876     struct scriptset *scripts;
2877 };
2878 
FindOrMakeNewFeatureLookup(struct ginfo * ginfo,OTLookup ** lookups,uint32 tag)2879 static int FindOrMakeNewFeatureLookup(struct ginfo *ginfo,OTLookup **lookups,
2880 	uint32 tag) {
2881     int i, j;
2882 
2883     for ( i=0; i<ginfo->fcnt; ++i ) {
2884 	if ( ginfo->feat_lookups[i].tag!= tag )
2885     continue;
2886 	if ( lookups==NULL && ginfo->feat_lookups[i].lookups==NULL )	/* 'size' feature */
2887 return( i );
2888 	if ( lookups==NULL || ginfo->feat_lookups[i].lookups==NULL )
2889     continue;
2890 	for ( j=0; lookups[j]!=NULL && ginfo->feat_lookups[i].lookups[j]!=NULL; ++j )
2891 	    if ( ginfo->feat_lookups[i].lookups[j]!=lookups[j] )
2892 	break;
2893 	if ( ginfo->feat_lookups[i].lookups[j]==lookups[j] ) {
2894 	    free(lookups);
2895 return( i );
2896 	}
2897     }
2898     if ( ginfo->fcnt>=ginfo->fmax )
2899 	ginfo->feat_lookups = realloc(ginfo->feat_lookups,(ginfo->fmax+=20)*sizeof(struct feat_lookups));
2900     ginfo->feat_lookups[i].feature_id = i;
2901     ginfo->feat_lookups[i].tag = tag;
2902     ginfo->feat_lookups[i].lookups = lookups;
2903     j=0;
2904     if ( lookups!=NULL ) for ( ; lookups[j]!=NULL; ++j );
2905     ginfo->feat_lookups[i].lcnt = j;
2906     ++ginfo->fcnt;
2907 return( i );
2908 }
2909 
feat_alphabetize(const void * _fl1,const void * _fl2)2910 static int feat_alphabetize(const void *_fl1, const void *_fl2) {
2911     const struct feat_lookups *fl1 = _fl1, *fl2 = _fl2;
2912 
2913     if ( fl1->tag<fl2->tag )
2914 return( -1 );
2915     if ( fl1->tag>fl2->tag )
2916 return( 1 );
2917 
2918 return( 0 );
2919 }
2920 
numeric_order(const void * _i1,const void * _i2)2921 static int numeric_order(const void *_i1, const void *_i2) {
2922     int i1 = *(const int *) _i1, i2 = *(const int *) _i2;
2923 
2924     if ( i1<i2 )
2925 return( -1 );
2926     if ( i1>i2 )
2927 return( 1 );
2928 
2929 return( 0 );
2930 }
2931 
LangSysMatch(struct scriptset * s,int ils1,int ils2)2932 static int LangSysMatch(struct scriptset *s,int ils1, int ils2 ) {
2933     struct langsys *ls1 = &s->langsys[ils1], *ls2 = &s->langsys[ils2];
2934     int i;
2935 
2936     if ( ls1->fc!=ls2->fc )
2937 return( false );
2938     for ( i=0; i<ls1->fc; ++i )
2939 	if ( ls1->feature_id[i]!=ls2->feature_id[i] )
2940 return( false );
2941 
2942 return( true );
2943 }
2944 
FindFeatures(SplineFont * sf,int is_gpos,struct ginfo * ginfo)2945 static void FindFeatures(SplineFont *sf,int is_gpos,struct ginfo *ginfo) {
2946     uint32 *scripts, *langs, *features;
2947     OTLookup **lookups;
2948     int sc, lc, fc, j;
2949 
2950     memset(ginfo,0,sizeof(struct ginfo));
2951 
2952     scripts = SFScriptsInLookups(sf,is_gpos);
2953     if ( scripts==NULL )	/* All lookups unused */
2954 return;
2955     for ( sc=0; scripts[sc]!=0; ++sc );
2956     ginfo->scripts = malloc(sc*sizeof(struct scriptset));
2957     ginfo->sc = sc;
2958     for ( sc=0; scripts[sc]!=0; ++sc ) {
2959 	langs = SFLangsInScript(sf,is_gpos,scripts[sc]);
2960 	for ( lc=0; langs[lc]!=0; ++lc );
2961 	ginfo->scripts[sc].script = scripts[sc];
2962 	ginfo->scripts[sc].lc = lc;
2963 	ginfo->scripts[sc].langsys = malloc(lc*sizeof(struct langsys));
2964 	for ( lc=0; langs[lc]!=0; ++lc ) {
2965 	    features = SFFeaturesInScriptLang(sf,is_gpos,scripts[sc],langs[lc]);
2966 	    for ( fc=0; features[fc]!=0; ++fc );
2967 	    ginfo->scripts[sc].langsys[lc].lang = langs[lc];
2968 	    ginfo->scripts[sc].langsys[lc].fc = fc;
2969 	    ginfo->scripts[sc].langsys[lc].feature_id = malloc(fc*sizeof(int));
2970 	    ginfo->scripts[sc].langsys[lc].same_as = -1;
2971 	    for ( fc=0; features[fc]!=0; ++fc ) {
2972 		lookups = SFLookupsInScriptLangFeature(sf,is_gpos,scripts[sc],langs[lc],features[fc]);
2973 		ginfo->scripts[sc].langsys[lc].feature_id[fc] =
2974 			FindOrMakeNewFeatureLookup(ginfo,lookups,features[fc]);
2975 		/* lookups is freed or used by FindOrMakeNewFeatureLookup */
2976 	    }
2977 	    free(features);
2978 	}
2979 	free(langs);
2980     }
2981     free(scripts);
2982 
2983     qsort(ginfo->feat_lookups,ginfo->fcnt,sizeof(struct feat_lookups),feat_alphabetize);
2984 
2985     /* Now we've disordered the features. Find each feature_id and turn it back*/
2986     /*  into a feature number */
2987     for ( sc=0; sc<ginfo->sc; ++sc ) {
2988 	for ( lc=0; lc<ginfo->scripts[sc].lc; ++lc ) {
2989 	    int fcmax = ginfo->scripts[sc].langsys[lc].fc;
2990 	    int *feature_id = ginfo->scripts[sc].langsys[lc].feature_id;
2991 	    for ( fc=0; fc<fcmax; ++fc ) {
2992 		int id = feature_id[fc];
2993 		for ( j=0; j<ginfo->fcnt; ++j )
2994 		    if ( id==ginfo->feat_lookups[j].feature_id )
2995 		break;
2996 		feature_id[fc] = j;
2997 	    }
2998 	    qsort(feature_id,fcmax,sizeof(int),numeric_order);
2999 	}
3000 	/* See if there are langsys tables which use exactly the same features*/
3001 	/*  They can use the same entry in the file. This optimization seems  */
3002 	/*  to be required for Japanese vertical writing to work in Uniscribe.*/
3003 	for ( lc=0; lc<ginfo->scripts[sc].lc; ++lc ) {
3004 	    for ( j=0; j<lc; ++j )
3005 		if ( LangSysMatch(&ginfo->scripts[sc],j,lc) ) {
3006 		    ginfo->scripts[sc].langsys[lc].same_as = j;
3007 	    break;
3008 		}
3009 	}
3010     }
3011 }
3012 
3013 
dump_script_table(FILE * g___,struct scriptset * ss,struct ginfo * ginfo)3014 static void dump_script_table(FILE *g___,struct scriptset *ss,struct ginfo *ginfo) {
3015     int i, lcnt, dflt_lang = -1;
3016     uint32 base;
3017     int j, req_index;
3018     uint32 offset;
3019 
3020     /* Count the languages, and find default */
3021     for ( lcnt=0; lcnt<ss->lc; ++lcnt )
3022 	if ( ss->langsys[lcnt].lang==DEFAULT_LANG )
3023 	    dflt_lang = lcnt;
3024     if ( dflt_lang != -1 )
3025 	--lcnt;
3026 
3027     base = ftell(g___);
3028     putshort(g___, 0 );				/* fill in later, Default Lang Sys */
3029     putshort(g___,lcnt);
3030     for ( i=0; i<ss->lc; ++i ) if ( i!=dflt_lang ) {
3031 	putlong(g___,ss->langsys[i].lang);	/* Language tag */
3032 	putshort(g___,0);			/* Fill in later, offset to langsys */
3033     }
3034 
3035     for ( lcnt=0; lcnt<ss->lc; ++lcnt ) {
3036 	if ( ss->langsys[lcnt].same_as!=-1 )
3037 	    offset = ss->langsys[ ss->langsys[lcnt].same_as ].offset;
3038 	else {
3039 	    offset = ftell(g___);
3040 	    ss->langsys[lcnt].offset = offset;
3041 	}
3042 	fseek(g___,lcnt==dflt_lang                 ? base :
3043 		   lcnt<dflt_lang || dflt_lang==-1 ? base + 4 + lcnt*6 +4 :
3044 			                             base + 4 + (lcnt-1)*6 +4 ,
3045 		      SEEK_SET );
3046 	putshort(g___,offset-base);
3047 	fseek(g___,0,SEEK_END);
3048 	if ( ss->langsys[lcnt].same_as==-1 ) {
3049 	    req_index = -1;
3050 	    for ( j=0; j<ss->langsys[lcnt].fc; ++j ) {
3051 		if ( ginfo->feat_lookups[ ss->langsys[lcnt].feature_id[j] ].tag == REQUIRED_FEATURE ) {
3052 		    req_index = ss->langsys[lcnt].feature_id[j];
3053 	    break;
3054 		}
3055 	    }
3056 	    putshort(g___,0);		/* LookupOrder, always NULL */
3057 	    putshort(g___,req_index);	/* index of required feature, if any */
3058 	    putshort(g___,ss->langsys[lcnt].fc - (req_index!=-1));
3059 					/* count of non-required features */
3060 	    for ( j=0; j<ss->langsys[lcnt].fc; ++j ) if (ss->langsys[lcnt].feature_id[j]!=req_index )
3061 		putshort(g___,ss->langsys[lcnt].feature_id[j]);
3062 	}
3063     }
3064 }
3065 
g___FigureExtensionSubTables(OTLookup * all,int startoffset,int is_gpos)3066 static FILE *g___FigureExtensionSubTables(OTLookup *all,int startoffset,int is_gpos) {
3067     OTLookup *otf;
3068     struct lookup_subtable *sub;
3069     int len, len2, gotmore;
3070     FILE *efile;
3071     int i, offset, cnt;
3072 
3073     if ( all==NULL )
3074 return( NULL );
3075     gotmore = true; cnt=len=0;
3076     while ( gotmore ) {
3077 	gotmore = false;
3078 	offset = startoffset + 8*cnt;
3079 	for ( otf=all; otf!=NULL; otf=otf->next ) if ( otf->lookup_index!=-1 ) {
3080 	    if ( otf->needs_extension )
3081 	continue;
3082 	    for ( sub = otf->subtables; sub!=NULL; sub=sub->next ) {
3083 		if ( sub->subtable_offset==-1 )
3084 	    continue;
3085 		if ( sub->extra_subtables!=NULL ) {
3086 		    for ( i=0; sub->extra_subtables[i]!=-1; ++i ) {
3087 			if ( sub->extra_subtables[i]+offset>65535 )
3088 		    break;
3089 		    }
3090 		    if ( sub->extra_subtables[i]!=-1 )
3091 	    break;
3092 		} else if ( sub->subtable_offset+offset>65535 )
3093 	    break;
3094 	    }
3095 	    if ( sub!=NULL ) {
3096 		otf->needs_extension = true;
3097 		gotmore = true;
3098 		len += 8*otf->subcnt;
3099 		++cnt;
3100 	    }
3101 	    offset -= 6+2*otf->subcnt;
3102 	}
3103     }
3104 
3105     if ( cnt==0 )		/* No offset overflows */
3106 return( NULL );
3107 
3108     /* Now we've worked out which lookups need extension tables and marked them*/
3109     /* Generate the extension tables, and update the offsets to reflect the size */
3110     /* of the extensions */
3111     efile = GFileTmpfile();
3112 
3113     len2 = 0;
3114     for ( otf=all; otf!=NULL; otf=otf->next ) if ( otf->lookup_index!=-1 ) {
3115 	for ( sub = otf->subtables; sub!=NULL; sub=sub->next ) {
3116 	    if ( sub->subtable_offset==-1 )
3117 	continue;
3118 	    if ( sub->extra_subtables!=NULL ) {
3119 		for ( i=0; sub->extra_subtables[i]!=-1; ++i ) {
3120 		    sub->extra_subtables[i] += len;
3121 		    if ( otf->needs_extension ) {
3122 			int off = ftell(efile);
3123 			putshort(efile,1);	/* exten subtable format (there's only one) */
3124 			putshort(efile,otf->lookup_type&0xff);
3125 			putlong(efile,sub->extra_subtables[i]-len2);
3126 			sub->extra_subtables[i] = off;
3127 			len2+=8;
3128 		    }
3129 		}
3130 	    } else {
3131 		sub->subtable_offset += len;
3132 		if ( otf->needs_extension ) {
3133 		    int off = ftell(efile);
3134 		    putshort(efile,1);	/* exten subtable format (there's only one) */
3135 		    putshort(efile,otf->lookup_type&0xff);
3136 		    putlong(efile,sub->subtable_offset-len2);
3137 		    sub->subtable_offset = off;
3138 			len2+=8;
3139 		}
3140 	    }
3141 	}
3142     }
3143 
3144 return( efile );
3145 }
3146 
findotffeatname(uint32 tag,SplineFont * sf)3147 struct otffeatname *findotffeatname(uint32 tag,SplineFont *sf) {
3148     struct otffeatname *fn;
3149 
3150     for ( fn=sf->feat_names; fn!=NULL && fn->tag!=tag; fn=fn->next );
3151 return( fn );
3152 }
3153 
dumpg___info(struct alltabs * at,SplineFont * sf,int is_gpos)3154 static FILE *dumpg___info(struct alltabs *at, SplineFont *sf,int is_gpos) {
3155     /* Dump out either a gpos or a gsub table. gpos handles kerns, gsub ligs */
3156     /*  we assume that SFFindUnusedLookups has been called */
3157     FILE *lfile, *g___, *efile;
3158     uint32 lookup_list_table_start, feature_list_table_start, here, scripts_start_offset;
3159     struct ginfo ginfo;
3160     int32 size_params_loc, size_params_ptr;
3161     int i,j, cnt, scnt, offset;
3162     OTLookup *otf, *all;
3163     struct lookup_subtable *sub;
3164     char *buf;
3165     struct otffeatname *fn;
3166 
3167     for ( fn=sf->feat_names; fn!=NULL; fn=fn->next )
3168 	fn->nid = 0;
3169 
3170     FindFeatures(sf,is_gpos,&ginfo);
3171     if ( ginfo.sc==0 )
3172 return( NULL );
3173     lfile = G___figureLookups(sf,is_gpos,at);
3174 
3175     if ( ginfo.sc==0 && ftell(lfile)==0 ) {
3176 	/* ftell(lfile)==0 => There are no lookups for this table */
3177 	/* ginfo.sc==0 => There are no scripts. */
3178 	/* If both are true then we don't need to output the table */
3179 	/* It is perfectly possible to have lookups without scripts */
3180 	/*  (if some other table refered to them -- we don't currently */
3181 	/*  support this, but we might some day). */
3182 	/* It is also possible to have scripts without lookups (to get */
3183 	/*  around a bug in Uniscribe which only processes some scripts */
3184 	/*  if both GPOS and GSUB entries are present. So we share scripts */
3185 	/*  between the two tables */
3186 	fclose(lfile);
3187 	/* if ginfo.sc==0 then there will be nothing to free in the ginfo struct*/
3188 return( NULL );
3189     }
3190 
3191     g___ = GFileTmpfile();
3192 
3193     putlong(g___,0x10000);		/* version number */
3194     putshort(g___,10);		/* offset to script table */
3195     putshort(g___,0);		/* offset to features. Come back for this */
3196     putshort(g___,0);		/* offset to lookups.  Come back for this */
3197 /* Now the scripts */
3198     scripts_start_offset = ftell(g___);
3199     putshort(g___,ginfo.sc);
3200     for ( i=0; i<ginfo.sc; ++i ) {
3201 	putlong(g___,ginfo.scripts[i].script);
3202 	putshort(g___,0);	/* fix up later */
3203     }
3204 
3205     /* Ok, that was the script_list_table which gives each script an offset */
3206     /* Now for each script we provide a Script table which contains an */
3207     /*  offset to a bunch of features for the default language, and a */
3208     /*  a more complex situation for non-default languages. */
3209     offset=2+4;			/* To the script pointer at the start of table */
3210     for ( i=0; i<ginfo.sc; ++i ) {
3211 	here = ftell(g___);
3212 	fseek(g___,scripts_start_offset+offset,SEEK_SET);
3213 	putshort(g___,here-scripts_start_offset);
3214 	offset+=6;
3215 	fseek(g___,here,SEEK_SET);
3216 	dump_script_table(g___,&ginfo.scripts[i],&ginfo);
3217     }
3218     /* And that should finish all the scripts/languages */
3219 
3220     /* so free the ginfo script/lang data */
3221     for ( i=0; i<ginfo.sc; ++i ) {
3222 	for ( j=0; j<ginfo.scripts[i].lc; ++j ) {
3223 	    free( ginfo.scripts[i].langsys[j].feature_id );
3224 	}
3225 	free( ginfo.scripts[i].langsys );
3226     }
3227     free( ginfo.scripts );
3228 
3229 /* Now the features */
3230     feature_list_table_start = ftell(g___);
3231     fseek(g___,6,SEEK_SET);
3232     putshort(g___,feature_list_table_start);
3233     fseek(g___,0,SEEK_END);
3234     putshort(g___,ginfo.fcnt);	/* Number of features */
3235     offset = 2+6*ginfo.fcnt;	/* Offset to start of first feature table from beginning of feature_list */
3236     for ( i=0; i<ginfo.fcnt; ++i ) {
3237 	putlong(g___,ginfo.feat_lookups[i].tag);
3238 	putshort(g___,offset);
3239 	offset += 4+2*ginfo.feat_lookups[i].lcnt;
3240     }
3241     /* for each feature, one feature table */
3242     size_params_ptr = 0;
3243     for ( i=0; i<ginfo.fcnt; ++i ) {
3244 	ginfo.feat_lookups[i].name_param_ptr = 0;
3245 	if ( ginfo.feat_lookups[i].tag==CHR('s','i','z','e') )
3246 	    size_params_ptr = ftell(g___);
3247 	else if ( ginfo.feat_lookups[i].tag>=CHR('s','s','0','1') && ginfo.feat_lookups[i].tag<=CHR('s','s','2','0'))
3248 	    ginfo.feat_lookups[i].name_param_ptr = ftell(g___);
3249 	putshort(g___,0);			/* No feature params (we'll come back for 'size') */
3250 	putshort(g___,ginfo.feat_lookups[i].lcnt);/* this many lookups */
3251 	for ( j=0; j<ginfo.feat_lookups[i].lcnt; ++j )
3252 	    putshort(g___,ginfo.feat_lookups[i].lookups[j]->lookup_index );
3253 	    	/* index of each lookup */
3254     }
3255     if ( size_params_ptr!=0 ) {
3256 	size_params_loc = ftell(g___);
3257 	fseek(g___,size_params_ptr,SEEK_SET);
3258 	putshort(g___,size_params_loc-size_params_ptr);
3259 	fseek(g___,size_params_loc,SEEK_SET);
3260 	putshort(g___,sf->design_size);
3261 	if ( sf->fontstyle_id!=0 || sf->fontstyle_name!=NULL ) {
3262 	    putshort(g___,sf->fontstyle_id);
3263 	    at->fontstyle_name_strid = at->next_strid++;
3264 	    putshort(g___,at->fontstyle_name_strid);
3265 	} else {
3266 	    putshort(g___,0);
3267 	    putshort(g___,0);
3268 	}
3269 	putshort(g___,sf->design_range_bottom);
3270 	putshort(g___,sf->design_range_top);
3271     }
3272     for ( i=0; i<ginfo.fcnt; ++i ) {
3273 	if ( ginfo.feat_lookups[i].name_param_ptr!=0 &&
3274 		(fn = findotffeatname(ginfo.feat_lookups[i].tag,sf))!=NULL ) {
3275 	    if ( fn->nid==0 )
3276 		fn->nid = at->next_strid++;
3277 	    uint32 name_param_loc = ftell(g___);
3278 	    fseek(g___,ginfo.feat_lookups[i].name_param_ptr,SEEK_SET);
3279 	    putshort(g___,name_param_loc-ginfo.feat_lookups[i].name_param_ptr);
3280 	    fseek(g___,name_param_loc,SEEK_SET);
3281 	    putshort(g___,0);		/* Minor version number */
3282 	    putshort(g___,fn->nid);
3283 	}
3284     }
3285     /* And that should finish all the features */
3286 
3287     /* so free the ginfo feature data */
3288     for ( i=0; i<ginfo.fcnt; ++i )
3289 	free( ginfo.feat_lookups[i].lookups );
3290     free( ginfo.feat_lookups );
3291 
3292 /* Now the lookups */
3293     all = is_gpos ? sf->gpos_lookups : sf->gsub_lookups;
3294     for ( cnt=0, otf = all; otf!=NULL; otf=otf->next ) {
3295 	if ( otf->lookup_index!=-1 )
3296 	    ++cnt;
3297     }
3298     lookup_list_table_start = ftell(g___);
3299     fseek(g___,8,SEEK_SET);
3300     putshort(g___,lookup_list_table_start);
3301     fseek(g___,0,SEEK_END);
3302     putshort(g___,cnt);
3303     offset = 2+2*cnt;		/* Offset to start of first lookup table from beginning of lookup list */
3304     for ( otf = all; otf!=NULL; otf=otf->next ) if ( otf->lookup_index!=-1 ) {
3305 	putshort(g___,offset);
3306 	for ( scnt=0, sub = otf->subtables; sub!=NULL; sub=sub->next ) {
3307 	    if ( sub->subtable_offset==-1 )
3308 	continue;
3309 	    else if ( sub->extra_subtables!=NULL ) {
3310 		for ( i=0; sub->extra_subtables[i]!=-1; ++i )
3311 		    ++scnt;
3312 	    } else
3313 		++scnt;
3314 	}
3315 	otf->subcnt = scnt;
3316 	offset += 6+2*scnt;		/* 6 bytes header +2 per lookup */
3317 	if ( otf->lookup_flags & pst_usemarkfilteringset )
3318 	    offset += 2;		/* For mark filtering set, if used */
3319     }
3320     offset -= 2+2*cnt;
3321     /* now the lookup tables */
3322       /* do we need any extension sub-tables? */
3323     efile=g___FigureExtensionSubTables(all,offset,is_gpos);
3324     for ( otf = all; otf!=NULL; otf=otf->next ) if ( otf->lookup_index!=-1 ) {
3325 	putshort(g___,!otf->needs_extension ? (otf->lookup_type&0xff)
3326 			: is_gpos ? 9 : 7);
3327 	putshort(g___,(otf->lookup_flags&0xffff));
3328 	putshort(g___,otf->subcnt);
3329 	for ( sub = otf->subtables; sub!=NULL; sub=sub->next ) {
3330 	    if ( sub->subtable_offset==-1 )
3331 	continue;
3332 	    else if ( sub->extra_subtables!=NULL ) {
3333 		for ( i=0; sub->extra_subtables[i]!=-1; ++i )
3334 		    putshort(g___,offset+sub->extra_subtables[i]);
3335 	    } else
3336 		putshort(g___,offset+sub->subtable_offset);
3337 
3338 	    /* Offset to lookup data which is in the temp file */
3339 	    /* we keep adjusting offset so it reflects the distance between */
3340 	    /* here and the place where the temp file will start, and then */
3341 	    /* we need to skip l->offset bytes in the temp file */
3342 	    /* If it's a big GPOS/SUB table we may also need some extension */
3343 	    /*  pointers, but FigureExtension will adjust for that */
3344 	}
3345 	offset -= 6+2*otf->subcnt;
3346 	if ( otf->lookup_flags & pst_usemarkfilteringset ) {
3347 	    putshort(g___,otf->lookup_flags>>16);
3348 	    offset -= 2;
3349 	}
3350     }
3351 
3352     buf = malloc(8096);
3353     if ( efile!=NULL ) {
3354 	rewind(efile);
3355 	while ( (i=fread(buf,1,8096,efile))>0 )
3356 	    fwrite(buf,1,i,g___);
3357 	fclose(efile);
3358     }
3359     rewind(lfile);
3360     while ( (i=fread(buf,1,8096,lfile))>0 )
3361 	fwrite(buf,1,i,g___);
3362     fclose(lfile);
3363     free(buf);
3364     for ( otf = all; otf!=NULL; otf=otf->next ) if ( otf->lookup_index!=-1 ) {
3365 	for ( sub = otf->subtables; sub!=NULL; sub=sub->next ) {
3366 	    free(sub->extra_subtables);
3367 	    sub->extra_subtables = NULL;
3368 	}
3369 	otf->needs_extension = false;
3370     }
3371 return( g___ );
3372 }
3373 
otf_dumpgpos(struct alltabs * at,SplineFont * sf)3374 void otf_dumpgpos(struct alltabs *at, SplineFont *sf) {
3375     /* Open Type, bless its annoying little heart, doesn't store kern info */
3376     /*  in the kern table. Of course not, how silly of me to think it might */
3377     /*  be consistent. It stores it in the much more complicated gpos table */
3378     AnchorClass *ac;
3379 
3380     for ( ac=sf->anchor; ac!=NULL; ac=ac->next )
3381 	ac->processed = false;
3382 
3383     at->gpos = dumpg___info(at, sf,true);
3384     if ( at->gpos!=NULL ) {
3385 	at->gposlen = ftell(at->gpos);
3386 	if ( at->gposlen&1 ) putc('\0',at->gpos);
3387 	if ( (at->gposlen+1)&2 ) putshort(at->gpos,0);
3388     }
3389 }
3390 
otf_dumpgsub(struct alltabs * at,SplineFont * sf)3391 void otf_dumpgsub(struct alltabs *at, SplineFont *sf) {
3392     /* substitutions such as: Ligatures, cjk vertical rotation replacement, */
3393     /*  arabic forms, small caps, ... */
3394     SFLigaturePrepare(sf);
3395     at->gsub = dumpg___info(at, sf, false);
3396     if ( at->gsub!=NULL ) {
3397 	at->gsublen = ftell(at->gsub);
3398 	if ( at->gsublen&1 ) putc('\0',at->gsub);
3399 	if ( (at->gsublen+1)&2 ) putshort(at->gsub,0);
3400     }
3401     SFLigatureCleanup(sf);
3402 }
3403 
LigCaretCnt(SplineChar * sc)3404 int LigCaretCnt(SplineChar *sc) {
3405     PST *pst;
3406     int j, cnt;
3407 
3408     for ( pst=sc->possub; pst!=NULL; pst=pst->next ) {
3409 	if ( pst->type == pst_lcaret ) {
3410 	    if ( sc->lig_caret_cnt_fixed )
3411 return( pst->u.lcaret.cnt );
3412 	    else {
3413 		/* only output non-zero carets */
3414 		cnt=0;
3415 		for ( j=pst->u.lcaret.cnt-1; j>=0 ; --j )
3416 		    if ( pst->u.lcaret.carets[j]!=0 )
3417 			++cnt;
3418 return( cnt );
3419 	    }
3420 	}
3421     }
3422 return( 0 );
3423 }
3424 
DumpLigCarets(FILE * gdef,SplineChar * sc)3425 static void DumpLigCarets(FILE *gdef,SplineChar *sc) {
3426     PST *pst;
3427     int i, j, offset, cnt;
3428 
3429     for ( pst=sc->possub; pst!=NULL; pst=pst->next ) {
3430 	if ( pst->type == pst_lcaret )
3431     break;
3432     }
3433     if ( pst==NULL )
3434 return;
3435     cnt = LigCaretCnt(sc);
3436     if ( cnt==0 )
3437 return;
3438 
3439     if ( SCRightToLeft(sc) ) {
3440 	for ( i=0; i<pst->u.lcaret.cnt-1; ++i )
3441 	    for ( j=i+1; j<pst->u.lcaret.cnt; ++j )
3442 		if ( pst->u.lcaret.carets[i]<pst->u.lcaret.carets[j] ) {
3443 		    int16 temp = pst->u.lcaret.carets[i];
3444 		    pst->u.lcaret.carets[i] = pst->u.lcaret.carets[j];
3445 		    pst->u.lcaret.carets[j] = temp;
3446 		}
3447     } else {
3448 	for ( i=0; i<pst->u.lcaret.cnt-1; ++i )
3449 	    for ( j=i+1; j<pst->u.lcaret.cnt; ++j )
3450 		if ( pst->u.lcaret.carets[i]>pst->u.lcaret.carets[j] ) {
3451 		    int16 temp = pst->u.lcaret.carets[i];
3452 		    pst->u.lcaret.carets[i] = pst->u.lcaret.carets[j];
3453 		    pst->u.lcaret.carets[j] = temp;
3454 		}
3455     }
3456 
3457     putshort(gdef,cnt);			/* this many carets */
3458     offset = sizeof(uint16) + sizeof(uint16)*cnt;
3459     for ( i=0; i<cnt; ++i ) {
3460 	putshort(gdef,offset);
3461 	offset+=4;
3462     }
3463     for ( i=0; i<pst->u.lcaret.cnt; ++i ) {
3464 	if ( sc->lig_caret_cnt_fixed || pst->u.lcaret.carets[i]!=0 ) {
3465 	    putshort(gdef,1);		/* Format 1 */
3466 	    putshort(gdef,pst->u.lcaret.carets[i]);
3467 	}
3468     }
3469 }
3470 
glyphnameinlist(char * haystack,char * name)3471 static int glyphnameinlist(char *haystack,char *name) {
3472     char *start, *pt;
3473     int ch, match, slen = strlen(name);
3474 
3475     for ( pt=haystack ; ; ) {
3476 	while ( *pt==' ' ) ++pt;
3477 	if ( *pt=='\0' )
3478 return( false );
3479 	start=pt;
3480 	while ( *pt!=' ' && *pt!='\0' ) ++pt;
3481 	if ( pt-start==slen ) {
3482 	    ch = *pt; *pt='\0';
3483 	    match = strcmp(start,name);
3484 	    *pt = ch;
3485 	    if ( match==0 )
3486 return( true );
3487 	}
3488     }
3489 }
3490 
ReferencedByGSUB(SplineChar * sc)3491 static int ReferencedByGSUB(SplineChar *sc) {
3492     PST *pst;
3493     SplineFont *sf = sc->parent;
3494     int gid;
3495     SplineChar *testsc;
3496     char *name = sc->name;
3497 
3498     /* If it is itself a ligature it will be referenced by GSUB */
3499     /* (because we store ligatures on the glyph generated) */
3500     for ( pst=sc->possub; pst!=NULL; pst=pst->next )
3501 	if ( pst->type == pst_ligature )
3502 return( true );
3503 
3504     for ( gid=0; gid<sf->glyphcnt; ++gid ) if ( (testsc=sf->glyphs[gid])!=NULL ) {
3505 	for ( pst=testsc->possub; pst!=NULL; pst=pst->next ) {
3506 	    if ( pst->type==pst_substitution || pst->type==pst_alternate ||
3507 		    pst->type==pst_multiple ) {
3508 		if ( glyphnameinlist(pst->u.mult.components,name) )
3509 return( true );
3510 	    }
3511 	}
3512     }
3513 return( false );
3514 }
3515 
gdefclass(SplineChar * sc)3516 int gdefclass(SplineChar *sc) {
3517     PST *pst;
3518     AnchorPoint *ap;
3519 
3520     if ( sc->glyph_class!=0 )
3521 return( sc->glyph_class-1 );
3522 
3523     if ( strcmp(sc->name,".notdef")==0 )
3524 return( 0 );
3525 
3526     /* It isn't clear to me what should be done if a glyph is both a ligature */
3527     /*  and a mark (There are some greek accent ligatures, it is probably more*/
3528     /*  important that they be indicated as marks). Here I chose mark rather  */
3529     /*  than ligature as the mark class is far more likely to be used */
3530     ap=sc->anchor;
3531     while ( ap!=NULL && (ap->type==at_centry || ap->type==at_cexit) )
3532 	ap = ap->next;
3533     if ( ap!=NULL && (ap->type==at_mark || ap->type==at_basemark) )
3534 return( 3 );
3535 
3536     for ( pst=sc->possub; pst!=NULL; pst=pst->next ) {
3537 	if ( pst->type == pst_ligature )
3538 return( 2 );			/* Ligature */
3539     }
3540 
3541 	/* I not quite sure what a componant glyph is. Probably something */
3542 	/*  that is not in the cmap table and is referenced in other glyphs */
3543 	/* (I've never seen it used by others) */
3544 	/* (Note: No glyph in a CID font can be components as all CIDs mean */
3545 	/*  something) (I think) */
3546     if ( sc->unicodeenc==-1 && sc->dependents!=NULL &&
3547 	    sc->parent->cidmaster!=NULL && !ReferencedByGSUB(sc))
3548 return( 4 );
3549     else
3550 return( 1 );
3551 }
3552 
otf_dumpgdef(struct alltabs * at,SplineFont * sf)3553 void otf_dumpgdef(struct alltabs *at, SplineFont *sf) {
3554     /* In spite of what the open type docs say, this table does appear to be */
3555     /*  required (at least the glyph class def table) if we do mark to base */
3556     /*  positioning */
3557     /* I was wondering at the apperant contradiction: something can be both a */
3558     /*  base glyph and a ligature component, but it appears that the component*/
3559     /*  class is unused and everything is a base unless it is a ligature or */
3560     /*  mark */
3561     /* All my example fonts ignore the attachment list subtable and the mark */
3562     /*  attach class def subtable, so I shall too */
3563     /* Ah. Some indic fonts need the mark attach class subtable for greater */
3564     /*  control of lookup flags */
3565     /* All my example fonts contain a ligature caret list subtable, which is */
3566     /*  empty. Odd, but perhaps important */
3567     int i,j,k, lcnt, needsclass;
3568     int pos, offset;
3569     int cnt, start, last, lastval;
3570     SplineChar **glyphs, *sc;
3571 
3572     /* Don't look in the cidmaster if we are only dumping one subfont */
3573     if ( sf->cidmaster && sf->cidmaster->glyphs!=NULL ) sf = sf->cidmaster;
3574     else if ( sf->mm!=NULL ) sf=sf->mm->normal;
3575 
3576     glyphs = NULL;
3577     for ( k=0; k<2; ++k ) {
3578 	lcnt = 0;
3579 	needsclass = false;
3580 	for ( i=0; i<at->gi.gcnt; ++i ) if ( at->gi.bygid[i]!=-1 ) {
3581 	    SplineChar *sc = sf->glyphs[at->gi.bygid[i]];
3582 	    if ( sc->glyph_class!=0 || gdefclass(sc)!=1 )
3583 		needsclass = true;
3584 	    if ( LigCaretCnt(sc)!=0 ) {
3585 		if ( glyphs!=NULL ) glyphs[lcnt] = sc;
3586 		++lcnt;
3587 	    }
3588 	}
3589 	if ( lcnt==0 )
3590     break;
3591 	if ( glyphs!=NULL )
3592     break;
3593 	glyphs = malloc((lcnt+1)*sizeof(SplineChar *));
3594 	glyphs[lcnt] = NULL;
3595     }
3596     if ( !needsclass && lcnt==0 && sf->mark_class_cnt==0 && sf->mark_set_cnt==0 )
3597 return;					/* No anchor positioning, no ligature carets */
3598 
3599     at->gdef = GFileTmpfile();
3600     if ( sf->mark_set_cnt==0 ) {
3601 	putlong(at->gdef,0x00010000);		/* Version */
3602         putshort(at->gdef, needsclass ? 12 : 0 ); /* glyph class defn table */
3603     } else {
3604 	putlong(at->gdef,0x00010002);		/* Version with mark sets */
3605         putshort(at->gdef, needsclass ? 14 : 0 ); /* glyph class defn table */
3606     }
3607     putshort(at->gdef, 0 );			/* attachment list table */
3608     putshort(at->gdef, 0 );			/* ligature caret table (come back and fix up later) */
3609     putshort(at->gdef, 0 );			/* mark attachment class table */
3610     if ( sf->mark_set_cnt>0 ) {
3611         putshort(at->gdef, 0 );                 /* mark attachment set table only meaningful if version is 0x10002*/
3612     }
3613 
3614 	/* Glyph class subtable */
3615     if ( needsclass ) {
3616 	/* Mark shouldn't conflict with anything */
3617 	/* Ligature is more important than Base */
3618 	/* Component is not used */
3619         /* ttx can't seem to support class format type 1 so let's output type 2 */
3620 	for ( j=0; j<2; ++j ) {
3621 	    cnt = 0;
3622 	    for ( i=0; i<at->gi.gcnt; ++i ) if ( at->gi.bygid[i]!=-1 ) {
3623 		sc = sf->glyphs[at->gi.bygid[i]];
3624 		if ( sc!=NULL && sc->ttf_glyph!=-1 ) {
3625 		    lastval = gdefclass(sc);
3626 		    start = last = i;
3627 		    for ( ; i<at->gi.gcnt; ++i ) if ( at->gi.bygid[i]!=-1 ) {
3628 			sc = sf->glyphs[at->gi.bygid[i]];
3629 			if ( gdefclass(sc)!=lastval )
3630 		    break;
3631 			last = i;
3632 		    }
3633 		    --i;
3634 		    if ( lastval!=0 ) {
3635 			if ( j==1 ) {
3636 			    putshort(at->gdef,start);
3637 			    putshort(at->gdef,last);
3638 			    putshort(at->gdef,lastval);
3639 			}
3640 			++cnt;
3641 		    }
3642 		}
3643 	    }
3644 	    if ( j==0 ) {
3645 		putshort(at->gdef,2);	/* class format 2, range list by class */
3646 		putshort(at->gdef,cnt);
3647 	    }
3648 	}
3649     }
3650 
3651 	/* Ligature caret subtable. Always include this if we have a GDEF */
3652     pos = ftell(at->gdef);
3653     fseek(at->gdef,8,SEEK_SET);			/* location of lig caret table offset */
3654     putshort(at->gdef,pos);
3655     fseek(at->gdef,0,SEEK_END);
3656     if ( lcnt==0 ) {
3657 	/* It always seems to be present, even if empty */
3658 	putshort(at->gdef,4);			/* Offset to (empty) coverage table */
3659 	putshort(at->gdef,0);			/* no ligatures */
3660 	putshort(at->gdef,2);			/* coverage table format 2 */
3661 	putshort(at->gdef,0);			/* no ranges in coverage table */
3662     } else {
3663 	pos = ftell(at->gdef);	/* coverage location */
3664 	putshort(at->gdef,0);			/* Offset to coverage table (fix up later) */
3665 	putshort(at->gdef,lcnt);
3666 	offset = 2*lcnt+4;
3667 	for ( i=0; i<lcnt; ++i ) {
3668 	    putshort(at->gdef,offset);
3669 	    offset+=2+6*LigCaretCnt(glyphs[i]);
3670 	}
3671 	for ( i=0; i<lcnt; ++i )
3672 	    DumpLigCarets(at->gdef,glyphs[i]);
3673 	offset = ftell(at->gdef);
3674 	fseek(at->gdef,pos,SEEK_SET);
3675 	putshort(at->gdef,offset-pos);
3676 	fseek(at->gdef,0,SEEK_END);
3677 	dumpcoveragetable(at->gdef,glyphs);
3678     }
3679 
3680 	/* Mark Attachment Class Subtable */
3681     if ( sf->mark_class_cnt>0 ) {
3682 	uint16 *mclasses = ClassesFromNames(sf,sf->mark_classes,sf->mark_class_cnt,at->maxp.numGlyphs,NULL,false);
3683 	pos = ftell(at->gdef);
3684 	fseek(at->gdef,10,SEEK_SET);		/* location of mark attach table offset */
3685 	putshort(at->gdef,pos);
3686 	fseek(at->gdef,0,SEEK_END);
3687 	DumpClass(at->gdef,mclasses,at->maxp.numGlyphs);
3688 	free(mclasses);
3689     }
3690 
3691 	/* Mark Attachment Class Subtable */
3692     if ( sf->mark_set_cnt>0 ) {
3693 	pos = ftell(at->gdef);
3694 	fseek(at->gdef,12,SEEK_SET);		/* location of mark attach table offset */
3695 	putshort(at->gdef,pos);
3696 	fseek(at->gdef,0,SEEK_END);
3697 	putshort(at->gdef,1);			/* Version number */
3698 	putshort(at->gdef,sf->mark_set_cnt);
3699 	for ( i=0; i<sf->mark_set_cnt; ++i )
3700 	    putlong(at->gdef,0);
3701 	for ( i=0; i<sf->mark_set_cnt; ++i ) {
3702 	    int here = ftell(at->gdef);
3703 	    fseek(at->gdef,pos+4+4*i,SEEK_SET);
3704 	    putlong(at->gdef,here-pos);
3705 	    fseek(at->gdef,0,SEEK_END);
3706 	    glyphs = OrderedGlyphsFromNames(sf,sf->mark_sets[i]);
3707 	    dumpcoveragetable(at->gdef,glyphs);
3708 	    free(glyphs);
3709 	}
3710     }
3711 
3712     at->gdeflen = ftell(at->gdef);
3713     if ( at->gdeflen&1 ) putc('\0',at->gdef);
3714     if ( (at->gdeflen+1)&2 ) putshort(at->gdef,0);
3715 }
3716 
3717 /******************************************************************************/
3718 /* ******************************* MATH Table ******************************* */
3719 /* ********************** (Not strictly OpenType yet) *********************** */
3720 /******************************************************************************/
3721 enum math_bits { mb_constants=0x01, mb_italic=0x02, mb_topaccent=0x04,
3722 	mb_extended=0x08, mb_mathkern=0x10, mb_vertvariant=0x20,
3723 	mb_horizvariant=0x40,
3724 	mb_all = 0x7f,
3725 	mb_gi=(mb_italic|mb_topaccent|mb_extended|mb_mathkern),
3726 	mb_gv=(mb_vertvariant|mb_horizvariant) };
3727 
MathBits(struct alltabs * at,SplineFont * sf)3728 static int MathBits(struct alltabs *at, SplineFont *sf) {
3729     int i, gid, ret;
3730     SplineChar *sc;
3731 
3732     ret = sf->MATH ? mb_constants : 0;
3733 
3734     for ( i=0; i<at->gi.gcnt; ++i ) {
3735 	if ( (gid=at->gi.bygid[i])!=-1 && (sc=sf->glyphs[gid])!=NULL ) {
3736 	    if ( sc->italic_correction!=TEX_UNDEF )
3737 		ret |= mb_italic;
3738 	    if ( sc->top_accent_horiz!=TEX_UNDEF )
3739 		ret |= mb_topaccent;
3740 	    if ( sc->is_extended_shape )
3741 		ret |= mb_extended;
3742 	    if ( sc->mathkern!=NULL )
3743 		ret |= mb_mathkern;
3744 	    if ( sc->vert_variants!=NULL )
3745 		ret |= mb_vertvariant;
3746 	    if ( sc->horiz_variants!=NULL )
3747 		ret |= mb_horizvariant;
3748 	    if ( ret==mb_all )
3749 return( mb_all );
3750 	}
3751     }
3752 return( ret );
3753 }
3754 
ttf_math_dump_italic_top(FILE * mathf,struct alltabs * at,SplineFont * sf,int is_italic)3755 static void ttf_math_dump_italic_top(FILE *mathf,struct alltabs *at, SplineFont *sf, int is_italic) {
3756     int i, gid, len;
3757     SplineChar *sc, **glyphs;
3758     uint32 coverage_pos, coverage_table;
3759     uint32 devtab_offset;
3760     DeviceTable *devtab;
3761 
3762     /* Figure out our glyph list (and count) */
3763     for ( i=len=0; i<at->gi.gcnt; ++i )
3764 	if ( (gid=at->gi.bygid[i])!=-1 && (sc=sf->glyphs[gid])!=NULL )
3765 	    if ( (is_italic && sc->italic_correction!=TEX_UNDEF) || (!is_italic && sc->top_accent_horiz!=TEX_UNDEF))
3766 		++len;
3767     glyphs = malloc((len+1)*sizeof(SplineChar *));
3768     for ( i=len=0; i<at->gi.gcnt; ++i )
3769 	if ( (gid=at->gi.bygid[i])!=-1 && (sc=sf->glyphs[gid])!=NULL )
3770 	    if ( (is_italic && sc->italic_correction!=TEX_UNDEF) || (!is_italic && sc->top_accent_horiz!=TEX_UNDEF))
3771 		glyphs[len++] = sc;
3772     glyphs[len] = NULL;
3773 
3774     coverage_pos = ftell(mathf);
3775     putshort(mathf,0);			/* Coverage table, return to this */
3776     putshort(mathf,len);
3777     devtab_offset = 4 + 4*len;
3778     for ( i=0; i<len; ++i ) {
3779 	putshort(mathf,is_italic ? glyphs[i]->italic_correction : glyphs[i]->top_accent_horiz );
3780 	devtab = is_italic ? glyphs[i]->italic_adjusts : glyphs[i]->top_accent_adjusts;
3781 	if ( devtab!=NULL ) {
3782 	    putshort(mathf,devtab_offset);
3783 	    devtab_offset += DevTabLen(devtab);
3784 	} else
3785 	    putshort(mathf,0);
3786     }
3787     for ( i=0; i<len; ++i ) {
3788 	devtab = is_italic ? glyphs[i]->italic_adjusts : glyphs[i]->top_accent_adjusts;
3789 	if ( devtab!=NULL )
3790 	    dumpgposdevicetable(mathf,devtab);
3791     }
3792     if ( devtab_offset!=ftell(mathf)-coverage_pos )
3793 	IError("Actual end did not match expected end in %s table, expected=%d, actual=%d",
3794 		is_italic ? "italic" : "top accent", devtab_offset, ftell(mathf)-coverage_pos );
3795     coverage_table = ftell(mathf);
3796     fseek( mathf, coverage_pos, SEEK_SET);
3797     putshort(mathf,coverage_table-coverage_pos);
3798     fseek(mathf,coverage_table,SEEK_SET);
3799     dumpcoveragetable(mathf,glyphs);
3800     free(glyphs);
3801 }
3802 
ttf_math_dump_extended(FILE * mathf,struct alltabs * at,SplineFont * sf)3803 static void ttf_math_dump_extended(FILE *mathf,struct alltabs *at, SplineFont *sf) {
3804     int i, gid, len;
3805     SplineChar *sc, **glyphs;
3806 
3807     for ( i=len=0; i<at->gi.gcnt; ++i )
3808 	if ( (gid=at->gi.bygid[i])!=-1 && (sc=sf->glyphs[gid])!=NULL )
3809 	    if ( sc->is_extended_shape )
3810 		++len;
3811     glyphs = malloc((len+1)*sizeof(SplineChar *));
3812     for ( i=len=0; i<at->gi.gcnt; ++i )
3813 	if ( (gid=at->gi.bygid[i])!=-1 && (sc=sf->glyphs[gid])!=NULL )
3814 	    if ( sc->is_extended_shape )
3815 		glyphs[len++] = sc;
3816     glyphs[len] = NULL;
3817     dumpcoveragetable(mathf,glyphs);
3818     free(glyphs);
3819 }
3820 
mkv_len(struct mathkernvertex * mkv)3821 static int mkv_len(struct mathkernvertex *mkv) {
3822 return( 2+8*mkv->cnt-4 );
3823 }
3824 
ttf_math_dump_mathkernvertex(FILE * mathf,struct mathkernvertex * mkv,int devtab_pos)3825 static int ttf_math_dump_mathkernvertex(FILE *mathf,struct mathkernvertex *mkv,
3826 	int devtab_pos) {
3827     int i;
3828     uint32 here = ftell(mathf);
3829 
3830     putshort(mathf,mkv->cnt-1);
3831 
3832     for ( i=0; i<mkv->cnt-1; ++i ) {
3833 	putshort(mathf,mkv->mkd[i].height);
3834 	if ( mkv->mkd[i].height_adjusts!=NULL ) {
3835 	    putshort(mathf,devtab_pos-here);
3836 	    devtab_pos += DevTabLen(mkv->mkd[i].height_adjusts);
3837 	} else
3838 	    putshort(mathf,0);
3839     }
3840     for ( i=0; i<mkv->cnt; ++i ) {
3841 	putshort(mathf,mkv->mkd[i].kern);
3842 	if ( mkv->mkd[i].kern_adjusts!=NULL ) {
3843 	    putshort(mathf,devtab_pos-here);
3844 	    devtab_pos += DevTabLen(mkv->mkd[i].kern_adjusts);
3845 	} else
3846 	    putshort(mathf,0);
3847     }
3848 return( devtab_pos );
3849 }
3850 
ttf_math_dump_mathkerndevtab(FILE * mathf,struct mathkernvertex * mkv)3851 static void ttf_math_dump_mathkerndevtab(FILE *mathf,struct mathkernvertex *mkv) {
3852     int i;
3853 
3854     for ( i=0; i<mkv->cnt-1; ++i )
3855 	if ( mkv->mkd[i].height_adjusts!=NULL )
3856 	    dumpgposdevicetable(mathf,mkv->mkd[i].height_adjusts);
3857     for ( i=0; i<mkv->cnt; ++i )
3858 	if ( mkv->mkd[i].kern_adjusts!=NULL )
3859 	    dumpgposdevicetable(mathf,mkv->mkd[i].kern_adjusts);
3860 }
3861 
ttf_math_dump_mathkern(FILE * mathf,struct alltabs * at,SplineFont * sf)3862 static void ttf_math_dump_mathkern(FILE *mathf,struct alltabs *at, SplineFont *sf) {
3863     int i, gid, len;
3864     SplineChar *sc, **glyphs;
3865     uint32 coverage_pos, coverage_table, kr_pos, midpos2;
3866 
3867     /* Figure out our glyph list (and count) */
3868     for ( i=len=0; i<at->gi.gcnt; ++i )
3869 	if ( (gid=at->gi.bygid[i])!=-1 && (sc=sf->glyphs[gid])!=NULL )
3870 	    if ( sc->mathkern!=NULL )
3871 		++len;
3872     glyphs = malloc((len+1)*sizeof(SplineChar *));
3873     for ( i=len=0; i<at->gi.gcnt; ++i )
3874 	if ( (gid=at->gi.bygid[i])!=-1 && (sc=sf->glyphs[gid])!=NULL )
3875 	    if ( sc->mathkern!=NULL )
3876 		glyphs[len++] = sc;
3877     glyphs[len] = NULL;
3878 
3879     coverage_pos = ftell(mathf);
3880     putshort(mathf,0);			/* Coverage table, return to this */
3881     putshort(mathf,len);
3882     kr_pos = coverage_pos + 4 + 8*len;
3883     for ( i=0; i<len; ++i ) {
3884 	struct mathkern *mk = glyphs[i]->mathkern;
3885 	if ( mk->top_right.cnt==0 )
3886 	    putshort(mathf,0);
3887 	else {
3888 	    putshort(mathf,kr_pos-coverage_pos);
3889 	    kr_pos += mkv_len(&mk->top_right);
3890 	}
3891 	if ( mk->top_left.cnt==0 )
3892 	    putshort(mathf,0);
3893 	else {
3894 	    putshort(mathf,kr_pos-coverage_pos);
3895 	    kr_pos += mkv_len(&mk->top_left);
3896 	}
3897 	if ( mk->bottom_right.cnt==0 )
3898 	    putshort(mathf,0);
3899 	else {
3900 	    putshort(mathf,kr_pos-coverage_pos);
3901 	    kr_pos += mkv_len(&mk->bottom_right);
3902 	}
3903 	if ( mk->bottom_left.cnt==0 )
3904 	    putshort(mathf,0);
3905 	else {
3906 	    putshort(mathf,kr_pos-coverage_pos);
3907 	    kr_pos += mkv_len(&mk->bottom_left);
3908 	}
3909     }
3910     if ( ftell(mathf)!=coverage_pos + 4 + 8*len )
3911 	IError("Actual midpoint1 did not match expected midpoint1 in mathkern table, expected=%d, actual=%d",
3912 		coverage_pos + 4 + 8*len, ftell(mathf) );
3913 
3914     midpos2 = kr_pos;
3915     for ( i=0; i<len; ++i ) {
3916 	struct mathkern *mk = glyphs[i]->mathkern;
3917 	if ( mk->top_right.cnt!=0 )
3918 	    kr_pos = ttf_math_dump_mathkernvertex(mathf,&mk->top_right,kr_pos);
3919 	if ( mk->top_left.cnt!=0 )
3920 	    kr_pos = ttf_math_dump_mathkernvertex(mathf,&mk->top_left,kr_pos);
3921 	if ( mk->bottom_right.cnt!=0 )
3922 	    kr_pos = ttf_math_dump_mathkernvertex(mathf,&mk->bottom_right,kr_pos);
3923 	if ( mk->bottom_left.cnt!=0 )
3924 	    kr_pos = ttf_math_dump_mathkernvertex(mathf,&mk->bottom_left,kr_pos);
3925     }
3926     if ( ftell(mathf)!=midpos2)
3927 	IError("Actual midpoint2 did not match expected midpoint2 in mathkern table, expected=%d, actual=%d",
3928 		midpos2, ftell(mathf) );
3929 
3930     for ( i=0; i<len; ++i ) {
3931 	struct mathkern *mk = glyphs[i]->mathkern;
3932 	if ( mk->top_right.cnt!=0 )
3933 	    ttf_math_dump_mathkerndevtab(mathf,&mk->top_right);
3934 	if ( mk->top_left.cnt!=0 )
3935 	    ttf_math_dump_mathkerndevtab(mathf,&mk->top_left);
3936 	if ( mk->bottom_right.cnt!=0 )
3937 	    ttf_math_dump_mathkerndevtab(mathf,&mk->bottom_right);
3938 	if ( mk->bottom_left.cnt!=0 )
3939 	    ttf_math_dump_mathkerndevtab(mathf,&mk->bottom_left);
3940     }
3941     if ( kr_pos!=ftell(mathf) )
3942 	IError("Actual end did not match expected end in mathkern table, expected=%d, actual=%d",
3943 		kr_pos, ftell(mathf) );
3944 
3945     coverage_table = ftell(mathf);
3946     fseek( mathf, coverage_pos, SEEK_SET);
3947     putshort(mathf,coverage_table-coverage_pos);
3948     fseek(mathf,coverage_table,SEEK_SET);
3949     dumpcoveragetable(mathf,glyphs);
3950     free(glyphs);
3951 }
3952 
gv_len(SplineFont * sf,struct glyphvariants * gv)3953 static int gv_len(SplineFont *sf, struct glyphvariants *gv) {
3954     char *pt, *start;
3955     int ch, cnt;
3956     SplineChar *sc;
3957 
3958     if ( gv==NULL || (gv->variants==NULL && gv->part_cnt==0))
3959 return( 0 );
3960     if ( gv->variants==NULL )
3961 return( 4 );		/* No variants, but we've got parts to assemble */
3962     cnt = 0;
3963     for ( start=gv->variants ;; ) {
3964 	while ( *start==' ' ) ++start;
3965 	if ( *start=='\0' )
3966 return( 4+4*cnt );		/* MathGlyphConstructionTable */
3967 	for ( pt = start ; *pt!=' ' && *pt!='\0'; ++pt );
3968 	ch = *pt; *pt = '\0';
3969 	sc = SFGetChar(sf,-1,start);
3970 	*pt = ch;
3971 	if ( sc!=NULL )
3972 	    ++cnt;
3973 	start = pt;
3974     }
3975 }
3976 
gvc_len(struct glyphvariants * gv)3977 static int gvc_len(struct glyphvariants *gv) {
3978     if ( gv->part_cnt==0 )
3979 return( 0 );
3980 
3981 return( 6+10*gv->part_cnt );
3982 }
3983 
ttf_math_dump_mathglyphconstructiontable(FILE * mathf,struct glyphvariants * gv,SplineFont * sf,uint32 pos,int is_v)3984 static uint32 ttf_math_dump_mathglyphconstructiontable(FILE *mathf,
3985 	struct glyphvariants *gv,SplineFont *sf, uint32 pos,int is_v) {
3986     char *pt, *start;
3987     int ch, cnt;
3988     SplineChar *sc;
3989     uint32 here = ftell(mathf);
3990     DBounds b;
3991 
3992     putshort(mathf,gv->part_cnt==0? 0 : pos-here);
3993     if ( gv->variants==NULL ) {
3994 	putshort(mathf,0);
3995     } else {
3996 	cnt = 0;
3997 	for ( start=gv->variants ;; ) {
3998 	    while ( *start==' ' ) ++start;
3999 	    if ( *start=='\0' )
4000 	break;
4001 	    for ( pt = start ; *pt!=' ' && *pt!='\0'; ++pt );
4002 	    ch = *pt; *pt = '\0';
4003 	    sc = SFGetChar(sf,-1,start);
4004 	    *pt = ch;
4005 	    if ( sc!=NULL )
4006 		++cnt;
4007 	    start = pt;
4008 	}
4009 	putshort(mathf,cnt);
4010 	for ( start=gv->variants ;; ) {
4011 	    while ( *start==' ' ) ++start;
4012 	    if ( *start=='\0' )
4013 	break;
4014 	    for ( pt = start ; *pt!=' ' && *pt!='\0'; ++pt );
4015 	    ch = *pt; *pt = '\0';
4016 	    sc = SFGetChar(sf,-1,start);
4017 	    *pt = ch;
4018 	    if ( sc!=NULL ) {
4019 		putshort(mathf,sc->ttf_glyph);
4020 		SplineCharFindBounds(sc,&b);
4021 		/* Don't ask me why I have a plus one here. In the MS font */
4022 		/*  CambriaMath all of these values are one more than I would */
4023 		/*  expect */
4024 		if ( is_v )
4025 		    putshort(mathf,b.maxy-b.miny +1);
4026 		else
4027 		    putshort(mathf,b.maxx-b.minx +1);
4028 	    }
4029 	    start=pt;
4030 	}
4031     }
4032 return( pos + gvc_len(gv));
4033 }
4034 
ttf_math_dump_mathglyphassemblytable(FILE * mathf,struct glyphvariants * gv,SplineFont * sf,uint32 devtab_pos)4035 static uint32 ttf_math_dump_mathglyphassemblytable(FILE *mathf,
4036 	struct glyphvariants *gv,SplineFont *sf, uint32 devtab_pos) {
4037     SplineChar *sc;
4038     uint32 here = ftell(mathf);
4039     int i;
4040 
4041     if ( gv->part_cnt==0 )
4042 return( devtab_pos );
4043     putshort(mathf,gv->italic_correction);
4044     if ( gv->italic_adjusts!=NULL ) {
4045 	putshort(mathf,devtab_pos-here);
4046 	devtab_pos += DevTabLen(gv->italic_adjusts);
4047     } else
4048 	putshort(mathf,0);
4049     putshort(mathf,gv->part_cnt);
4050     for ( i=0; i<gv->part_cnt; ++i ) {
4051 	sc = SFGetChar(sf,-1,gv->parts[i].component);
4052 	if ( sc==NULL )
4053 	    putshort(mathf,0);		/* .notdef */
4054 	else
4055 	    putshort(mathf,sc->ttf_glyph);
4056 	putshort(mathf,gv->parts[i].startConnectorLength);
4057 	putshort(mathf,gv->parts[i].endConnectorLength);
4058 	putshort(mathf,gv->parts[i].fullAdvance);
4059 	putshort(mathf,gv->parts[i].is_extender);
4060     }
4061 return(devtab_pos);
4062 }
4063 
ttf_math_dump_glyphvariant(FILE * mathf,struct alltabs * at,SplineFont * sf)4064 static void ttf_math_dump_glyphvariant(FILE *mathf,struct alltabs *at, SplineFont *sf) {
4065     int i, gid, vlen, hlen;
4066     SplineChar *sc, **vglyphs, **hglyphs;
4067     uint32 coverage_pos, coverage_table, offset, pos, assembly_pos;
4068 
4069     /* Figure out our glyph list (and count) */
4070     for ( i=vlen=hlen=0; i<at->gi.gcnt; ++i )
4071 	if ( (gid=at->gi.bygid[i])!=-1 && (sc=sf->glyphs[gid])!=NULL ) {
4072 	    if ( sc->vert_variants!=NULL )
4073 		++vlen;
4074 	    if ( sc->horiz_variants!=NULL )
4075 		++hlen;
4076 	}
4077 
4078     vglyphs = malloc((vlen+1)*sizeof(SplineChar *));
4079     hglyphs = malloc((hlen+1)*sizeof(SplineChar *));
4080     for ( i=vlen=hlen=0; i<at->gi.gcnt; ++i )
4081 	if ( (gid=at->gi.bygid[i])!=-1 && (sc=sf->glyphs[gid])!=NULL ) {
4082 	    if ( sc->vert_variants!=NULL )
4083 		vglyphs[vlen++] = sc;
4084 	    if ( sc->horiz_variants!=NULL )
4085 		hglyphs[hlen++] = sc;
4086 	}
4087     vglyphs[vlen] = NULL;
4088     hglyphs[hlen] = NULL;
4089 
4090     putshort(mathf,sf->MATH==NULL?(sf->ascent+sf->descent)/50 : sf->MATH->MinConnectorOverlap );
4091     coverage_pos = ftell(mathf);
4092     putshort(mathf,0);			/* Vertical Coverage table, return to this */
4093     putshort(mathf,0);			/* Horizontal Coverage table, return to this */
4094     putshort(mathf,vlen);
4095     putshort(mathf,hlen);
4096     offset = 5*2+vlen*2+hlen*2;
4097     for ( i=0; i<vlen; ++i ) {
4098 	putshort(mathf,offset);
4099 	offset += gv_len(sf,vglyphs[i]->vert_variants);
4100     }
4101     for ( i=0; i<hlen; ++i ) {
4102 	putshort(mathf,offset);
4103 	offset += gv_len(sf,hglyphs[i]->horiz_variants);
4104     }
4105     assembly_pos = pos = (coverage_pos-2)+offset;
4106     for ( i=0; i<vlen; ++i ) {
4107 	/*uint32 start = ftell(mathf);*/
4108 	pos = ttf_math_dump_mathglyphconstructiontable(mathf,
4109 		vglyphs[i]->vert_variants,sf,pos,true);
4110 	/*if ( ftell(mathf)-start != gv_len(sf,vglyphs[i]->vert_variants))*/
4111 	    /*IError("v gv_len incorrect");*/
4112     }
4113     for ( i=0; i<hlen; ++i ) {
4114 	/*uint32 start = ftell(mathf);*/
4115 	pos = ttf_math_dump_mathglyphconstructiontable(mathf,
4116 		hglyphs[i]->horiz_variants,sf,pos,false);
4117 	/*if ( ftell(mathf)-start != gv_len(sf,hglyphs[i]->horiz_variants))*/
4118 	    /*IError("h gv_len incorrect: %s", hglyphs[i]->name);*/
4119     }
4120     if ( ftell(mathf)!=assembly_pos )
4121 	IError("assembly tables at wrong place");
4122 
4123     for ( i=0; i<vlen; ++i )
4124 	pos = ttf_math_dump_mathglyphassemblytable(mathf,
4125 		vglyphs[i]->vert_variants,sf,pos);
4126     for ( i=0; i<hlen; ++i )
4127 	pos = ttf_math_dump_mathglyphassemblytable(mathf,
4128 		hglyphs[i]->horiz_variants,sf,pos);
4129     for ( i=0; i<vlen; ++i )
4130 	if ( vglyphs[i]->vert_variants->part_cnt!=0 &&
4131 		vglyphs[i]->vert_variants->italic_adjusts!=NULL )
4132 	    dumpgposdevicetable(mathf,vglyphs[i]->vert_variants->italic_adjusts);
4133     for ( i=0; i<hlen; ++i )
4134 	if ( hglyphs[i]->horiz_variants->part_cnt!=0 &&
4135 		hglyphs[i]->horiz_variants->italic_adjusts!=NULL )
4136 	    dumpgposdevicetable(mathf,hglyphs[i]->horiz_variants->italic_adjusts);
4137     if ( vlen!=0 ) {
4138 	coverage_table = ftell(mathf);
4139 	fseek( mathf, coverage_pos, SEEK_SET);
4140 	putshort(mathf,coverage_table-(coverage_pos-2));
4141 	fseek(mathf,coverage_table,SEEK_SET);
4142 	dumpcoveragetable(mathf,vglyphs);
4143     }
4144     free(vglyphs);
4145     if ( hlen!=0 ) {
4146 	coverage_table = ftell(mathf);
4147 	fseek( mathf, coverage_pos+2, SEEK_SET);
4148 	putshort(mathf,coverage_table-(coverage_pos-2));
4149 	fseek(mathf,coverage_table,SEEK_SET);
4150 	dumpcoveragetable(mathf,hglyphs);
4151     }
4152     free(hglyphs);
4153 }
4154 
otf_dump_math(struct alltabs * at,SplineFont * sf)4155 void otf_dump_math(struct alltabs *at, SplineFont *sf) {
4156     FILE *mathf;
4157     struct MATH *math;
4158     int i;
4159     uint32 devtab_offsets[60], const_start, gi_start, v_start;
4160     int bits = MathBits(at,sf);
4161 
4162     if ( sf->MATH!=NULL )
4163 	math = sf->MATH;
4164     else if ( bits!=0 )
4165 	math = MathTableNew(sf);
4166     else
4167 	return;
4168 
4169     at->math = mathf = GFileTmpfile();
4170 
4171     putlong(mathf,  0x00010000 );		/* Version 1 */
4172     putshort(mathf, 10);			/* Offset to constants */
4173     putshort(mathf,  0);			/* GlyphInfo, fix later */
4174     putshort(mathf,  0);			/* Variants, fix later */
4175 
4176     /* Start on constants */
4177     memset(devtab_offsets,0,sizeof(devtab_offsets));
4178     const_start = ftell(mathf);
4179     for ( i=0; math_constants_descriptor[i].script_name!=NULL; ++i ) {
4180 	int16 *pos = (int16 *) (((char *) math) + math_constants_descriptor[i].offset );
4181 	if ( pos == (int16 *) &math->MinConnectorOverlap )
4182     continue;		/* Actually lives in the Variant table, not here */
4183 	putshort(mathf, *pos);
4184 	if ( math_constants_descriptor[i].devtab_offset != -1 ) {
4185 	    devtab_offsets[i] = ftell(mathf);
4186 	    putshort(mathf, 0);		/* Fix up later if we support device tables */
4187 	}
4188     }
4189     for ( i=0; math_constants_descriptor[i].script_name!=NULL; ++i ) {
4190 	int16 *pos = (int16 *) (((char *) math) + math_constants_descriptor[i].offset );
4191 	DeviceTable **devtab = (DeviceTable **) (((char *) math) + math_constants_descriptor[i].devtab_offset );
4192 	if ( pos == (int16 *) &math->MinConnectorOverlap )
4193     continue;		/* Actually lives in the Variant table, not here */
4194 	if ( math_constants_descriptor[i].devtab_offset >= 0 && *devtab!=NULL ) {
4195 	    uint32 here = ftell(mathf);
4196 	    fseek(mathf,devtab_offsets[i],SEEK_SET);
4197 	    putshort(mathf, here-const_start);
4198 	    fseek(mathf,here,SEEK_SET);
4199 	    dumpgposdevicetable(mathf,*devtab);
4200 	}
4201     }
4202 
4203     /* The spec does not say this can be NULL */
4204     if ( 1 /* bits&mb_gi*/ ) {
4205 	gi_start = ftell(mathf);
4206 	fseek(mathf,6,SEEK_SET);
4207 	putshort(mathf,gi_start);
4208 	fseek(mathf,gi_start,SEEK_SET);
4209 
4210 	putshort(mathf,0);		/* Italics correction */
4211 	putshort(mathf,0);		/* top accent */
4212 	putshort(mathf,0);		/* is extended shape */
4213 	putshort(mathf,0);		/* math kern info */
4214 
4215 	if ( bits&mb_italic ) {
4216 	    v_start = ftell(mathf);
4217 	    fseek(mathf,gi_start,SEEK_SET);
4218 	    putshort(mathf,v_start-gi_start);
4219 	    fseek(mathf,v_start,SEEK_SET);
4220 
4221 	    ttf_math_dump_italic_top(mathf,at,sf,true);
4222 	}
4223 
4224 	if ( bits&mb_topaccent ) {
4225 	    v_start = ftell(mathf);
4226 	    fseek(mathf,gi_start+2,SEEK_SET);
4227 	    putshort(mathf,v_start-gi_start);
4228 	    fseek(mathf,v_start,SEEK_SET);
4229 
4230 	    ttf_math_dump_italic_top(mathf,at,sf,false);
4231 	}
4232 
4233 	if ( bits&mb_extended ) {
4234 	    v_start = ftell(mathf);
4235 	    fseek(mathf,gi_start+4,SEEK_SET);
4236 	    putshort(mathf,v_start-gi_start);
4237 	    fseek(mathf,v_start,SEEK_SET);
4238 
4239 	    ttf_math_dump_extended(mathf,at,sf);
4240 	}
4241 
4242 	if ( bits&mb_mathkern ) {
4243 	    v_start = ftell(mathf);
4244 	    fseek(mathf,gi_start+6,SEEK_SET);
4245 	    putshort(mathf,v_start-gi_start);
4246 	    fseek(mathf,v_start,SEEK_SET);
4247 
4248 	    ttf_math_dump_mathkern(mathf,at,sf);
4249 	}
4250     }
4251 
4252     /* The spec does not say this can be NULL */
4253     if ( 1 /* bits&mb_gv*/ ) {
4254 	v_start = ftell(mathf);
4255 	fseek(mathf,8,SEEK_SET);
4256 	putshort(mathf,v_start);
4257 	fseek(mathf,v_start,SEEK_SET);
4258 
4259 	ttf_math_dump_glyphvariant(mathf,at,sf);
4260     }
4261 
4262     at->mathlen = ftell(mathf);
4263     if ( ftell(mathf)&1 )
4264 	putc('\0',mathf);
4265     if ( ftell(mathf)&2 )
4266 	putshort(mathf,0);
4267 
4268     if ( sf->MATH==NULL )
4269 	free(math);
4270 }
4271 
4272 struct taglist {
4273     uint32 tag;
4274     struct taglist *next;
4275 };
4276 
taglistcompar(const void * _cv1,const void * _cv2)4277 static int taglistcompar(const void *_cv1, const void *_cv2) {
4278     const struct taglist *const *tl1 = _cv1, *const *tl2 = _cv2;
4279 
4280     if ( (*tl1)->tag==(*tl2)->tag )
4281 return( 0 );
4282     if ( (*tl1)->tag>(*tl2)->tag )
4283 return( 1 );
4284 
4285 return( -1 );
4286 }
4287 
langlistcompar(const void * _cv1,const void * _cv2)4288 static int langlistcompar(const void *_cv1, const void *_cv2) {
4289     const struct taglist *const *tl1 = _cv1, *const *tl2 = _cv2;
4290 
4291     if ( (*tl1)->tag==(*tl2)->tag )
4292 return( 0 );
4293     if ( (*tl1)->tag == DEFAULT_LANG )
4294 return( -1 );
4295     if ( (*tl2)->tag == DEFAULT_LANG )
4296 return( 1 );
4297     if ( (*tl1)->tag>(*tl2)->tag )
4298 return( 1 );
4299 
4300 return( -1 );
4301 }
4302 
sorttaglist(struct taglist * list,int (* compar)(const void *,const void *))4303 static struct taglist *sorttaglist(struct taglist *list,int (*compar)(const void *,const void*)) {
4304     struct taglist *t, **array;
4305     int i,cnt;
4306 
4307     if ( list==NULL || list->next==NULL )
4308 return( list );
4309 
4310     for ( t=list, cnt=0; t!=NULL; t=t->next, ++cnt );
4311     array = malloc(cnt*sizeof(struct taglist *));
4312     for ( t=list, cnt=0; t!=NULL; t=t->next, ++cnt )
4313 	array[cnt] = t;
4314     qsort(array,cnt,sizeof(struct taglist *),compar);
4315     for ( i=1; i<cnt; ++i )
4316 	array[i-1]->next = array[i];
4317     array[cnt-1]->next = NULL;
4318     list = array[0];
4319     free( array );
4320 return( list );
4321 }
4322 
_base_sort(struct Base * base)4323 static void _base_sort(struct Base *base) {
4324     /* Sort the base lines. Which can reorder the def_baseline index in the */
4325     /*  script, and the baseline_pos lists */
4326     /* Sort the script list */
4327     /* Sort the language lists in each script */
4328     /* Sort the feature lists in each language */
4329     int i,j,pos, tag;
4330     struct basescript *bs;
4331     struct baselangextent *langs;
4332 
4333     if ( base==NULL )
4334 return;
4335 
4336     if ( base->baseline_cnt!=0 ) {
4337 	for ( i=0; i<base->baseline_cnt; ++i )
4338 	    for ( j=i+1; j<base->baseline_cnt; ++j ) {
4339 		if ( base->baseline_tags[i]>base->baseline_tags[j] ) {
4340 		    tag = base->baseline_tags[i];
4341 		    base->baseline_tags[i] = base->baseline_tags[j];
4342 		    base->baseline_tags[j] = tag;
4343 		    for ( bs=base->scripts ; bs!=NULL; bs=bs->next ) {
4344 			if ( bs->def_baseline==i )
4345 			    bs->def_baseline = j;
4346 			else if ( bs->def_baseline==j )
4347 			    bs->def_baseline = i;
4348 			pos = bs->baseline_pos[i];
4349 			bs->baseline_pos[i] = bs->baseline_pos[j];
4350 			bs->baseline_pos[j] = pos;
4351 		    }
4352 		}
4353 	    }
4354     }
4355     base->scripts = (struct basescript *) sorttaglist((struct taglist *) base->scripts,taglistcompar);
4356     for ( bs=base->scripts ; bs!=NULL; bs=bs->next ) {
4357 	bs->langs = (struct baselangextent *) sorttaglist((struct taglist *) bs->langs,langlistcompar);
4358 	for ( langs = bs->langs; langs!=NULL; langs = langs->next )
4359 	    langs->features = (struct baselangextent *) sorttaglist((struct taglist *) langs->features,taglistcompar);
4360     }
4361 }
4362 
SFBaseSort(SplineFont * sf)4363 void SFBaseSort(SplineFont *sf) {
4364     _base_sort(sf->horiz_base);
4365     _base_sort(sf->vert_base);
4366 }
4367 
dump_minmax(FILE * basef,struct baselangextent * bl)4368 static void dump_minmax(FILE *basef,struct baselangextent *bl) {
4369     struct baselangextent *fl;
4370     int fcnt;
4371 
4372     putshort(basef,bl->descent);
4373     putshort(basef,bl->ascent);
4374     for ( fl=bl->features, fcnt=0; fl!=NULL; fl=fl->next, ++fcnt );
4375     putshort(basef,fcnt);
4376     for ( fl=bl->features; fl!=NULL; fl=fl->next ) {
4377 	putlong(basef,fl->lang);	/* feature tag really */
4378 	putshort(basef,fl->descent);
4379 	putshort(basef,fl->ascent);
4380     }
4381 }
4382 
otf_dumpbase(struct alltabs * at,SplineFont * sf)4383 void otf_dumpbase(struct alltabs *at, SplineFont *sf) {
4384     FILE *basef;
4385     int i,j, cnt, lcnt;
4386     uint32 here, bsl;
4387     struct basescript *bs;
4388     struct baselangextent *bl, *dflt;
4389     int offset;
4390 
4391     if ( sf->horiz_base==NULL && sf->vert_base==NULL )
4392 return;
4393 
4394     SFBaseSort(sf);
4395 
4396     at->base = basef = GFileTmpfile();
4397 
4398     putlong(basef,  0x00010000 );		/* Version 1 */
4399     putshort(basef,  0 );			/* offset to horizontal baselines, fill in later */
4400     putshort(basef,  0 );			/* offset to vertical baselines, fill in later */
4401 
4402     for ( i=0; i<2; ++i ) {
4403 	struct Base *base = i==0 ? sf->horiz_base : sf->vert_base;
4404 	if ( base==NULL )
4405     continue;
4406 	here = ftell(basef);
4407 	fseek(basef,4+2*i,SEEK_SET);
4408 	putshort(basef,here-0);
4409 	fseek(basef,here,SEEK_SET);
4410 
4411 	/* axis table */
4412 	putshort(basef,base->baseline_cnt==0 ? 0 : 4 );
4413 	putshort(basef,base->baseline_cnt==0 ? 4 :
4414 			4+2+4*base->baseline_cnt );
4415 
4416 	if ( base->baseline_cnt!=0 ) {
4417 	/* BaseTagList table */
4418 	    putshort(basef,base->baseline_cnt);
4419 	    for ( j=0; j<base->baseline_cnt; ++j )
4420 		putlong(basef,base->baseline_tags[j]);
4421 	}
4422 
4423 	/* BaseScriptList table */
4424 	bsl = ftell(basef);
4425 	for ( bs=base->scripts, cnt=0; bs!=NULL; bs=bs->next, ++cnt );
4426 	putshort(basef,cnt);
4427 	for ( bs=base->scripts; bs!=NULL; bs=bs->next ) {
4428 	    putlong(basef,bs->script);
4429 	    putshort(basef,0);
4430 	}
4431 
4432 	/* BaseScript table */
4433 	for ( bs=base->scripts, cnt=0; bs!=NULL; bs=bs->next, ++cnt ) {
4434 	    uint32 bst = ftell(basef);
4435 	    fseek(basef,bsl+2+6*cnt+4,SEEK_SET);
4436 	    putshort(basef,bst-bsl);
4437 	    fseek(basef,bst,SEEK_SET);
4438 
4439 	    for ( bl=bs->langs, dflt=NULL, lcnt=0; bl!=NULL; bl=bl->next ) {
4440 		if ( bl->lang==DEFAULT_LANG )
4441 		    dflt = bl;
4442 		else
4443 		    ++lcnt;
4444 	    }
4445 	    offset = 6+6*lcnt;
4446 	    putshort(basef,base->baseline_cnt==0?0:offset);
4447 	    if ( base->baseline_cnt!=0 )
4448 		offset += 4+2*base->baseline_cnt+4*base->baseline_cnt;
4449 	    putshort(basef,dflt==NULL ? 0 : offset);
4450 	    putshort(basef,lcnt);
4451 	    for ( bl=bs->langs; bl!=NULL; bl=bl->next ) if ( bl->lang!=DEFAULT_LANG ) {
4452 		putlong(basef,bl->lang);
4453 		putshort(basef,0);
4454 	    }
4455 
4456 	    /* Base Values table */
4457 	    if ( base->baseline_cnt!=0 ) {
4458 		offset = 4+2*base->baseline_cnt;
4459 		putshort(basef,bs->def_baseline);
4460 		putshort(basef,base->baseline_cnt);
4461 		for ( j=0; j<base->baseline_cnt; ++j ) {
4462 		    putshort(basef,offset);
4463 		    offset += 2*2;
4464 		}
4465 		for ( j=0; j<base->baseline_cnt; ++j ) {
4466 		    putshort(basef,1);		/* format 1 */
4467 		    putshort(basef,bs->baseline_pos[j]);
4468 		}
4469 	    }
4470 
4471 	    if ( dflt!=NULL )
4472 		dump_minmax(basef,dflt);
4473 	    for ( bl=bs->langs, dflt=NULL, lcnt=0; bl!=NULL; bl=bl->next ) if ( bl->lang!=DEFAULT_LANG ) {
4474 		uint32 here = ftell(basef);
4475 		fseek(basef,bst+6+6*lcnt+4,SEEK_SET);
4476 		putshort(basef,here-bst);
4477 		fseek(basef,here,SEEK_SET);
4478 		dump_minmax(basef,bl);
4479 	    }
4480 	}
4481     }
4482 
4483     at->baselen = ftell(basef);
4484     if ( ftell(basef)&1 )
4485 	putc('\0',basef);
4486     if ( ftell(basef)&2 )
4487 	putshort(basef,0);
4488 }
4489 
jscriptsort(const void * _s1,const void * _s2)4490 static int jscriptsort(const void *_s1,const void *_s2) {
4491     const Justify * const * __s1 = (const Justify * const *) _s1;
4492     const Justify * const * __s2 = (const Justify * const *) _s2;
4493     const Justify *s1 = *__s1;
4494     const Justify *s2 = *__s2;
4495 
4496     if ( s1->script>s2->script )
4497 return( 1 );
4498     else if ( s1->script<s2->script )
4499 return( -1 );
4500     else
4501 return( 0 );
4502 }
4503 
jlangsort(const void * _s1,const void * _s2)4504 static int jlangsort(const void *_s1,const void *_s2) {
4505     const struct jstf_lang * const * __s1 = (const struct jstf_lang * const *) _s1;
4506     const struct jstf_lang * const * __s2 = (const struct jstf_lang * const *) _s2;
4507     const struct jstf_lang *s1 = *__s1;
4508     const struct jstf_lang *s2 = *__s2;
4509 
4510     if ( s1->lang==s2->lang )
4511 return( 0 );
4512 
4513     if ( s1->lang==DEFAULT_LANG )
4514 return( -1 );
4515     if ( s2->lang==DEFAULT_LANG )
4516 return( 1 );
4517 
4518     if ( s1->lang>s2->lang )
4519 return( 1 );
4520     else
4521 return( -1 );
4522 }
4523 
lookup_order(const void * _s1,const void * _s2)4524 static int lookup_order(const void *_s1,const void *_s2) {
4525     const OTLookup * const * __s1 = (const OTLookup * const *) _s1;
4526     const OTLookup * const * __s2 = (const OTLookup * const *) _s2;
4527     const OTLookup *s1 = *__s1;
4528     const OTLookup *s2 = *__s2;
4529 
4530     if ( s1->lookup_index>s2->lookup_index )
4531 return( 1 );
4532     else if ( s1->lookup_index<s2->lookup_index )
4533 return( -1 );
4534     else
4535 return( 0 );
4536 }
4537 
SFJstfSort(SplineFont * sf)4538 static void SFJstfSort(SplineFont *sf) {
4539     /* scripts must be ordered */
4540     /* languages must be ordered within scripts */
4541     /* lookup lists must be ordered */
4542     Justify *jscript, **scripts;
4543     int i,cnt,lmax;
4544     struct jstf_lang **langs;
4545 
4546     for ( cnt=0, jscript= sf->justify; jscript!=NULL; ++cnt, jscript=jscript->next );
4547     if ( cnt>1 ) {
4548 	scripts = malloc(cnt*sizeof(Justify *));
4549 	for ( i=0, jscript= sf->justify; jscript!=NULL; ++i, jscript=jscript->next )
4550 	    scripts[i] = jscript;
4551 	qsort(scripts,cnt,sizeof(Justify *),jscriptsort);
4552 	for ( i=1; i<cnt; ++i )
4553 	    scripts[i-1]->next = scripts[i];
4554 	scripts[cnt-1]->next = NULL;
4555 	sf->justify = scripts[0];
4556 	free(scripts);
4557     }
4558 
4559     langs = NULL; lmax=0;
4560     for ( jscript= sf->justify; jscript!=NULL; jscript=jscript->next ) {
4561 	struct jstf_lang *jlang;
4562 	for ( cnt=0, jlang=jscript->langs; jlang!=NULL; ++cnt, jlang=jlang->next );
4563 	if ( cnt>1 ) {
4564 	    if ( cnt>lmax )
4565 		langs = realloc(langs,(lmax=cnt+10)*sizeof(struct jstf_lang *));
4566 	    for ( i=0, jlang=jscript->langs; jlang!=NULL; ++i, jlang=jlang->next )
4567 		langs[i] = jlang;
4568 	    qsort(langs,cnt,sizeof(Justify *),jlangsort);
4569 	    for ( i=1; i<cnt; ++i )
4570 		langs[i-1]->next = langs[i];
4571 	    langs[cnt-1]->next = NULL;
4572 	    jscript->langs = langs[0];
4573 	}
4574     }
4575     free(langs);
4576 
4577     /* don't bother to sort the lookup lists yet. We need to separate them into*/
4578     /* GPOS/GSUB first, might as well do it all at once later */
4579 }
4580 
jstf_SplitTables(OTLookup ** mixed,OTLookup *** _SUB,OTLookup *** _POS)4581 static void jstf_SplitTables(OTLookup **mixed,OTLookup ***_SUB,OTLookup ***_POS) {
4582     /* (later is now, see comment above) */
4583     /* mixed contains both gsub and gpos lookups. put them into their own */
4584     /* lists, and then sort them */
4585     int cnt, s, p;
4586     OTLookup **SUB, **POS;
4587 
4588     if ( mixed==NULL || mixed[0]==NULL ) {
4589 	*_SUB = NULL;
4590 	*_POS = NULL;
4591 return;
4592     }
4593 
4594     for ( cnt=0; mixed[cnt]!=NULL; ++cnt);
4595     SUB = malloc((cnt+1)*sizeof(OTLookup *));
4596     POS = malloc((cnt+1)*sizeof(OTLookup *));
4597     for ( cnt=s=p=0; mixed[cnt]!=NULL; ++cnt) {
4598 	if ( mixed[cnt]->lookup_index==-1 )		/* Not actually used */
4599     continue;
4600 	if ( mixed[cnt]->lookup_type>=gpos_start )
4601 	    POS[p++] = mixed[cnt];
4602 	else
4603 	    SUB[s++] = mixed[cnt];
4604     }
4605     POS[p] = SUB[s] = NULL;
4606 
4607     if ( p>1 )
4608 	qsort(POS,p,sizeof(OTLookup *),lookup_order);
4609     if ( s>1 )
4610 	qsort(SUB,s,sizeof(OTLookup *),lookup_order);
4611     if ( p==0 ) {
4612 	free(POS);
4613 	POS=NULL;
4614     }
4615     if ( s==0 ) {
4616 	free(SUB);
4617 	SUB=NULL;
4618     }
4619     *_SUB = SUB;
4620     *_POS = POS;
4621 }
4622 
jstf_dumplklist(FILE * jstf,OTLookup ** PS,uint32 base)4623 static uint32 jstf_dumplklist(FILE *jstf,OTLookup **PS,uint32 base) {
4624     uint32 here;
4625     int i;
4626 
4627     if ( PS==NULL )
4628 return( 0 );
4629 
4630     here = ftell(jstf);
4631     for ( i=0; PS[i]!=NULL; ++i );
4632     putshort(jstf,i);			/* Lookup cnt */
4633     for ( i=0; PS[i]!=NULL; ++i )
4634 	putshort( jstf, PS[i]->lookup_index );
4635     free(PS);
4636 return( here - base );
4637 }
4638 
jstf_dumpmaxlookups(FILE * jstf,SplineFont * sf,struct alltabs * at,OTLookup ** maxes,uint32 base)4639 static uint32 jstf_dumpmaxlookups(FILE *jstf,SplineFont *sf,struct alltabs *at,
4640 	OTLookup **maxes,uint32 base) {
4641     uint32 here, lbase;
4642     int cnt,i;
4643     int scnt, j;
4644     struct lookup_subtable *sub;
4645 
4646     if ( maxes==NULL )
4647 return( 0 );
4648 
4649     for ( cnt=i=0; maxes[i]!=NULL; ++i )
4650 	if ( !maxes[i]->unused )
4651 	    ++cnt;
4652     if ( cnt==0 )
4653 return( 0 );
4654 
4655     if ( (here=ftell(jstf))<0 )
4656 return( 0 );
4657 
4658     putshort( jstf,cnt );
4659     for ( i=0; maxes[i]!=NULL; ++i ) if ( !maxes[i]->unused )
4660 	putshort( jstf,0 );
4661     for ( cnt=i=0; maxes[i]!=NULL; ++i ) if ( !maxes[i]->unused ) {
4662 	if ( (lbase=ftell(jstf))<0 )
4663 return( 0 );
4664 	fseek(jstf,here+2+2*cnt,SEEK_SET);
4665 	putshort(jstf,lbase-here);
4666 	fseek(jstf,lbase,SEEK_SET);
4667 
4668 	putshort(jstf,maxes[i]->lookup_type - gpos_start );
4669 	putshort(jstf,maxes[i]->lookup_flags);
4670 
4671 	for ( scnt=0, sub=maxes[i]->subtables; sub!=NULL; sub=sub->next )
4672 	    if ( !sub->unused )
4673 		++scnt;
4674 	putshort( jstf,scnt );
4675 	for ( j=0; j<scnt; ++j )
4676 	    putshort( jstf,0 );
4677 	/* I don't think extension lookups get a MarkAttachmentType, I guess */
4678 	/*  that inherits from the parent? */
4679 
4680 	otf_dumpALookup(jstf, maxes[i], sf, at);
4681 	fseek(jstf,lbase+6,SEEK_SET);
4682 	for ( sub=maxes[i]->subtables; sub!=NULL; sub=sub->next )
4683 	    if ( !sub->unused )
4684 		putshort(jstf,sub->subtable_offset-lbase);
4685 	++cnt;
4686     }
4687 
4688 return( here - base );
4689 }
4690 
otf_dumpjstf(struct alltabs * at,SplineFont * sf)4691 void otf_dumpjstf(struct alltabs *at, SplineFont *sf) {
4692     FILE *jstf;
4693     int i, cnt, lcnt, offset;
4694     uint32 here, base;
4695     Justify *jscript;
4696     struct jstf_lang *jlang;
4697 
4698     if ( sf->justify==NULL )
4699 return;
4700 
4701     SFJstfSort(sf);
4702     for ( jscript=sf->justify, cnt=0; jscript!=NULL; jscript=jscript->next, ++cnt );
4703 
4704     at->jstf = jstf = GFileTmpfile();
4705 
4706     putlong(jstf,  0x00010000 );		/* Version 1 */
4707     putshort(jstf, cnt );			/* script count */
4708     for ( jscript=sf->justify; jscript!=NULL; jscript=jscript->next ) {
4709 	putlong(jstf, jscript->script);
4710 	putshort(jstf, 0);			/* Come back to this later */
4711     }
4712     for ( jscript=sf->justify, cnt=0; jscript!=NULL; jscript=jscript->next, ++cnt ) {
4713 	base = ftell(jstf);
4714 	if ( base>0xffff )
4715 	    ff_post_error(_("Failure"),_("Offset in JSTF table is too big. The resultant font will not work."));
4716 	fseek(jstf, 6+6*cnt+4,SEEK_SET);
4717 	putshort(jstf,base);
4718 	fseek(jstf, base, SEEK_SET);
4719 
4720 	putshort(jstf,0);		/* extender glyphs */
4721 	putshort(jstf,0);		/* default lang */
4722 	for ( jlang=jscript->langs, lcnt=0; jlang!=NULL; jlang=jlang->next, ++lcnt );
4723 	if ( lcnt>0 && jscript->langs->lang==DEFAULT_LANG )
4724 	    --lcnt;
4725 	putshort(jstf,lcnt);		/* count of non-default languages */
4726 	jlang = jscript->langs;
4727 	if ( jlang!=NULL && jlang->lang==DEFAULT_LANG )
4728 	    jlang=jlang->next;
4729 	for ( ; jlang!=NULL; jlang=jlang->next ) {
4730 	    putlong(jstf, jlang->lang);
4731 	    putshort(jstf, 0);			/* Come back to this later */
4732 	}
4733 
4734 	if ( jscript->extenders!=NULL ) {
4735 	    SplineChar **glyphs;
4736 	    int gcnt,g;
4737 
4738 	    here = ftell(jstf);
4739 	    fseek(jstf,base,SEEK_SET);
4740 	    putshort(jstf,here-base);
4741 	    fseek(jstf,here,SEEK_SET);
4742 
4743 	    glyphs = OrderedGlyphsFromNames(sf,jscript->extenders);
4744 	    if ( glyphs==NULL )
4745 		gcnt=0;
4746 	    else
4747 		for ( gcnt=0; glyphs[gcnt]!=NULL; ++gcnt);
4748 	    putshort(jstf,gcnt);
4749 	    for ( g=0; g<gcnt; ++g )
4750 		putshort(jstf,glyphs[g]->ttf_glyph);
4751 	    free(glyphs);
4752 	}
4753 
4754 	offset=0;
4755 	for ( jlang=jscript->langs, lcnt=0; jlang!=NULL; jlang=jlang->next, ++lcnt ) {
4756 	    here = ftell(jstf);
4757 	    if ( jlang->lang==DEFAULT_LANG ) {
4758 		fseek(jstf,base+2,SEEK_SET);
4759 		offset = -6;
4760 	    } else
4761 		fseek(jstf,base+offset+10+lcnt*6,SEEK_SET);
4762 	    putshort(jstf,here-base);
4763 	    fseek(jstf,here,SEEK_SET);
4764 
4765 	    putshort(jstf,jlang->cnt);
4766 	    for ( i=0; i<jlang->cnt; ++i )
4767 		putshort(jstf,0);
4768 	    for ( i=0; i<jlang->cnt; ++i ) {
4769 		OTLookup **enSUB, **enPOS, **disSUB, **disPOS;
4770 		uint32 enSUBoff, enPOSoff, disSUBoff, disPOSoff, maxOff;
4771 		uint32 pbase;
4772 		pbase = ftell(jstf);
4773 		fseek(jstf,here+2+i*2,SEEK_SET);
4774 		putshort(jstf,pbase-here);
4775 		fseek(jstf,pbase,SEEK_SET);
4776 
4777 		putshort(jstf,0);
4778 		putshort(jstf,0);
4779 		putshort(jstf,0);
4780 		putshort(jstf,0);
4781 		putshort(jstf,0);
4782 		putshort(jstf,0);
4783 		putshort(jstf,0);
4784 		putshort(jstf,0);
4785 		putshort(jstf,0);
4786 		putshort(jstf,0);
4787 
4788 		jstf_SplitTables(jlang->prios[i].enableShrink,&enSUB,&enPOS);
4789 		jstf_SplitTables(jlang->prios[i].disableShrink,&disSUB,&disPOS);
4790 		enSUBoff = jstf_dumplklist(jstf,enSUB,  pbase);
4791 		disSUBoff = jstf_dumplklist(jstf,disSUB,pbase);
4792 		enPOSoff = jstf_dumplklist(jstf,enPOS,  pbase);
4793 		disPOSoff = jstf_dumplklist(jstf,disPOS,pbase);
4794 		maxOff = jstf_dumpmaxlookups(jstf,sf,at,jlang->prios[i].maxShrink,pbase);
4795 
4796 		fseek(jstf,pbase,SEEK_SET);
4797 		putshort(jstf,enSUBoff);
4798 		putshort(jstf,disSUBoff);
4799 		putshort(jstf,enPOSoff);
4800 		putshort(jstf,disPOSoff);
4801 		putshort(jstf,maxOff);
4802 
4803 		fseek(jstf,0,SEEK_END);
4804 		jstf_SplitTables(jlang->prios[i].enableExtend,&enSUB,&enPOS);
4805 		jstf_SplitTables(jlang->prios[i].disableExtend,&disSUB,&disPOS);
4806 		enSUBoff = jstf_dumplklist(jstf,enSUB,  pbase);
4807 		disSUBoff = jstf_dumplklist(jstf,disSUB,pbase);
4808 		enPOSoff = jstf_dumplklist(jstf,enPOS,  pbase);
4809 		disPOSoff = jstf_dumplklist(jstf,disPOS,pbase);
4810 		maxOff = jstf_dumpmaxlookups(jstf,sf,at,jlang->prios[i].maxExtend,pbase);
4811 
4812 		fseek(jstf,pbase+10,SEEK_SET);
4813 		putshort(jstf,enSUBoff);
4814 		putshort(jstf,disSUBoff);
4815 		putshort(jstf,enPOSoff);
4816 		putshort(jstf,disPOSoff);
4817 		putshort(jstf,maxOff);
4818 		fseek(jstf,0,SEEK_END);
4819 	    }
4820 	}
4821     }
4822 
4823     fseek(jstf,0,SEEK_END);
4824     at->jstflen = ftell(jstf);
4825     if ( ftell(jstf)&1 )
4826 	putc('\0',jstf);
4827     if ( ftell(jstf)&2 )
4828 	putshort(jstf,0);
4829 }
4830 
otf_dump_dummydsig(struct alltabs * at,SplineFont * sf)4831 void otf_dump_dummydsig(struct alltabs *at, SplineFont *sf) {
4832     FILE *dsigf;
4833 
4834     /* I think the DSIG table is a big crock. At best the most it can do is */
4835     /*  tell you that the font hasn't changed since it was signed. It gives */
4836     /*  no guarantee that the data are reasonable. I think it's stupid. */
4837     /* I think it is even more stupid that MS choses this useless table as a*/
4838     /*  mark of whether a ttf font is OpenType or not. */
4839     /* But users want their fonts to show up as OpenType under MS. And I'm  */
4840     /*  told an empty DSIG table works for that. So... a truely pointless   */
4841     /*  instance of a pointless table. I suppose that's a bit ironic. */
4842 
4843     at->dsigf = dsigf = GFileTmpfile();
4844     putlong(dsigf,0x00000001);		/* Standard version (and why isn't it 0x10000 like everything else?) */
4845     putshort(dsigf,0);			/* No signatures in my signature table*/
4846     putshort(dsigf,0);			/* No flags */
4847 
4848     at->dsiglen = ftell(dsigf);
4849     if ( ftell(dsigf)&1 )
4850 	putc('\0',dsigf);
4851     if ( ftell(dsigf)&2 )
4852 	putshort(dsigf,0);
4853 }
4854