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