w32tex
About: TeX Live provides a comprehensive TeX system including all the major TeX-related programs, macro packages, and fonts that are free software. Windows sources.
  Fossies Dox: w32tex-src.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

tottfgpos.c
Go to the documentation of this file.
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 #include "fontforgevw.h"
28 #include <utype.h>
29 
32 
33 #include "ttf.h"
34 
35 /* This file contains routines to create the otf gpos and gsub tables and their */
36 /* attendant subtables */
37 
38 /* Undocumented fact: ATM (which does kerning for otf fonts in Word) can't handle features with multiple lookups */
39 
40 /* Undocumented fact: Only one feature with a given tag allowed per script/lang */
41 /* So if we have multiple lookups with the same tag they must be merged into */
42 /* one feature with many lookups */
43 
44 /* scripts (for opentype) that I understand */
45  /* see also list in lookups.c mapping script tags to friendly names */
46 
47 static uint32 scripts[][15] = {
48 /* Arabic */ { CHR('a','r','a','b'), 0x0600, 0x06ff, 0xfb50, 0xfdff, 0xfe70, 0xfefe },
49 /* Aramaic */ { CHR('a','r','a','m'), 0x820, 0x83f },
50 /* Armenian */ { CHR('a','r','m','n'), 0x0530, 0x058f, 0xfb13, 0xfb17 },
51 /* Balinese */ { CHR('b','a','l','i'), 0x1b00, 0x1b7f },
52 /* Bengali */ { CHR('b','e','n','g'), 0x0980, 0x09ff },
53 /* Bliss symb */{ CHR('b','l','i','s'), 0x12200, 0x124ff },
54 /* Bopomofo */ { CHR('b','o','p','o'), 0x3100, 0x312f, 0x31a0, 0x31bf },
55 /* Braille */ { CHR('b','r','a','i'), 0x2800, 0x28ff },
56 /* Buginese */ { CHR('b','u','g','i'), 0x1a00, 0x1a1f },
57 /* Buhid */ { CHR('b','u','h','d'), 0x1740, 0x1753 },
58 /* Byzantine M*/{ CHR('b','y','z','m'), 0x1d000, 0x1d0ff },
59 /* Canadian Syl*/{CHR('c','a','n','s'), 0x1400, 0x167f },
60 /* Carian */ {CHR('c','a','r','i'), 0x0, 0x0 },
61 /* Cham */ {CHR('c','h','a','m'), 0x0, 0x0 },
62 /* Cherokee */ { CHR('c','h','e','r'), 0x13a0, 0x13ff },
63 /* Cirth */ { CHR('c','i','r','t'), 0x12080, 0x120ff },
64 /* CJKIdeogra */{ CHR('h','a','n','i'), 0x3300, 0x9fff, 0xf900, 0xfaff, 0x020000, 0x02ffff },
65 /* Coptic */ { CHR('c','o','p','t'), 0x2c80, 0x2cff },
66 /* Cypriot */ { CHR('c','p','m','n'), 0x10800, 0x1083f },
67 /* Cyrillic */ { CHR('c','y','r','l'), 0x0400, 0x052f, 0x1d2b, 0x1d2b, 0x1d78, 0x1d78,
68  0x2de0, 0x2dff, 0xa640, 0xa6ff },
69 /* Deseret */ { CHR('d','s','r','t'), 0x10400, 0x1044f },
70 /* Devanagari */{ CHR('d','e','v','a'), 0x0900, 0x097f },
71 /* Ethiopic */ { CHR('e','t','h','i'), 0x1200, 0x139f },
72 /* Georgian */ { CHR('g','e','o','r'), 0x1080, 0x10ff },
73 /* Glagolitic */{ CHR('g','l','a','g'), 0x1080, 0x10ff },
74 /* Gothic */ { CHR('g','o','t','h'), 0x10330, 0x1034a },
75 /* Greek */ { CHR('g','r','e','k'), 0x0370, 0x03ff, 0x1f00, 0x1fff },
76 /* Gujarati */ { CHR('g','u','j','r'), 0x0a80, 0x0aff },
77 /* Gurmukhi */ { CHR('g','u','r','u'), 0x0a00, 0x0a7f },
78 /* Hangul */ { CHR('h','a','n','g'), 0xac00, 0xd7af, 0x3130, 0x319f, 0xffa0, 0xff9f },
79 /* Hanunoo */ { CHR('h','a','n','o'), 0x1720, 0x1734 },
80  /* I'm not sure what the difference is between the 'hang' tag and the 'jamo' */
81  /* tag. 'Jamo' is said to be the precomposed forms, but what's 'hang'? */
82 /* Hebrew */ { CHR('h','e','b','r'), 0x0590, 0x05ff, 0xfb1e, 0xfb4f },
83 /* Hiragana used to have its own tag 'hira', but has since been merged with katakana */
84 /* Hangul Jamo*/{ CHR('j','a','m','o'), 0x1100, 0x11ff, 0x3130, 0x319f, 0xffa0, 0xffdf },
85 /* Javanese */ { CHR('j','a','v','a'), 0 }, /* MS has a tag, but there is no unicode range */
86 /* Katakana */ { CHR('k','a','n','a'), 0x3040, 0x30ff, 0xff60, 0xff9f },
87 /* Kayah Li */ { CHR('k','a','l','i'), 0 },
88 /* Kannada */ { CHR('k','n','d','a'), 0x0c80, 0x0cff },
89 /* Kharosthi */ { CHR('k','h','a','r'), 0x10a00, 0x10a5f },
90 /* Khmer */ { CHR('k','h','m','r'), 0x1780, 0x17ff },
91 /* Latin */ { CHR('l','a','t','n'), 0x0041, 0x005a, 0x0061, 0x007a,
92  0x00c0, 0x02af, 0x1d00, 0x1eff, 0xfb00, 0xfb0f, 0xff00, 0xff5f, 0xa770, 0xa7ff },
93 /* Lao */ { CHR('l','a','o',' '), 0x0e80, 0x0eff },
94 /* Lepcha */ { CHR('l','e','p','c'), 0 },
95 /* Limbu */ { CHR('l','i','m','b'), 0x1900, 0x194f },
96 /* Linear A */ /*{ CHR('l','i','n','a'), 0x10180, 0x102cf },*/ /* What happened to linear A? */
97 /* Linear B */ { CHR('l','i','n','b'), 0x10000, 0x100fa },
98 /* Lycian */ { CHR('l','y','c','i'), 0 },
99 /* Lydian */ { CHR('l','y','d','i'), 0 },
100 /* Malayalam */ { CHR('m','l','y','m'), 0x0d00, 0x0d7f },
101 /* Mathematical Alphanumeric Symbols */
102  { CHR('m','a','t','h'), 0x1d400, 0x1d7ff },
103 /* Mongolian */ { CHR('m','o','n','g'), 0x1800, 0x18af },
104 /* Musical */ { CHR('m','u','s','c'), 0x1d100, 0x1d1ff },
105 /* Myanmar */ { CHR('m','y','m','r'), 0x1000, 0x107f },
106 /* New Tai Lue*/{ CHR('t','a','l','u'), 0 },
107 /* N'Ko */ { CHR('n','k','o',' '), 0x07c0, 0x07fa },
108 /* Ogham */ { CHR('o','g','a','m'), 0x1680, 0x169f },
109 /* Ol Chiki */ { CHR('o','l','c','k'), 0 },
110 /* Old Italic */{ CHR('i','t','a','l'), 0x10300, 0x1031e },
111 /* Old Permic */{ CHR('p','e','r','m'), 0x10350, 0x1037f },
112 /* Old Persian cuneiform */
113  { CHR('x','p','e','o'), 0x103a0, 0x103df },
114 /* Oriya */ { CHR('o','r','y','a'), 0x0b00, 0x0b7f },
115 /* Osmanya */ { CHR('o','s','m','a'), 0x10480, 0x104a9 },
116 /* Phags-pa */ { CHR('p','h','a','g'), 0xa840, 0xa87f },
117 /* Phoenician */{ CHR('p','h','n','x'), 0x10900, 0x1091f },
118 /* Pollard */ { CHR('p','l','r','d'), 0x104b0, 0x104d9 },
119 /* Rejang */ { CHR('r','j','n','g'), 0 },
120 /* Rongorongo */{ CHR('r','o','r','o'), 0 },
121 /* Runic */ { CHR('r','u','n','r'), 0x16a0, 0x16ff },
122 /* Saurashtra*/ { CHR('s','a','u','r'), 0 },
123 /* Shavian */ { CHR('s','h','a','w'), 0x10450, 0x1047f },
124 /* Sinhala */ { CHR('s','i','n','h'), 0x0d80, 0x0dff },
125 /* Sumero-Akkadian Cuneiform */
126  { CHR('x','s','u','x'), 0x12000, 0x1236e },
127 /* Sundanese */ { CHR('s','u','n','d'), 0 },
128 /* Syloti Nagri */
129  { CHR('s','y','l','o'), 0xa800, 0xa82f },
130 /* Syriac */ { CHR('s','y','r','c'), 0x0700, 0x074f },
131 /* Tagalog */ { CHR('t','a','g','l'), 0x1700, 0x1714 },
132 /* Tagbanwa */ { CHR('t','a','g','b'), 0x1760, 0x1773 },
133 /* Tai Le */ { CHR('t','a','l','e'), 0x1950, 0x1974 },
134 /* Tai Lu */ { CHR('t','a','l','u'), 0x1980, 0x19df },
135 /* Tamil */ { CHR('t','a','m','l'), 0x0b80, 0x0bff },
136 /* Telugu */ { CHR('t','e','l','u'), 0x0c00, 0x0c7f },
137 /* Tengwar */ { CHR('t','e','n','g'), 0x12000, 0x1207f },
138 /* Thaana */ { CHR('t','h','a','a'), 0x0780, 0x07bf },
139 /* Thai */ { CHR('t','h','a','i'), 0x0e00, 0x0e7f },
140 /* Tibetan */ { CHR('t','i','b','t'), 0x0f00, 0x0fff },
141 /* Tifinagh */ { CHR('t','f','n','g'), 0x2d30, 0x2d7f },
142 /* Ugaritic */ { CHR('u','g','a','r'), 0x10380, 0x1039d },
143 /* Yi */ { CHR('y','i',' ',' '), 0xa000, 0xa4c6 },
144  { 0 }
145 };
146 
148 
150  if ( script==CHR('a','r','a','b') || script==CHR('h','e','b','r') ||
151  script==CHR('c','p','m','n') || script==CHR('k','h','a','r') ||
152  script==CHR('s','y','r','c') || script==CHR('t','h','a','a') ||
153  script==CHR('n','k','o',' '))
154 return( true );
155 
156 return( false );
157 }
158 
160  int s, k;
161 
162  if ( (int32)u!=-1 ) {
163  for ( s=0; scripts[s][0]!=0; ++s ) {
164  for ( k=1; scripts[s][k+1]!=0; k += 2 )
165  if ( u>=scripts[s][k] && u<=scripts[s][k+1] )
166  break;
167  if ( scripts[s][k+1]!=0 )
168  break;
169  }
170  if ( scripts[s][0]!=0 ) {
171  uint32 script = scripts[s][0];
172  if ( use_second_indic_scripts ) {
173  /* MS has a parallel set of script tags for their new */
174  /* Indic font shaper */
175  if ( script == CHR('b','e','n','g' )) script = CHR('b','n','g','2');
176  else if ( script == CHR('d','e','v','a' )) script = CHR('d','e','v','2');
177  else if ( script == CHR('g','u','j','r' )) script = CHR('g','j','r','2');
178  else if ( script == CHR('g','u','r','u' )) script = CHR('g','u','r','2');
179  else if ( script == CHR('k','n','d','a' )) script = CHR('k','n','d','2');
180  else if ( script == CHR('m','l','y','m' )) script = CHR('m','l','m','2');
181  else if ( script == CHR('o','r','y','a' )) script = CHR('o','r','y','2');
182  else if ( script == CHR('t','a','m','l' )) script = CHR('t','m','l','2');
183  else if ( script == CHR('t','e','l','u' )) script = CHR('t','e','l','2');
184  }
185 return( script );
186  }
187  } else if ( sf!=NULL ) {
188  if ( sf->cidmaster!=NULL || sf->subfontcnt!=0 ) {
189  if ( sf->cidmaster!=NULL ) sf = sf->cidmaster;
190  if ( strmatch(sf->ordering,"Identity")==0 )
191 return( DEFAULT_SCRIPT );
192  else if ( strmatch(sf->ordering,"Korean")==0 )
193 return( CHR('h','a','n','g'));
194  else
195 return( CHR('h','a','n','i') );
196  }
197  }
198 
199 return( DEFAULT_SCRIPT );
200 }
201 
203  const char *pt;
204  PST *pst;
205  SplineFont *sf;
206  int i; unsigned uni;
208 
209  if ( sc==NULL )
210 return( DEFAULT_SCRIPT );
211 
212  sf = sc->parent;
213  if ( sc->unicodeenc!=-1 &&
214  !(sc->unicodeenc>=0xe000 && sc->unicodeenc<0xf8ff) &&
215  !(sc->unicodeenc>=0xf0000 && sc->unicodeenc<0x10ffff))
216 return( ScriptFromUnicode( sc->unicodeenc,sf ));
217 
218  pt = sc->name;
219  if ( *pt ) for ( ++pt; *pt!='\0' && *pt!='_' && *pt!='.'; ++pt );
220  if ( *pt!='\0' ) {
221  char *str = copyn(sc->name,pt-sc->name);
222  int uni = UniFromName(str,ui_none,&custom);
223  free(str);
224  if ( uni!=-1 )
225 return( ScriptFromUnicode( uni,sf ));
226  }
227  /* Adobe ligature uniXXXXXXXX */
228  if ( strncmp(sc->name,"uni",3)==0 && sscanf(sc->name+3,"%4x", &uni)==1 )
229 return( ScriptFromUnicode( uni,sf ));
230 
231  if ( sf==NULL )
232 return( DEFAULT_SCRIPT );
233 
234  if ( sf->cidmaster ) sf=sf->cidmaster;
235  else if ( sf->mm!=NULL ) sf=sf->mm->normal;
236  for ( i=0; i<2; ++i ) {
237  for ( pst=sc->possub; pst!=NULL; pst=pst->next ) {
238  if ( pst->type == pst_lcaret )
239  continue;
240  for ( features = pst->subtable->lookup->features; features!=NULL; features=features->next ) {
241  if ( features->scripts!=NULL )
242 return( features->scripts->script );
243  }
244  }
245  }
246 return( ScriptFromUnicode( sc->unicodeenc,sf ));
247 }
248 
250 
251  if ( sc->unicodeenc>=0x10800 && sc->unicodeenc<=0x10fff )
252 return( true ); /* Supplemental Multilingual Plane, RTL scripts */
253  if ( sc->unicodeenc!=-1 && sc->unicodeenc<0x10000 )
254 return( isrighttoleft(sc->unicodeenc ));
255 
257 }
258 
259 static void GlyphMapFree(SplineChar ***map) {
260  int i;
261 
262  if ( map==NULL )
263  return;
264  for ( i=0; map[i]!=NULL; ++i )
265  free(map[i]);
266  free(map);
267 }
268 
270  SplineChar *spc[30], **space = spc;
271  int max = sizeof(spc)/sizeof(spc[0]);
272  int cnt=0;
273  char *pt, *start;
274  SplineChar *subssc, **ret;
275  PST *pst;
276 
277  for ( pst=sc->possub; pst!=NULL; pst=pst->next ) {
278  if ( pst->subtable==sub ) {
279  pt = pst->u.subs.variant;
280  while ( 1 ) {
281  while ( *pt==' ' ) ++pt; // Burn leading spaces.
282  // Start tokenizing the space-delimited list of references.
283  start = pt; // Note the beginning of the current item.
284  pt = strchr(start,' '); // Find the end of the current item.
285  if ( pt!=NULL )
286  *pt = '\0'; // Temporarily terminate the item.
287  subssc = SFGetChar(sc->parent,-1,start); // Find the corresponding SplineChar.
288  if ( subssc!=NULL && subssc->ttf_glyph!=-1 ) {
289  // Extend the list if necessary.
290  if ( cnt>=max ) {
291  if ( spc==space ) {
292  space = malloc((max+=30)*sizeof(SplineChar *));
293  memcpy(space,spc,(max-30)*sizeof(SplineChar *));
294  } else
295  space = realloc(space,(max+=30)*sizeof(SplineChar *));
296  }
297  // Write the SplineChar to the list.
298  space[cnt++] = subssc;
299  }
300  if ( pt==NULL )
301  break; // No more items.
302  *pt=' '; // Repair the string from the tokenization process.
303  }
304  }
305  }
306  // Returning NULL causes problems and seems to be unnecessary for now.
307  ret = malloc((cnt+1)*sizeof(SplineChar *));
308  memcpy(ret,space,cnt*sizeof(SplineChar *));
309  ret[cnt] = NULL;
310  if ( space!=spc )
311  free(space); // Free the temp space only if it is dynamically allocated.
312  return( ret );
313 }
314 
316  int cnt;
317  SplineChar *sc;
318  int i;
319  SplineChar ***maps=NULL;
320 
321  for ( cnt=0; glyphs[cnt]!=NULL; ++cnt );
322  maps = malloc((cnt+1)*sizeof(SplineChar **));
323  for ( i=0; i<cnt; ++i ) {
324  sc = glyphs[i];
325  maps[i] = FindSubs(sc,sub);
326  if (maps[i] == NULL) {
327  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) ;
328  }
329  }
330  maps[cnt] = NULL;
331 return( maps );
332 }
333 
334 void AnchorClassDecompose(SplineFont *sf,AnchorClass *_ac, int classcnt, int *subcnts,
335  SplineChar ***marks,SplineChar ***base,
336  SplineChar ***lig,SplineChar ***mkmk,
337  struct glyphinfo *gi) {
338  /* Run through the font finding all characters with this anchor class */
339  /* (and the cnt-1 classes after it) */
340  /* and distributing in the four possible anchor types */
341  int i,j,k,gid, gmax;
342  struct sclist { int cnt; SplineChar **glyphs; } heads[at_max];
343  AnchorPoint *test;
344  AnchorClass *ac;
345 
346  memset(heads,0,sizeof(heads));
347  memset(subcnts,0,classcnt*sizeof(int));
348  memset(marks,0,classcnt*sizeof(SplineChar **));
349  gmax = gi==NULL ? sf->glyphcnt : gi->gcnt;
350  for ( j=0; j<2; ++j ) {
351  for ( i=0; i<gmax; ++i ) if ( (gid = gi==NULL ? i : gi->bygid[i])!=-1 && gid < sf->glyphcnt && sf->glyphs[gid]!=NULL ) {
352  for ( ac = _ac, k=0; k<classcnt; ac=ac->next ) if ( ac->matches ) {
353  for ( test=sf->glyphs[gid]->anchor; test!=NULL ; test=test->next ) {
354  if ( test->anchor==ac ) {
355  if ( test->type==at_mark ) {
356  if ( j )
357  marks[k][subcnts[k]] = sf->glyphs[gid];
358  ++subcnts[k];
359  if ( ac->type!=act_mkmk )
360  break;
361  } else if ( test->type!=at_centry && test->type!=at_cexit ) {
362  if ( heads[test->type].glyphs!=NULL ) {
363  /* If we have multiple mark classes, we may use the same base glyph */
364  /* with more than one mark class. But it should only appear once in */
365  /* the output */
366  if ( heads[test->type].cnt==0 ||
367  heads[test->type].glyphs[heads[test->type].cnt-1]!=sf->glyphs[gid] ) {
368  heads[test->type].glyphs[heads[test->type].cnt] = sf->glyphs[gid];
369  ++heads[test->type].cnt;
370  }
371  } else
372  ++heads[test->type].cnt;
373  if ( ac->type!=act_mkmk )
374  break;
375  }
376  }
377  }
378  ++k;
379  }
380  }
381  if ( j==1 )
382  break;
383  for ( i=0; i<4; ++i )
384  if ( heads[i].cnt!=0 ) {
385  heads[i].glyphs = malloc((heads[i].cnt+1)*sizeof(SplineChar *));
386  /* I used to set glyphs[cnt] to NULL here. But it turns out */
387  /* cnt may be an overestimate on the first pass. So we can */
388  /* only set it at the end of the second pass */
389  heads[i].cnt = 0;
390  }
391  for ( k=0; k<classcnt; ++k ) if ( subcnts[k]!=0 ) {
392  marks[k] = malloc((subcnts[k]+1)*sizeof(SplineChar *));
393  marks[k][subcnts[k]] = NULL;
394  subcnts[k] = 0;
395  }
396  }
397  for ( i=0; i<4; ++i ) {
398  if ( heads[i].glyphs!=NULL )
399  heads[i].glyphs[heads[i].cnt] = NULL;
400  }
401  for ( i=0; i<classcnt; ++i ) {
402  if ( subcnts[k]!=0 )
403  SFOrderedGlyphs(marks[i]);
404  }
405 
408  *mkmk = SFOrderedGlyphs(heads[at_basemark].glyphs);
409 }
410 
412  /* Run through the font finding all characters with this anchor class */
413  int i,j, cnt, gmax, gid;
414  SplineChar **array;
415  AnchorPoint *test;
416 
417  array=NULL;
418  gmax = gi==NULL ? sf->glyphcnt : gi->gcnt;
419  for ( j=0; j<2; ++j ) {
420  cnt = 0;
421  for ( i=0; i<gmax; ++i ) if ( (gid = gi==NULL ? i : gi->bygid[i])!=-1 && sf->glyphs[gid]!=NULL ) {
422  for ( test=sf->glyphs[gid]->anchor; test!=NULL && test->anchor!=ac; test=test->next );
423  if ( test!=NULL && (test->type==at_centry || test->type==at_cexit )) {
424  if ( array!=NULL )
425  array[cnt] = sf->glyphs[gid];
426  ++cnt;
427  }
428  }
429  if ( cnt==0 )
430 return( NULL );
431  if ( j==1 )
432  break;
433  array = malloc((cnt+1)*sizeof(SplineChar *));
434  array[cnt] = NULL;
435  }
436 return( array );
437 }
438 
439 static void AnchorGuessContext(SplineFont *sf,struct alltabs *at) {
440  int i;
441  int maxbase=0, maxmark=0, basec, markc;
442  AnchorPoint *ap;
443  int hascursive = 0;
444 
445  /* the order in which we examine the glyphs does not matter here, so */
446  /* we needn't add the complexity running though in gid order */
447  for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i] ) {
448  basec = markc = 0;
449  for ( ap = sf->glyphs[i]->anchor; ap!=NULL; ap=ap->next )
450  if ( ap->type==at_basemark )
451  ++markc;
452  else if ( ap->type==at_basechar || ap->type==at_baselig )
453  ++basec;
454  else if ( ap->type==at_centry )
455  hascursive = true;
456  if ( basec>maxbase ) maxbase = basec;
457  if ( markc>maxmark ) maxmark = markc;
458  }
459 
460  if ( maxbase*(maxmark+1)>at->os2.maxContext )
461  at->os2.maxContext = maxbase*(maxmark+1);
462  if ( hascursive && at->os2.maxContext<2 )
463  at->os2.maxContext=2;
464 }
465 
466 static void dumpcoveragetable(FILE *gpos,SplineChar **glyphs) {
467  int i, last = -2, range_cnt=0, start, r;
468  /* the glyph list should already be sorted */
469  /* figure out whether it is better (smaller) to use an array of glyph ids */
470  /* or a set of glyph id ranges */
471 
472  for ( i=0; glyphs[i]!=NULL; ++i ) {
473  if ( glyphs[i]->ttf_glyph<=last )
474  IError("Glyphs must be ordered when creating coverage table");
475  if ( glyphs[i]->ttf_glyph!=last+1 )
476  ++range_cnt;
477  last = glyphs[i]->ttf_glyph;
478  }
479  /* I think Windows will only accept format 2 coverage tables? */
480  if ( !(coverageformatsallowed&2) || ((coverageformatsallowed&1) && i<=3*range_cnt )) {
481  /* We use less space with a list of glyphs than with a set of ranges */
482  putshort(gpos,1); /* Coverage format=1 => glyph list */
483  putshort(gpos,i); /* count of glyphs */
484  for ( i=0; glyphs[i]!=NULL; ++i )
485  putshort(gpos,glyphs[i]->ttf_glyph); /* array of glyph IDs */
486  } else {
487  putshort(gpos,2); /* Coverage format=2 => range list */
488  putshort(gpos,range_cnt); /* count of ranges */
489  last = -2; start = -2; /* start is a index in our glyph array, last is ttf_glyph */
490  r = 0;
491  for ( i=0; glyphs[i]!=NULL; ++i ) {
492  if ( glyphs[i]->ttf_glyph!=last+1 ) {
493  if ( last!=-2 ) {
494  putshort(gpos,glyphs[start]->ttf_glyph); /* start glyph ID */
495  putshort(gpos,last); /* end glyph ID */
496  putshort(gpos,start); /* coverage index of start glyph */
497  ++r;
498  }
499  start = i;
500  }
501  last = glyphs[i]->ttf_glyph;
502  }
503  if ( last!=-2 ) {
504  putshort(gpos,glyphs[start]->ttf_glyph); /* start glyph ID */
505  putshort(gpos,last); /* end glyph ID */
506  putshort(gpos,start); /* coverage index of start glyph */
507  ++r;
508  }
509  if ( r!=range_cnt )
510  IError("Miscounted ranges in format 2 coverage table output");
511  }
512 }
513 
514 static int sc_ttf_order( const void *_sc1, const void *_sc2) {
515  const SplineChar *sc1 = *(const SplineChar **) _sc1, *sc2 = *(const SplineChar **) _sc2;
516 return( sc1->ttf_glyph - sc2->ttf_glyph );
517 }
518 
520  int cnt, i, k;
521  if ( glyphs==NULL )
522 return( NULL );
523  for ( cnt=0; glyphs[cnt]!=NULL; ++cnt);
525  if ( glyphs[0]->ttf_glyph==-1 ) {
526  /* Not sure if this can happen, but it's easy to fix */
527  for ( k=0; k<cnt && glyphs[k]->ttf_glyph==-1; ++k);
528  for ( i=0; i<=cnt-k; ++i )
529  glyphs[i] = glyphs[i+k];
530  }
531  for ( i=0; i<cnt-1; ++i )
532  if (glyphs[i]->ttf_glyph==glyphs[i+1]->ttf_glyph) {
533  memmove(glyphs+i, glyphs+i+1, (cnt-i)*sizeof(SplineChar *));
534  --cnt;
535  }
536 return( glyphs );
537 }
538 
541  return SFOrderedGlyphs(glyphs);
542 }
543 
545  int cnt, ch;
546  char *pt, *end;
547  SplineChar *sc, **glyphs;
548 
549  if ( names==NULL )
550 return( calloc(1,sizeof(SplineChar *)) );
551 
552  cnt = 0;
553  for ( pt = names; *pt; pt = end+1 ) {
554  ++cnt;
555  end = strchr(pt,' ');
556  if ( end==NULL )
557  break;
558  }
559 
560  glyphs = malloc((cnt+1)*sizeof(SplineChar *));
561  cnt = 0;
562  for ( pt = names; *pt; pt = end+1 ) {
563  end = strchr(pt,' ');
564  if ( end==NULL )
565  end = pt+strlen(pt);
566  ch = *end;
567  *end = '\0';
568  sc = SFGetChar(sf,-1,pt);
569  if ( sc!=NULL && sc->ttf_glyph!=-1 )
570  glyphs[cnt++] = sc;
571  *end = ch;
572  if ( ch=='\0' )
573  break;
574  }
575  glyphs[cnt] = NULL;
576 return( glyphs );
577 }
578 
581  int i,j;
582 
583  if ( glyphs==NULL || glyphs[0]==NULL )
584 return( glyphs );
585 
586  for ( i=0; glyphs[i+1]!=NULL; ++i ) for ( j=i+1; glyphs[j]!=NULL; ++j ) {
587  if ( glyphs[i]->ttf_glyph > glyphs[j]->ttf_glyph ) {
588  SplineChar *sc = glyphs[i];
589  glyphs[i] = glyphs[j];
590  glyphs[j] = sc;
591  }
592  }
593  if ( glyphs[0]!=NULL ) { /* Glyphs should not appear twice in the name list, just just in case they do... */
594  for ( i=0; glyphs[i+1]!=NULL; ++i ) {
595  if ( glyphs[i]==glyphs[i+1] ) {
596  for ( j=i+1; glyphs[j]!=NULL; ++j )
597  glyphs[j] = glyphs[j+1];
598  }
599  }
600  }
601 return( glyphs );
602 }
603 
604 static void gposvrmaskeddump(FILE *gpos,int vf1,int mask,int offset) {
605  if ( vf1&1 ) putshort(gpos,mask&1 ? offset : 0 );
606  if ( vf1&2 ) putshort(gpos,mask&2 ? offset : 0 );
607  if ( vf1&4 ) putshort(gpos,mask&4 ? offset : 0 );
608  if ( vf1&8 ) putshort(gpos,mask&8 ? offset : 0 );
609 }
610 
611 static int devtaboffsetsize(DeviceTable *dt) {
612  int type = 1, i;
613 
614  for ( i=dt->last_pixel_size-dt->first_pixel_size; i>=0; --i ) {
615  if ( dt->corrections[i]>=8 || dt->corrections[i]<-8 )
616 return( 3 );
617  else if ( dt->corrections[i]>=2 || dt->corrections[i]<-2 )
618  type = 2;
619  }
620 return( type );
621 }
622 
623 static void dumpgposdevicetable(FILE *gpos,DeviceTable *dt) {
624  int type;
625  int i,cnt,b;
626 
627  if ( dt==NULL || dt->corrections==NULL )
628 return;
629  type = devtaboffsetsize(dt);
630  putshort(gpos,dt->first_pixel_size);
631  putshort(gpos,dt->last_pixel_size );
632  putshort(gpos,type);
633  cnt = dt->last_pixel_size - dt->first_pixel_size + 1;
634  if ( type==3 ) {
635  for ( i=0; i<cnt; ++i )
636  putc(dt->corrections[i],gpos);
637  if ( cnt&1 )
638  putc(0,gpos);
639  } else if ( type==2 ) {
640  for ( i=0; i<cnt; i+=4 ) {
641  int val = 0;
642  for ( b=0; b<4 && i+b<cnt; ++b )
643  val |= (dt->corrections[i+b]&0x000f)<<(12-b*4);
644  putshort(gpos,val);
645  }
646  } else {
647  for ( i=0; i<cnt; i+=8 ) {
648  int val = 0;
649  for ( b=0; b<8 && i+b<cnt; ++b )
650  val |= (dt->corrections[i+b]&0x0003)<<(14-b*2);
651  putshort(gpos,val);
652  }
653  }
654 }
655 
656 static int DevTabLen(DeviceTable *dt) {
657  int type;
658  int cnt;
659 
660  if ( dt==NULL || dt->corrections==NULL )
661 return( 0 );
662  cnt = dt->last_pixel_size - dt->first_pixel_size + 1;
663  type = devtaboffsetsize(dt);
664  if ( type==3 )
665  cnt = (cnt+1)/2;
666  else if ( type==2 )
667  cnt = (cnt+3)/4;
668  else
669  cnt = (cnt+7)/8;
670  cnt += 3; /* first, last, type */
671 return( sizeof(uint16)*cnt );
672 }
673 
674 static int ValDevTabLen(ValDevTab *vdt) {
675 
676  if ( vdt==NULL )
677 return( 0 );
678 
679 return( DevTabLen(&vdt->xadjust) + DevTabLen(&vdt->yadjust) +
680  DevTabLen(&vdt->xadv) + DevTabLen(&vdt->yadv) );
681 }
682 
683 static int gposdumpvaldevtab(FILE *gpos,ValDevTab *vdt,int bits,int next_dev_tab ) {
684 
685  if ( bits&0x10 ) {
686  if ( vdt==NULL || vdt->xadjust.corrections==NULL )
687  putshort(gpos,0);
688  else {
689  putshort(gpos,next_dev_tab);
690  next_dev_tab += DevTabLen(&vdt->xadjust);
691  }
692  }
693  if ( bits&0x20 ) {
694  if ( vdt==NULL || vdt->yadjust.corrections==NULL )
695  putshort(gpos,0);
696  else {
697  putshort(gpos,next_dev_tab);
698  next_dev_tab += DevTabLen(&vdt->yadjust);
699  }
700  }
701  if ( bits&0x40 ) {
702  if ( vdt==NULL || vdt->xadv.corrections==NULL )
703  putshort(gpos,0);
704  else {
705  putshort(gpos,next_dev_tab);
706  next_dev_tab += DevTabLen(&vdt->xadv);
707  }
708  }
709  if ( bits&0x80 ) {
710  if ( vdt==NULL || vdt->yadv.corrections==NULL )
711  putshort(gpos,0);
712  else {
713  putshort(gpos,next_dev_tab);
714  next_dev_tab += DevTabLen(&vdt->yadv);
715  }
716  }
717 return( next_dev_tab );
718 }
719 
720 static int gposmaskeddumpdevtab(FILE *gpos,DeviceTable *dt,int bits,int mask,
721  int next_dev_tab ) {
722 
723  if ( bits&0x10 ) {
724  if ( !(mask&0x10) || dt==NULL )
725  putshort(gpos,0);
726  else {
727  putshort(gpos,next_dev_tab);
728  next_dev_tab += DevTabLen(dt);
729  }
730  }
731  if ( bits&0x20 ) {
732  if ( !(mask&0x20) || dt==NULL )
733  putshort(gpos,0);
734  else {
735  putshort(gpos,next_dev_tab);
736  next_dev_tab += DevTabLen(dt);
737  }
738  }
739  if ( bits&0x40 ) {
740  if ( !(mask&0x40) || dt==NULL )
741  putshort(gpos,0);
742  else {
743  putshort(gpos,next_dev_tab);
744  next_dev_tab += DevTabLen(dt);
745  }
746  }
747  if ( bits&0x80 ) {
748  if ( !(mask&0x80) || dt==NULL )
749  putshort(gpos,0);
750  else {
751  putshort(gpos,next_dev_tab);
752  next_dev_tab += DevTabLen(dt);
753  }
754  }
755 return( next_dev_tab );
756 }
757 
758 static int DevTabsSame(DeviceTable *dt1, DeviceTable *dt2) {
759  DeviceTable _dt;
760  int i;
761 
762  if ( dt1==NULL && dt2==NULL )
763 return( true );
764  if ( dt1==NULL ) {
765  memset(&_dt,0,sizeof(_dt));
766  dt1 = &_dt;
767  }
768  if ( dt2==NULL ) {
769  memset(&_dt,0,sizeof(_dt));
770  dt2 = &_dt;
771  }
772  if ( dt1->corrections==NULL && dt2->corrections==NULL )
773 return( true );
774  if ( dt1->corrections==NULL || dt2->corrections==NULL )
775 return( false );
776  if ( dt1->first_pixel_size!=dt2->first_pixel_size ||
777  dt1->last_pixel_size!=dt2->last_pixel_size )
778 return( false );
779  for ( i=dt2->last_pixel_size-dt1->first_pixel_size; i>=0; --i )
780  if ( dt1->corrections[i]!=dt2->corrections[i] )
781 return( false );
782 
783 return( true );
784 }
785 
786 static int ValDevTabsSame(ValDevTab *vdt1, ValDevTab *vdt2) {
787  ValDevTab _vdt;
788 
789  if ( vdt1==NULL && vdt2==NULL )
790 return( true );
791  if ( vdt1==NULL ) {
792  memset(&_vdt,0,sizeof(_vdt));
793  vdt1 = &_vdt;
794  }
795  if ( vdt2==NULL ) {
796  memset(&_vdt,0,sizeof(_vdt));
797  vdt2 = &_vdt;
798  }
799 return( DevTabsSame(&vdt1->xadjust,&vdt2->xadjust) &&
800  DevTabsSame(&vdt1->yadjust,&vdt2->yadjust) &&
801  DevTabsSame(&vdt1->xadv,&vdt2->xadv) &&
802  DevTabsSame(&vdt1->yadv,&vdt2->yadv) );
803 }
804 
805 static void dumpGPOSsimplepos(FILE *gpos,SplineFont *sf,struct lookup_subtable *sub ) {
806  int cnt, cnt2;
807  int32 coverage_pos, end;
808  PST *pst, *first=NULL;
809  int bits = 0, same=true;
810  SplineChar **glyphs;
811 
813  for ( cnt=cnt2=0; glyphs[cnt]!=NULL; ++cnt) {
814  for ( pst=glyphs[cnt]->possub; pst!=NULL; pst=pst->next ) {
815  if ( pst->subtable==sub && pst->type==pst_position ) {
816  if ( first==NULL ) first = pst;
817  else if ( same ) {
818  if ( first->u.pos.xoff!=pst->u.pos.xoff ||
819  first->u.pos.yoff!=pst->u.pos.yoff ||
820  first->u.pos.h_adv_off!=pst->u.pos.h_adv_off ||
821  first->u.pos.v_adv_off!=pst->u.pos.v_adv_off )
822  same = false;
823  if ( !ValDevTabsSame(pst->u.pos.adjust,first->u.pos.adjust))
824  same = false;
825  }
826  if ( pst->u.pos.xoff!=0 ) bits |= 1;
827  if ( pst->u.pos.yoff!=0 ) bits |= 2;
828  if ( pst->u.pos.h_adv_off!=0 ) bits |= 4;
829  if ( pst->u.pos.v_adv_off!=0 ) bits |= 8;
830  if ( pst->u.pos.adjust!=NULL ) {
831  if ( pst->u.pos.adjust->xadjust.corrections!=NULL ) bits |= 0x10;
832  if ( pst->u.pos.adjust->yadjust.corrections!=NULL ) bits |= 0x20;
833  if ( pst->u.pos.adjust->xadv.corrections!=NULL ) bits |= 0x40;
834  if ( pst->u.pos.adjust->yadv.corrections!=NULL ) bits |= 0x80;
835  }
836  ++cnt2;
837  break;
838  }
839  }
840  }
841  if ( bits==0 ) bits=1;
842  if ( cnt!=cnt2 )
843  IError( "Count mismatch in dumpGPOSsimplepos#1 %d vs %d\n", cnt, cnt2 );
844 
845  putshort(gpos,same?1:2); /* 1 means all value records same */
846  coverage_pos = ftell(gpos);
847  putshort(gpos,0); /* offset to coverage table */
848  putshort(gpos,bits);
849  if ( same ) {
850  if ( bits&1 ) putshort(gpos,first->u.pos.xoff);
851  if ( bits&2 ) putshort(gpos,first->u.pos.yoff);
852  if ( bits&4 ) putshort(gpos,first->u.pos.h_adv_off);
853  if ( bits&8 ) putshort(gpos,first->u.pos.v_adv_off);
854  if ( bits&0xf0 ) {
855  int next_dev_tab = ftell(gpos)-coverage_pos+2+
856  sizeof(int16)*((bits&0x10?1:0) + (bits&0x20?1:0) + (bits&0x40?1:0) + (bits&0x80?1:0));
857  if ( bits&0x10 ) { putshort(gpos,next_dev_tab); next_dev_tab += DevTabLen(&first->u.pos.adjust->xadjust); }
858  if ( bits&0x20 ) { putshort(gpos,next_dev_tab); next_dev_tab += DevTabLen(&first->u.pos.adjust->yadjust); }
859  if ( bits&0x40 ) { putshort(gpos,next_dev_tab); next_dev_tab += DevTabLen(&first->u.pos.adjust->xadv); }
860  if ( bits&0x80 ) { putshort(gpos,next_dev_tab); next_dev_tab += DevTabLen(&first->u.pos.adjust->yadv); }
861  if ( bits&0x10 ) dumpgposdevicetable(gpos,&first->u.pos.adjust->xadjust);
862  if ( bits&0x20 ) dumpgposdevicetable(gpos,&first->u.pos.adjust->yadjust);
863  if ( bits&0x40 ) dumpgposdevicetable(gpos,&first->u.pos.adjust->xadv);
864  if ( bits&0x80 ) dumpgposdevicetable(gpos,&first->u.pos.adjust->yadv);
865  if ( next_dev_tab!=ftell(gpos)-coverage_pos+2 )
866  IError( "Device Table offsets wrong in simple positioning 2");
867  }
868  } else {
869  int vr_size =
870  sizeof(int16)*((bits&0x1?1:0) + (bits&0x2?1:0) + (bits&0x4?1:0) + (bits&0x8?1:0) +
871  (bits&0x10?1:0) + (bits&0x20?1:0) + (bits&0x40?1:0) + (bits&0x80?1:0));
872  int next_dev_tab = ftell(gpos)-coverage_pos+2+2+vr_size*cnt;
873  putshort(gpos,cnt);
874  for ( cnt2 = 0; glyphs[cnt2]!=NULL; ++cnt2 ) {
875  for ( pst=glyphs[cnt2]->possub; pst!=NULL; pst=pst->next ) {
876  if ( pst->subtable==sub && pst->type==pst_position ) {
877  if ( bits&1 ) putshort(gpos,pst->u.pos.xoff);
878  if ( bits&2 ) putshort(gpos,pst->u.pos.yoff);
879  if ( bits&4 ) putshort(gpos,pst->u.pos.h_adv_off);
880  if ( bits&8 ) putshort(gpos,pst->u.pos.v_adv_off);
881  next_dev_tab = gposdumpvaldevtab(gpos,pst->u.pos.adjust,bits,
882  next_dev_tab);
883  break;
884  }
885  }
886  }
887  if ( cnt!=cnt2 )
888  IError( "Count mismatch in dumpGPOSsimplepos#3 %d vs %d\n", cnt, cnt2 );
889  if ( bits&0xf0 ) {
890  for ( cnt2 = 0; glyphs[cnt2]!=NULL; ++cnt2 ) {
891  for ( pst=glyphs[cnt2]->possub; pst!=NULL; pst=pst->next ) {
892  if ( pst->subtable==sub && pst->type==pst_position ) {
893  if ( bits&0x10 ) dumpgposdevicetable(gpos,&first->u.pos.adjust->xadjust);
894  if ( bits&0x20 ) dumpgposdevicetable(gpos,&first->u.pos.adjust->yadjust);
895  if ( bits&0x40 ) dumpgposdevicetable(gpos,&first->u.pos.adjust->xadv);
896  if ( bits&0x80 ) dumpgposdevicetable(gpos,&first->u.pos.adjust->yadv);
897  }
898  }
899  }
900  }
901  if ( next_dev_tab!=ftell(gpos)-coverage_pos+2 )
902  IError( "Device Table offsets wrong in simple positioning 2");
903  }
904  end = ftell(gpos);
905  fseek(gpos,coverage_pos,SEEK_SET);
906  putshort(gpos,end-coverage_pos+2);
907  fseek(gpos,end,SEEK_SET);
909  fseek(gpos,0,SEEK_END);
910  free(glyphs);
911 }
912 
913 struct sckppst {
919 /* The first few fields are only meaningful in the first structure in the array*/
920 /* and provide information about the entire rest of the array */
925 };
926 
927 static int cmp_gid( const void *_s1, const void *_s2 ) {
928  const struct sckppst *s1 = _s1, *s2 = _s2;
929 return( ((int) s1->other_gid) - ((int) s2->other_gid) );
930 }
931 
932 static void dumpGPOSpairpos(FILE *gpos,SplineFont *sf,struct lookup_subtable *sub) {
933  int cnt;
934  int32 coverage_pos, offset_pos, end, start, pos;
935  PST *pst;
936  KernPair *kp;
937  int vf1 = 0, vf2=0, i, j, k, tot, bit_cnt, v;
938  int start_cnt, end_cnt;
939  int chunk_cnt, chunk_max;
940  SplineChar *sc, **glyphs, *gtemp;
941  struct sckppst **seconds;
942  int devtablen;
943  int next_dev_tab;
944 
945  /* Figure out all the data we need. First the glyphs with kerning info */
946  /* then the glyphs to which they kern, and by how much */
948  for ( cnt=0; glyphs[cnt]!=NULL; ++cnt);
949  seconds = malloc(cnt*sizeof(struct sckppst *));
950  for ( cnt=0; glyphs[cnt]!=NULL; ++cnt) {
951  for ( k=0; k<2; ++k ) {
952  devtablen = 0;
953  tot = 0;
954  for ( pst=glyphs[cnt]->possub; pst!=NULL; pst=pst->next ) {
955  if ( pst->subtable==sub && pst->type==pst_pair &&
956  (sc = SFGetChar(sf,-1,pst->u.pair.paired))!=NULL &&
957  sc->ttf_glyph!=-1 ) {
958  if ( k ) {
959  seconds[cnt][tot].sc = sc;
960  seconds[cnt][tot].other_gid = sc->ttf_glyph;
961  seconds[cnt][tot].pst = pst;
964 
965  }
966  ++tot;
967  }
968  }
969  for ( v=0; v<2; ++v ) {
970  for ( kp = v ? glyphs[cnt]->vkerns : glyphs[cnt]->kerns; kp!=NULL; kp=kp->next ) {
971  if( kp->subtable!=sub ) continue; // process only glyphs from the current subtable
972  if ( kp->sc->ttf_glyph!=-1 ) {
973  if ( k ) {
974  seconds[cnt][tot].other_gid = kp->sc->ttf_glyph;
975  seconds[cnt][tot].sc = kp->sc;
976  seconds[cnt][tot].kp = kp;
977  seconds[cnt][tot].isv = v;
978  devtablen += DevTabLen(kp->adjust);
979  }
980  ++tot;
981  }
982  }
983  }
984  if ( k==0 ) {
985  seconds[cnt] = calloc(tot+1,sizeof(struct sckppst));
986  } else {
987  qsort(seconds[cnt],tot,sizeof(struct sckppst),cmp_gid);
988  seconds[cnt][0].tot = tot;
989  /* Devtablen is 0 unless we are configured for device tables */
990  seconds[cnt][0].devtablen = devtablen;
991  seconds[cnt][0].samewas = 0xffff;
992  }
993  }
994  }
995 
996  /* Some fonts do a primitive form of class based kerning, several glyphs */
997  /* can share the same list of second glyphs & offsets */
998  for ( cnt=0; glyphs[cnt]!=NULL; ++cnt) {
999  struct sckppst *test = seconds[cnt], *test2;
1000  for ( i=cnt-1; i>=0; --i ) {
1001  test2 = seconds[i];
1002  if ( test[0].tot != test2[0].tot || test2[0].samewas!=0xffff )
1003  continue;
1004  for ( j=test[0].tot-1; j>=0; --j ) {
1005  if ( test[j].other_gid != test2[j].other_gid )
1006  break;
1007  if ( test[j].kp!=NULL && test2[j].kp!=NULL &&
1008  test[j].kp->off == test2[j].kp->off
1009  && DevTabsSame(test[j].kp->adjust,test2[j].kp->adjust)
1010  )
1011  /* So far, so good */;
1012  else if ( test[j].pst!=NULL && test2[j].pst!=NULL &&
1013  test[j].pst->u.pair.vr[0].xoff == test2[j].pst->u.pair.vr[0].xoff &&
1014  test[j].pst->u.pair.vr[0].yoff == test2[j].pst->u.pair.vr[0].yoff &&
1015  test[j].pst->u.pair.vr[0].h_adv_off == test2[j].pst->u.pair.vr[0].h_adv_off &&
1016  test[j].pst->u.pair.vr[0].v_adv_off == test2[j].pst->u.pair.vr[0].v_adv_off &&
1017  test[j].pst->u.pair.vr[1].xoff == test2[j].pst->u.pair.vr[1].xoff &&
1018  test[j].pst->u.pair.vr[1].yoff == test2[j].pst->u.pair.vr[1].yoff &&
1019  test[j].pst->u.pair.vr[1].h_adv_off == test2[j].pst->u.pair.vr[1].h_adv_off &&
1020  test[j].pst->u.pair.vr[1].v_adv_off == test2[j].pst->u.pair.vr[1].v_adv_off
1021  && ValDevTabsSame(test[j].pst->u.pair.vr[0].adjust,test2[j].pst->u.pair.vr[0].adjust)
1022  && ValDevTabsSame(test[j].pst->u.pair.vr[1].adjust,test2[j].pst->u.pair.vr[1].adjust)
1023  )
1024  /* That's ok too. */;
1025  else
1026  break;
1027  }
1028  if ( j>=0 )
1029  continue;
1030  test[0].samewas = i;
1031  break;
1032  }
1033  }
1034 
1035  /* Ok, how many offsets must we output? Normal kerning will just use */
1036  /* one offset (with perhaps a device table), but the standard allows */
1037  /* us to adjust 8 different values (with 8 different device tables) */
1038  /* Find out which we need */
1039  for ( cnt=0; glyphs[cnt]!=NULL; ++cnt) {
1040  for ( tot=0 ; tot<seconds[cnt][0].tot; ++tot ) {
1041  if ( (pst=seconds[cnt][tot].pst)!=NULL ) {
1042  if ( pst->subtable==sub && pst->type==pst_pair ) {
1043  if ( pst->u.pair.vr[0].xoff!=0 ) vf1 |= 1;
1044  if ( pst->u.pair.vr[0].yoff!=0 ) vf1 |= 2;
1045  if ( pst->u.pair.vr[0].h_adv_off!=0 ) vf1 |= 4;
1046  if ( pst->u.pair.vr[0].v_adv_off!=0 ) vf1 |= 8;
1047  if ( pst->u.pair.vr[0].adjust!=NULL ) {
1048  if ( pst->u.pair.vr[0].adjust->xadjust.corrections!=NULL ) vf1 |= 0x10;
1049  if ( pst->u.pair.vr[0].adjust->yadjust.corrections!=NULL ) vf1 |= 0x20;
1050  if ( pst->u.pair.vr[0].adjust->xadv.corrections!=NULL ) vf1 |= 0x40;
1051  if ( pst->u.pair.vr[0].adjust->yadv.corrections!=NULL ) vf1 |= 0x80;
1052  }
1053  if ( pst->u.pair.vr[1].xoff!=0 ) vf2 |= 1;
1054  if ( pst->u.pair.vr[1].yoff!=0 ) vf2 |= 2;
1055  if ( pst->u.pair.vr[1].h_adv_off!=0 ) vf2 |= 4;
1056  if ( pst->u.pair.vr[1].v_adv_off!=0 ) vf2 |= 8;
1057  if ( pst->u.pair.vr[1].adjust!=NULL ) {
1058  if ( pst->u.pair.vr[1].adjust->xadjust.corrections!=NULL ) vf2 |= 0x10;
1059  if ( pst->u.pair.vr[1].adjust->yadjust.corrections!=NULL ) vf2 |= 0x20;
1060  if ( pst->u.pair.vr[1].adjust->xadv.corrections!=NULL ) vf2 |= 0x40;
1061  if ( pst->u.pair.vr[1].adjust->yadv.corrections!=NULL ) vf2 |= 0x80;
1062  }
1063  }
1064  }
1065  if ( (kp = seconds[cnt][tot].kp)!=NULL ) {
1066  int mask = 0, mask2=0;
1067  if ( seconds[cnt][tot].isv )
1068  mask = 0x0008;
1069  else
1070  mask = 0x0004;
1071  if ( kp->adjust!=NULL ) {
1072  mask |= mask<<4;
1073  mask2 |= mask2<<4;
1074  }
1075  vf1 |= mask;
1076  vf2 |= mask2;
1077  }
1078  }
1079  }
1080  if ( vf1==0 && vf2==0 ) vf1=1;
1081  bit_cnt = 0;
1082  for ( i=0; i<8; ++i ) {
1083  if ( vf1&(1<<i) ) ++bit_cnt;
1084  if ( vf2&(1<<i) ) ++bit_cnt;
1085  }
1086 
1087  chunk_max = chunk_cnt = 0;
1088  for ( start_cnt=0; start_cnt<cnt; start_cnt=end_cnt ) {
1089  int len = 5*2; /* Subtable header */
1090  for ( end_cnt=start_cnt; end_cnt<cnt; ++end_cnt ) {
1091  int glyph_len = 2; /* For the glyph's offset */
1092  if ( seconds[end_cnt][0].samewas==0xffff || seconds[end_cnt][0].samewas<start_cnt )
1093  glyph_len += (bit_cnt*2+2)*seconds[end_cnt][0].tot +
1094  seconds[end_cnt][0].devtablen +
1095  2; /* Number of secondary glyphs */
1096  if ( glyph_len>65535 && end_cnt==start_cnt ) {
1097  LogError(_("Lookup subtable %s contains a glyph %s whose kerning information takes up more than 64k bytes\n"),
1098  sub->subtable_name, glyphs[start_cnt]->name );
1099  len += glyph_len;
1100  } else if ( len+glyph_len>65535 ) {
1101  if( start_cnt==0 )
1102  LogError(_("Lookup subtable %s had to be split into several subtables\nbecause it was too big.\n"),
1103  sub->subtable_name );
1104  break;
1105  } else
1106  len += glyph_len;
1107  }
1108  if ( start_cnt!=0 || end_cnt!=cnt ) {
1109  if ( chunk_cnt>=chunk_max )
1110  sub->extra_subtables = realloc(sub->extra_subtables,((chunk_max+=10)+1)*sizeof(uint32));
1111  sub->extra_subtables[chunk_cnt++] = ftell(gpos);
1112  sub->extra_subtables[chunk_cnt] = -1;
1113  }
1114 
1115  start = ftell(gpos);
1116  putshort(gpos,1); /* 1 means char pairs (ie. not classes) */
1117  coverage_pos = ftell(gpos);
1118  putshort(gpos,0); /* offset to coverage table */
1119  putshort(gpos,vf1);
1120  putshort(gpos,vf2);
1121  putshort(gpos,end_cnt-start_cnt);
1122  offset_pos = ftell(gpos);
1123  for ( i=start_cnt; i<end_cnt; ++i )
1124  putshort(gpos,0); /* Fill in later */
1125  for ( i=start_cnt; i<end_cnt; ++i ) {
1126  if ( seconds[i][0].samewas>= start_cnt && seconds[i][0].samewas!=0xffff ) {
1127  /* It's the same as the glyph at samewas, so just copy the */
1128  /* offset from there. We don't need to do anything else */
1129  int offset;
1130  fseek(gpos,offset_pos+(seconds[i][0].samewas-start_cnt)*sizeof(uint16),SEEK_SET);
1131  offset = getushort(gpos);
1132  fseek(gpos,offset_pos+(i-start_cnt)*sizeof(uint16),SEEK_SET);
1133  putshort(gpos,offset);
1134  fseek(gpos,0,SEEK_END);
1135  continue;
1136  }
1137  next_dev_tab = ftell(gpos)-start;
1138  if ( (vf1&0xf0) || (vf2&0xf0) ) {
1139  for ( tot=0 ; tot<seconds[i][0].tot; ++tot ) {
1140  if ( (pst=seconds[i][tot].pst)!=NULL ) {
1141  if ( pst->u.pair.vr[0].adjust!=NULL ) {
1144  dumpgposdevicetable(gpos,&pst->u.pair.vr[0].adjust->xadv);
1145  dumpgposdevicetable(gpos,&pst->u.pair.vr[0].adjust->yadv);
1146  }
1147  if ( pst->u.pair.vr[1].adjust!=NULL ) {
1150  dumpgposdevicetable(gpos,&pst->u.pair.vr[1].adjust->xadv);
1151  dumpgposdevicetable(gpos,&pst->u.pair.vr[1].adjust->yadv);
1152  }
1153  }
1154  if ( (kp=seconds[i][tot].kp)!=NULL && kp->adjust!=NULL )
1155  dumpgposdevicetable(gpos,kp->adjust);
1156  }
1157  }
1158  pos = ftell(gpos);
1159  fseek(gpos,offset_pos+(i-start_cnt)*sizeof(uint16),SEEK_SET);
1160  putshort(gpos,pos-start);
1161  fseek(gpos,pos,SEEK_SET);
1162 
1163  putshort(gpos,seconds[i][0].tot);
1164  for ( tot=0 ; tot<seconds[i][0].tot; ++tot ) {
1165  putshort(gpos,seconds[i][tot].other_gid);
1166  if ( (pst=seconds[i][tot].pst)!=NULL ) {
1167  if ( vf1&1 ) putshort(gpos,pst->u.pair.vr[0].xoff);
1168  if ( vf1&2 ) putshort(gpos,pst->u.pair.vr[0].yoff);
1169  if ( vf1&4 ) putshort(gpos,pst->u.pair.vr[0].h_adv_off);
1170  if ( vf1&8 ) putshort(gpos,pst->u.pair.vr[0].v_adv_off);
1171  next_dev_tab = gposdumpvaldevtab(gpos,pst->u.pair.vr[0].adjust,vf1,
1172  next_dev_tab);
1173  if ( vf2&1 ) putshort(gpos,pst->u.pair.vr[1].xoff);
1174  if ( vf2&2 ) putshort(gpos,pst->u.pair.vr[1].yoff);
1175  if ( vf2&4 ) putshort(gpos,pst->u.pair.vr[1].h_adv_off);
1176  if ( vf2&8 ) putshort(gpos,pst->u.pair.vr[1].v_adv_off);
1177  next_dev_tab = gposdumpvaldevtab(gpos,pst->u.pair.vr[1].adjust,vf2,
1178  next_dev_tab);
1179  } else if ( (kp=seconds[i][tot].kp)!=NULL ) {
1180  int mask=0, mask2=0;
1181  if ( seconds[i][tot].isv )
1182  mask = 0x8;
1183  else
1184  mask = 0x4;
1185  gposvrmaskeddump(gpos,vf1,mask,kp->off);
1186  next_dev_tab = gposmaskeddumpdevtab(gpos,kp->adjust,vf1,mask<<4,
1187  next_dev_tab);
1188  gposvrmaskeddump(gpos,vf2,mask2,kp->off);
1189  next_dev_tab = gposmaskeddumpdevtab(gpos,kp->adjust,vf2,mask2<<4,
1190  next_dev_tab);
1191  }
1192  }
1193  }
1194  end = ftell(gpos);
1195  fseek(gpos,coverage_pos,SEEK_SET);
1196  if ( end-start>65535 )
1197  IError(_("I miscalculated the size of subtable %s, this means the kerning output is wrong."), sub->subtable_name );
1198  putshort(gpos,end-start);
1199  fseek(gpos,end,SEEK_SET);
1200  gtemp = glyphs[end_cnt]; glyphs[end_cnt] = NULL;
1201  dumpcoveragetable(gpos,glyphs+start_cnt);
1202  glyphs[end_cnt] = gtemp;
1203  }
1204  for ( i=0; i<cnt; ++i )
1205  free(seconds[i]);
1206  free(seconds);
1207  free(glyphs);
1208 }
1209 
1210 uint16 *ClassesFromNames(SplineFont *sf,char **classnames,int class_cnt,
1211  int numGlyphs, SplineChar ***glyphs, int apple_kc) {
1212  uint16 *class;
1213  int i;
1214  char *pt, *end, ch;
1215  SplineChar *sc, **gs=NULL;
1216  int offset = (apple_kc && classnames[0]!=NULL);
1217 
1218  class = calloc(numGlyphs,sizeof(uint16));
1219  if ( glyphs ) *glyphs = gs = calloc(numGlyphs,sizeof(SplineChar *));
1220  for ( i=0; i<class_cnt; ++i ) {
1221  if ( i==0 && classnames[0]==NULL )
1222  continue;
1223  for ( pt = classnames[i]; *pt; pt = end+1 ) {
1224  while ( *pt==' ' ) ++pt;
1225  if ( *pt=='\0' )
1226  break;
1227  end = strchr(pt,' ');
1228  if ( end==NULL )
1229  end = pt+strlen(pt);
1230  ch = *end;
1231  *end = '\0';
1232  sc = SFGetChar(sf,-1,pt);
1233  if ( sc!=NULL && sc->ttf_glyph!=-1 ) {
1234  class[sc->ttf_glyph] = i+offset;
1235  if ( gs!=NULL )
1236  gs[sc->ttf_glyph] = sc;
1237  }
1238  *end = ch;
1239  if ( ch=='\0' )
1240  break;
1241  }
1242  }
1243 return( class );
1244 }
1245 
1246 static SplineChar **GlyphsFromClasses(SplineChar **gs, int numGlyphs) {
1247  int i, cnt;
1248  SplineChar **glyphs;
1249 
1250  for ( i=cnt=0; i<numGlyphs; ++i )
1251  if ( gs[i]!=NULL ) ++cnt;
1252  glyphs = malloc((cnt+1)*sizeof(SplineChar *));
1253  for ( i=cnt=0; i<numGlyphs; ++i )
1254  if ( gs[i]!=NULL )
1255  glyphs[cnt++] = gs[i];
1256  glyphs[cnt++] = NULL;
1257  free(gs);
1258 return( glyphs );
1259 }
1260 
1261 static SplineChar **GlyphsFromInitialClasses(SplineChar **gs, int numGlyphs, uint16 *classes, uint16 *initial) {
1262  int i, j, cnt;
1263  SplineChar **glyphs;
1264 
1265  for ( i=cnt=0; i<numGlyphs; ++i ) {
1266  for ( j=0; initial[j]!=0xffff; ++j )
1267  if ( initial[j]==classes[i])
1268  break;
1269  if ( initial[j]!=0xffff && gs[i]!=NULL ) ++cnt;
1270  }
1271  glyphs = malloc((cnt+1)*sizeof(SplineChar *));
1272  for ( i=cnt=0; i<numGlyphs; ++i ) {
1273  for ( j=0; initial[j]!=0xffff; ++j )
1274  if ( initial[j]==classes[i])
1275  break;
1276  if ( initial[j]!=0xffff && gs[i]!=NULL )
1277  glyphs[cnt++] = gs[i];
1278  }
1279  glyphs[cnt++] = NULL;
1280 return( glyphs );
1281 }
1282 
1283 static void DumpClass(FILE *gpos,uint16 *class,int numGlyphs) {
1284  int ranges, i, cur, first= -1, last=-1, istart;
1285 
1286  for ( i=ranges=0; i<numGlyphs; ) {
1287  istart = i;
1288  cur = class[i];
1289  while ( i<numGlyphs && class[i]==cur )
1290  ++i;
1291  if ( cur!=0 ) {
1292  ++ranges;
1293  if ( first==-1 ) first = istart;
1294  last = i-1;
1295  }
1296  }
1297  if ( ranges*3+1>last-first+1+2 || first==-1 ) {
1298  if ( first==-1 ) first = last = 0;
1299  putshort(gpos,1); /* Format 1, list of all posibilities */
1300  putshort(gpos,first);
1301  putshort(gpos,last-first+1);
1302  for ( i=first; i<=last ; ++i )
1303  putshort(gpos,class[i]);
1304  } else {
1305  putshort(gpos,2); /* Format 2, series of ranges */
1306  putshort(gpos,ranges);
1307  for ( i=0; i<numGlyphs; ) {
1308  istart = i;
1309  cur = class[i];
1310  while ( i<numGlyphs && class[i]==cur )
1311  ++i;
1312  if ( cur!=0 ) {
1313  putshort(gpos,istart);
1314  putshort(gpos,i-1);
1315  putshort(gpos,cur);
1316  }
1317  }
1318  }
1319 }
1320 
1322  struct lookup_subtable *sub, struct alltabs *at) {
1323  uint32 begin_off = ftell(gpos), pos;
1324  uint16 *class1, *class2;
1325  KernClass *kc = sub->kc, *test;
1326  SplineChar **glyphs;
1327  int i, isv;
1328  int anydevtab = false;
1329  int next_devtab;
1330 
1331  putshort(gpos,2); /* format 2 of the pair adjustment subtable */
1332  putshort(gpos,0); /* offset to coverage table */
1333  for ( i=0; i<kc->first_cnt*kc->second_cnt; ++i ) {
1334  if ( kc->adjusts[i].corrections!=NULL ) {
1335  anydevtab = true;
1336  break;
1337  }
1338  }
1339 
1340  for ( test=sf->vkerns; test!=NULL && test!=kc; test=test->next );
1341  isv = test==kc;
1342 
1343  if ( isv ) {
1344  /* As far as I know there is no "bottom to top" writing direction */
1345  /* Oh. There is. Ogham, Runic */
1346  putshort(gpos,anydevtab?0x0088:0x0008); /* Alter YAdvance of first character */
1347  putshort(gpos,0x0000); /* leave second char alone */
1348  } else {
1349  putshort(gpos,anydevtab?0x0044:0x0004); /* Alter XAdvance of first character */
1350  putshort(gpos,0x0000); /* leave second char alone */
1351  }
1352  class1 = ClassesFromNames(sf,kc->firsts,kc->first_cnt,at->maxp.numGlyphs,&glyphs,false);
1354  class2 = ClassesFromNames(sf,kc->seconds,kc->second_cnt,at->maxp.numGlyphs,NULL,false);
1355  putshort(gpos,0); /* offset to first glyph classes */
1356  putshort(gpos,0); /* offset to second glyph classes */
1357  putshort(gpos,kc->first_cnt);
1358  putshort(gpos,kc->second_cnt);
1359  next_devtab = ftell(gpos)-begin_off + kc->first_cnt*kc->second_cnt*2*sizeof(uint16);
1360  for ( i=0; i<kc->first_cnt*kc->second_cnt; ++i ) {
1361  putshort(gpos,kc->offsets[i]);
1362  if ( anydevtab && kc->adjusts[i].corrections!=NULL ) {
1363  putshort(gpos,next_devtab);
1364  next_devtab += DevTabLen(&kc->adjusts[i]);
1365  } else if ( anydevtab )
1366  putshort(gpos,0);
1367  }
1368  if ( anydevtab ) {
1369  for ( i=0; i<kc->first_cnt*kc->second_cnt; ++i ) {
1370  if ( kc->adjusts[i].corrections!=NULL )
1371  dumpgposdevicetable(gpos,&kc->adjusts[i]);
1372  }
1373  if ( next_devtab!=ftell(gpos)-begin_off )
1374  IError("Device table offsets screwed up in kerning class");
1375  }
1376  pos = ftell(gpos);
1377  fseek(gpos,begin_off+4*sizeof(uint16),SEEK_SET);
1378  putshort(gpos,pos-begin_off);
1379  fseek(gpos,pos,SEEK_SET);
1380  DumpClass(gpos,class1,at->maxp.numGlyphs);
1381 
1382  pos = ftell(gpos);
1383  fseek(gpos,begin_off+5*sizeof(uint16),SEEK_SET);
1384  putshort(gpos,pos-begin_off);
1385  fseek(gpos,pos,SEEK_SET);
1386  DumpClass(gpos,class2,at->maxp.numGlyphs);
1387 
1388  pos = ftell(gpos);
1389  fseek(gpos,begin_off+sizeof(uint16),SEEK_SET);
1390  putshort(gpos,pos-begin_off);
1391  fseek(gpos,pos,SEEK_SET);
1392  dumpcoveragetable(gpos,glyphs);
1393 
1394  free(glyphs);
1395  free(class1);
1396  free(class2);
1397 }
1398 
1399 static void dumpanchor(FILE *gpos,AnchorPoint *ap, int is_ttf ) {
1400  int base = ftell(gpos);
1401 
1402  if ( ap->xadjust.corrections!=NULL || ap->yadjust.corrections!=NULL )
1403  putshort(gpos,3); /* format 3 w/ device tables */
1404  else
1405  if ( ap->has_ttf_pt && is_ttf )
1406  putshort(gpos,2); /* format 2 w/ a matching ttf point index */
1407  else
1408  putshort(gpos,1); /* Anchor format 1 just location*/
1409  putshort(gpos,ap->me.x); /* X coord of attachment */
1410  putshort(gpos,ap->me.y); /* Y coord of attachment */
1411  if ( ap->xadjust.corrections!=NULL || ap->yadjust.corrections!=NULL ) {
1412  putshort(gpos,ap->xadjust.corrections==NULL?0:
1413  ftell(gpos)-base+4);
1414  putshort(gpos,ap->yadjust.corrections==NULL?0:
1415  ftell(gpos)-base+2+DevTabLen(&ap->xadjust));
1416  dumpgposdevicetable(gpos,&ap->xadjust);
1417  dumpgposdevicetable(gpos,&ap->yadjust);
1418  } else
1419  if ( ap->has_ttf_pt && is_ttf )
1420  putshort(gpos,ap->ttf_pt_index);
1421 }
1422 
1424  struct lookup_subtable *sub,struct glyphinfo *gi) {
1425  AnchorClass *ac, *testac;
1426  SplineChar **entryexit;
1427  int cnt, offset,j;
1428  AnchorPoint *ap, *entry, *exit;
1429  uint32 coverage_offset, start;
1430 
1431  ac = NULL;
1432  for ( testac=sf->anchor; testac!=NULL; testac = testac->next ) {
1433  if ( testac->subtable == sub ) {
1434  if ( ac==NULL )
1435  ac = testac;
1436  else {
1437  ff_post_error(_("Two cursive anchor classes"),_("Two cursive anchor classes in the same subtable, %s"),
1438  sub->subtable_name);
1439  break;
1440  }
1441  }
1442  }
1443  if ( ac==NULL ) {
1444  IError( "Missing anchor class for %s", sub->subtable_name );
1445 return;
1446  }
1447  entryexit = EntryExitDecompose(sf,ac,gi);
1448  if ( entryexit==NULL )
1449 return;
1450 
1451  for ( cnt=0; entryexit[cnt]!=NULL; ++cnt );
1452 
1453  start = ftell(gpos);
1454  putshort(gpos,1); /* format 1 for this subtable */
1455  putshort(gpos,0); /* Fill in later, offset to coverage table */
1456  putshort(gpos,cnt); /* number of glyphs */
1457 
1458  offset = 6+2*2*cnt;
1459  for ( j=0; j<cnt; ++j ) {
1460  entry = exit = NULL;
1461  for ( ap=entryexit[j]->anchor; ap!=NULL; ap=ap->next ) {
1462  if ( ap->anchor==ac && ap->type==at_centry ) entry = ap;
1463  if ( ap->anchor==ac && ap->type==at_cexit ) exit = ap;
1464  }
1465  if ( entry!=NULL ) {
1466  putshort(gpos,offset);
1467  offset += 6;
1468  if ( entry->xadjust.corrections!=NULL || entry->yadjust.corrections!=NULL )
1469  offset += 4 + DevTabLen(&entry->xadjust) + DevTabLen(&entry->yadjust);
1470  if ( gi->is_ttf && entry->has_ttf_pt )
1471  offset += 2;
1472  } else
1473  putshort(gpos,0);
1474  if ( exit!=NULL ) {
1475  putshort(gpos,offset);
1476  offset += 6;
1477  if ( exit->xadjust.corrections!=NULL || exit->yadjust.corrections!=NULL )
1478  offset += 4 + DevTabLen(&exit->xadjust) + DevTabLen(&exit->yadjust);
1479  else
1480  if ( gi->is_ttf && exit->has_ttf_pt )
1481  offset += 2;
1482  } else
1483  putshort(gpos,0);
1484  }
1485  for ( j=0; j<cnt; ++j ) {
1486  entry = exit = NULL;
1487  for ( ap=entryexit[j]->anchor; ap!=NULL; ap=ap->next ) {
1488  if ( ap->anchor==ac && ap->type==at_centry ) entry = ap;
1489  if ( ap->anchor==ac && ap->type==at_cexit ) exit = ap;
1490  }
1491  if ( entry!=NULL )
1492  dumpanchor(gpos,entry,gi->is_ttf);
1493  if ( exit!=NULL )
1494  dumpanchor(gpos,exit,gi->is_ttf);
1495  }
1496  coverage_offset = ftell(gpos);
1497  dumpcoveragetable(gpos,entryexit);
1498  fseek(gpos,start+2,SEEK_SET);
1499  putshort(gpos,coverage_offset-start);
1500  fseek(gpos,0,SEEK_END);
1501 
1502  free(entryexit);
1503 }
1504 
1505 static int orderglyph(const void *_sc1,const void *_sc2) {
1506  SplineChar * const *sc1 = _sc1, * const *sc2 = _sc2;
1507 
1508 return( (*sc1)->ttf_glyph - (*sc2)->ttf_glyph );
1509 }
1510 
1511 static SplineChar **allmarkglyphs(SplineChar ***glyphlist, int classcnt) {
1512  SplineChar **glyphs;
1513  int i, tot, k;
1514 
1515  if ( classcnt==1 )
1516 return( SFOrderedGlyphs(glyphlist[0]));
1517 
1518  for ( i=tot=0; i<classcnt; ++i ) {
1519  for ( k=0; glyphlist[i][k]!=NULL; ++k );
1520  tot += k;
1521  }
1522  glyphs = malloc((tot+1)*sizeof(SplineChar *));
1523  for ( i=tot=0; i<classcnt; ++i ) {
1524  for ( k=0; glyphlist[i][k]!=NULL; ++k )
1525  glyphs[tot++] = glyphlist[i][k];
1526  }
1527  qsort(glyphs,tot,sizeof(SplineChar *),orderglyph);
1528  for ( i=k=0; i<tot; ++i ) {
1529  while ( i+1<tot && glyphs[i]==glyphs[i+1]) ++i;
1530  glyphs[k++] = glyphs[i];
1531  }
1532  glyphs[k] = NULL;
1533 return( glyphs );
1534 }
1535 
1536 static void dumpgposAnchorData(FILE *gpos,AnchorClass *_ac,
1537  enum anchor_type at,
1538  SplineChar ***marks,SplineChar **base,
1539  int classcnt, struct glyphinfo *gi) {
1540  AnchorClass *ac=NULL;
1541  int j,cnt,k,l, pos, offset, tot, max;
1542  uint32 coverage_offset, markarray_offset, subtable_start;
1543  AnchorPoint *ap, **aps;
1544  SplineChar **markglyphs;
1545 
1546  for ( cnt=0; base[cnt]!=NULL; ++cnt );
1547 
1548  subtable_start = ftell(gpos);
1549  putshort(gpos,1); /* format 1 for this subtable */
1550  putshort(gpos,0); /* Fill in later, offset to mark coverage table */
1551  putshort(gpos,0); /* Fill in later, offset to base coverage table */
1552  putshort(gpos,classcnt);
1553  putshort(gpos,0); /* Fill in later, offset to mark array */
1554  putshort(gpos,12); /* Offset to base array */
1555  /* Base array */
1556  putshort(gpos,cnt); /* Number of entries in array */
1557  if ( at==at_basechar || at==at_basemark ) {
1558  offset = 2;
1559  for ( l=0; l<3; ++l ) {
1560  for ( j=0; j<cnt; ++j ) {
1561  for ( k=0, ac=_ac; k<classcnt; ac=ac->next ) if ( ac->matches ) {
1562  if ( !ac->has_mark || !ac->has_base )
1563  continue;
1564  for ( ap=base[j]->anchor; ap!=NULL && (ap->anchor!=ac || ap->type!=at);
1565  ap=ap->next );
1566  switch ( l ) {
1567  case 0:
1568  offset += 2;
1569  break;
1570  case 1:
1571  if ( ap==NULL )
1572  putshort(gpos,0);
1573  else {
1574  putshort(gpos,offset);
1575  offset += 6;
1576  if ( ap->xadjust.corrections!=NULL || ap->yadjust.corrections!=NULL )
1577  offset += 4 + DevTabLen(&ap->xadjust) + DevTabLen(&ap->yadjust);
1578  else
1579  if ( gi->is_ttf && ap->has_ttf_pt )
1580  offset += 2;
1581  }
1582  break;
1583  case 2:
1584  if ( ap!=NULL )
1585  dumpanchor(gpos,ap,gi->is_ttf);
1586  break;
1587  }
1588  ++k;
1589  }
1590  }
1591  }
1592  } else {
1593  offset = 2+2*cnt;
1594  max = 0;
1595  for ( j=0; j<cnt; ++j ) {
1596  putshort(gpos,offset);
1597  pos = tot = 0;
1598  for ( ap=base[j]->anchor; ap!=NULL ; ap=ap->next )
1599  for ( k=0, ac=_ac; k<classcnt; ac=ac->next ) if ( ac->matches ) {
1600  if ( ap->anchor==ac ) {
1601  if ( ap->lig_index>pos ) pos = ap->lig_index;
1602  ++tot;
1603  }
1604  ++k;
1605  }
1606  if ( pos>max ) max = pos;
1607  offset += 2+(pos+1)*classcnt*2+tot*6;
1608  /* 2 for component count, for each component an offset to an offset to an anchor record */
1609  }
1610  ++max;
1611  int special_ceiling = classcnt*max;
1612  aps = malloc((classcnt*max+max)*sizeof(AnchorPoint *));
1613  for ( j=0; j<cnt; ++j ) {
1614  memset(aps,0,(classcnt*max+max)*sizeof(AnchorPoint *));
1615  pos = 0;
1616  for ( ap=base[j]->anchor; ap!=NULL ; ap=ap->next )
1617  for ( k=0, ac=_ac; k<classcnt; ac=ac->next ) if ( ac->matches ) {
1618  if ( ap->anchor==ac ) {
1619  if ( ap->lig_index>pos ) pos = ap->lig_index;
1620  if (k*max+ap->lig_index > special_ceiling || k*max+ap->lig_index < 0) {
1621  fprintf(stderr, "A ligature index is invalid.\n");
1622  } else {
1623  aps[k*max+ap->lig_index] = ap;
1624  }
1625  }
1626  ++k;
1627  }
1628  ++pos;
1629  putshort(gpos,pos);
1630  offset = 2+2*pos*classcnt;
1631  for ( l=0; l<pos; ++l ) {
1632  for ( k=0; k<classcnt; ++k ) {
1633  if ( aps[k*max+l]==NULL )
1634  putshort(gpos,0);
1635  else {
1636  putshort(gpos,offset);
1637  offset += 6;
1638  if ( aps[k*max+l]->xadjust.corrections!=NULL || aps[k*max+l]->yadjust.corrections!=NULL )
1639  offset += 4 + DevTabLen(&aps[k*max+l]->xadjust) +
1640  DevTabLen(&aps[k*max+l]->yadjust);
1641  else
1642  if ( gi->is_ttf && aps[k*max+l]->has_ttf_pt )
1643  offset += 2;
1644  }
1645  }
1646  }
1647  for ( l=0; l<pos; ++l ) {
1648  for ( k=0; k<classcnt; ++k ) {
1649  if ( aps[k*max+l]!=NULL ) {
1650  dumpanchor(gpos,aps[k*max+l],gi->is_ttf);
1651  }
1652  }
1653  }
1654  }
1655  free(aps); aps = NULL;
1656  }
1657  coverage_offset = ftell(gpos);
1658  fseek(gpos,subtable_start+4,SEEK_SET);
1659  putshort(gpos,coverage_offset-subtable_start);
1660  fseek(gpos,0,SEEK_END);
1661  dumpcoveragetable(gpos,base);
1662 
1663  /* We tried sharing the mark table, (among all these sub-tables) but */
1664  /* that doesn't work because we need to be able to reorder the sub-tables */
1665  markglyphs = allmarkglyphs(marks,classcnt);
1666  coverage_offset = ftell(gpos);
1667  dumpcoveragetable(gpos,markglyphs);
1668  markarray_offset = ftell(gpos);
1669  for ( cnt=0; markglyphs[cnt]!=NULL; ++cnt );
1670  putshort(gpos,cnt);
1671  offset = 2+4*cnt;
1672  for ( j=0; j<cnt; ++j ) {
1673  if ( classcnt==0 ) {
1674  putshort(gpos,0); /* Only one class */
1675  ap = NULL;
1676  } else {
1677  for ( k=0, ac=_ac; k<classcnt; ac=ac->next ) {
1678  if ( ac->matches ) {
1679  for ( ap = markglyphs[j]->anchor; ap!=NULL && (ap->anchor!=ac || ap->type!=at_mark);
1680  ap=ap->next );
1681  if ( ap!=NULL )
1682  break;
1683  ++k;
1684  }
1685  }
1686  putshort(gpos,k);
1687  }
1688  putshort(gpos,offset);
1689  offset += 6;
1690  if ( ap!=NULL && (ap->xadjust.corrections!=NULL || ap->yadjust.corrections!=NULL ))
1691  offset += 4 + DevTabLen(&ap->xadjust) + DevTabLen(&ap->yadjust);
1692  else
1693  if ( gi->is_ttf && ap->has_ttf_pt )
1694  offset += 2;
1695  }
1696  for ( j=0; j<cnt; ++j ) {
1697  for ( k=0, ac=_ac; k<classcnt; ac=ac->next ) {
1698  if ( ac->matches ) {
1699  for ( ap = markglyphs[j]->anchor; ap!=NULL && (ap->anchor!=ac || ap->type!=at_mark);
1700  ap=ap->next );
1701  if ( ap!=NULL )
1702  break;
1703  ++k;
1704  }
1705  }
1706  dumpanchor(gpos,ap,gi->is_ttf);
1707  }
1708  if ( markglyphs!=marks[0] )
1709  free(markglyphs);
1710 
1711  fseek(gpos,subtable_start+2,SEEK_SET); /* mark coverage table offset */
1712  putshort(gpos,coverage_offset-subtable_start);
1713  fseek(gpos,4,SEEK_CUR);
1714  putshort(gpos,markarray_offset-subtable_start);
1715 
1716  fseek(gpos,0,SEEK_END);
1717 }
1718 
1720  int cnt, diff, ok = true;
1721  int32 coverage_pos, end;
1722  SplineChar **glyphs, ***maps;
1723 
1725  maps = generateMapList(glyphs,sub);
1726 
1727  diff = (*maps[0])->ttf_glyph - glyphs[0]->ttf_glyph;
1728  for ( cnt=0; glyphs[cnt]!=NULL; ++cnt)
1729  if ( diff!= maps[cnt][0]->ttf_glyph-glyphs[cnt]->ttf_glyph ) ok = false;
1730 
1731  if ( ok ) {
1732  putshort(gsub,1); /* delta format */
1733  coverage_pos = ftell(gsub);
1734  putshort(gsub,0); /* offset to coverage table */
1735  putshort(gsub,diff);
1736  } else {
1737  putshort(gsub,2); /* glyph list format */
1738  coverage_pos = ftell(gsub);
1739  putshort(gsub,0); /* offset to coverage table */
1740  putshort(gsub,cnt);
1741  for ( cnt = 0; glyphs[cnt]!=NULL; ++cnt )
1742  putshort(gsub,(*maps[cnt])->ttf_glyph);
1743  }
1744  end = ftell(gsub);
1745  fseek(gsub,coverage_pos,SEEK_SET);
1746  putshort(gsub,end-coverage_pos+2);
1747  fseek(gsub,end,SEEK_SET);
1748  dumpcoveragetable(gsub,glyphs);
1749 
1750  free(glyphs);
1751  GlyphMapFree(maps);
1752 }
1753 
1755  int cnt, offset;
1756  int32 coverage_pos, end;
1757  int gc;
1758  SplineChar **glyphs, ***maps;
1759 
1761  maps = generateMapList(glyphs,sub);
1762  for ( cnt=0; glyphs[cnt]!=NULL; ++cnt);
1763 
1764  putshort(gsub,1); /* glyph list format */
1765  coverage_pos = ftell(gsub);
1766  putshort(gsub,0); /* offset to coverage table */
1767  putshort(gsub,cnt);
1768  offset = 6+2*cnt;
1769  for ( cnt = 0; glyphs[cnt]!=NULL; ++cnt ) {
1770  putshort(gsub,offset);
1771  if (maps[cnt] == NULL) {
1772  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) ;
1773  }
1774  for ( gc=0; maps[cnt][gc]!=NULL; ++gc );
1775  offset += 2+2*gc;
1776  }
1777  for ( cnt = 0; glyphs[cnt]!=NULL; ++cnt ) {
1778  for ( gc=0; maps[cnt][gc]!=NULL; ++gc );
1779  putshort(gsub,gc);
1780  for ( gc=0; maps[cnt][gc]!=NULL; ++gc )
1781  putshort(gsub,maps[cnt][gc]->ttf_glyph);
1782  }
1783  end = ftell(gsub);
1784  fseek(gsub,coverage_pos,SEEK_SET);
1785  putshort(gsub,end-coverage_pos+2);
1786  fseek(gsub,end,SEEK_SET);
1787  dumpcoveragetable(gsub,glyphs);
1788 
1789  free(glyphs);
1790  GlyphMapFree(maps);
1791 }
1792 
1793 static int AllToBeOutput(LigList *lig) {
1794  struct splinecharlist *cmp;
1795 
1796  if ( lig->lig->u.lig.lig->ttf_glyph==-1 ||
1797  lig->first->ttf_glyph==-1 )
1798 return( 0 );
1799  for ( cmp=lig->components; cmp!=NULL; cmp=cmp->next )
1800  if ( cmp->sc->ttf_glyph==-1 )
1801 return( 0 );
1802 return( true );
1803 }
1804 
1805 static void dumpGSUBligdata(FILE *gsub,SplineFont *sf,
1806  struct lookup_subtable *sub, struct alltabs *at) {
1807  int32 coverage_pos, next_val_pos, here, lig_list_start;
1808  int cnt, i, pcnt, lcnt, max=100, j;
1809  uint16 *offsets=NULL, *ligoffsets=malloc(max*sizeof(uint16));
1810  SplineChar **glyphs;
1811  LigList *ll;
1812  struct splinecharlist *scl;
1813 
1815  cnt=0;
1816  if ( glyphs!=NULL ) for ( ; glyphs[cnt]!=NULL; ++cnt );
1817 
1818  putshort(gsub,1); /* only one format for ligatures */
1819  coverage_pos = ftell(gsub);
1820  putshort(gsub,0); /* offset to coverage table */
1821  putshort(gsub,cnt);
1822  next_val_pos = ftell(gsub);
1823  if ( glyphs!=NULL )
1824  offsets = malloc(cnt*sizeof(int16));
1825  for ( i=0; i<cnt; ++i )
1826  putshort(gsub,0);
1827  for ( i=0; i<cnt; ++i ) {
1828  offsets[i] = ftell(gsub)-coverage_pos+2;
1829  for ( pcnt = 0, ll = glyphs[i]->ligofme; ll!=NULL; ll=ll->next )
1830  if ( ll->lig->subtable==sub && AllToBeOutput(ll))
1831  ++pcnt;
1832  putshort(gsub,pcnt);
1833  if ( pcnt>=max ) {
1834  max = pcnt+100;
1835  ligoffsets = realloc(ligoffsets,max*sizeof(int));
1836  }
1837  lig_list_start = ftell(gsub);
1838  for ( j=0; j<pcnt; ++j )
1839  putshort(gsub,0); /* Place holders */
1840  for ( pcnt=0, ll = glyphs[i]->ligofme; ll!=NULL; ll=ll->next ) {
1841  if ( ll->lig->subtable==sub && AllToBeOutput(ll)) {
1842  ligoffsets[pcnt] = ftell(gsub)-lig_list_start+2;
1843  putshort(gsub,ll->lig->u.lig.lig->ttf_glyph);
1844  for ( lcnt=0, scl=ll->components; scl!=NULL; scl=scl->next ) ++lcnt;
1845  putshort(gsub, lcnt+1);
1846  if ( lcnt+1>at->os2.maxContext )
1847  at->os2.maxContext = lcnt+1;
1848  for ( scl=ll->components; scl!=NULL; scl=scl->next )
1849  putshort(gsub, scl->sc->ttf_glyph );
1850  ++pcnt;
1851  }
1852  }
1853  fseek(gsub,lig_list_start,SEEK_SET);
1854  for ( j=0; j<pcnt; ++j )
1855  putshort(gsub,ligoffsets[j]);
1856  fseek(gsub,0,SEEK_END);
1857  }
1858  free(ligoffsets);
1859  if ( glyphs!=NULL ) {
1860  here = ftell(gsub);
1861  fseek(gsub,coverage_pos,SEEK_SET);
1862  putshort(gsub,here-coverage_pos+2);
1863  fseek(gsub,next_val_pos,SEEK_SET);
1864  for ( i=0; i<cnt; ++i )
1865  putshort(gsub,offsets[i]);
1866  fseek(gsub,here,SEEK_SET);
1867  dumpcoveragetable(gsub,glyphs);
1868  free(glyphs);
1869  free(offsets);
1870  }
1871 }
1872 
1873 static int ui16cmp(const void *_i1, const void *_i2) {
1874  if ( *(const uint16 *) _i1 > *(const uint16 *) _i2 )
1875 return( 1 );
1876  if ( *(const uint16 *) _i1 < *(const uint16 *) _i2 )
1877 return( -1 );
1878 
1879 return( 0 );
1880 }
1881 
1883  uint16 *initial = malloc((fpst->nccnt+1)*sizeof(uint16));
1884  int i, cnt, j;
1885 
1886  initial[fpst->nccnt] = 0xffff;
1887  for ( i=cnt=0; i<fpst->rule_cnt; ++i ) {
1888  for ( j=0; j<cnt ; ++j )
1889  if ( initial[j] == fpst->rules[i].u.class.nclasses[0] )
1890  break;
1891  if ( j==cnt )
1892  initial[cnt++] = fpst->rules[i].u.class.nclasses[0];
1893  }
1894  qsort(initial,cnt,sizeof(uint16),ui16cmp);
1895  initial[cnt] = 0xffff;
1896 return( initial );
1897 }
1898 
1900  SplineChar **glyphs, *sc;
1901  int i, j, cnt, ch;
1902  char *pt, *names;
1903 
1904  glyphs = malloc((fpst->rule_cnt+1)*sizeof(SplineChar *));
1905  for ( i=cnt=0; i<fpst->rule_cnt; ++i ) {
1906  names = fpst->rules[i].u.glyph.names;
1907  pt = strchr(names,' ');
1908  if ( pt==NULL ) pt = names+strlen(names);
1909  ch = *pt; *pt = '\0';
1910  sc = SFGetChar(sf,-1,names);
1911  *pt = ch;
1912  for ( j=0; j<cnt; ++j )
1913  if ( glyphs[j]==sc )
1914  break;
1915  if ( j==cnt && sc!=NULL )
1916  glyphs[cnt++] = sc;
1917  }
1918  glyphs[cnt] = NULL;
1919  if ( cnt==0 )
1920 return( glyphs );
1921 
1922  for ( i=0; glyphs[i+1]!=NULL; ++i ) for ( j=i+1; glyphs[j]!=NULL; ++j ) {
1923  if ( glyphs[i]->ttf_glyph > glyphs[j]->ttf_glyph ) {
1924  sc = glyphs[i];
1925  glyphs[i] = glyphs[j];
1926  glyphs[j] = sc;
1927  }
1928  }
1929 return( glyphs );
1930 }
1931 
1932 static int NamesStartWith(SplineChar *sc,char *names ) {
1933  char *pt;
1934 
1935  pt = strchr(names,' ');
1936  if ( pt==NULL ) pt = names+strlen(names);
1937  if ( pt-names!=strlen(sc->name))
1938 return( false );
1939 
1940 return( strncmp(sc->name,names,pt-names)==0 );
1941 }
1942 
1944  int i, cnt;
1945 
1946  for ( i=cnt=0; i<fpst->rule_cnt; ++i ) {
1947  if ( NamesStartWith(sc,fpst->rules[i].u.glyph.names))
1948  ++cnt;
1949  }
1950 return( cnt );
1951 }
1952 
1953 static int CntRulesStartingWithClass(FPST *fpst,uint16 cval) {
1954  int i, cnt;
1955 
1956  for ( i=cnt=0; i<fpst->rule_cnt; ++i ) {
1957  if ( fpst->rules[i].u.class.nclasses[0]==cval )
1958  ++cnt;
1959  }
1960 return( cnt );
1961 }
1962 
1964  struct lookup_subtable *sub, struct alltabs *at) {
1965  FPST *fpst = sub->fpst;
1966  int iscontext = fpst->type==pst_contextpos || fpst->type==pst_contextsub;
1967  uint32 base = ftell(lfile);
1968  int i,cnt, subcnt, j,k,l, maxcontext,curcontext;
1969  SplineChar **glyphs, **subglyphs;
1970  int lc;
1971 
1972  glyphs = OrderedInitialGlyphs(sf,fpst);
1973  for ( cnt=0; glyphs[cnt]!=NULL; ++cnt );
1974 
1975  putshort(lfile,1); /* Sub format 1 => glyph lists */
1976  putshort(lfile,(3+cnt)*sizeof(short)); /* offset to coverage */
1977  putshort(lfile,cnt);
1978  for ( i=0; i<cnt; ++i )
1979  putshort(lfile,0); /* Offset to rule */
1980  dumpcoveragetable(lfile,glyphs);
1981 
1982  maxcontext = 0;
1983 
1984  for ( i=0; i<cnt; ++i ) {
1985  uint32 pos = ftell(lfile);
1986  fseek(lfile,base+(3+i)*sizeof(short),SEEK_SET);
1987  putshort(lfile,pos-base);
1988  fseek(lfile,pos,SEEK_SET);
1989  subcnt = CntRulesStartingWith(fpst,glyphs[i]);
1990  putshort(lfile,subcnt);
1991  for ( j=0; j<subcnt; ++j )
1992  putshort(lfile,0);
1993  for ( j=k=0; k<fpst->rule_cnt; ++k ) if ( NamesStartWith(glyphs[i],fpst->rules[k].u.glyph.names )) {
1994  uint32 subpos = ftell(lfile);
1995  fseek(lfile,pos+(1+j)*sizeof(short),SEEK_SET);
1996  putshort(lfile,subpos-pos);
1997  fseek(lfile,subpos,SEEK_SET);
1998 
1999  for ( l=lc=0; l<fpst->rules[k].lookup_cnt; ++l )
2000  if ( fpst->rules[k].lookups[l].lookup->lookup_index!=-1 )
2001  ++lc;
2002  if ( iscontext ) {
2003  subglyphs = SFGlyphsFromNames(sf,fpst->rules[k].u.glyph.names);
2004  for ( l=0; subglyphs[l]!=NULL; ++l );
2005  putshort(lfile,l);
2006  curcontext = l;
2007  putshort(lfile,lc);
2008  for ( l=1; subglyphs[l]!=NULL; ++l )
2009  putshort(lfile,subglyphs[l]->ttf_glyph);
2010  free(subglyphs);
2011  } else {
2012  subglyphs = SFGlyphsFromNames(sf,fpst->rules[k].u.glyph.back);
2013  for ( l=0; subglyphs[l]!=NULL; ++l );
2014  putshort(lfile,l);
2015  curcontext = l;
2016  for ( l=0; subglyphs[l]!=NULL; ++l )
2017  putshort(lfile,subglyphs[l]->ttf_glyph);
2018  free(subglyphs);
2019  subglyphs = SFGlyphsFromNames(sf,fpst->rules[k].u.glyph.names);
2020  for ( l=0; subglyphs[l]!=NULL; ++l );
2021  putshort(lfile,l);
2022  curcontext += l;
2023  for ( l=1; subglyphs[l]!=NULL; ++l )
2024  putshort(lfile,subglyphs[l]->ttf_glyph);
2025  free(subglyphs);
2026  subglyphs = SFGlyphsFromNames(sf,fpst->rules[k].u.glyph.fore);
2027  for ( l=0; subglyphs[l]!=NULL; ++l );
2028  putshort(lfile,l);
2029  curcontext += l;
2030  for ( l=0; subglyphs[l]!=NULL; ++l )
2031  putshort(lfile,subglyphs[l]->ttf_glyph);
2032  free(subglyphs);
2033  putshort(lfile,lc);
2034  }
2035  for ( l=0; l<fpst->rules[k].lookup_cnt; ++l )
2036  if ( fpst->rules[k].lookups[l].lookup->lookup_index!=-1 ) {
2037  putshort(lfile,fpst->rules[k].lookups[l].seq);
2038  putshort(lfile,fpst->rules[k].lookups[l].lookup->lookup_index);
2039  }
2040  ++j;
2041  if ( curcontext>maxcontext ) maxcontext = curcontext;
2042  }
2043  }
2044  free(glyphs);
2045 
2046  if ( maxcontext>at->os2.maxContext )
2047  at->os2.maxContext = maxcontext;
2048 }
2049 
2051  struct lookup_subtable *sub, struct alltabs *at) {
2052  FPST *fpst = sub->fpst;
2053  int iscontext = fpst->type==pst_contextpos || fpst->type==pst_contextsub;
2054  uint32 base = ftell(lfile), rulebase, pos, subpos, npos;
2055  uint16 *initialclasses, *iclass, *bclass, *lclass;
2056  SplineChar **iglyphs, **bglyphs, **lglyphs, **glyphs;
2057  int i,ii,cnt, subcnt, j,k,l , maxcontext,curcontext;
2058  int lc;
2059 
2060  putshort(lfile,2); /* Sub format 2 => class */
2061  putshort(lfile,0); /* offset to coverage table */
2062  if ( iscontext )
2063  putshort(lfile,0); /* offset to input classdef */
2064  else {
2065  putshort(lfile,0); /* offset to backtrack classdef */
2066  putshort(lfile,0); /* offset to input classdef */
2067  putshort(lfile,0); /* offset to lookahead classdef */
2068  }
2069  initialclasses = FigureInitialClasses(fpst);
2070  putshort(lfile,fpst->nccnt);
2071  rulebase = ftell(lfile);
2072  for ( cnt=0; cnt<fpst->nccnt; ++cnt )
2073  putshort(lfile,0);
2074 
2075  iclass = ClassesFromNames(sf,fpst->nclass,fpst->nccnt,at->maxp.numGlyphs,&iglyphs,false);
2076  lglyphs = bglyphs = NULL; bclass = lclass = NULL;
2077  if ( !iscontext ) {
2078  bclass = ClassesFromNames(sf,fpst->bclass,fpst->bccnt,at->maxp.numGlyphs,&bglyphs,false);
2079  lclass = ClassesFromNames(sf,fpst->fclass,fpst->fccnt,at->maxp.numGlyphs,&lglyphs,false);
2080  }
2081  pos = ftell(lfile);
2082  fseek(lfile,base+sizeof(uint16),SEEK_SET);
2083  putshort(lfile,pos-base);
2084  fseek(lfile,pos,SEEK_SET);
2085  glyphs = GlyphsFromInitialClasses(iglyphs,at->maxp.numGlyphs,iclass,initialclasses);
2086  dumpcoveragetable(lfile,glyphs);
2087  free(glyphs);
2088  free(iglyphs); free(bglyphs); free(lglyphs);
2089 
2090  if ( iscontext ) {
2091  pos = ftell(lfile);
2092  fseek(lfile,base+2*sizeof(uint16),SEEK_SET);
2093  putshort(lfile,pos-base);
2094  fseek(lfile,pos,SEEK_SET);
2095  DumpClass(lfile,iclass,at->maxp.numGlyphs);
2096  free(iclass);
2097  } else {
2098  pos = ftell(lfile);
2099  fseek(lfile,base+2*sizeof(uint16),SEEK_SET);
2100  putshort(lfile,pos-base);
2101  fseek(lfile,pos,SEEK_SET);
2102  DumpClass(lfile,bclass,at->maxp.numGlyphs);
2103  if ( ClassesMatch(fpst->bccnt,fpst->bclass,fpst->nccnt,fpst->nclass)) {
2104  npos = pos;
2105  fseek(lfile,base+3*sizeof(uint16),SEEK_SET);
2106  putshort(lfile,npos-base);
2107  fseek(lfile,0,SEEK_END);
2108  } else {
2109  npos = ftell(lfile);
2110  fseek(lfile,base+3*sizeof(uint16),SEEK_SET);
2111  putshort(lfile,npos-base);
2112  fseek(lfile,npos,SEEK_SET);
2113  DumpClass(lfile,iclass,at->maxp.numGlyphs);
2114  }
2115  if ( ClassesMatch(fpst->fccnt,fpst->fclass,fpst->bccnt,fpst->bclass)) {
2116  fseek(lfile,base+4*sizeof(uint16),SEEK_SET);
2117  putshort(lfile,pos-base);
2118  fseek(lfile,0,SEEK_END);
2119  } else if ( ClassesMatch(fpst->fccnt,fpst->fclass,fpst->nccnt,fpst->nclass)) {
2120  fseek(lfile,base+4*sizeof(uint16),SEEK_SET);
2121  putshort(lfile,npos-base);
2122  fseek(lfile,0,SEEK_END);
2123  } else {
2124  pos = ftell(lfile);
2125  fseek(lfile,base+4*sizeof(uint16),SEEK_SET);
2126  putshort(lfile,pos-base);
2127  fseek(lfile,pos,SEEK_SET);
2128  DumpClass(lfile,lclass,at->maxp.numGlyphs);
2129  }
2130  free(iclass); free(bclass); free(lclass);
2131  }
2132 
2133  ii=0;
2134  for ( i=0; i<fpst->nccnt; ++i ) {
2135  if ( initialclasses[ii]!=i ) {
2136  /* This class isn't an initial one, so leave it's rule pointer NULL */
2137  } else {
2138  ++ii;
2139  pos = ftell(lfile);
2140  fseek(lfile,rulebase+i*sizeof(short),SEEK_SET);
2141  putshort(lfile,pos-base);
2142  fseek(lfile,pos,SEEK_SET);
2143  subcnt = CntRulesStartingWithClass(fpst,i);
2144  putshort(lfile,subcnt);
2145  for ( j=0; j<subcnt; ++j )
2146  putshort(lfile,0);
2147  for ( j=k=0; k<fpst->rule_cnt; ++k ) if ( i==fpst->rules[k].u.class.nclasses[0] ) {
2148  subpos = ftell(lfile);
2149  fseek(lfile,pos+(1+j)*sizeof(short),SEEK_SET);
2150  putshort(lfile,subpos-pos);
2151  fseek(lfile,subpos,SEEK_SET);
2152 
2153  for ( l=lc=0; l<fpst->rules[k].lookup_cnt; ++l )
2154  if ( fpst->rules[k].lookups[l].lookup->lookup_index!=-1 )
2155  ++lc;
2156  if ( iscontext ) {
2157  putshort(lfile,fpst->rules[k].u.class.ncnt);
2158  putshort(lfile,lc);
2159  for ( l=1; l<fpst->rules[k].u.class.ncnt; ++l )
2160  putshort(lfile,fpst->rules[k].u.class.nclasses[l]);
2161  } else {
2162  putshort(lfile,fpst->rules[k].u.class.bcnt);
2163  for ( l=0; l<fpst->rules[k].u.class.bcnt; ++l )
2164  putshort(lfile,fpst->rules[k].u.class.bclasses[l]);
2165  putshort(lfile,fpst->rules[k].u.class.ncnt);
2166  for ( l=1; l<fpst->rules[k].u.class.ncnt; ++l )
2167  putshort(lfile,fpst->rules[k].u.class.nclasses[l]);
2168  putshort(lfile,fpst->rules[k].u.class.fcnt);
2169  for ( l=0; l<fpst->rules[k].u.class.fcnt; ++l )
2170  putshort(lfile,fpst->rules[k].u.class.fclasses[l]);
2171  putshort(lfile,lc);
2172  }
2173  for ( l=0; l<fpst->rules[k].lookup_cnt; ++l )
2174  if ( fpst->rules[k].lookups[l].lookup->lookup_index!=-1 ) {
2175  putshort(lfile,fpst->rules[k].lookups[l].seq);
2176  putshort(lfile,fpst->rules[k].lookups[l].lookup->lookup_index);
2177  }
2178  ++j;
2179  }
2180  }
2181  }
2182  free(initialclasses);
2183 
2184  maxcontext = 0;
2185  for ( i=0; i<fpst->rule_cnt; ++i ) {
2186  curcontext = fpst->rules[i].u.class.ncnt+fpst->rules[i].u.class.bcnt+fpst->rules[i].u.class.fcnt;
2187  if ( curcontext>maxcontext ) maxcontext = curcontext;
2188  }
2189  if ( maxcontext>at->os2.maxContext )
2190  at->os2.maxContext = maxcontext;
2191 }
2192 
2194  struct lookup_subtable *sub, struct alltabs *at) {
2195  FPST *fpst = sub->fpst;
2196  int iscontext = fpst->type==pst_contextpos || fpst->type==pst_contextsub;
2197  uint32 base = ftell(lfile), ibase, lbase, bbase;
2198  int i, l;
2199  SplineChar **glyphs;
2200  int curcontext;
2201  int lc;
2202 
2203  if ( fpst->rule_cnt!=1 )
2204  IError("Bad rule cnt in coverage context lookup");
2205  if ( fpst->format==pst_reversecoverage && fpst->rules[0].u.rcoverage.always1!=1 )
2206  IError("Bad input count in reverse coverage lookup" );
2207 
2208  putshort(lfile,3); /* Sub format 3 => coverage */
2209  for ( l=lc=0; l<fpst->rules[0].lookup_cnt; ++l )
2210  if ( fpst->rules[0].lookups[l].lookup->lookup_index!=-1 )
2211  ++lc;
2212  if ( iscontext ) {
2213  putshort(lfile,fpst->rules[0].u.coverage.ncnt);
2214  putshort(lfile,lc);
2215  for ( i=0; i<fpst->rules[0].u.coverage.ncnt; ++i )
2216  putshort(lfile,0);
2217  for ( i=0; i<fpst->rules[0].lookup_cnt; ++i )
2218  if ( fpst->rules[0].lookups[i].lookup->lookup_index!=-1 ) {
2219  putshort(lfile,fpst->rules[0].lookups[i].seq);
2220  putshort(lfile,fpst->rules[0].lookups[i].lookup->lookup_index);
2221  }
2222  for ( i=0; i<fpst->rules[0].u.coverage.ncnt; ++i ) {
2223  uint32 pos = ftell(lfile);
2224  fseek(lfile,base+6+2*i,SEEK_SET);
2225  putshort(lfile,pos-base);
2226  fseek(lfile,pos,SEEK_SET);
2227  glyphs = OrderedGlyphsFromNames(sf,fpst->rules[0].u.coverage.ncovers[i]);
2228  dumpcoveragetable(lfile,glyphs);
2229  free(glyphs);
2230  }
2231  } else {
2232  if ( fpst->format==pst_reversecoverage ) {
2233  ibase = ftell(lfile);
2234  putshort(lfile,0);
2235  }
2236  putshort(lfile,fpst->rules[0].u.coverage.bcnt);
2237  bbase = ftell(lfile);
2238  for ( i=0; i<fpst->rules[0].u.coverage.bcnt; ++i )
2239  putshort(lfile,0);
2240  if ( fpst->format==pst_coverage ) {
2241  putshort(lfile,fpst->rules[0].u.coverage.ncnt);
2242  ibase = ftell(lfile);
2243  for ( i=0; i<fpst->rules[0].u.coverage.ncnt; ++i )
2244  putshort(lfile,0);
2245  }
2246  putshort(lfile,fpst->rules[0].u.coverage.fcnt);
2247  lbase = ftell(lfile);
2248  for ( i=0; i<fpst->rules[0].u.coverage.fcnt; ++i )
2249  putshort(lfile,0);
2250  if ( fpst->format==pst_coverage ) {
2251  putshort(lfile,lc);
2252  for ( i=0; i<fpst->rules[0].lookup_cnt; ++i )
2253  if ( fpst->rules[0].lookups[i].lookup->lookup_index!=-1 ) {
2254  putshort(lfile,fpst->rules[0].lookups[i].seq);
2255  putshort(lfile,fpst->rules[0].lookups[i].lookup->lookup_index);
2256  }
2257  } else { /* reverse coverage */
2258  glyphs = SFGlyphsFromNames(sf,fpst->rules[0].u.rcoverage.replacements);
2259  for ( i=0; glyphs[i]!=0; ++i );
2260  putshort(lfile,i);
2261  for ( i=0; glyphs[i]!=0; ++i )
2262  putshort(lfile,glyphs[i]->ttf_glyph);
2263  }
2264  for ( i=0; i<fpst->rules[0].u.coverage.ncnt; ++i ) {
2265  uint32 pos = ftell(lfile);
2266  fseek(lfile,ibase+2*i,SEEK_SET);
2267  putshort(lfile,pos-base);
2268  fseek(lfile,pos,SEEK_SET);
2269  glyphs = OrderedGlyphsFromNames(sf,fpst->rules[0].u.coverage.ncovers[i]);
2270  dumpcoveragetable(lfile,glyphs);
2271  free(glyphs);
2272  }
2273  for ( i=0; i<fpst->rules[0].u.coverage.bcnt; ++i ) {
2274  uint32 pos = ftell(lfile);
2275  fseek(lfile,bbase+2*i,SEEK_SET);
2276  putshort(lfile,pos-base);
2277  fseek(lfile,pos,SEEK_SET);
2278  glyphs = OrderedGlyphsFromNames(sf,fpst->rules[0].u.coverage.bcovers[i]);
2279  dumpcoveragetable(lfile,glyphs);
2280  free(glyphs);
2281  }
2282  for ( i=0; i<fpst->rules[0].u.coverage.fcnt; ++i ) {
2283  uint32 pos = ftell(lfile);
2284  fseek(lfile,lbase+2*i,SEEK_SET);
2285  putshort(lfile,pos-base);
2286  fseek(lfile,pos,SEEK_SET);
2287  glyphs = OrderedGlyphsFromNames(sf,fpst->rules[0].u.coverage.fcovers[i]);
2288  dumpcoveragetable(lfile,glyphs);
2289  free(glyphs);
2290  }
2291  }
2292 
2293  curcontext = fpst->rules[0].u.coverage.ncnt+fpst->rules[0].u.coverage.bcnt+fpst->rules[0].u.coverage.fcnt;
2294  if ( curcontext>at->os2.maxContext )
2295  at->os2.maxContext = curcontext;
2296 }
2297 
2299  struct lookup_subtable *sub, struct alltabs *at) {
2300  FPST *fpst = sub->fpst;
2301 
2302  switch ( fpst->format ) {
2303  case pst_glyphs:
2304  dumpg___ContextChainGlyphs(lfile,sf,sub,at);
2305  break;
2306  case pst_class:
2307  dumpg___ContextChainClass(lfile,sf,sub,at);
2308  break;
2309  case pst_coverage:
2310  case pst_reversecoverage:
2312  break;
2313  }
2314 
2315  fseek(lfile,0,SEEK_END);
2316 
2317 }
2318 
2319 static void AnchorsAway(FILE *lfile,SplineFont *sf,
2320  struct lookup_subtable *sub, struct glyphinfo *gi ) {
2321  SplineChar **base, **lig, **mkmk;
2322  AnchorClass *ac, *acfirst;
2323  SplineChar ***marks;
2324  int *subcnts;
2325  int cmax, classcnt;
2326  int i;
2327 
2328  marks = malloc((cmax=20)*sizeof(SplineChar **));
2329  subcnts = malloc(cmax*sizeof(int));
2330 
2331  classcnt = 0;
2332  acfirst = NULL;
2333  for ( ac=sf->anchor; ac!=NULL; ac = ac->next ) {
2334  ac->matches = false;
2335  if ( ac->subtable==sub && !ac->processed ) {
2336  if ( acfirst == NULL )
2337  acfirst = ac;
2338  if ( ac->type==act_curs )
2339  continue;
2340  else if ( ac->has_mark && ac->has_base ) {
2341  ac->matches = ac->processed = true;
2342  ++classcnt;
2343  }
2344  }
2345  }
2346  if ( classcnt>cmax ) {
2347  marks = realloc(marks,(cmax=classcnt+10)*sizeof(SplineChar **));
2348  subcnts = realloc(subcnts,cmax*sizeof(int));
2349  }
2350  AnchorClassDecompose(sf,acfirst,classcnt,subcnts,marks,&base,&lig,&mkmk,gi);
2351  switch ( sub->lookup->lookup_type ) {
2352  case gpos_mark2base:
2353  if ( marks[0]!=NULL && base!=NULL )
2354  dumpgposAnchorData(lfile,acfirst,at_basechar,marks,base,classcnt,gi);
2355  break;
2356  case gpos_mark2ligature:
2357  if ( marks[0]!=NULL && lig!=NULL )
2358  dumpgposAnchorData(lfile,acfirst,at_baselig,marks,lig,classcnt,gi);
2359  break;
2360  case gpos_mark2mark:
2361  if ( marks[0]!=NULL && mkmk!=NULL )
2362  dumpgposAnchorData(lfile,acfirst,at_basemark,marks,mkmk,classcnt,gi);
2363  break;
2364  default:;
2365  }
2366  for ( i=0; i<classcnt; ++i )
2367  free(marks[i]);
2368  free(base);
2369  free(lig);
2370  free(mkmk);
2371  free(marks);
2372  free(subcnts);
2373 }
2374 
2375 static int lookup_size_cmp(const void *_l1, const void *_l2) {
2376  const OTLookup *l1 = *(OTLookup **) _l1, *l2 = *(OTLookup **) _l2;
2377 return( l1->lookup_length-l2->lookup_length );
2378 }
2379 
2380 static int FPSTRefersToOTL(FPST *fpst,OTLookup *otl) {
2381  int i, j;
2382 
2383  if ( fpst==NULL || fpst->type == pst_reversesub )
2384 return( false );
2385  for ( i=0; i<fpst->rule_cnt; ++i ) {
2386  for ( j=0; j< fpst->rules[i].lookup_cnt; ++j )
2387  if ( fpst->rules[i].lookups[j].lookup == otl )
2388 return( true );
2389  }
2390 return( false );
2391 }
2392 
2393 static int OnlyMac(OTLookup *otl, OTLookup *all) {
2395  int anymac = 0;
2396  struct lookup_subtable *sub;
2397 
2398  switch ( otl->lookup_type ) {
2399  /* These two lookup types are mac only */
2400  case kern_statemachine: case morx_indic: case morx_context: case morx_insert:
2401  return( true );
2402  /* These lookup types are OpenType only */
2403  case gsub_multiple: case gsub_alternate: case gsub_context:
2405  case gpos_single: case gpos_cursive: case gpos_mark2base:
2407  case gpos_context: case gpos_contextchain:
2408  return( false );
2409  /* These two can be expressed in both, and might be either */
2410  case gpos_pair: case gsub_single: case gsub_ligature:
2411  for ( features = otl->features; features!=NULL; features = features->next ) {
2412  if ( !features->ismac )
2413  return( false );
2414  else
2415  anymac = true;
2416  }
2417  /* Either it has no features at all (nested), or all its features */
2418  /* are mac feature settings. Even if all are mac feature settings it */
2419  /* might still be used as under control of a contextual feature */
2420  /* so in both cases check for nested */
2421  while ( all!=NULL ) {
2422  if ( all!=otl && !all->unused &&
2423  (all->lookup_type==gpos_context ||
2424  all->lookup_type==gpos_contextchain ||
2425  all->lookup_type==gsub_context ||
2426  all->lookup_type==gsub_contextchain /*||
2427  all->lookup_type==gsub_reversecchain*/ )) {
2428  for ( sub=all->subtables; sub!=NULL; sub=sub->next ) if ( !sub->unused && sub->fpst!=NULL ) {
2429  if ( FPSTRefersToOTL(sub->fpst,otl) )
2430  return( false );
2431  }
2432  }
2433  all = all->next;
2434  }
2435  if ( anymac )
2436  return( true );
2437  /* As far as I can tell, this lookup isn't used at all */
2438  /* Let's output it anyway, just in case we ever support some other */
2439  /* table that uses GPOS/GSUB lookups (I think JUST) */
2440  return( false );
2441  default:;
2442  }
2443  /* Should never get here, but gcc probably thinks we might */
2444 return( true );
2445 }
2446 
2447 static void otf_dumpALookup(FILE *lfile, OTLookup *otl, SplineFont *sf,
2448  struct alltabs *at) {
2449  struct lookup_subtable *sub;
2450  int lookup_sub_table_contains_no_data_count = 0;
2451  int lookup_sub_table_is_too_big_count = 0;
2452 
2453  otl->lookup_offset = ftell(lfile);
2454  for ( sub = otl->subtables; sub!=NULL; sub=sub->next ) {
2455  sub->extra_subtables = NULL;
2456  if ( sub->unused )
2457  sub->subtable_offset = -1;
2458  else {
2459  sub->subtable_offset = ftell(lfile);
2460  switch ( otl->lookup_type ) {
2461  /* GPOS lookup types */
2462  case gpos_single:
2463  dumpGPOSsimplepos(lfile,sf,sub);
2464  break;
2465 
2466  case gpos_pair:
2467  if ( at->os2.maxContext<2 )
2468  at->os2.maxContext = 2;
2469  if ( sub->kc!=NULL )
2470  dumpgposkernclass(lfile,sf,sub,at);
2471  else
2472  dumpGPOSpairpos(lfile,sf,sub);
2473  break;
2474 
2475  case gpos_cursive:
2476  dumpgposCursiveAttach(lfile,sf,sub,&at->gi);
2477  break;
2478 
2479  case gpos_mark2base:
2480  case gpos_mark2ligature:
2481  case gpos_mark2mark:
2482  AnchorsAway(lfile,sf,sub,&at->gi);
2483  break;
2484 
2485  case gpos_contextchain:
2486  case gpos_context:
2487  dumpg___ContextChain(lfile,sf,sub,at);
2488  break;
2489 
2490  /* GSUB lookup types */
2491  case gsub_single:
2492  dumpGSUBsimplesubs(lfile,sf,sub);
2493  break;
2494 
2495  case gsub_multiple:
2496  case gsub_alternate:
2497  dumpGSUBmultiplesubs(lfile,sf,sub);
2498  break;
2499 
2500  case gsub_ligature:
2501  dumpGSUBligdata(lfile,sf,sub,at);
2502  break;
2503 
2504  case gsub_contextchain:
2505  case gsub_context:
2506  case gsub_reversecchain:
2507  dumpg___ContextChain(lfile,sf,sub,at);
2508  break;
2509  default:;
2510  }
2511  if ( ftell(lfile)-sub->subtable_offset==0 ) {
2512  if ( lookup_sub_table_contains_no_data_count < 32 ) {
2513  IError( "Lookup sub table, %s in %s, contains no data.\n",
2514  sub->subtable_name, sub->lookup->lookup_name );
2515  lookup_sub_table_contains_no_data_count ++;
2516  }
2517  sub->unused = true;
2518  sub->subtable_offset = -1;
2519  } else if ( sub->extra_subtables==NULL &&
2520  ftell(lfile)-sub->subtable_offset>65535 )
2521  if ( lookup_sub_table_is_too_big_count < 32 ) {
2522  IError( "Lookup sub table, %s in %s, is too big. Will not be useable.\n",
2523  sub->subtable_name, sub->lookup->lookup_name );
2524  lookup_sub_table_is_too_big_count ++;
2525  }
2526  }
2527  }
2528  otl->lookup_length = ftell(lfile)-otl->lookup_offset;
2529 }
2530 
2531 static FILE *G___figureLookups(SplineFont *sf,int is_gpos,
2532  struct alltabs *at) {
2533  OTLookup *otl;
2534  struct lookup_subtable *sub;
2535  int index, i,j;
2536  FILE *final;
2537  FILE *lfile = tmpfile2();
2538  OTLookup **sizeordered;
2539  OTLookup *all = is_gpos ? sf->gpos_lookups : sf->gsub_lookups;
2540  char *buffer;
2541  int len;
2542 
2543  index = 0;
2544  for ( otl=all; otl!=NULL; otl=otl->next ) {
2545  if ( otl->unused || OnlyMac(otl,all) || otl->only_jstf || otl->temporary_kern )
2546  otl->lookup_index = -1;
2547  else
2548  otl->lookup_index = index++;
2549  }
2550  for ( otl=all; otl!=NULL; otl=otl->next ) {
2551  if ( otl->lookup_index!=-1 ) {
2552  otf_dumpALookup(lfile, otl, sf, at );
2553  }
2554  }
2555  if ( is_gpos )
2556  AnchorGuessContext(sf,at);
2557 
2558  /* We don't need to reorder short files */
2559  if ( ftell(lfile)<65536 )
2560 return( lfile );
2561 
2562  /* Order the lookups so that the smallest ones come first */
2563  /* thus we are less likely to need extension tables */
2564  /* I think it's better to order the entire lookup rather than ordering the*/
2565  /* subtables -- since the extension subtable would be required for all */
2566  /* subtables in the lookup, so might as well keep them all together */
2567  sizeordered = malloc(index*sizeof(OTLookup *));
2568  for ( otl=is_gpos ? sf->gpos_lookups : sf->gsub_lookups; otl!=NULL; otl=otl->next )
2569  if ( otl->lookup_index!=-1 )
2570  sizeordered[ otl->lookup_index ] = otl;
2571  qsort(sizeordered,index,sizeof(OTLookup *),lookup_size_cmp);
2572 
2573  final = tmpfile2();
2574  buffer = malloc(32768);
2575  for ( i=0; i<index; ++i ) {
2576  uint32 diff;
2577  otl = sizeordered[i];
2578  fseek(lfile,otl->lookup_offset,SEEK_SET);
2579  diff = ftell(final) - otl->lookup_offset;
2580  otl->lookup_offset = ftell(final);
2581  len = otl->lookup_length;
2582  while ( len>=32768 ) {
2583  int done = fread(buffer,1,32768,lfile);
2584  if ( done==0 ) /* fread returns 0 on error, not EOF */
2585  break;
2586  fwrite(buffer,1,done,final);
2587  len -= done;
2588  }
2589  if ( len>0 && len<=32768 ) {
2590  int done = fread(buffer,1,len,lfile);
2591  if ( done==0 )
2592  break;
2593  fwrite(buffer,1,done,final);
2594  }
2595  for ( sub = otl->subtables; sub!=NULL; sub=sub->next ) {
2596  if ( !sub->unused ) {
2597  sub->subtable_offset += diff;
2598  if ( sub->extra_subtables!=NULL ) {
2599  for ( j=0; sub->extra_subtables[j]!=-1; ++j )
2600  sub->extra_subtables[j] += diff;
2601  }
2602  }
2603  }
2604  }
2605  free(buffer);
2606  free(sizeordered);
2607  fclose(lfile);
2608 return( final );
2609 }
2610 
2613  int lcnt;
2615  int feature_id; /* Initially consecutive, but may be rearranged by sorting */
2617 };
2618 
2619 struct langsys {
2621  int fc;
2623  int same_as;
2625 };
2626 
2627 struct scriptset {
2629  int lc;
2630  struct langsys *langsys;
2631 };
2632 
2633 struct ginfo {
2634  int fmax, fcnt;
2636  int sc;
2638 };
2639 
2640 static int FindOrMakeNewFeatureLookup(struct ginfo *ginfo,OTLookup **lookups,
2641  uint32 tag) {
2642  int i, j;
2643 
2644  for ( i=0; i<ginfo->fcnt; ++i ) {
2645  if ( ginfo->feat_lookups[i].tag!= tag )
2646  continue;
2647  if ( lookups==NULL && ginfo->feat_lookups[i].lookups==NULL ) /* 'size' feature */
2648 return( i );
2649  if ( lookups==NULL || ginfo->feat_lookups[i].lookups==NULL )
2650  continue;
2651  for ( j=0; lookups[j]!=NULL && ginfo->feat_lookups[i].lookups[j]!=NULL; ++j )
2652  if ( ginfo->feat_lookups[i].lookups[j]!=lookups[j] )
2653  break;
2654  if ( ginfo->feat_lookups[i].lookups[j]==lookups[j] ) {
2655  free(lookups);
2656 return( i );
2657  }
2658  }
2659  if ( ginfo->fcnt>=ginfo->fmax )
2660  ginfo->feat_lookups = realloc(ginfo->feat_lookups,(ginfo->fmax+=20)*sizeof(struct feat_lookups));
2662  ginfo->feat_lookups[i].tag = tag;
2663  ginfo->feat_lookups[i].lookups = lookups;
2664  j=0;
2665  if ( lookups!=NULL ) for ( ; lookups[j]!=NULL; ++j );
2666  ginfo->feat_lookups[i].lcnt = j;
2667  ++ginfo->fcnt;
2668 return( i );
2669 }
2670 
2671 static int feat_alphabetize(const void *_fl1, const void *_fl2) {
2672  const struct feat_lookups *fl1 = _fl1, *fl2 = _fl2;
2673 
2674  if ( fl1->tag<fl2->tag )
2675 return( -1 );
2676  if ( fl1->tag>fl2->tag )
2677 return( 1 );
2678 
2679 return( 0 );
2680 }
2681 
2682 static int numeric_order(const void *_i1, const void *_i2) {
2683  int i1 = *(const int *) _i1, i2 = *(const int *) _i2;
2684 
2685  if ( i1<i2 )
2686 return( -1 );
2687  if ( i1>i2 )
2688 return( 1 );
2689 
2690 return( 0 );
2691 }
2692 
2693 static int LangSysMatch(struct scriptset *s,int ils1, int ils2 ) {
2694  struct langsys *ls1 = &s->langsys[ils1], *ls2 = &s->langsys[ils2];
2695  int i;
2696 
2697  if ( ls1->fc!=ls2->fc )
2698 return( false );
2699  for ( i=0; i<ls1->fc; ++i )
2700  if ( ls1->feature_id[i]!=ls2->feature_id[i] )
2701 return( false );
2702 
2703 return( true );
2704 }
2705 
2706 static void FindFeatures(SplineFont *sf,int is_gpos,struct ginfo *ginfo) {
2708  OTLookup **lookups;
2709  int sc, lc, fc, j;
2710 
2711  memset(ginfo,0,sizeof(struct ginfo));
2712 
2713  scripts = SFScriptsInLookups(sf,is_gpos);
2714  if ( scripts==NULL ) /* All lookups unused */
2715 return;
2716  for ( sc=0; scripts[sc]!=0; ++sc );
2717  ginfo->scripts = malloc(sc*sizeof(struct scriptset));
2718  ginfo->sc = sc;
2719  for ( sc=0; scripts[sc]!=0; ++sc ) {
2720  langs = SFLangsInScript(sf,is_gpos,scripts[sc]);
2721  for ( lc=0; langs[lc]!=0; ++lc );
2723  ginfo->scripts[sc].lc = lc;
2724  ginfo->scripts[sc].langsys = malloc(lc*sizeof(struct langsys));
2725  for ( lc=0; langs[lc]!=0; ++lc ) {
2727  for ( fc=0; features[fc]!=0; ++fc );
2729  ginfo->scripts[sc].langsys[lc].fc = fc;
2730  ginfo->scripts[sc].langsys[lc].feature_id = malloc(fc*sizeof(int));
2731  ginfo->scripts[sc].langsys[lc].same_as = -1;
2732  for ( fc=0; features[fc]!=0; ++fc ) {
2733  lookups = SFLookupsInScriptLangFeature(sf,is_gpos,scripts[sc],langs[lc],features[fc]);
2736  /* lookups is freed or used by FindOrMakeNewFeatureLookup */
2737  }
2738  free(features);
2739  }
2740  free(langs);
2741  }
2742  free(scripts);
2743 
2745 
2746  /* Now we've disordered the features. Find each feature_id and turn it back*/
2747  /* into a feature number */
2748  for ( sc=0; sc<ginfo->sc; ++sc ) {
2749  for ( lc=0; lc<ginfo->scripts[sc].lc; ++lc ) {
2750  int fcmax = ginfo->scripts[sc].langsys[lc].fc;
2752  for ( fc=0; fc<fcmax; ++fc ) {
2753  int id = feature_id[fc];
2754  for ( j=0; j<ginfo->fcnt; ++j )
2755  if ( id==ginfo->feat_lookups[j].feature_id )
2756  break;
2757  feature_id[fc] = j;
2758  }
2759  qsort(feature_id,fcmax,sizeof(int),numeric_order);
2760  }
2761  /* See if there are langsys tables which use exactly the same features*/
2762  /* They can use the same entry in the file. This optimization seems */
2763  /* to be required for Japanese vertical writing to work in Uniscribe.*/
2764  for ( lc=0; lc<ginfo->scripts[sc].lc; ++lc ) {
2765  for ( j=0; j<lc; ++j )
2766  if ( LangSysMatch(&ginfo->scripts[sc],j,lc) ) {
2768  break;
2769  }
2770  }
2771  }
2772 }
2773 
2774 
2775 static void dump_script_table(FILE *g___,struct scriptset *ss,struct ginfo *ginfo) {
2776  int i, lcnt, dflt_lang = -1;
2777  uint32 base;
2778  int j, req_index;
2779  uint32 offset;
2780 
2781  /* Count the languages, and find default */
2782  for ( lcnt=0; lcnt<ss->lc; ++lcnt )
2783  if ( ss->langsys[lcnt].lang==DEFAULT_LANG )
2784  dflt_lang = lcnt;
2785  if ( dflt_lang != -1 )
2786  --lcnt;
2787 
2788  base = ftell(g___);
2789  putshort(g___, 0 ); /* fill in later, Default Lang Sys */
2790  putshort(g___,lcnt);
2791  for ( i=0; i<ss->lc; ++i ) if ( i!=dflt_lang ) {
2792  putlong(g___,ss->langsys[i].lang); /* Language tag */
2793  putshort(g___,0); /* Fill in later, offset to langsys */
2794  }
2795 
2796  for ( lcnt=0; lcnt<ss->lc; ++lcnt ) {
2797  if ( ss->langsys[lcnt].same_as!=-1 )
2798  offset = ss->langsys[ ss->langsys[lcnt].same_as ].offset;
2799  else {
2800  offset = ftell(g___);
2801  ss->langsys[lcnt].offset = offset;
2802  }
2803  fseek(g___,lcnt==dflt_lang ? base :
2804  lcnt<dflt_lang || dflt_lang==-1 ? base + 4 + lcnt*6 +4 :
2805  base + 4 + (lcnt-1)*6 +4 ,
2806  SEEK_SET );
2807  putshort(g___,offset-base);
2808  fseek(g___,0,SEEK_END);
2809  if ( ss->langsys[lcnt].same_as==-1 ) {
2810  req_index = -1;
2811  for ( j=0; j<ss->langsys[lcnt].fc; ++j ) {
2812  if ( ginfo->feat_lookups[ ss->langsys[lcnt].feature_id[j] ].tag == REQUIRED_FEATURE ) {
2813  req_index = ss->langsys[lcnt].feature_id[j];
2814  break;
2815  }
2816  }
2817  putshort(g___,0); /* LookupOrder, always NULL */
2818  putshort(g___,req_index); /* index of required feature, if any */
2819  putshort(g___,ss->langsys[lcnt].fc - (req_index!=-1));
2820  /* count of non-required features */
2821  for ( j=0; j<ss->langsys[lcnt].fc; ++j ) if (ss->langsys[lcnt].feature_id[j]!=req_index )
2822  putshort(g___,ss->langsys[lcnt].feature_id[j]);
2823  }
2824  }
2825 }
2826 
2827 static FILE *g___FigureExtensionSubTables(OTLookup *all,int startoffset,int is_gpos) {
2828  OTLookup *otf;
2829  struct lookup_subtable *sub;
2830  int len, len2, gotmore;
2831  FILE *efile;
2832  int i, offset, cnt;
2833  int any= false;
2834 
2835  if ( all==NULL )
2836 return( NULL );
2837  gotmore = true; cnt=len=0;
2838  while ( gotmore ) {
2839  gotmore = false;
2840  offset = startoffset + 8*cnt;
2841  for ( otf=all; otf!=NULL; otf=otf->next ) if ( otf->lookup_index!=-1 ) {
2842  if ( otf->needs_extension )
2843  continue;
2844  for ( sub = otf->subtables; sub!=NULL; sub=sub->next ) {
2845  if ( sub->subtable_offset==-1 )
2846  continue;
2847  if ( sub->extra_subtables!=NULL ) {
2848  for ( i=0; sub->extra_subtables[i]!=-1; ++i ) {
2849  if ( sub->extra_subtables[i]+offset>65535 )
2850  break;
2851  }
2852  if ( sub->extra_subtables[i]!=-1 )
2853  break;
2854  } else if ( sub->subtable_offset+offset>65535 )
2855  break;
2856  }
2857  if ( sub!=NULL ) {
2858  if ( !any ) {
2859  ff_post_notice(_("Lookup potentially too big"),
2860  _("Lookup %s has an\noffset bigger than 65535 bytes. This means\nFontForge must use an extension lookup to output it.\nNot all applications support extension lookups."),
2861  otf->lookup_name );
2862  any = true;
2863  }
2864  otf->needs_extension = true;
2865  gotmore = true;
2866  len += 8*otf->subcnt;
2867  ++cnt;
2868  }
2869  offset -= 6+2*otf->subcnt;
2870  }
2871  }
2872 
2873  if ( cnt==0 ) /* No offset overflows */
2874 return( NULL );
2875 
2876  /* Now we've worked out which lookups need extension tables and marked them*/
2877  /* Generate the extension tables, and update the offsets to reflect the size */
2878  /* of the extensions */
2879  efile = tmpfile2();
2880 
2881  len2 = 0;
2882  for ( otf=all; otf!=NULL; otf=otf->next ) if ( otf->lookup_index!=-1 ) {
2883  for ( sub = otf->subtables; sub!=NULL; sub=sub->next ) {
2884  if ( sub->subtable_offset==-1 )
2885  continue;
2886  if ( sub->extra_subtables!=NULL ) {
2887  for ( i=0; sub->extra_subtables[i]!=-1; ++i ) {
2888  sub->extra_subtables[i] += len;
2889  if ( otf->needs_extension ) {
2890  int off = ftell(efile);
2891  putshort(efile,1); /* exten subtable format (there's only one) */
2892  putshort(efile,otf->lookup_type&0xff);
2893  putlong(efile,sub->extra_subtables[i]-len2);
2894  sub->extra_subtables[i] = off;
2895  len2+=8;
2896  }
2897  }
2898  } else {
2899  sub->subtable_offset += len;
2900  if ( otf->needs_extension ) {
2901  int off = ftell(efile);
2902  putshort(efile,1); /* exten subtable format (there's only one) */
2903  putshort(efile,otf->lookup_type&0xff);
2904  putlong(efile,sub->subtable_offset-len2);
2905  sub->subtable_offset = off;
2906  len2+=8;
2907  }
2908  }
2909  }
2910  }
2911 
2912 return( efile );
2913 }
2914 
2916  struct otffeatname *fn;
2917 
2918  for ( fn=sf->feat_names; fn!=NULL && fn->tag!=tag; fn=fn->next );
2919 return( fn );
2920 }
2921 
2922 static FILE *dumpg___info(struct alltabs *at, SplineFont *sf,int is_gpos) {
2923  /* Dump out either a gpos or a gsub table. gpos handles kerns, gsub ligs */
2924  /* we assume that SFFindUnusedLookups has been called */
2925  FILE *lfile, *g___, *efile;
2926  uint32 lookup_list_table_start, feature_list_table_start, here, scripts_start_offset;
2927  struct ginfo ginfo;
2928  int32 size_params_loc, size_params_ptr;
2929  int i,j, cnt, scnt, offset;
2930  OTLookup *otf, *all;
2931  struct lookup_subtable *sub;
2932  char *buf;
2933  struct otffeatname *fn;
2934 
2935  for ( fn=sf->feat_names; fn!=NULL; fn=fn->next )
2936  fn->nid = 0;
2937 
2938  FindFeatures(sf,is_gpos,&ginfo);
2939  if ( ginfo.sc==0 )
2940 return( NULL );
2941  lfile = G___figureLookups(sf,is_gpos,at);
2942 
2943  if ( ginfo.sc==0 && ftell(lfile)==0 ) {
2944  /* ftell(lfile)==0 => There are no lookups for this table */
2945  /* ginfo.sc==0 => There are no scripts. */
2946  /* If both are true then we don't need to output the table */
2947  /* It is perfectly possible to have lookups without scripts */
2948  /* (if some other table refered to them -- we don't currently */
2949  /* support this, but we might some day). */
2950  /* It is also possible to have scripts without lookups (to get */
2951  /* around a bug in Uniscribe which only processes some scripts */
2952  /* if both GPOS and GSUB entries are present. So we share scripts */
2953  /* between the two tables */
2954  fclose(lfile);
2955  /* if ginfo.sc==0 then there will be nothing to free in the ginfo struct*/
2956 return( NULL );
2957  }
2958 
2959  g___ = tmpfile2();
2960 
2961  putlong(g___,0x10000); /* version number */
2962  putshort(g___,10); /* offset to script table */
2963  putshort(g___,0); /* offset to features. Come back for this */
2964  putshort(g___,0); /* offset to lookups. Come back for this */
2965 /* Now the scripts */
2966  scripts_start_offset = ftell(g___);
2967  putshort(g___,ginfo.sc);
2968  for ( i=0; i<ginfo.sc; ++i ) {
2969  putlong(g___,ginfo.scripts[i].script);
2970  putshort(g___,0); /* fix up later */
2971  }
2972 
2973  /* Ok, that was the script_list_table which gives each script an offset */
2974  /* Now for each script we provide a Script table which contains an */
2975  /* offset to a bunch of features for the default language, and a */
2976  /* a more complex situation for non-default languages. */
2977  offset=2+4; /* To the script pointer at the start of table */
2978  for ( i=0; i<ginfo.sc; ++i ) {
2979  here = ftell(g___);
2980  fseek(g___,scripts_start_offset+offset,SEEK_SET);
2981  putshort(g___,here-scripts_start_offset);
2982  offset+=6;
2983  fseek(g___,here,SEEK_SET);
2985  }
2986  /* And that should finish all the scripts/languages */
2987 
2988  /* so free the ginfo script/lang data */
2989  for ( i=0; i<ginfo.sc; ++i ) {
2990  for ( j=0; j<ginfo.scripts[i].lc; ++j ) {
2992  }
2993  free( ginfo.scripts[i].langsys );
2994  }
2995  free( ginfo.scripts );
2996 
2997 /* Now the features */
2998  feature_list_table_start = ftell(g___);
2999  fseek(g___,6,SEEK_SET);
3000  putshort(g___,feature_list_table_start);
3001  fseek(g___,0,SEEK_END);
3002  putshort(g___,ginfo.fcnt); /* Number of features */
3003  offset = 2+6*ginfo.fcnt; /* Offset to start of first feature table from beginning of feature_list */
3004  for ( i=0; i<ginfo.fcnt; ++i ) {
3005  putlong(g___,ginfo.feat_lookups[i].tag);
3006  putshort(g___,offset);
3007  offset += 4+2*ginfo.feat_lookups[i].lcnt;
3008  }
3009  /* for each feature, one feature table */
3010  size_params_ptr = 0;
3011  for ( i=0; i<ginfo.fcnt; ++i ) {
3013  if ( ginfo.feat_lookups[i].tag==CHR('s','i','z','e') )
3014  size_params_ptr = ftell(g___);
3015  else if ( ginfo.feat_lookups[i].tag>=CHR('s','s','0','1') && ginfo.feat_lookups[i].tag<=CHR('s','s','2','0'))
3017  putshort(g___,0); /* No feature params (we'll come back for 'size') */
3018  putshort(g___,ginfo.feat_lookups[i].lcnt);/* this many lookups */
3019  for ( j=0; j<ginfo.feat_lookups[i].lcnt; ++j )
3021  /* index of each lookup */
3022  }
3023  if ( size_params_ptr!=0 ) {
3024  size_params_loc = ftell(g___);
3025  fseek(g___,size_params_ptr,SEEK_SET);
3026  putshort(g___,size_params_loc-size_params_ptr);
3027  fseek(g___,size_params_loc,SEEK_SET);
3028  putshort(g___,sf->design_size);
3029  if ( sf->fontstyle_id!=0 || sf->fontstyle_name!=NULL ) {
3030  putshort(g___,sf->fontstyle_id);
3031  at->fontstyle_name_strid = at->next_strid++;
3032  putshort(g___,at->fontstyle_name_strid);
3033  } else {
3034  putshort(g___,0);
3035  putshort(g___,0);
3036  }
3037  putshort(g___,sf->design_range_bottom);
3038  putshort(g___,sf->design_range_top);
3039  }
3040  for ( i=0; i<ginfo.fcnt; ++i ) {
3041  if ( ginfo.feat_lookups[i].name_param_ptr!=0 &&
3043  if ( fn->nid==0 )
3044  fn->nid = at->next_strid++;
3045  uint32 name_param_loc = ftell(g___);
3047  putshort(g___,name_param_loc-ginfo.feat_lookups[i].name_param_ptr);
3048  fseek(g___,name_param_loc,SEEK_SET);
3049  putshort(g___,0); /* Minor version number */
3050  putshort(g___,fn->nid);
3051  }
3052  }
3053  /* And that should finish all the features */
3054 
3055  /* so free the ginfo feature data */
3056  for ( i=0; i<ginfo.fcnt; ++i )
3058  free( ginfo.feat_lookups );
3059 
3060 /* Now the lookups */
3061  all = is_gpos ? sf->gpos_lookups : sf->gsub_lookups;
3062  for ( cnt=0, otf = all; otf!=NULL; otf=otf->next ) {
3063  if ( otf->lookup_index!=-1 )
3064  ++cnt;
3065  }
3066  lookup_list_table_start = ftell(g___);
3067  fseek(g___,8,SEEK_SET);
3068  putshort(g___,lookup_list_table_start);
3069  fseek(g___,0,SEEK_END);
3070  putshort(g___,cnt);
3071  offset = 2+2*cnt; /* Offset to start of first lookup table from beginning of lookup list */
3072  for ( otf = all; otf!=NULL; otf=otf->next ) if ( otf->lookup_index!=-1 ) {
3073  putshort(g___,offset);
3074  for ( scnt=0, sub = otf->subtables; sub!=NULL; sub=sub->next ) {
3075  if ( sub->subtable_offset==-1 )
3076  continue;
3077  else if ( sub->extra_subtables!=NULL ) {
3078  for ( i=0; sub->extra_subtables[i]!=-1; ++i )
3079  ++scnt;
3080  } else
3081  ++scnt;
3082  }
3083  otf->subcnt = scnt;
3084  offset += 6+2*scnt; /* 6 bytes header +2 per lookup */
3086  offset += 2; /* For mark filtering set, if used */
3087  }
3088  offset -= 2+2*cnt;
3089  /* now the lookup tables */
3090  /* do we need any extension sub-tables? */
3091  efile=g___FigureExtensionSubTables(all,offset,is_gpos);
3092  for ( otf = all; otf!=NULL; otf=otf->next ) if ( otf->lookup_index!=-1 ) {
3093  putshort(g___,!otf->needs_extension ? (otf->lookup_type&0xff)
3094  : is_gpos ? 9 : 7);
3095  putshort(g___,(otf->lookup_flags&0xffff));
3096  putshort(g___,otf->subcnt);
3097  for ( sub = otf->subtables; sub!=NULL; sub=sub->next ) {
3098  if ( sub->subtable_offset==-1 )
3099  continue;
3100  else if ( sub->extra_subtables!=NULL ) {
3101  for ( i=0; sub->extra_subtables[i]!=-1; ++i )
3102  putshort(g___,offset+sub->extra_subtables[i]);
3103  } else
3104  putshort(g___,offset+sub->subtable_offset);
3105 
3106  /* Offset to lookup data which is in the temp file */
3107  /* we keep adjusting offset so it reflects the distance between */
3108  /* here and the place where the temp file will start, and then */
3109  /* we need to skip l->offset bytes in the temp file */
3110  /* If it's a big GPOS/SUB table we may also need some extension */
3111  /* pointers, but FigureExtension will adjust for that */
3112  }
3113  offset -= 6+2*otf->subcnt;
3114  if ( otf->lookup_flags & pst_usemarkfilteringset ) {
3115  putshort(g___,otf->lookup_flags>>16);
3116  offset -= 2;
3117  }
3118  }
3119 
3120  buf = malloc(8096);
3121  if ( efile!=NULL ) {
3122  rewind(efile);
3123  while ( (i=fread(buf,1,8096,efile))>0 )
3124  fwrite(buf,1,i,g___);
3125  fclose(efile);
3126  }
3127  rewind(lfile);
3128  while ( (i=fread(buf,1,8096,lfile))>0 )
3129  fwrite(buf,1,i,g___);
3130  fclose(lfile);
3131  free(buf);
3132  for ( otf = all; otf!=NULL; otf=otf->next ) if ( otf->lookup_index!=-1 ) {
3133  for ( sub = otf->subtables; sub!=NULL; sub=sub->next ) {
3134  free(sub->extra_subtables);
3135  sub->extra_subtables = NULL;
3136  }
3137  otf->needs_extension = false;
3138  }
3139 return( g___ );
3140 }
3141 
3142 void otf_dumpgpos(struct alltabs *at, SplineFont *sf) {
3143  /* Open Type, bless its annoying little heart, doesn't store kern info */
3144  /* in the kern table. Of course not, how silly of me to think it might */
3145  /* be consistent. It stores it in the much more complicated gpos table */
3146  AnchorClass *ac;
3147 
3148  for ( ac=sf->anchor; ac!=NULL; ac=ac->next )
3149  ac->processed = false;
3150 
3151  at->gpos = dumpg___info(at, sf,true);
3152  if ( at->gpos!=NULL ) {
3153  at->gposlen = ftell(at->gpos);
3154  if ( at->gposlen&1 ) putc('\0',at->gpos);
3155  if ( (at->gposlen+1)&2 ) putshort(at->gpos,0);
3156  }
3157 }
3158 
3159 void otf_dumpgsub(struct alltabs *at, SplineFont *sf) {
3160  /* substitutions such as: Ligatures, cjk vertical rotation replacement, */
3161  /* arabic forms, small caps, ... */
3163  at->gsub = dumpg___info(at, sf, false);
3164  if ( at->gsub!=NULL ) {
3165  at->gsublen = ftell(at->gsub);
3166  if ( at->gsublen&1 ) putc('\0',at->gsub);
3167  if ( (at->gsublen+1)&2 ) putshort(at->gsub,0);
3168  }
3170 }
3171 
3173  PST *pst;
3174  int j, cnt;
3175 
3176  for ( pst=sc->possub; pst!=NULL; pst=pst->next ) {
3177  if ( pst->type == pst_lcaret ) {
3178  if ( sc->lig_caret_cnt_fixed )
3179 return( pst->u.lcaret.cnt );
3180  else {
3181  /* only output non-zero carets */
3182  cnt=0;
3183  for ( j=pst->u.lcaret.cnt-1; j>=0 ; --j )
3184  if ( pst->u.lcaret.carets[j]!=0 )
3185  ++cnt;
3186 return( cnt );
3187  }
3188  }
3189  }
3190 return( 0 );
3191 }
3192 
3193 static void DumpLigCarets(FILE *gdef,SplineChar *sc) {
3194  PST *pst;
3195  int i, j, offset, cnt;
3196 
3197  for ( pst=sc->possub; pst!=NULL; pst=pst->next ) {
3198  if ( pst->type == pst_lcaret )
3199  break;
3200  }
3201  if ( pst==NULL )
3202 return;
3203  cnt = LigCaretCnt(sc);
3204  if ( cnt==0 )
3205 return;
3206 
3207  if ( SCRightToLeft(sc) ) {
3208  for ( i=0; i<pst->u.lcaret.cnt-1; ++i )
3209  for ( j=i+1; j<pst->u.lcaret.cnt; ++j )
3210  if ( pst->u.lcaret.carets[i]<pst->u.lcaret.carets[j] ) {
3211  int16 temp = pst->u.lcaret.carets[i];
3212  pst->u.lcaret.carets[i] = pst->u.lcaret.carets[j];
3213  pst->u.lcaret.carets[j] = temp;
3214  }
3215  } else {
3216  for ( i=0; i<pst->u.lcaret.cnt-1; ++i )
3217  for ( j=i+1; j<pst->u.lcaret.cnt; ++j )
3218  if ( pst->u.lcaret.carets[i]>pst->u.lcaret.carets[j] ) {
3219  int16 temp = pst->u.lcaret.carets[i];
3220  pst->u.lcaret.carets[i] = pst->u.lcaret.carets[j];
3221  pst->u.lcaret.carets[j] = temp;
3222  }
3223  }
3224 
3225  putshort(gdef,cnt); /* this many carets */
3226  offset = sizeof(uint16) + sizeof(uint16)*cnt;
3227  for ( i=0; i<cnt; ++i ) {
3228  putshort(gdef,offset);
3229  offset+=4;
3230  }
3231  for ( i=0; i<pst->u.lcaret.cnt; ++i ) {
3232  if ( sc->lig_caret_cnt_fixed || pst->u.lcaret.carets[i]!=0 ) {
3233  putshort(gdef,1); /* Format 1 */
3234  putshort(gdef,pst->u.lcaret.carets[i]);
3235  }
3236  }
3237 }
3238 
3239 static int glyphnameinlist(char *haystack,char *name) {
3240  char *start, *pt;
3241  int ch, match, slen = strlen(name);
3242 
3243  for ( pt=haystack ; ; ) {
3244  while ( *pt==' ' ) ++pt;
3245  if ( *pt=='\0' )
3246 return( false );
3247  start=pt;
3248  while ( *pt!=' ' && *pt!='\0' ) ++pt;
3249  if ( pt-start==slen ) {
3250  ch = *pt; *pt='\0';
3251  match = strcmp(start,name);
3252  *pt = ch;
3253  if ( match==0 )
3254 return( true );
3255  }
3256  }
3257 }
3258 
3260  PST *pst;
3261  SplineFont *sf = sc->parent;
3262  int gid;
3263  SplineChar *testsc;
3264  char *name = sc->name;
3265 
3266  /* If it is itself a ligature it will be referenced by GSUB */
3267  /* (because we store ligatures on the glyph generated) */
3268  for ( pst=sc->possub; pst!=NULL; pst=pst->next )
3269  if ( pst->type == pst_ligature )
3270 return( true );
3271 
3272  for ( gid=0; gid<sf->glyphcnt; ++gid ) if ( (testsc=sf->glyphs[gid])!=NULL ) {
3273  for ( pst=testsc->possub; pst!=NULL; pst=pst->next ) {
3274  if ( pst->type==pst_substitution || pst->type==pst_alternate ||
3275  pst->type==pst_multiple ) {
3276  if ( glyphnameinlist(pst->u.mult.components,name) )
3277 return( true );
3278  }
3279  }
3280  }
3281 return( false );
3282 }
3283 
3285  PST *pst;
3286  AnchorPoint *ap;
3287 
3288  if ( sc->glyph_class!=0 )
3289 return( sc->glyph_class-1 );
3290 
3291  if ( strcmp(sc->name,".notdef")==0 )
3292 return( 0 );
3293 
3294  /* It isn't clear to me what should be done if a glyph is both a ligature */
3295  /* and a mark (There are some greek accent ligatures, it is probably more*/
3296  /* important that they be indicated as marks). Here I chose mark rather */
3297  /* than ligature as the mark class is far more likely to be used */
3298  ap=sc->anchor;
3299  while ( ap!=NULL && (ap->type==at_centry || ap->type==at_cexit) )
3300  ap = ap->next;
3301  if ( ap!=NULL && (ap->type==at_mark || ap->type==at_basemark) )
3302 return( 3 );
3303 
3304  for ( pst=sc->possub; pst!=NULL; pst=pst->next ) {
3305  if ( pst->type == pst_ligature )
3306 return( 2 ); /* Ligature */
3307  }
3308 
3309  /* I not quite sure what a componant glyph is. Probably something */
3310  /* that is not in the cmap table and is referenced in other glyphs */
3311  /* (I've never seen it used by others) */
3312  /* (Note: No glyph in a CID font can be components as all CIDs mean */
3313  /* something) (I think) */
3314  if ( sc->unicodeenc==-1 && sc->dependents!=NULL &&
3315  sc->parent->cidmaster!=NULL && !ReferencedByGSUB(sc))
3316 return( 4 );
3317  else
3318 return( 1 );
3319 }
3320 
3321 void otf_dumpgdef(struct alltabs *at, SplineFont *sf) {
3322  /* In spite of what the open type docs say, this table does appear to be */
3323  /* required (at least the glyph class def table) if we do mark to base */
3324  /* positioning */
3325  /* I was wondering at the apperant contradiction: something can be both a */
3326  /* base glyph and a ligature component, but it appears that the component*/
3327  /* class is unused and everything is a base unless it is a ligature or */
3328  /* mark */
3329  /* All my example fonts ignore the attachment list subtable and the mark */
3330  /* attach class def subtable, so I shall too */
3331  /* Ah. Some indic fonts need the mark attach class subtable for greater */
3332  /* control of lookup flags */
3333  /* All my example fonts contain a ligature caret list subtable, which is */
3334  /* empty. Odd, but perhaps important */
3335  int i,j,k, lcnt, needsclass;
3336  int pos, offset;
3337  int cnt, start, last, lastval;
3338  SplineChar **glyphs, *sc;
3339 
3340  /* Don't look in the cidmaster if we are only dumping one subfont */
3341  if ( sf->cidmaster && sf->cidmaster->glyphs!=NULL ) sf = sf->cidmaster;
3342  else if ( sf->mm!=NULL ) sf=sf->mm->normal;
3343 
3344  glyphs = NULL;
3345  for ( k=0; k<2; ++k ) {
3346  lcnt = 0;
3347  needsclass =