1 /* Copyright (C) 2000-2012 by George Williams */
2 /*
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions are met:
5 
6  * Redistributions of source code must retain the above copyright notice, this
7  * list of conditions and the following disclaimer.
8 
9  * Redistributions in binary form must reproduce the above copyright notice,
10  * this list of conditions and the following disclaimer in the documentation
11  * and/or other materials provided with the distribution.
12 
13  * The name of the author may not be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15 
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <fontforge-config.h>
29 
30 #include "tottfaat.h"
31 
32 #include "asmfpst.h"
33 #include "fontforge.h"
34 #include "fvfonts.h"
35 #include "gfile.h"
36 #include "macenc.h"
37 #include "splinesaveafm.h"
38 #include "splineutil.h"
39 #include "tottf.h"
40 #include "tottfgpos.h"
41 #include "utype.h"
42 
43 #include "ttf.h"
44 
45 /* This file contains routines to create some of the Apple Advanced Typography Tables */
46 /*  (or GX fonts)  */
47 
48 /* ************************************************************************** */
49 /* *************************    The 'acnt' table    ************************* */
50 /* ************************************************************************** */
51 
aat_dumpacnt(struct alltabs * at,SplineFont * sf)52 void aat_dumpacnt(struct alltabs *at, SplineFont *sf) {
53 }
54 
55 /* ************************************************************************** */
56 /* *************************    The 'kern' table    ************************* */
57 /* ************************************************************************** */
58 
59 
60 /* Apple's docs imply that kerning info is always provided left to right, even*/
61 /*  for right to left scripts. If that be so then we need code in here to reverse */
62 /*  the order of the characters for right to left since pfaedit's convention */
63 /*  is to follow writing order rather than to go left to right */
64 
65 
DumpKernClass(FILE * file,uint16 * class,int cnt,int add,int mul)66 static void DumpKernClass(FILE *file, uint16 *class,int cnt,int add,int mul) {
67     int i, first=-1, last=-1;
68 
69     for ( i=0; i<cnt; ++i ) {
70 	if ( class[i] ) last = i;
71 	if ( class[i] && first==-1 ) first = i;
72     }
73     putshort(file,first);
74     putshort(file,last-first+1);
75     for ( i=first; i<=last; ++i )
76 	putshort(file,class[i]*mul+add);
77 }
78 
79 static int morx_dumpASM(FILE *temp,ASM *sm, struct alltabs *at, SplineFont *sf );
80 
81 struct kerncounts {
82     int cnt;
83     int vcnt;
84     int mh, mv;
85     int kccnt;
86     int vkccnt;
87     int ksm;
88     int hsubs;
89     int *hbreaks;
90     int vsubs;
91     int *vbreaks;
92 };
93 
CountKerns(struct alltabs * at,SplineFont * sf,struct kerncounts * kcnt)94 static int CountKerns(struct alltabs *at, SplineFont *sf, struct kerncounts *kcnt) {
95     int i, cnt, vcnt, j, kccnt=0, vkccnt=0, ksm=0, mh, mv;
96     KernPair *kp;
97     KernClass *kc;
98     ASM *sm;
99 
100     cnt = mh = vcnt = mv = 0;
101     for ( i=0; i<at->gi.gcnt; ++i ) if ( at->gi.bygid[i]!=-1 ) {
102 	j = 0;
103 	for ( kp = sf->glyphs[at->gi.bygid[i]]->kerns; kp!=NULL; kp=kp->next )
104 	    if ( kp->off!=0 && kp->sc->ttf_glyph!=-1 &&
105 		    LookupHasDefault(kp->subtable->lookup ))
106 		++cnt, ++j;
107 	if ( j>mh ) mh=j;
108 	j=0;
109 	for ( kp = sf->glyphs[at->gi.bygid[i]]->vkerns; kp!=NULL; kp=kp->next )
110 	    if ( kp->off!=0 && kp->sc->ttf_glyph!=-1 &&
111 		    LookupHasDefault(kp->subtable->lookup ))
112 		++vcnt, ++j;
113 	if ( j>mv ) mv=j;
114     }
115     kcnt->cnt = cnt;
116     kcnt->vcnt = vcnt;
117     kcnt->mh = mh;
118     kcnt->mv = mv;
119     kcnt->hbreaks = kcnt->vbreaks = NULL;
120     if ( cnt>=10000 ) {
121 	/* the sub-table size is 6*cnt+14 or so and needs to be less 65535 */
122 	/*  so break it up into little bits */
123 	/* We might not need this when applemode is set because the subtable */
124 	/*  length is a long. BUT... there's a damn binsearch header with */
125 	/*  shorts in it still */
126 	int b=0;
127 	kcnt->hbreaks = malloc((at->gi.gcnt+1)*sizeof(int));
128 	cnt = 0;
129 	for ( i=0; i<at->gi.gcnt; ++i ) if ( at->gi.bygid[i]!=-1 ) {
130 	    j = 0;
131 	    for ( kp = sf->glyphs[at->gi.bygid[i]]->kerns; kp!=NULL; kp=kp->next )
132 		if ( kp->off!=0 && LookupHasDefault(kp->subtable->lookup ))
133 		    ++j;
134 	    if ( (cnt+j)*6>64000L && cnt!=0 ) {
135 		kcnt->hbreaks[b++] = cnt;
136 		cnt = 0;
137 	    }
138 	    cnt += j;
139 	}
140 	kcnt->hbreaks[b++] = cnt;
141 	kcnt->hsubs = b;
142     } else if ( cnt!=0 )
143 	kcnt->hsubs = 1;
144     else
145 	kcnt->hsubs = 0;
146     if ( vcnt>=10000 ) {
147 	int b=0;
148 	kcnt->vbreaks = malloc((at->gi.gcnt+1)*sizeof(int));
149 	vcnt = 0;
150 	for ( i=0; i<at->gi.gcnt; ++i ) if ( at->gi.bygid[i]!=-1 ) {
151 	    j = 0;
152 	    for ( kp = sf->glyphs[at->gi.bygid[i]]->vkerns; kp!=NULL; kp=kp->next )
153 		if ( kp->off!=0 && LookupHasDefault(kp->subtable->lookup))
154 		    ++j;
155 	    if ( (vcnt+j)*6>64000L && vcnt!=0 ) {
156 		kcnt->vbreaks[b++] = vcnt;
157 		vcnt = 0;
158 	    }
159 	    vcnt += j;
160 	}
161 	kcnt->vbreaks[b++] = vcnt;
162 	kcnt->vsubs = b;
163     } else if ( vcnt!=0 )
164 	kcnt->vsubs = 1;
165     else
166 	kcnt->vsubs = 0;
167 
168     if ( at->applemode ) {	/* if we aren't outputting Apple's extensions to kerning (by classes, and by state machine) then don't check for those extensions */
169 	for ( kc=sf->kerns; kc!=NULL; kc = kc->next ) if ( LookupHasDefault(kc->subtable->lookup) )
170 	    ++kccnt;
171 	for ( kc=sf->vkerns; kc!=NULL; kc = kc->next ) if ( LookupHasDefault(kc->subtable->lookup) )
172 	    ++vkccnt;
173 	for ( sm=sf->sm; sm!=NULL; sm=sm->next )
174 	    if ( sm->type == asm_kern )
175 		++ksm;
176     }
177     kcnt->kccnt = kccnt;
178     kcnt->vkccnt = vkccnt;
179     kcnt->ksm = ksm;
180 return( kcnt->hsubs + kcnt->vsubs + kccnt + vkccnt + ksm );
181 }
182 
ttf_dumpsfkerns(struct alltabs * at,SplineFont * sf,int tupleIndex,int version)183 static void ttf_dumpsfkerns(struct alltabs *at, SplineFont *sf, int tupleIndex, int version) {
184     struct kerncounts kcnt;
185     int i, j, k, m, c, gid, tot, km;
186     KernPair *kp;
187     KernClass *kc;
188     ASM *sm;
189     uint16 *glnum, *offsets;
190     int isv;
191     int tupleMask = tupleIndex==-1 ? 0 : 0x2000;
192     int b, bmax;
193     int *breaks;
194     int winfail=0;
195     int subtableBeginPos,subtableEndPos;
196 
197     if ( CountKerns(at,sf,&kcnt)==0 )
198 return;
199 
200     if ( tupleIndex==-1 ) tupleIndex = 0;
201 
202     for ( isv=0; isv<2; ++isv ) {
203 	c = isv ? kcnt.vcnt : kcnt.cnt;
204 	bmax = isv ? kcnt.vsubs : kcnt.hsubs;
205 	breaks = isv ? kcnt.vbreaks : kcnt.hbreaks;
206 	if ( c!=0 ) {
207 	    km = isv ? kcnt.mv : kcnt.mh;
208 	    glnum = malloc(km*sizeof(uint16));
209 	    offsets = malloc(km*sizeof(uint16));
210 	    gid = 0;
211 	    for ( b=0; b<bmax; ++b ) {
212 		c = bmax==1 ? c : breaks[b];
213 
214 		// skip subtable header because we don't know the number of kern pairs yet
215 		subtableBeginPos=ftell(at->kern);
216 		if(version==0) fseek(at->kern,7*sizeof(uint16),SEEK_CUR);
217 		else fseek(at->kern,8*sizeof(uint16),SEEK_CUR);
218 
219 		for ( tot = 0; gid<at->gi.gcnt && tot<c; ++gid ) if ( at->gi.bygid[gid]!=-1 ) {
220 		    SplineChar *sc = sf->glyphs[at->gi.bygid[gid]];
221 		    // if requested, omit kern pairs with unmapped glyphs
222 		    // (required for compatibility with non-OpenType-aware Windows applications)
223 		    if( (at->gi.flags&ttf_flag_oldkernmappedonly) && (unsigned)(sc->unicodeenc)>0xFFFF ) continue;
224 		    m = 0;
225 		    for ( kp = isv ? sc->vkerns : sc->kerns; kp!=NULL; kp=kp->next ) {
226 			// if requested, omit kern pairs with unmapped glyphs
227 			// (required for compatibility with non-OpenType-aware Windows applications)
228 			if( (at->gi.flags&ttf_flag_oldkernmappedonly) && (unsigned)(kp->sc->unicodeenc)>0xFFFF ) continue;
229 			if ( kp->off!=0 && kp->sc->ttf_glyph!=-1 &&
230 				LookupHasDefault(kp->subtable->lookup)) {
231 			    /* order the pairs */
232 			    for ( j=0; j<m; ++j )
233 				if ( kp->sc->ttf_glyph<glnum[j] )
234 			    break;
235 			    for ( k=m; k>j; --k ) {
236 				glnum[k] = glnum[k-1];
237 				offsets[k] = offsets[k-1];
238 			    }
239 			    glnum[j] = kp->sc->ttf_glyph;
240 			    offsets[j] = kp->off;
241 			    ++m;
242 			    /* check if a pair will cause problems on Windows */
243 			    /* If the glyph is outside BMP, so either unicode >0xffff */
244 			    /*  or -1. Cast to unsigned catches both */
245 			    if( (unsigned)(sf->glyphs[at->gi.bygid[gid]]->unicodeenc)>0xFFFF ||
246 				    (unsigned)(sf->glyphs[at->gi.bygid[glnum[j]]]->unicodeenc)>0xFFFF )
247 				winfail++;
248 			}
249 		    }
250 		    for ( j=0; j<m; ++j ) {
251 			putshort(at->kern,gid);
252 			putshort(at->kern,glnum[j]);
253 			putshort(at->kern,offsets[j]);
254 		    }
255 		    tot += m;
256 		}
257 
258 		// now we can fill the subtable header
259 		c=tot;
260 		subtableEndPos=ftell(at->kern);
261 		fseek(at->kern,subtableBeginPos,SEEK_SET);
262 		if ( version==0 ) {
263 		    putshort(at->kern,0);		/* subtable version */
264 		    if ( c>10920 )
265 			ff_post_error(_("Too many kern pairs"),_("The 'kern' table supports at most 10920 kern pairs in a subtable"));
266 		    putshort(at->kern,(7+3*c)*sizeof(uint16)); /* subtable length */
267 		    putshort(at->kern,!isv);	/* coverage, flags=hor/vert&format=0 */
268 		} else {
269 		    putlong(at->kern,(8+3*c)*sizeof(uint16)); /* subtable length */
270 		    /* Apple's new format has a completely different coverage format */
271 		    putshort(at->kern,(isv?0x8000:0)| /* format 0, horizontal/vertical flags (coverage) */
272 				    tupleMask);
273 		    putshort(at->kern,tupleIndex);
274 		}
275 		putshort(at->kern,c);
276 		for ( i=1,j=0; i<=c; i<<=1, ++j );
277 		i>>=1; --j;
278 		putshort(at->kern,i*6);		/* binary search headers */
279 		putshort(at->kern,j);
280 		putshort(at->kern,6*(c-i));
281 		fseek(at->kern,subtableEndPos,SEEK_SET);
282 	    }
283 	    free(offsets);
284 	    free(glnum);
285 	}
286     }
287     free(kcnt.hbreaks); free(kcnt.vbreaks);
288 
289     if( winfail > 0 )
290 	ff_post_error(_("Kerning is likely to fail on Windows"),_(
291 		"Note: On Windows many apps can have problems with this font's kerning, because %d of its glyph kern pairs cannot be mapped to unicode-BMP kern pairs (eg, they have a Unicode value of -1) To avoid this, go to Generate, Options, and check the \"Windows-compatible \'kern\'\" option."),
292 	    winfail);
293 
294     if ( at->applemode ) for ( isv=0; isv<2; ++isv ) {
295 	for ( kc=isv ? sf->vkerns : sf->kerns; kc!=NULL; kc=kc->next ) if ( LookupHasDefault(kc->subtable->lookup) ) {
296 	    /* If we are here, we must be using version 1 */
297 	    uint32 len_pos = ftell(at->kern), pos;
298 	    uint16 *class1, *class2;
299 	    int first_cnt = kc->first_cnt;
300 
301 	    /* OpenType fonts can actually have a set of glyphs in class[0] of*/
302 	    /*  the first class. This happens when there are glyphs in the */
303 	    /*  coverage table which are not in any of the classes. Otherwise */
304 	    /*  class 0 is sort of useless in opentype */
305 	    if ( kc->firsts[0]!=NULL )
306 		++first_cnt;
307 
308 	    putlong(at->kern,0); /* subtable length */
309 	    putshort(at->kern,(isv?0x8002:2)|	/* format 2, horizontal/vertical flags (coverage) */
310 			    tupleMask);
311 	    putshort(at->kern,tupleIndex);
312 
313 	    putshort(at->kern,sizeof(uint16)*kc->second_cnt);
314 	    putshort(at->kern,0);		/* left classes */
315 	    putshort(at->kern,0);		/* right classes */
316 	    putshort(at->kern,16);		/* Offset to array, next byte */
317 
318 	    if ( kc->firsts[0]!=NULL ) {
319 		/* Create a dummy class to correspond to the mac's class 0 */
320 		/*  all entries will be 0 */
321 		for ( i=0 ; i<kc->second_cnt; ++i )
322 		    putshort(at->kern,0);
323 	    }
324 	    for ( i=0; i<kc->first_cnt*kc->second_cnt; ++i )
325 		putshort(at->kern,kc->offsets[i]);
326 
327 	    pos = ftell(at->kern);
328 	    fseek(at->kern,len_pos+10,SEEK_SET);
329 	    putshort(at->kern,pos-len_pos);
330 	    fseek(at->kern,pos,SEEK_SET);
331 	    class1 = ClassesFromNames(sf,kc->firsts,kc->first_cnt,at->maxp.numGlyphs,NULL,true);
332 	    DumpKernClass(at->kern,class1,at->maxp.numGlyphs,16,sizeof(uint16)*kc->second_cnt);
333 	    free(class1);
334 
335 	    pos = ftell(at->kern);
336 	    fseek(at->kern,len_pos+12,SEEK_SET);
337 	    putshort(at->kern,pos-len_pos);
338 	    fseek(at->kern,pos,SEEK_SET);
339 	    class2 = ClassesFromNames(sf,kc->seconds,kc->second_cnt,at->maxp.numGlyphs,NULL,true);
340 	    DumpKernClass(at->kern,class2,at->maxp.numGlyphs,0,sizeof(uint16));
341 	    free(class2);
342 
343 	    pos = ftell(at->kern);
344 	    fseek(at->kern,len_pos,SEEK_SET);
345 	    putlong(at->kern,pos-len_pos);
346 	    fseek(at->kern,pos,SEEK_SET);
347 	}
348     }
349 
350     if ( at->applemode ) if ( kcnt.ksm!=0 ) {
351 	for ( sm=sf->sm; sm!=NULL; sm=sm->next ) if ( sm->type == asm_kern ) {
352 	    uint32 len_pos = ftell(at->kern), pos;
353 
354 	    putlong(at->kern,0); 		/* subtable length */
355 	    putshort(at->kern,((sm->flags&0x8000)?0x8001:1)|	/* format 1, horizontal/vertical flags (coverage) */
356 			    tupleMask);
357 	    putshort(at->kern,tupleIndex);
358 	    morx_dumpASM(at->kern,sm,at,sf);
359 
360 	    pos = ftell(at->kern);
361 	    fseek(at->kern,len_pos,SEEK_SET);
362 	    putlong(at->kern,pos-len_pos);
363 	    fseek(at->kern,pos,SEEK_SET);
364 	}
365     }
366 }
367 
ttf_dumpkerns(struct alltabs * at,SplineFont * sf)368 void ttf_dumpkerns(struct alltabs *at, SplineFont *sf) {
369     int i, mmcnt=0, sum;
370     int version;
371     MMSet *mm = at->dovariations ? sf->mm : NULL;
372     struct kerncounts kcnt;
373     int must_use_old_style = 0;
374 
375     if ( !at->applemode && (!at->opentypemode || (at->gi.flags&ttf_flag_oldkern)) ) {
376 	must_use_old_style = true;
377 	SFKernClassTempDecompose(sf,false);
378 	mm = NULL;
379     } else {
380 	if ( mm!=NULL ) {
381 	    for ( i=0; i<mm->instance_count; ++i ) {
382 		mmcnt += CountKerns(at,mm->instances[i],&kcnt);
383 		free(kcnt.hbreaks); free(kcnt.vbreaks);
384 	    }
385 	    sf = mm->normal;
386 	}
387     }
388 
389     sum = CountKerns(at,sf,&kcnt);
390     free(kcnt.hbreaks); free(kcnt.vbreaks);
391     if ( sum==0 && mmcnt==0 ) {
392 	if ( must_use_old_style )
393 	    SFKernCleanup(sf,false);
394 return;
395     }
396 
397     /* Old kerning format (version 0) uses 16 bit quantities */
398     /* Apple's new format (version 0x00010000) uses 32 bit quantities */
399     at->kern = GFileTmpfile();
400     if ( must_use_old_style  ||
401 	    ( kcnt.kccnt==0 && kcnt.vkccnt==0 && kcnt.ksm==0 && mmcnt==0 )) {
402 	/* MS does not support format 1,2,3 kern sub-tables so if we have them */
403 	/*  we might as well admit that this table is for apple only and use */
404 	/*  the new format apple recommends. Otherwise, use the old format */
405 	/* If we might need to store tuple data, use the new format */
406 	putshort(at->kern,0);			/* version */
407 	putshort(at->kern,sum);			/* number of subtables */
408 	version = 0;
409     } else {
410 	putlong(at->kern,0x00010000);		/* version */
411 	putlong(at->kern,sum+mmcnt);		/* number of subtables */
412 	version = 1;
413     }
414 
415     ttf_dumpsfkerns(at, sf, -1, version);
416     if ( mm!=NULL ) {
417 	for ( i=0; i<mm->instance_count; ++i )
418 	    ttf_dumpsfkerns(at, mm->instances[i], i, version);
419     }
420     if ( must_use_old_style )
421 	SFKernCleanup(sf,false);
422 
423     at->kernlen = ftell(at->kern);
424     if ( at->kernlen&2 )
425 	putshort(at->kern,0);		/* pad it */
426 }
427 
428 /* ************************************************************************** */
429 /* *************************    The 'lcar' table    ************************* */
430 /* ************************************************************************** */
431 
haslcaret(SplineChar * sc)432 static PST *haslcaret(SplineChar *sc) {
433     PST *pst; int j;
434 
435     for ( pst=sc->possub; pst!=NULL && pst->type!=pst_lcaret; pst=pst->next );
436     if ( pst!=NULL ) {
437 	if ( !sc->lig_caret_cnt_fixed ) {
438 	    for ( j=pst->u.lcaret.cnt-1; j>=0 && pst->u.lcaret.carets[j]==0; --j );
439 	    if ( j==-1 )
440 		pst = NULL;
441 	} else {
442 	    if ( pst->u.lcaret.cnt==0 )
443 		pst = NULL;
444 	}
445     }
446 return( pst );
447 }
448 
aat_dumplcar(struct alltabs * at,SplineFont * sf)449 void aat_dumplcar(struct alltabs *at, SplineFont *sf) {
450     int i, j, k, l, seg_cnt, tot, last, offset;
451     PST *pst;
452     FILE *lcar=NULL;
453     SplineChar *sc;
454     /* We do four passes. The first just calculates how much space we will need */
455     /*  the second provides the top-level lookup table structure */
456     /*  the third provides the arrays of offsets needed for type 4 lookup tables */
457     /*  the fourth provides the actual data on the ligature carets */
458 
459     for ( k=0; k<4; ++k ) {
460 	for ( i=seg_cnt=tot=0; i<at->gi.gcnt; ++i )
461 		if ( at->gi.bygid[i]!=-1 &&
462 		    (pst = haslcaret(sc = sf->glyphs[at->gi.bygid[i]]))!=NULL ) {
463 	    if ( k==1 )
464 		tot = 0;
465 	    else if ( k==2 ) {
466 		putshort(lcar,offset);
467 		offset += 2 + 2*LigCaretCnt(sc);
468 	    } else if ( k==3 ) {
469 		putshort(lcar,LigCaretCnt(sc));
470 		for ( l=0; l<pst->u.lcaret.cnt; ++l )
471 		    if ( pst->u.lcaret.carets[l]!=0 || sc->lig_caret_cnt_fixed )
472 			putshort(lcar,pst->u.lcaret.carets[l]);
473 	    }
474 	    last = i;
475 	    for ( j=i+1, ++tot; j<at->gi.gcnt && at->gi.bygid[j]!=-1; ++j ) {
476 		if ( (pst = haslcaret(sc = sf->glyphs[at->gi.bygid[j]]))== NULL )
477 	    break;
478 		++tot;
479 		last = j;
480 		if ( k==2 ) {
481 		    putshort(lcar,offset);
482 		    offset += 2 + 2*LigCaretCnt(sc);
483 		} else if ( k==3 ) {
484 		    putshort(lcar,LigCaretCnt(sc));
485 		    for ( l=0; l<pst->u.lcaret.cnt; ++l )
486 			if ( pst->u.lcaret.carets[l]!=0 || sc->lig_caret_cnt_fixed )
487 			    putshort(lcar,pst->u.lcaret.carets[l]);
488 		}
489 	    }
490 	    if ( k==1 ) {
491 		putshort(lcar,last);
492 		putshort(lcar,i);
493 		putshort(lcar,offset);
494 		offset += 2*tot;
495 	    }
496 	    ++seg_cnt;
497 	    i = j-1;
498 	}
499 	if ( k==0 ) {
500 	    if ( seg_cnt==0 )
501 return;
502 	    lcar = GFileTmpfile();
503 	    putlong(lcar, 0x00010000);	/* version */
504 	    putshort(lcar,0);		/* data are distances (not points) */
505 
506 	    putshort(lcar,4);		/* Lookup table format 4 */
507 		/* Binary search header */
508 	    putshort(lcar,6);		/* Entry size */
509 	    putshort(lcar,seg_cnt);	/* Number of segments */
510 	    for ( j=0,l=1; l<=seg_cnt; l<<=1, ++j );
511 	    --j; l>>=1;
512 	    putshort(lcar,6*l);
513 	    putshort(lcar,j);
514 	    putshort(lcar,6*(seg_cnt-l));
515 	    offset = /*4+2+*/6*2 + seg_cnt*6 + 6 /* fake segment at end */;
516 		    /* Offset relative to lookup table, not to lcar_start */
517 		    /* Or, that's true while we build the lookup table. Once we */
518 		    /*  start working on the data offsets they are relative to */
519 		    /*  lcar_start */
520 	} else if ( k==1 ) {		/* flag entry */
521 	    putshort(lcar,0xffff);
522 	    putshort(lcar,0xffff);
523 	    putshort(lcar,0);
524 
525 	    offset += 6;	/* Now offsets are relative to lcar_start */
526 	}
527     }
528     at->lcar = lcar;
529     at->lcarlen = ftell(at->lcar);
530     if ( at->lcarlen&2 )
531 	putshort(at->lcar,0);
532 }
533 
534 /* ************************************************************************** */
535 /* *************************    The 'morx' table    ************************* */
536 /* *************************      (and 'feat')      ************************* */
537 /* ************************************************************************** */
538 
539 /* Each lookup gets its own subtable, so there may be multiple subtables */
540 /*  with the same feature/setting. The subtables will be ordered the same */
541 /*  way the lookups are, which might lead to awkwardness if there are many */
542 /*  chains and the same feature occurs in several of them */
543 /* (only the default language will be used) */
544 struct feature {
545     int16 featureType, featureSetting;
546     MacFeat *mf, *smf;
547     struct macsetting *ms, *sms;
548     unsigned int vertOnly: 1;
549     unsigned int r2l: 1;	/* I think this is the "descending" flag */
550     unsigned int needsOff: 1;
551     unsigned int singleMutex: 1;
552     unsigned int dummyOff: 1;
553     uint8 subtable_type;
554     int chain;
555     int32 flag, offFlags;
556     uint32 feature_start;
557     uint32 feature_len;		/* Does not include header yet */
558     struct feature *next;	/* features in output order */
559     struct feature *nexttype;	/* features in feature/setting order */
560     struct feature *nextsame;	/* all features with the same feature/setting */
561     int setting_cnt, setting_index, real_index;
562 };
563 
564 static struct feature *featureFromSubtable(SplineFont *sf, struct lookup_subtable *sub );
565 static int PSTHasTag(PST *pst, uint32 tag);
566 
morxfeaturesfree(struct feature * features)567 static void morxfeaturesfree(struct feature *features) {
568     struct feature *n;
569 
570     for ( ; features!=NULL; features=n ) {
571 	n = features->next;
572 	chunkfree( features,sizeof(*features) );
573     }
574 }
575 
mort_classes(FILE * temp,SplineFont * sf,struct glyphinfo * gi)576 static void mort_classes(FILE *temp,SplineFont *sf,struct glyphinfo *gi) {
577     int first, last, i, cnt;
578     /* Mort tables just have a trimmed byte array for the classes */
579 
580     for ( first=0; first<gi->gcnt; ++first )
581 	if ( gi->bygid[first]!=-1 && sf->glyphs[gi->bygid[first]]->lsidebearing!=1 )
582     break;
583     for ( last=gi->gcnt-1; last>first; --last )
584 	if ( gi->bygid[last]!=-1 && sf->glyphs[gi->bygid[last]]->lsidebearing!=1 )
585     break;
586     cnt = last-first+1;
587 
588     putshort(temp,first);
589     putshort(temp,cnt);
590     for ( i=first; i<=last; ++i )
591 	if ( gi->bygid[i]==-1 )
592 	    putc(1,temp);
593 	else
594 	    putc(sf->glyphs[gi->bygid[i]]->lsidebearing,temp);
595     if ( cnt&1 )
596 	putc(1,temp);			/* Pad to a word boundary */
597 }
598 
morx_lookupmap(FILE * temp,SplineChar ** glyphs,uint16 * maps,int gcnt)599 static void morx_lookupmap(FILE *temp,SplineChar **glyphs,uint16 *maps,int gcnt) {
600     int i, j, k, l, seg_cnt, tot, last, offset;
601     /* We do four passes. The first just calculates how much space we will need (if any) */
602     /*  the second provides the top-level lookup table structure */
603     /*  the third provides the arrays of offsets needed for type 4 lookup tables */
604 
605     for ( k=0; k<3; ++k ) {
606 	for ( i=seg_cnt=tot=0; i<gcnt; ++i ) {
607 	    if ( glyphs[i]==NULL )
608 	continue;
609 	    if ( k==1 )
610 		tot = 0;
611 	    else if ( k==2 ) {
612 		putshort(temp,maps[i]);
613 	    }
614 	    last = i;
615 	    for ( j=i+1, ++tot; j<gcnt && glyphs[j]!=NULL && glyphs[j]->ttf_glyph==glyphs[i]->ttf_glyph+j-i; ++j ) {
616 		++tot;
617 		last = j;
618 		if ( k==2 ) {
619 		    putshort(temp,maps[j]);
620 		}
621 	    }
622 	    if ( k==1 ) {
623 		putshort(temp,glyphs[last]->ttf_glyph);
624 		putshort(temp,glyphs[i]->ttf_glyph);
625 		putshort(temp,offset);
626 		offset += 2*tot;
627 	    }
628 	    ++seg_cnt;
629 	    i = j-1;
630 	}
631 	if ( k==0 ) {
632 	    putshort(temp,4);		/* Lookup table format 4 */
633 		/* Binary search header */
634 	    putshort(temp,6);		/* Entry size */
635 	    putshort(temp,seg_cnt);	/* Number of segments */
636 	    for ( j=0,l=1; l<=seg_cnt; l<<=1, ++j );
637 	    --j; l>>=1;
638 	    putshort(temp,6*l);
639 	    putshort(temp,j);
640 	    putshort(temp,6*(seg_cnt-l));
641 	    if ( seg_cnt==0 )
642 return;
643 	    offset = 6*2 + seg_cnt*6 + 6;
644 	} else if ( k==1 ) {		/* flag entry */
645 	    putshort(temp,0xffff);
646 	    putshort(temp,0xffff);
647 	    putshort(temp,0);
648 	}
649     }
650 }
651 
morx_dumpSubsFeature(FILE * temp,SplineChar ** glyphs,uint16 * maps,int gcnt)652 static void morx_dumpSubsFeature(FILE *temp,SplineChar **glyphs,uint16 *maps,int gcnt) {
653     morx_lookupmap(temp,glyphs,maps,gcnt);
654 }
655 
aat_dumpmorx_substitutions(struct alltabs * at,SplineFont * sf,FILE * temp,struct feature * features,struct lookup_subtable * sub)656 static struct feature *aat_dumpmorx_substitutions(struct alltabs *at, SplineFont *sf,
657 	FILE *temp, struct feature *features, struct lookup_subtable *sub) {
658     int i, k, gcnt;
659     SplineChar *sc, *msc, **glyphs;
660     uint16 *maps;
661     struct feature *cur;
662     PST *pst;
663 
664     for ( k=0; k<2; ++k ) {
665 	gcnt = 0;
666 	for ( i=0; i<at->gi.gcnt; ++i ) if ( at->gi.bygid[i]!=-1 ) {
667 	    sc = sf->glyphs[at->gi.bygid[i]];
668 	    for ( pst=sc->possub; pst!=NULL && pst->subtable!=sub; pst=pst->next );
669 	    if ( pst!=NULL ) {
670 		if ( k==1 ) {
671 		    msc = SFGetChar(sf,-1,pst->u.subs.variant);
672 		    glyphs[gcnt] = sc;
673 		    if ( msc!=NULL && msc->ttf_glyph!=-1 ) {
674 			maps[gcnt++] = msc->ttf_glyph;
675 		    } else if ( msc==NULL &&
676 			    strcmp(pst->u.subs.variant,MAC_DELETED_GLYPH_NAME)==0 ) {
677 			maps[gcnt++] = 0xffff;
678 		    }
679 		} else
680 		    ++gcnt;
681 	    }
682 	}
683 	if ( k==0 ) {
684 	    if ( gcnt==0 )
685 return( features );
686 	    glyphs = malloc((gcnt+1)*sizeof(SplineChar *));
687 	    maps = malloc((gcnt+1)*sizeof(uint16));
688 	} else {
689 	    glyphs[gcnt] = NULL; maps[gcnt] = 0;
690 	}
691     }
692 
693     cur = featureFromSubtable(sf,sub);
694     cur->next = features;
695     cur->r2l = sub->lookup->lookup_flags&pst_r2l ? true : false;
696     features = cur;
697     cur->subtable_type = 4;
698     cur->feature_start = ftell(temp);
699     morx_dumpSubsFeature(temp,glyphs,maps,gcnt);
700     if ( (ftell(temp)-cur->feature_start)&1 )
701 	putc('\0',temp);
702     if ( (ftell(temp)-cur->feature_start)&2 )
703 	putshort(temp,0);
704     cur->feature_len = ftell(temp)-cur->feature_start;
705     free(glyphs); free(maps);
706 return( features);
707 }
708 
LigListMatchSubtable(SplineFont * sf,LigList * ligs,struct lookup_subtable * sub)709 static LigList *LigListMatchSubtable(SplineFont *sf,LigList *ligs,
710 	struct lookup_subtable *sub) {
711     LigList *l;
712 
713     for ( l=ligs; l!=NULL; l=l->next )
714 	if ( l->lig->subtable==sub )
715 return( l );
716 return( NULL );
717 }
718 
IsMarkChar(SplineChar * sc)719 static int IsMarkChar( SplineChar *sc ) {
720     AnchorPoint *ap;
721 
722     ap=sc->anchor;
723     while ( ap!=NULL && (ap->type==at_centry || ap->type==at_cexit) )
724 	ap = ap->next;
725     if ( ap!=NULL && (ap->type==at_mark || ap->type==at_basemark) )
726 return( true );
727 
728 return( false );
729 }
730 
731 struct transition { uint16 next_state, dontconsume, ismark, trans_ent; LigList *l; };
732 struct trans_entries { uint16 next_state, flags, act_index; LigList *l; };
morx_dumpLigaFeature(FILE * temp,SplineChar ** glyphs,int gcnt,struct lookup_subtable * sub,struct alltabs * at,SplineFont * sf,int ignoremarks)733 static void morx_dumpLigaFeature(FILE *temp,SplineChar **glyphs,int gcnt,
734 	struct lookup_subtable *sub, struct alltabs *at, SplineFont *sf,
735 	int ignoremarks) {
736     LigList *l;
737     struct splinecharlist *comp;
738     uint16 *used = calloc(at->maxp.numGlyphs,sizeof(uint16));
739     SplineChar **cglyphs;
740     uint16 *map;
741     int i,j,k,class, state_max, state_cnt, base, last;
742     uint32 start;
743     struct transition **states;
744     struct trans_entries *trans;
745     int trans_cnt;
746     int maxccnt=0;
747     int acnt, lcnt, charcnt;
748     uint32 *actions;
749     uint16 *components, *lig_glyphs;
750     uint32 here;
751     struct splinecharlist *scl;
752     int anymarks;
753 
754     /* figure out the classes (one for each character used to make a lig) */
755     for ( i=0; i<gcnt; ++i ) {
756 	used[glyphs[i]->ttf_glyph] = true;
757 	for ( l=glyphs[i]->ligofme; l!=NULL; l=l->next ) if ( l->lig->subtable==sub ) {
758 	    for ( comp = l->components; comp!=NULL; comp=comp->next )
759 		used[comp->sc->ttf_glyph] = true;
760 	}
761     }
762     class = 4;
763     for ( i=0; i<at->maxp.numGlyphs; ++i ) if ( used[i] )
764 	used[i] = class++;
765     anymarks = false;
766     charcnt = class;
767     if ( ignoremarks ) {
768 	for ( i=0; i<at->gi.gcnt; ++i ) if ( at->gi.bygid[i]!=-1 ) {
769 	    if ( IsMarkChar(sf->glyphs[at->gi.bygid[i]])) {
770 		anymarks = true;
771 		++charcnt;
772 		used[i] = class;
773 	    }
774 	}
775 	if ( anymarks )
776 	    ++class;
777     }
778     cglyphs = malloc((charcnt+1)*sizeof(SplineChar *));
779     map = malloc((charcnt+1)*sizeof(uint16));
780     j=0;
781     for ( i=k=0; i<at->maxp.numGlyphs; ++i ) if ( used[i] ) {
782 	j = at->gi.bygid[i];
783 	if ( j!=-1 ) {
784 	    cglyphs[k] = sf->glyphs[j];
785 	    map[k++] = used[i];
786 	}
787     }
788     cglyphs[k] = NULL;
789 
790     start = ftell(temp);
791     putlong(temp,class);
792     putlong(temp,7*sizeof(uint32));
793     putlong(temp,0);		/* Fill in later */
794     putlong(temp,0);
795     putlong(temp,0);
796     putlong(temp,0);
797     putlong(temp,0);
798     morx_lookupmap(temp,cglyphs,map,k);	/* dump the class lookup table */
799     free( cglyphs ); free( map );
800     here = ftell(temp);
801     fseek(temp,start+2*sizeof(uint32),SEEK_SET);
802     putlong(temp,here-start);			/* Point to start of state arrays */
803     fseek(temp,0,SEEK_END);
804 
805     /* Now build the state machine */
806     /* Note: the ligofme list is so ordered that the longest ligatures come first */
807     /*  we will depend on that in the case of "ffl", "ffi", "ff" */
808     state_max = 40; state_cnt = 2;
809     states = malloc(state_max*sizeof(struct transition *));
810     states[0] = calloc(class,sizeof(struct transition));	/* Initial state */
811     states[1] = calloc(class,sizeof(struct transition));	/* other Initial state */
812     for ( i=0; i<gcnt; ++i ) {
813 	if ( state_cnt>=state_max )
814 	    states = realloc(states,(state_max += 40)*sizeof(struct transition *));
815 	base = state_cnt;
816 	states[0][used[glyphs[i]->ttf_glyph]].next_state = state_cnt;
817 	states[1][used[glyphs[i]->ttf_glyph]].next_state = state_cnt;
818 	states[state_cnt++] = calloc(class,sizeof(struct transition));
819 	for ( l=glyphs[i]->ligofme; l!=NULL; l=l->next ) if ( l->lig->subtable==sub ) {
820 	    if ( l->ccnt > maxccnt ) maxccnt = l->ccnt;
821 	    last = base;
822 	    for ( comp = l->components; comp!=NULL; comp=comp->next ) {
823 		if ( states[last][used[comp->sc->ttf_glyph]].next_state==0 ) {
824 		    if ( comp->next==NULL )
825 			states[last][used[comp->sc->ttf_glyph]].l = l;
826 		    else {
827 			states[last][used[comp->sc->ttf_glyph]].next_state = state_cnt;
828 			if ( state_cnt>=state_max )
829 			    states = realloc(states,(state_max += 40)*sizeof(struct transition *));
830 			last = state_cnt;
831 			states[state_cnt++] = calloc(class,sizeof(struct transition));
832 		    }
833 		} else {
834 		    last = states[last][used[comp->sc->ttf_glyph]].next_state;
835 		    if ( comp->next==NULL ) {
836 			/* this is where we depend on the ordering */
837 			for ( j=0; j<class; ++j )
838 			    if ( states[last][j].next_state==0 && states[last][j].l==NULL ) {
839 				states[last][j].l = l;
840 				states[last][j].dontconsume = true;
841 				/* the next state should continue to be 0 (initial) */
842 			    }
843 		    }
844 		}
845 	    }
846 	}
847     }
848     if ( anymarks ) {
849 	/* behavior for a mark is the same everywhere: stay in current state */
850 	/*  do no operations. consume the mark */
851 	for ( i=0; i<state_cnt; ++i ) {
852 	    states[i][class-1].next_state = i;
853 	    states[i][class-1].ismark = true;
854 	}
855     }
856     /* Ok, we've got the state machine now. Convert it into apple's wierd */
857     /*  (space saving) format */
858     trans = malloc(class*state_cnt*sizeof(struct trans_entries));
859     trans_cnt = 0;
860     for ( i=0; i<state_cnt; ++i ) for ( j=0; j<class; ++j ) {
861 	if ( states[i][j].ismark )
862 	    k = trans_cnt;
863 	else for ( k=0; k<trans_cnt; ++k ) {
864 	    if ( trans[k].next_state==states[i][j].next_state &&
865 		    (trans[k].flags&0x4000?1:0) == states[i][j].dontconsume &&
866 		    trans[k].l ==states[i][j].l )
867 	break;
868 	}
869 	states[i][j].trans_ent = k;
870 	if ( k==trans_cnt ) {
871 	    trans[k].next_state = states[i][j].next_state;
872 	    trans[k].l = states[i][j].l;
873 	    trans[k].flags = 0;
874 	    if ( states[i][j].dontconsume )
875 		trans[k].flags = 0x4000;
876 	    else if ( states[i][j].ismark )
877 		/* Do nothing */;
878 	    else if ( trans[k].next_state!=0 || trans[k].l!=NULL )
879 		trans[k].flags = 0x8000;
880 	    if ( trans[k].l!=NULL )
881 		trans[k].flags |= 0x2000;
882 	    trans[k].act_index = 0;
883 	    ++trans_cnt;
884 	}
885     }
886     /* Oops. Bug. */
887     /* Suppose we have two ligatures f+l=>fl & s+t->st. */
888     /* Suppose we get input "fst"			*/
889     /* Now the state machine we've built so far will go to the f branch, see */
890     /*  the "s" and go back to state 0 */
891     /* Obviously that's wrong, we've lost the st. So either we go back to 0 */
892     /*  but don't advance the glyph, or we take the transition from state 0 */
893     /*  and copy it to here. The second is easier for me just now */
894     for ( i=2; i<state_cnt; ++i ) for ( j=4; j<class; ++j ) {
895 	if ( states[i][j].trans_ent == 0 && states[0][j].trans_ent != 0 )
896 	    states[i][j].trans_ent = states[0][j].trans_ent;
897     }
898 
899     /* Dump out the state machine */
900     for ( i=0; i<state_cnt; ++i ) for ( j=0; j<class; ++j )
901 	putshort( temp, states[i][j].trans_ent );
902 
903     /* Now figure out the ligature actions (and all the other tables) */
904     actions = malloc(trans_cnt*maxccnt*sizeof(uint32));
905     components = malloc(trans_cnt*maxccnt*sizeof(uint16));
906     lig_glyphs = malloc(trans_cnt*sizeof(uint16));
907     acnt = lcnt = 0;
908     for ( i=0; i<trans_cnt; ++i ) if ( trans[i].l!=NULL ) {
909 	lig_glyphs[lcnt] = trans[i].l->lig->u.lig.lig->ttf_glyph;
910 	/* component Glyphs get popped off the stack in the reverse order */
911 	/*  so we must built our tables backwards */
912 	components[acnt+trans[i].l->ccnt-1] = lcnt;
913 	actions[acnt+trans[i].l->ccnt-1] = 0x80000000 |
914 		((acnt+trans[i].l->ccnt-1 - trans[i].l->first->ttf_glyph)&0x3fffffff);
915 	for ( scl=trans[i].l->components,j=trans[i].l->ccnt-2; scl!=NULL; scl=scl->next, --j ) {
916 	    components[acnt+j] = 0;
917 	    actions[acnt+j] = (acnt+j - scl->sc->ttf_glyph)&0x3fffffff;
918 	}
919 	trans[i].act_index = acnt;
920 	++lcnt;
921 	acnt += trans[i].l->ccnt;
922     }
923 
924     /* Now we know how big all the tables will be. Dump out their locations */
925     here = ftell(temp);
926     fseek(temp,start+3*sizeof(uint32),SEEK_SET);
927     putlong(temp,here-start);			/* Point to start of entry array */
928     putlong(temp,here-start+6*trans_cnt);	/* Point to start of actions */
929     putlong(temp,here-start+6*trans_cnt+4*acnt);/* Point to start of components */
930     putlong(temp,here-start+6*trans_cnt+6*acnt);/* Point to start of ligatures */
931     fseek(temp,0,SEEK_END);
932 
933     /* Now dump the transitions */
934     for ( i=0; i<trans_cnt; ++i ) {
935 	putshort(temp,trans[i].next_state);
936 	putshort(temp,trans[i].flags);
937 	putshort(temp,trans[i].act_index);
938     }
939     /* And the actions */
940     for ( i=0; i<acnt; ++i )
941 	putlong(temp,actions[i]);
942     /* And the components */
943     for ( i=0; i<acnt; ++i )
944 	putshort(temp,components[i]);
945     /* Do A simple check on the validity of what we've done */
946     if ( here+6*trans_cnt+6*acnt != ftell(temp) )
947 	IError( "Offset wrong in morx ligature table\n" );
948     /* And finally the ligature glyph indeces */
949     for ( i=0; i<lcnt; ++i )
950 	putshort(temp,lig_glyphs[i]);
951 
952     /* clean up */
953     free(actions); free(components); free(lig_glyphs);
954     free(trans);
955     for ( i=0; i<state_cnt; ++i )
956 	free(states[i]);
957     free(states);
958     free(used);
959 }
960 
aat_dumpmorx_ligatures(struct alltabs * at,SplineFont * sf,FILE * temp,struct feature * features,struct lookup_subtable * sub)961 static struct feature *aat_dumpmorx_ligatures(struct alltabs *at, SplineFont *sf,
962 	FILE *temp, struct feature *features, struct lookup_subtable *sub) {
963     int i, k, gcnt;
964     SplineChar *sc, *ssc, **glyphs;
965     struct feature *cur;
966     LigList *l;
967 
968     glyphs = malloc((at->maxp.numGlyphs+1)*sizeof(SplineChar *));
969     for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
970 	sf->glyphs[i]->ticked = false;
971 
972     for ( i=0; i<at->gi.gcnt; ++i )
973 	    if ( at->gi.bygid[i]!=-1 && !(sc=sf->glyphs[at->gi.bygid[i]])->ticked &&
974 		    (l = LigListMatchSubtable(sf,sc->ligofme,sub))!=NULL ) {
975 	int ignoremarks = sub->lookup->lookup_flags & pst_ignorecombiningmarks ? 1 : 0 ;
976 	for ( k=i, gcnt=0; k<at->gi.gcnt; ++k )
977 		if ( at->gi.bygid[k]!=-1 &&
978 			(ssc=sf->glyphs[at->gi.bygid[k]])!=NULL && !ssc->ticked &&
979 			LigListMatchSubtable(sf,ssc->ligofme,sub)) {
980 	    glyphs[gcnt++] = ssc;
981 	    ssc->ticked = true;
982 	}
983 	glyphs[gcnt] = NULL;
984 	cur = featureFromSubtable(sf,sub);
985 	cur->next = features;
986 	features = cur;
987 	cur->subtable_type = 2;		/* ligature */
988 	cur->feature_start = ftell(temp);
989 	morx_dumpLigaFeature(temp,glyphs,gcnt,sub,at,sf,ignoremarks);
990 	if ( (ftell(temp)-cur->feature_start)&1 )
991 	    putc('\0',temp);
992 	if ( (ftell(temp)-cur->feature_start)&2 )
993 	    putshort(temp,0);
994 	cur->feature_len = ftell(temp)-cur->feature_start;
995 	cur->r2l = sub->lookup->lookup_flags&pst_r2l ? true : false;
996     }
997 
998     free(glyphs);
999 return( features);
1000 }
1001 
morx_dumpnestedsubs(FILE * temp,SplineFont * sf,OTLookup * otl,struct glyphinfo * gi)1002 static void morx_dumpnestedsubs(FILE *temp,SplineFont *sf,OTLookup *otl,struct glyphinfo *gi) {
1003     int i, j, gcnt;
1004     PST *pst;
1005     SplineChar **glyphs, *sc;
1006     uint16 *map;
1007     struct lookup_subtable *sub = otl->subtables;	/* Mac can't have more than one subtable/lookup */
1008 
1009     for ( j=0; j<2; ++j ) {
1010 	gcnt = 0;
1011 	for ( i = 0; i<gi->gcnt; ++i ) if ( gi->bygid[i]!=-1 ) {
1012 	    for ( pst=sf->glyphs[gi->bygid[i]]->possub;
1013 		    pst!=NULL && pst->subtable!=sub;  pst=pst->next );
1014 	    if ( pst!=NULL && pst->type==pst_substitution &&
1015 		    (sc=SFGetChar(sf,-1,pst->u.subs.variant))!=NULL &&
1016 		    sc->ttf_glyph!=-1 ) {
1017 		if ( j ) {
1018 		    glyphs[gcnt] = sf->glyphs[gi->bygid[i]];
1019 		    map[gcnt] = sc->ttf_glyph;
1020 		}
1021 		++gcnt;
1022 	    }
1023 	}
1024 	if ( !j ) {
1025 	    glyphs = malloc((gcnt+1)*sizeof(SplineChar *));
1026 	    map = malloc(gcnt*sizeof(uint16));
1027 	    glyphs[gcnt] = NULL;
1028 	}
1029     }
1030     morx_lookupmap(temp,glyphs,map,gcnt);
1031     free(glyphs);
1032     free(map);
1033 }
1034 
NamesToGlyphs(SplineFont * sf,char * names,uint16 * cnt)1035 static uint16 *NamesToGlyphs(SplineFont *sf,char *names,uint16 *cnt) {
1036     char *pt, *start;
1037     int c, ch;
1038     uint16 *ret;
1039     SplineChar *sc;
1040 
1041     for ( c=0, pt=names; *pt; ++pt )
1042 	if ( *pt==' ' ) ++c;
1043     ret = malloc((c+1)*sizeof(uint16));
1044 
1045     for ( c=0, pt=names; *pt; ) {
1046 	while ( *pt==' ' ) ++pt;
1047 	if ( *pt=='\0' )
1048     break;
1049 	start = pt;
1050 	while ( *pt!=' ' && *pt!='\0' ) ++pt;
1051 	ch = *pt; *pt='\0';
1052 	sc = SFGetChar(sf,-1,start);
1053 	*pt = ch;
1054 	if ( sc!=NULL && sc->ttf_glyph!=-1 )
1055 	    ret[c++] = sc->ttf_glyph;
1056     }
1057     *cnt = c;
1058 return( ret );
1059 }
1060 
morx_dumpASM(FILE * temp,ASM * sm,struct alltabs * at,SplineFont * sf)1061 static int morx_dumpASM(FILE *temp,ASM *sm, struct alltabs *at, SplineFont *sf ) {
1062     int i, j, k, gcnt, ch;
1063     char *pt, *end;
1064     uint16 *map;
1065     SplineChar **glyphs, *sc;
1066     int stcnt, tcnt;
1067     struct ins { char *names; uint16 len,pos; uint16 *glyphs; } *subsins=NULL;
1068     OTLookup **subslookups=NULL;
1069     uint32 start, here, substable_pos, state_offset;
1070     struct transdata { uint16 transition, mark_index, cur_index; } *transdata;
1071     struct trans { uint16 ns, flags, mi, ci; } *trans;
1072     int ismort = sm->type == asm_kern;
1073     FILE *kernvalues;
1074 
1075     for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
1076 	sf->glyphs[i]->lsidebearing = 1;
1077 
1078     gcnt = 0;
1079     for ( i=4; i<sm->class_cnt; ++i ) {
1080 	for ( pt = sm->classes[i]; ; pt=end ) {
1081 	    while ( *pt==' ' ) ++pt;
1082 	    if ( *pt=='\0' )
1083 	break;
1084 	    for ( end=pt; *end!='\0' && *end!=' '; ++end );
1085 	    ch = *end; *end = '\0';
1086 	    sc = SFGetChar(sf,-1,pt);
1087 	    *end = ch;
1088 	    if ( sc!=NULL ) {
1089 		sc->lsidebearing = i;
1090 		++gcnt;
1091 	    }
1092 	}
1093     }
1094     glyphs = malloc((gcnt+1)*sizeof(SplineChar *));
1095     map = malloc((gcnt+1)*sizeof(uint16));
1096     gcnt = 0;
1097     for ( i=0; i<at->gi.gcnt; ++i ) if ( at->gi.bygid[i]!=-1 && sf->glyphs[at->gi.bygid[i]]->lsidebearing!=1 ) {
1098 	glyphs[gcnt] = sf->glyphs[at->gi.bygid[i]];
1099 	map[gcnt++] = sf->glyphs[at->gi.bygid[i]]->lsidebearing;
1100     }
1101     glyphs[gcnt] = NULL;
1102 
1103     /* Give each subs tab an index into the mac's substitution lookups */
1104     transdata = calloc(sm->state_cnt*sm->class_cnt,sizeof(struct transdata));
1105     stcnt = 0;
1106     subslookups = NULL; subsins = NULL;
1107     if ( sm->type==asm_context ) {
1108 	subslookups = malloc(2*sm->state_cnt*sm->class_cnt*sizeof(OTLookup*));
1109 	for ( j=0; j<sm->state_cnt*sm->class_cnt; ++j ) {
1110 	    struct asm_state *this = &sm->state[j];
1111 	    transdata[j].mark_index = transdata[j].cur_index = 0xffff;
1112 	    if ( this->u.context.mark_lookup!=NULL ) {
1113 		for ( i=0; i<stcnt; ++i )
1114 		    if ( subslookups[i]==this->u.context.mark_lookup )
1115 		break;
1116 		if ( i==stcnt )
1117 		    subslookups[stcnt++] = this->u.context.mark_lookup;
1118 		transdata[j].mark_index = i;
1119 	    }
1120 	    if ( this->u.context.cur_lookup!=NULL ) {
1121 		for ( i=0; i<stcnt; ++i )
1122 		    if ( subslookups[i]==this->u.context.cur_lookup )
1123 		break;
1124 		if ( i==stcnt )
1125 		    subslookups[stcnt++] = this->u.context.cur_lookup;
1126 		transdata[j].cur_index = i;
1127 	    }
1128 	}
1129     } else if ( sm->type==asm_insert ) {
1130 	subsins = malloc(2*sm->state_cnt*sm->class_cnt*sizeof(struct ins));
1131 	for ( j=0; j<sm->state_cnt*sm->class_cnt; ++j ) {
1132 	    struct asm_state *this = &sm->state[j];
1133 	    transdata[j].mark_index = transdata[j].cur_index = 0xffff;
1134 	    if ( this->u.insert.mark_ins!=0 ) {
1135 		for ( i=0; i<stcnt; ++i )
1136 		    if ( strcmp(subsins[i].names,this->u.insert.mark_ins)==0 )
1137 		break;
1138 		if ( i==stcnt ) {
1139 		    subsins[stcnt].pos = stcnt==0 ? 0 : subsins[stcnt-1].pos +
1140 							subsins[stcnt-1].len;
1141 		    subsins[stcnt].names = this->u.insert.mark_ins;
1142 		    subsins[stcnt].glyphs = NamesToGlyphs(sf,subsins[stcnt].names,&subsins[stcnt].len);
1143 		    ++stcnt;
1144 		}
1145 		transdata[j].mark_index = subsins[i].pos;
1146 	    }
1147 	    if ( this->u.insert.cur_ins!=0 ) {
1148 		for ( i=0; i<stcnt; ++i )
1149 		    if ( strcmp(subsins[i].names,this->u.insert.cur_ins)==0 )
1150 		break;
1151 		if ( i==stcnt ) {
1152 		    subsins[stcnt].pos = stcnt==0 ? 0 : subsins[stcnt-1].pos +
1153 							subsins[stcnt-1].len;
1154 		    subsins[stcnt].names = this->u.insert.cur_ins;
1155 		    subsins[stcnt].glyphs = NamesToGlyphs(sf,subsins[stcnt].names,&subsins[stcnt].len);
1156 		    ++stcnt;
1157 		}
1158 		transdata[j].cur_index = subsins[i].pos;
1159 	    }
1160 	}
1161     } else if ( sm->type==asm_kern ) {
1162 	int off=0;
1163 	kernvalues = GFileTmpfile();
1164 	for ( j=0; j<sm->state_cnt*sm->class_cnt; ++j ) {
1165 	    struct asm_state *this = &sm->state[j];
1166 	    transdata[j].mark_index = 0xffff;
1167 	    if ( this->u.kern.kcnt!=0 ) {
1168 		for ( k=0; k<j; ++k )
1169 		    if ( sm->state[k].u.kern.kcnt==this->u.kern.kcnt &&
1170 			    memcmp(sm->state[k].u.kern.kerns,this->u.kern.kerns,
1171 				    this->u.kern.kcnt*sizeof(int16))==0 )
1172 		break;
1173 		if ( k!=j )
1174 		    transdata[j].mark_index = transdata[k].mark_index;
1175 		else {
1176 		    transdata[j].mark_index = off;
1177 		    off += this->u.kern.kcnt*sizeof(int16);
1178 		    /* kerning values must be output backwards */
1179 		    for ( k=this->u.kern.kcnt-1; k>=1; --k )
1180 			putshort(kernvalues,this->u.kern.kerns[k]&~1);
1181 		    /* And the last one must be odd */
1182 		    putshort(kernvalues,this->u.kern.kerns[0]|1);
1183 		}
1184 	    }
1185 	}
1186     }
1187 
1188     trans = malloc(sm->state_cnt*sm->class_cnt*sizeof(struct trans));
1189     tcnt = 0;
1190     for ( j=0; j<sm->state_cnt*sm->class_cnt; ++j ) {
1191 	struct asm_state *this = &sm->state[j];
1192 	for ( i=0; i<tcnt; ++i )
1193 	    if ( trans[i].ns==this->next_state && trans[i].flags==this->flags &&
1194 		    trans[i].mi==transdata[j].mark_index &&
1195 		    trans[i].ci==transdata[j].cur_index )
1196 	break;
1197 	if ( i==tcnt ) {
1198 	    trans[tcnt].ns = this->next_state;
1199 	    trans[tcnt].flags = this->flags;
1200 	    trans[tcnt].mi = transdata[j].mark_index;
1201 	    trans[tcnt++].ci = transdata[j].cur_index;
1202 	}
1203 	transdata[j].transition = i;
1204     }
1205 
1206 
1207     /* Output the header */
1208     start = ftell(temp);
1209     if ( ismort /* old format still used for kerning */ ) {
1210 	putshort(temp,sm->class_cnt);
1211 	putshort(temp,5*sizeof(uint16));	/* class offset */
1212 	putshort(temp,0);			/* state offset */
1213 	putshort(temp,0);			/* transition entry offset */
1214 	putshort(temp,0);			/* kerning values offset */
1215 	mort_classes(temp,sf,&at->gi);			/* dump the class table */
1216     } else {
1217 	putlong(temp,sm->class_cnt);
1218 	if ( sm->type==asm_indic ) {
1219 	    putlong(temp,4*sizeof(uint32));	/* class offset */
1220 	    putlong(temp,0);			/* state offset */
1221 	    putlong(temp,0);			/* transition entry offset */
1222 	} else {
1223 	    putlong(temp,5*sizeof(uint32));	/* class offset */
1224 	    putlong(temp,0);			/* state offset */
1225 	    putlong(temp,0);			/* transition entry offset */
1226 	    putlong(temp,0);			/* substitution/insertion table offset */
1227 	}
1228 	morx_lookupmap(temp,glyphs,map,gcnt);/* dump the class lookup table */
1229     }
1230     free(glyphs); free(map);
1231 
1232 
1233     state_offset = ftell(temp)-start;
1234     if ( ismort ) {
1235 	fseek(temp,start+2*sizeof(uint16),SEEK_SET);
1236 	putshort(temp,state_offset);		/* Point to start of state arrays */
1237     } else {
1238 	fseek(temp,start+2*sizeof(uint32),SEEK_SET);
1239 	putlong(temp,state_offset);		/* Point to start of state arrays */
1240     }
1241     fseek(temp,0,SEEK_END);
1242 
1243     if ( ismort ) {
1244 	for ( j=0; j<sm->state_cnt*sm->class_cnt; ++j )
1245 	    putc(transdata[j].transition,temp);
1246 	if ( ftell(temp)&1 )
1247 	    putc(0,temp);			/* Pad to a word boundry */
1248     } else {
1249 	for ( j=0; j<sm->state_cnt*sm->class_cnt; ++j )
1250 	    putshort(temp,transdata[j].transition);
1251     }
1252     free(transdata);
1253 
1254     here = ftell(temp);
1255     if ( ismort ) {
1256 	fseek(temp,start+3*sizeof(uint16),SEEK_SET);
1257 	putshort(temp,here-start);		/* Point to start of transition arrays */
1258     } else {
1259 	fseek(temp,start+3*sizeof(uint32),SEEK_SET);
1260 	putlong(temp,here-start);		/* Point to start of transition arrays */
1261     }
1262     fseek(temp,0,SEEK_END);
1263 
1264     /* Now the transitions */
1265     if ( sm->type==asm_kern ) {
1266 	substable_pos = here+tcnt*2*sizeof(int16);
1267 	for ( i=0; i<tcnt; ++i ) {
1268 	    /* mort tables use an offset rather than the state number */
1269 	    putshort(temp,trans[i].ns*sm->class_cnt+state_offset);
1270 	    if ( trans[i].mi!=0xffff )
1271 		trans[i].flags |= substable_pos-start+trans[i].mi;
1272 	    putshort(temp,trans[i].flags);
1273 	}
1274     } else {
1275 	for ( i=0; i<tcnt; ++i ) {
1276 	    putshort(temp,trans[i].ns);
1277 	    putshort(temp,trans[i].flags);
1278 	    if ( sm->type!=asm_indic && sm->type!=asm_kern ) {
1279 		putshort(temp,trans[i].mi );
1280 		putshort(temp,trans[i].ci );
1281 	    }
1282 	}
1283     }
1284     free(trans);
1285 
1286     if ( sm->type==asm_context ) {
1287 	substable_pos = ftell(temp);
1288 	fseek(temp,start+4*sizeof(uint32),SEEK_SET);
1289 	putlong(temp,substable_pos-start);		/* Point to start of substitution lookup offsets */
1290 	fseek(temp,0,SEEK_END);
1291 
1292 	/* And finally the substitutions */
1293 	for ( i=0; i<stcnt; ++i )
1294 	    putlong(temp,0);	/* offsets to the substitutions */
1295 	for ( i=0; i<stcnt; ++i ) {
1296 	    here = ftell(temp);
1297 	    fseek(temp,substable_pos+i*sizeof(uint32),SEEK_SET);
1298 	    putlong(temp,here-substable_pos);
1299 	    fseek(temp,0,SEEK_END);
1300 	    morx_dumpnestedsubs(temp,sf,subslookups[i],&at->gi);
1301 	}
1302 	free(subslookups);
1303     } else if ( sm->type==asm_insert ) {
1304 	substable_pos = ftell(temp);
1305 	fseek(temp,start+4*sizeof(uint32),SEEK_SET);
1306 	putlong(temp,substable_pos-start);		/* Point to start of insertions */
1307 	fseek(temp,0,SEEK_END);
1308 
1309 	for ( i=0; i<stcnt; ++i ) {
1310 	    for ( j=0; j<subsins[i].len; ++j )
1311 		putshort(temp,subsins[i].glyphs[j]);
1312 	    free(subsins[i].glyphs);
1313 	}
1314 	free(subsins);
1315     } else if ( sm->type==asm_kern ) {
1316 	if ( substable_pos!=ftell(temp) )
1317 	    IError( "Kern Values table in wrong place.\n" );
1318 	fseek(temp,start+4*sizeof(uint16),SEEK_SET);
1319 	putshort(temp,substable_pos-start);		/* Point to start of insertions */
1320 	fseek(temp,0,SEEK_END);
1321 	if ( !ttfcopyfile(temp,kernvalues,substable_pos,"kern-subtable")) at->error = true;
1322     }
1323 return( true );
1324 }
1325 
aat_dumpmorx_asm(struct alltabs * at,SplineFont * sf,FILE * temp,struct feature * features,ASM * sm)1326 static struct feature *aat_dumpmorx_asm(struct alltabs *at, SplineFont *sf,
1327 	FILE *temp, struct feature *features, ASM *sm) {
1328     struct feature *cur;
1329 
1330     cur = featureFromSubtable(sf,sm->subtable);
1331     cur->vertOnly = sm->flags&0x8000?1:0;
1332     cur->r2l = sm->flags&0x4000?1:0;
1333     cur->subtable_type = sm->type;		/* contextual glyph subs */
1334     cur->feature_start = ftell(temp);
1335     if ( morx_dumpASM(temp,sm,at,sf)) {
1336 	cur->next = features;
1337 	features = cur;
1338 	if ( (ftell(temp)-cur->feature_start)&1 )
1339 	    putc('\0',temp);
1340 	if ( (ftell(temp)-cur->feature_start)&2 )
1341 	    putshort(temp,0);
1342 	cur->feature_len = ftell(temp)-cur->feature_start;
1343     } else
1344 	chunkfree(cur,sizeof(struct feature));
1345 return( features);
1346 }
1347 
aat_dumpmorx_cvtopentype(struct alltabs * at,SplineFont * sf,FILE * temp,struct feature * features,struct lookup_subtable * sub)1348 static struct feature *aat_dumpmorx_cvtopentype(struct alltabs *at, SplineFont *sf,
1349 	FILE *temp, struct feature *features, struct lookup_subtable *sub) {
1350     ASM *sm;
1351 
1352     if ( FPSTisMacable(sf,sub->fpst)) {
1353 	sm = ASMFromFPST(sf,sub->fpst,true);
1354 	if ( sm!=NULL ) {
1355 	    features = aat_dumpmorx_asm(at,sf,temp,features,sm);
1356 	    ASMFree(sm);
1357 	}
1358     }
1359 return( features );
1360 }
1361 
IsOtfArabicFormFeature(OTLookup * otl)1362 static int IsOtfArabicFormFeature(OTLookup *otl) {
1363     FeatureScriptLangList *fl;
1364 
1365     for ( fl=otl->features; fl!=NULL; fl=fl->next ) {
1366 	if (( fl->featuretag == CHR('i','n','i','t') ||
1367 		fl->featuretag==CHR('m','e','d','i') ||
1368 		fl->featuretag==CHR('f','i','n','a') ||
1369 		fl->featuretag==CHR('i','s','o','l') ) &&
1370 		    scriptsHaveDefault(fl->scripts))
1371 return( true );
1372     }
1373 return( false );
1374 }
1375 
HasCursiveConnectionSM(SplineFont * sf)1376 static int HasCursiveConnectionSM(SplineFont *sf) {
1377     int featureType, featureSetting;
1378     uint32 tag;
1379     ASM *sm;
1380 
1381     if ( OTTagToMacFeature(CHR('i','s','o','l'),&featureType,&featureSetting) ) {
1382 	tag = (featureType<<16) | featureSetting;
1383 	for ( sm = sf->sm; sm!=NULL; sm=sm->next ) {
1384 	    if ( sm->subtable->lookup->features->featuretag==tag )
1385 return( true );
1386 	}
1387     }
1388     for ( sm = sf->sm; sm!=NULL; sm=sm->next ) {
1389 	if ( sm->subtable->lookup->features->featuretag==CHR('i','s','o','l') )
1390 return( true );
1391     }
1392 return( false );
1393 }
1394 
FormedScripts(SplineFont * sf)1395 static uint32 *FormedScripts(SplineFont *sf) {
1396     OTLookup *otl;
1397     uint32 *ret = NULL;
1398     int scnt=0, smax=0;
1399     FeatureScriptLangList *fl;
1400     struct scriptlanglist *sl;
1401     int i;
1402 
1403     for ( otl= sf->gsub_lookups; otl!=NULL; otl=otl->next ) {
1404 	if ( otl->lookup_type == gsub_single ) {
1405 	    for ( fl=otl->features; fl!=NULL; fl=fl->next ) {
1406 		if ( fl->featuretag == CHR('i','n','i','t') ||
1407 			fl->featuretag==CHR('m','e','d','i') ||
1408 			fl->featuretag==CHR('f','i','n','a') ||
1409 			fl->featuretag==CHR('i','s','o','l') ) {
1410 		    for ( sl=fl->scripts; sl!=NULL; sl=sl->next ) {
1411 			for ( i=0; i<sl->lang_cnt; ++i ) {
1412 			    if ( (i<MAX_LANG ? sl->langs[i] : sl->morelangs[i-MAX_LANG])==DEFAULT_LANG ) {
1413 				if ( scnt<=smax )
1414 				    ret = realloc(ret,(smax+=5)*sizeof(uint32));
1415 				ret[scnt++] = sl->script;
1416 			    }
1417 			}
1418 		    }
1419 		}
1420 	    }
1421 	}
1422     }
1423     if ( scnt==0 )
1424 return( NULL );
1425     if ( scnt<=smax )
1426 	ret = realloc(ret,(smax+=1)*sizeof(uint32));
1427     ret[scnt] = 0;
1428 return( ret );
1429 }
1430 
Macable(SplineFont * sf,OTLookup * otl)1431 int Macable(SplineFont *sf, OTLookup *otl) {
1432     int ft, fs;
1433     FeatureScriptLangList *features;
1434 
1435     switch ( otl->lookup_type ) {
1436     /* These lookup types are mac only */
1437       case kern_statemachine: case morx_indic: case morx_context: case morx_insert:
1438 return( true );
1439     /* These lookup types or OpenType only */
1440       case gsub_multiple: case gsub_alternate:
1441       case gpos_single: case gpos_cursive: case gpos_mark2base:
1442       case gpos_mark2ligature: case gpos_mark2mark:
1443 return( false );
1444     /* These are OpenType only, but they might be convertable to a state */
1445     /*  machine */
1446       case gsub_context:
1447       case gsub_contextchain: case gsub_reversecchain:
1448       case gpos_context: case gpos_contextchain:
1449 	if ( sf==NULL || sf->sm!=NULL )
1450 return( false );
1451 	/* Else fall through into the test on the feature tag */;
1452     /* These two can be expressed in both, and might be either */
1453       case gsub_single: case gsub_ligature: case gpos_pair:
1454 	for ( features = otl->features; features!=NULL; features = features->next ) {
1455 	    if ( features->ismac || OTTagToMacFeature(features->featuretag,&ft,&fs))
1456 return( true );
1457 	}
1458     }
1459 return( false );
1460 }
1461 
aat_dumpmorx_cvtopentypeforms(struct alltabs * at,SplineFont * sf,FILE * temp,struct feature * features)1462 static struct feature *aat_dumpmorx_cvtopentypeforms(struct alltabs *at, SplineFont *sf,
1463 	FILE *temp, struct feature *features) {
1464     ASM *sm;
1465     uint32 *scripts;
1466     int featureType, featureSetting;
1467     int i;
1468     OTLookup *otl;
1469 
1470     if ( sf->cidmaster!=NULL )
1471 	sf = sf->cidmaster;
1472     else if ( sf->mm!=NULL ) sf=sf->mm->normal;
1473 
1474     for ( otl=sf->gsub_lookups; otl!=NULL; otl=otl->next )
1475 	if ( Macable(sf,otl) && otl->lookup_type==gsub_single && IsOtfArabicFormFeature(otl))
1476 	    otl->ticked = true;
1477 
1478     if ( OTTagToMacFeature(CHR('i','s','o','l'),&featureType,&featureSetting) ) {
1479 	scripts = FormedScripts(sf);
1480 	for ( i=0; scripts[i]!=0; ++i ) {
1481 	    sm = ASMFromOpenTypeForms(sf,scripts[i]);
1482 	    if ( sm!=NULL ) {
1483 		features = aat_dumpmorx_asm(at,sf,temp,features,sm);
1484 		ASMFree(sf->sm);
1485 	    }
1486 	}
1487 	free(scripts);
1488     }
1489 return( features );
1490 }
1491 
featuresReverse(struct feature * features)1492 static struct feature *featuresReverse(struct feature *features) {
1493     struct feature *p, *n;
1494 
1495     p = NULL;
1496     while ( features!=NULL ) {
1497 	n = features->next;
1498 	features->next = p;
1499 	p = features;
1500 	features = n;
1501     }
1502 return( p );
1503 }
1504 
featuresOrderByType(struct feature * features)1505 static struct feature *featuresOrderByType(struct feature *features) {
1506     struct feature *f, **all;
1507     int i, j, cnt/*, saw_default*/;
1508 
1509     for ( cnt=0, f=features; f!=NULL; f=f->next, ++cnt );
1510     if ( cnt==1 ) {
1511 return( features );
1512     }
1513     all = malloc(cnt*sizeof(struct feature *));
1514     for ( i=0, f=features; f!=NULL; f=f->next, ++i )
1515 	all[i] = f;
1516     for ( i=0; i<cnt-1; ++i ) for ( j=i+1; j<cnt; ++j ) {
1517 	if ( all[i]->featureType>all[j]->featureType ||
1518 		(all[i]->featureType==all[j]->featureType && all[i]->featureSetting>all[j]->featureSetting )) {
1519 	    f = all[i];
1520 	    all[i] = all[j];
1521 	    all[j] = f;
1522 	}
1523     }
1524     for ( i=0; i<cnt-1; ++i )
1525 	all[i]->nexttype = all[i+1];
1526     all[cnt-1]->nexttype = NULL;
1527     features = all[0];
1528     free( all );
1529 return( features );
1530 }
1531 
AddExclusiveNoops(SplineFont * sf,struct feature * features)1532 static struct feature *AddExclusiveNoops(SplineFont *sf, struct feature *features) {
1533     struct feature *f, *n, *def, *p, *t;
1534     /* mutually exclusive features need to have a setting which does nothing */
1535 
1536     for ( f=features; f!=NULL; f=n ) {
1537 	n= f->nexttype;
1538 	if ( f->mf!=NULL && f->mf->ismutex ) {
1539 	    def = NULL;
1540 	    for ( n=f; n!=NULL && n->featureType==f->featureType; n=n->nexttype ) {
1541 		if ( n->featureSetting==f->mf->default_setting )
1542 		    def = n;
1543 	    }
1544 	    if ( def==NULL ) {
1545 		t = chunkalloc(sizeof(struct feature));
1546 		*t = *f;
1547 		t->feature_start = 0; t->feature_len=0; t->next = NULL;
1548 		t->featureSetting = f->mf->default_setting;
1549 		t->ms = FindMacSetting(sf,t->featureType,f->mf->default_setting,&t->sms);
1550 		t->flag = 0;
1551 		t->dummyOff = true;
1552 		if ( f==features )
1553 		    p = NULL;
1554 		else
1555 		    for ( p=features; p->nexttype!=f; p=p->nexttype );
1556 		n = f;
1557 		while ( n!=NULL && n->featureType==t->featureType && n->featureSetting<t->featureSetting ) {
1558 		    p = n;
1559 		    n = n->nexttype;
1560 		}
1561 		t->nexttype = n;
1562 		if ( p==NULL )
1563 		    features = t;
1564 		else
1565 		    p->nexttype = t;
1566 		while ( n!=NULL && n->featureType==t->featureType )
1567 		    n=n->nexttype;
1568 	    }
1569 	}
1570     }
1571 return( features );
1572 }
1573 
SetExclusiveOffs(struct feature * features)1574 static void SetExclusiveOffs(struct feature *features) {
1575     struct feature *f, *n;
1576     int offFlags;
1577     /* mutually exclusive features need to have a setting which does nothing */
1578 
1579     for ( f=features; f!=NULL; f=n ) {
1580 	n= f->nexttype;
1581 	if ( f->mf!=NULL && f->mf->ismutex ) {
1582 	    offFlags=0;
1583 	    for ( n=f; n!=NULL && n->featureType==f->featureType; n=n->nexttype ) {
1584 		offFlags |= n->flag;
1585 	    }
1586 	    for ( n=f; n!=NULL && n->featureType==f->featureType; n=n->nexttype )
1587 		n->offFlags = ~(offFlags&~n->flag);
1588 	}
1589     }
1590 return;
1591 }
1592 
aat_dumpfeat(struct alltabs * at,SplineFont * sf,struct feature * feature)1593 static void aat_dumpfeat(struct alltabs *at, SplineFont *sf, struct feature *feature) {
1594     int scnt, fcnt, cnt;
1595     struct feature *f, *n, *p;
1596     int k;
1597     uint32 offset;
1598     int strid = at->next_strid;
1599     int fn=0;
1600     MacFeat *mf, *smf;
1601     struct macsetting *ms, *sms;
1602     /* Dump the 'feat' table which is a connection between morx features and */
1603     /*  the name table */
1604     /* We do three passes. The first just calculates how much space we will need */
1605     /*  the second provides names for the feature types */
1606     /*  and the third provides names for the feature settings */
1607     /* As we fill up the feat table we also create an array of strings */
1608     /*  (strid, char *pointer) which will be used by the 'name' table to */
1609     /*  give names to the features and their settings */
1610     /* The mac documentation says that the features should be sorted by feature type */
1611     /*  This is a lie. Features should appear in the same order they appear */
1612     /*  in the morx table, otherwise WorldText goes blooie */
1613     /* WorldText doesn't exist any more. Perhaps the morx table needs to be */
1614     /*  sorted by feature id too? No, it can't be. Feature 0 must come last */
1615 
1616     if ( feature==NULL )
1617 return;
1618 
1619     fcnt = scnt = 0;
1620     for ( k=0; k<3; ++k ) {
1621 	if ( k==1 ) {
1622 		/* FeatureName entry for All Typographics */
1623 	    mf = FindMacFeature(sf,0,&smf);
1624 	    if ( (mf!=NULL && mf->featname!=NULL) || (smf!=NULL && smf->featname!=NULL)) {
1625 		at->feat_name[fn].mn = mf!=NULL ? mf->featname : NULL;
1626 		at->feat_name[fn].smn = smf!=NULL ? smf->featname : NULL;
1627 		at->feat_name[fn++].strid = strid;
1628 	    }
1629 	    putshort(at->feat,0);
1630 	    putshort(at->feat,1);
1631 	    putlong(at->feat,offset);
1632 	    putshort(at->feat,0x0000);	/* non exclusive */
1633 	    putshort(at->feat,strid++);
1634 	    offset += 1*4;		/* (1 setting, 4 bytes) All Features */
1635 	} else if ( k==2 ) {
1636 		/* Setting Name Array for All Typographic Features */
1637 	    ms = FindMacSetting(sf,0,0,&sms);
1638 	    if ( (ms!=NULL && ms->setname!=NULL) || (sms!=NULL && sms->setname!=NULL)) {
1639 		at->feat_name[fn].mn = ms!=NULL ? ms->setname: NULL;
1640 		at->feat_name[fn].smn = sms!=NULL ? sms->setname: NULL;
1641 		at->feat_name[fn++].strid = strid;
1642 	    }
1643 	    putshort(at->feat,0);
1644 	    putshort(at->feat,strid++);
1645 	}
1646 	for ( f=feature; f!=NULL; f=n ) {
1647 	    cnt=1;
1648 	    if ( k!=2 ) {
1649 		p = f;
1650 		for ( n=f->nexttype; n!=NULL && n->featureType==f->featureType; n = n->nexttype ) {
1651 		    if ( p->featureSetting!=n->featureSetting ) {
1652 			++cnt;
1653 			p = n;
1654 		    }
1655 		}
1656 	    } else {
1657 		p = f;
1658 		for ( n=f; n!=NULL && n->featureType==f->featureType; n = n->nexttype ) {
1659 		    if ( n==f || p->featureSetting!=n->featureSetting ) {
1660 			if (( n->ms!=NULL && n->ms->setname!=NULL ) ||
1661 				( n->sms!=NULL && n->sms->setname!=NULL)) {
1662 			    at->feat_name[fn].mn = n->ms!=NULL ? n->ms->setname : NULL;
1663 			    at->feat_name[fn].smn = n->sms!=NULL ? n->sms->setname : NULL;
1664 			    at->feat_name[fn++].strid = strid;
1665 			}
1666 			putshort(at->feat,n->featureSetting);
1667 			putshort(at->feat,strid++);
1668 			p = n;
1669 		    }
1670 		}
1671 	    }
1672 	    if ( k==0 ) {
1673 		++fcnt;
1674 		scnt += cnt;
1675 	    } else if ( k==1 ) {
1676 		if ( (f->mf!=NULL && f->mf->featname!=NULL) || (f->smf!=NULL && f->smf->featname!=NULL) ) {
1677 		    at->feat_name[fn].mn = f->mf!=NULL ? f->mf->featname : NULL;
1678 		    at->feat_name[fn].smn = f->smf!=NULL ? f->smf->featname : NULL;
1679 		    at->feat_name[fn++].strid = strid;
1680 		}
1681 		putshort(at->feat,f->featureType);
1682 		putshort(at->feat,cnt);
1683 		putlong(at->feat,offset);
1684 		putshort(at->feat,f->mf!=NULL && f->mf->ismutex?(0xc000|f->mf->default_setting):
1685 			0);
1686 		putshort(at->feat,strid++);
1687 		offset += 4*cnt;
1688 	    }
1689 	}
1690 	if ( k==0 ) {
1691 	    ++fcnt;		/* Add one for "All Typographic Features" */
1692 	    ++scnt;		/* Add one for All Features */
1693 	    at->feat = GFileTmpfile();
1694 	    at->feat_name = malloc((fcnt+scnt+1)*sizeof(struct feat_name));
1695 	    putlong(at->feat,0x00010000);
1696 	    putshort(at->feat,fcnt);
1697 	    putshort(at->feat,0);
1698 	    putlong(at->feat,0);
1699 	    offset = 12 /* header */ + fcnt*12;
1700 	}
1701     }
1702     memset( &at->feat_name[fn],0,sizeof(struct feat_name));
1703     at->next_strid = strid;
1704 
1705     at->featlen = ftell(at->feat);
1706     if ( at->featlen&2 )
1707 	putshort(at->feat,0);
1708 }
1709 
featuresAssignFlagsChains(struct feature * features,struct feature * feature_by_type)1710 static int featuresAssignFlagsChains(struct feature *features, struct feature *feature_by_type) {
1711     int bit, cnt, chain, fcnt, i, mybit;
1712     struct feature *f, *n, *p;
1713     uint16 chains_features[32];
1714     uint32 chains_bitindex[32];		/* Index for bit of first setting of this feature */
1715 
1716     if ( features==NULL )
1717 return( 0 );
1718 
1719     /* A feature may have several subtables which need not be contiguous in */
1720     /*  the feature list */
1721     /* Indeed we could have a feature in several different chains */
1722     /* Sigh */
1723     /* we figure out how many possible settings there are for each feature */
1724     /*  and reserve that many bits for the feature in all chains in which it */
1725     /*  occurs */
1726     /* Note that here we count dummy settings (they need turn off bits) */
1727     /*  so we use feature_by_type */
1728     for ( f=feature_by_type; f!=NULL; f=n ) {
1729 	cnt=0;
1730 	p = NULL;
1731 	for ( n=f; n!=NULL && n->featureType==f->featureType; n=n->nexttype ) {
1732 	    if ( p==NULL || n->featureSetting != p->featureSetting ) {
1733 		++cnt;
1734 		p = n;
1735 	    }
1736 	    n->setting_index = cnt-1;
1737 	}
1738 	for ( n=f; n!=NULL && n->featureType==f->featureType; n=n->nexttype )
1739 	    n->setting_cnt = cnt;
1740     }
1741     /* When we counted flags we need to count the dummy features for turning  */
1742     /*  things off. Those features live in features_by_type. When we put      */
1743     /*  things in chains we want only the meaningful features, and we want    */
1744     /*  them to be properly ordered. That we get from the "features" list     */
1745     fcnt = 0; chain = 0; bit=0;
1746     for ( f=features; f!=NULL; f=f->next ) {
1747 	for ( i=0; i<fcnt && chains_features[i]!=f->featureType; ++i );
1748 	if ( i==fcnt ) {
1749 	    if ( bit+f->setting_cnt>=32 ) {
1750 		++chain;
1751 		bit = 0;
1752 		fcnt = 0;
1753 	    }
1754 	    chains_features[fcnt] = f->featureType;
1755 	    chains_bitindex[fcnt++] = bit;
1756 	    mybit = bit;
1757 	    bit += f->setting_cnt;
1758 	} else
1759 	    mybit = chains_bitindex[i];
1760 	f->real_index = mybit+f->setting_index;
1761 	f->flag = 1<<f->real_index;
1762 	if ( f->mf!=NULL && f->mf->ismutex ) {
1763 	    int off = (~((~0)<<f->setting_cnt))<<mybit;
1764 	    off &= !f->flag;
1765 	    f->offFlags = off;
1766 	} else {
1767 	    if ( f->featureSetting&1 ) {
1768 		for ( n=feature_by_type; n!=NULL &&
1769 			(n->featureType!=f->featureType || n->featureSetting!=f->featureSetting+1);
1770 			n=n->next );
1771 	    } else {
1772 		for ( n=feature_by_type; n!=NULL &&
1773 			(n->featureType!=f->featureType || n->featureSetting!=f->featureSetting+1);
1774 			n=n->next );
1775 	    }
1776 	    if ( n!=NULL )
1777 		f->offFlags = 1<<(mybit+n->setting_index);
1778 	    else
1779 		f->offFlags = ~0;
1780 	}
1781 	f->chain = chain;
1782     }
1783 return( chain+1 );
1784 }
1785 
morxDumpChain(struct alltabs * at,struct feature * features,struct feature * features_by_type,int chain,FILE * temp)1786 static void morxDumpChain(struct alltabs *at,struct feature *features,
1787 	struct feature *features_by_type, int chain, FILE *temp) {
1788     uint32 def_flags=0;
1789     struct feature *f, *n;
1790     uint32 chain_start, end;
1791     char *buf;
1792     int len, tot, fs_cnt, sub_cnt;
1793     struct feature *all[32];
1794     int i,offFlags, last_ri=-1, last_f=-1, ri;
1795 
1796     memset(all,0,sizeof(all));
1797     for ( f=features, fs_cnt=sub_cnt=0; f!=NULL; f=f->next ) {
1798 	if ( f->chain==chain ) {
1799 	    if ( all[f->real_index]==NULL ) {
1800 		int base = f->real_index-f->setting_index;
1801 		/* Note we use features_by_type here. It will have the default*/
1802 		/*  settings for features, and will be ordered nicely */
1803 		for ( n=features_by_type; n!=NULL; n=n->nexttype ) {
1804 		    if ( n->featureType==f->featureType && n->chain==chain ) {
1805 			n->nextsame = all[base+n->setting_index];
1806 			all[base+n->setting_index] = n;
1807 			if ( n->ms!=NULL && n->ms->initially_enabled )
1808 			    def_flags |= n->flag;
1809 		    }
1810 		}
1811 	    }
1812 	    ++sub_cnt;
1813 	}
1814     }
1815 
1816     /* Chain header */
1817     chain_start = ftell(at->morx);
1818     putlong(at->morx,def_flags);
1819     putlong(at->morx,0);		/* Fix up length later */
1820     putlong(at->morx,0);		/* fix up feature count */
1821     putlong(at->morx,sub_cnt);		/* subtable cnt */
1822 
1823     /* Features */
1824     fs_cnt = 0;
1825     for ( i=0; i<32; ++i ) if ( all[i]!=NULL ) {
1826 	putshort(at->morx,all[i]->featureType);
1827 	putshort(at->morx,all[i]->featureSetting);
1828 	if ( all[i]->dummyOff ) {
1829 	    putlong(at->morx,0);
1830 	    if ( last_f==all[i]->featureType )
1831 		ri = last_ri;
1832 	    else if ( i<31 && all[i+1]!=NULL && all[i+1]->featureType == all[i]->featureType )
1833 		ri = i+1 - all[i+1]->real_index;
1834 	    else
1835 		ri = 0;		/* This can't happen */
1836 	} else {
1837 	    putlong(at->morx,1<<i);
1838 	    ri = i-all[i]->real_index;
1839 	    last_ri = ri; last_f = all[i]->featureType;
1840 	}
1841 	offFlags = all[i]->offFlags;
1842 	if ( ri>0 )
1843 	    offFlags<<=(ri);
1844 	else if ( ri<0 )
1845 	    offFlags>>=(-ri);
1846 	putlong(at->morx,offFlags);
1847 	++fs_cnt;
1848 
1849 	if ( all[i]->needsOff && (i==31 || all[i+1]==NULL ||
1850 		all[i+1]->featureType!=all[i]->featureType ||
1851 		all[i+1]->featureSetting!=all[i]->featureSetting+1 )) {
1852 	    putshort(at->morx,all[i]->featureType);
1853 	    putshort(at->morx,all[i]->featureSetting+1);
1854 	    putlong(at->morx,0);
1855 	    putlong(at->morx,all[i]->offFlags & ~all[i]->flag );
1856 	    ++fs_cnt;
1857 	}
1858 	/* I used to have code to output the default setting of a mutex */
1859 	/*  but I should already have put that in the feature list */
1860     }
1861     /* The feature list of every chain must end with these two features */
1862     putshort(at->morx,0);		/* All Typo Features */
1863     putshort(at->morx,0);		/* All Features */
1864     putlong(at->morx,0xffffffff);	/* enable */
1865     putlong(at->morx,0xffffffff);	/* disable */
1866     putshort(at->morx,0);		/* All Typo Features */
1867     putshort(at->morx,1);		/* No Features */
1868     putlong(at->morx,0);		/* enable */
1869     putlong(at->morx,0);		/* disable */
1870     fs_cnt += 2;
1871 
1872     buf = malloc(16*1024);
1873     /* Subtables */
1874     for ( f=features; f!=NULL; f=f->next ) if ( f->chain==chain ) {
1875 	putlong(at->morx,f->feature_len+12);		/* Size of header needs to be added */
1876 	putlong(at->morx,(f->vertOnly?0x80000000:f->r2l?0x40000000:0) | f->subtable_type);
1877 	putlong(at->morx,f->flag);
1878 	tot = f->feature_len;
1879 	fseek(temp, f->feature_start, SEEK_SET);
1880 	while ( tot!=0 ) {
1881 	    len = tot;
1882 	    if ( len>16*1024 ) len = 16*1024;
1883 	    len = fread(buf,1,len,temp);
1884 	    len = fwrite(buf,1,len,at->morx);
1885 	    if ( len<=0 ) {
1886 		IError( "Disk error\n" );
1887 	break;
1888 	    }
1889 	    tot -= len;
1890 	}
1891     }
1892     free(buf);
1893 
1894     /* Pad chain to a multiple of four */
1895     if ( (ftell(at->morx)-chain_start)&1 )
1896 	putc('\0',at->morx);
1897     if ( (ftell(at->morx)-chain_start)&2 )
1898 	putshort(at->morx,0);
1899     end = ftell(at->morx);
1900     fseek(at->morx,chain_start+4,SEEK_SET);
1901     putlong(at->morx,end-chain_start);
1902     putlong(at->morx,fs_cnt);
1903     fseek(at->morx,0,SEEK_END);
1904 }
1905 
aat_dumpmorx(struct alltabs * at,SplineFont * sf)1906 void aat_dumpmorx(struct alltabs *at, SplineFont *sf) {
1907     FILE *temp = GFileTmpfile();
1908     struct feature *features = NULL, *features_by_type;
1909     int nchains, i;
1910     OTLookup *otl;
1911     struct lookup_subtable *sub;
1912 
1913     /* Arabic Form features all need to be merged together and formed into */
1914     /*  a cursive connection state machine. So the first time we see one of */
1915     /*  we handle all of them. After that we ignore all of them. Note: if */
1916     /*  OpenType has them happening in different orders, that information */
1917     /*  will be lost. All will be processed at once. */
1918     for ( otl = sf->gsub_lookups; otl!=NULL; otl=otl->next )
1919 	otl->ticked = false;
1920 
1921     SFLigaturePrepare(sf);
1922 
1923     /* Retain the same lookup ordering */
1924     for ( otl = sf->gsub_lookups; otl!=NULL; otl=otl->next ) {
1925 	if ( !Macable(sf,otl))
1926     continue;
1927 	if ( otl->lookup_type==gsub_single && IsOtfArabicFormFeature(otl) ) {
1928 	    if ( otl->ticked )
1929 		/* Already processed */;
1930 	    else if ( HasCursiveConnectionSM(sf) )
1931 		/* Skip the OpenType conversion and use the native state machine */;
1932 	    else
1933 		features = aat_dumpmorx_cvtopentypeforms(at,sf,temp,features);
1934 	} else {
1935 	    for ( sub=otl->subtables; sub!=NULL; sub=sub->next ) {
1936 		switch ( otl->lookup_type ) {
1937 		  case gsub_single:
1938 		    features = aat_dumpmorx_substitutions(at,sf,temp,features,sub);
1939 		  break;
1940 		  case gsub_ligature:
1941 		    features = aat_dumpmorx_ligatures(at,sf,temp,features,sub);
1942 		  break;
1943 		  case morx_indic: case morx_context: case morx_insert:
1944 		    features = aat_dumpmorx_asm(at,sf,temp,features,sub->sm);
1945 		  break;
1946 		  default:
1947 		    if ( sf->sm==NULL )
1948 			features = aat_dumpmorx_cvtopentype(at,sf,temp,features,sub);
1949 		}
1950 	    }
1951 	}
1952     }
1953 
1954     SFLigatureCleanup(sf);
1955 
1956     if ( features==NULL ) {
1957 	fclose(temp);
1958 return;
1959     }
1960     /* The features are in reverse execution order */
1961     features = featuresReverse(features);
1962     /* But the feature table requires them in numeric order */
1963     features_by_type = featuresOrderByType(features);
1964     features_by_type = AddExclusiveNoops(sf,features_by_type);
1965     aat_dumpfeat(at, sf, features_by_type);
1966     nchains = featuresAssignFlagsChains(features,features_by_type);
1967     SetExclusiveOffs(features_by_type);
1968 
1969     at->morx = GFileTmpfile();
1970     putlong(at->morx,0x00020000);
1971     putlong(at->morx,nchains);
1972     for ( i=0; i<nchains; ++i )
1973 	morxDumpChain(at,features,features_by_type,i,temp);
1974     fclose(temp);
1975     morxfeaturesfree(features_by_type);
1976 
1977     at->morxlen = ftell(at->morx);
1978     if ( at->morxlen&1 )
1979 	putc('\0',at->morx);
1980     if ( (at->morxlen+1)&2 )
1981 	putshort(at->morx,0);
1982 }
1983 
1984 /* ************************************************************************** */
1985 /* *************************    The 'opbd' table    ************************* */
1986 /* ************************************************************************** */
1987 
haslrbounds(SplineChar * sc,PST ** left,PST ** right)1988 int haslrbounds(SplineChar *sc, PST **left, PST **right) {
1989     PST *pst;
1990 
1991     *left = *right = NULL;
1992     for ( pst=sc->possub; pst!=NULL ; pst=pst->next ) {
1993 	if ( pst->type == pst_position ) {
1994 	    if ( PSTHasTag(pst,CHR('l','f','b','d')) ) {
1995 		*left = pst;
1996 		if ( *right )
1997 return( true );
1998 	    } else if ( PSTHasTag(pst,CHR('r','t','b','d')) ) {
1999 		*right = pst;
2000 		if ( *left )
2001 return( true );
2002 	    }
2003 	}
2004     }
2005 return( *left!=NULL || *right!=NULL );
2006 }
2007 
aat_dumpopbd(struct alltabs * at,SplineFont * _sf)2008 void aat_dumpopbd(struct alltabs *at, SplineFont *_sf) {
2009     int i, j, k, l, seg_cnt, tot, last, offset;
2010     PST *left, *right;
2011     FILE *opbd=NULL;
2012     /* We do four passes. The first just calculates how much space we will need (if any) */
2013     /*  the second provides the top-level lookup table structure */
2014     /*  the third provides the arrays of offsets needed for type 4 lookup tables */
2015     /*  the fourth provides the actual data on the optical bounds */
2016     SplineChar *sc;
2017 
2018     for ( k=0; k<4; ++k ) {
2019 	for ( i=seg_cnt=tot=0; i<at->gi.gcnt; ++i ) if ( at->gi.bygid[i]!=-1 ) {
2020 	    l = 0;
2021 	    sc = _sf->glyphs[at->gi.bygid[i]];
2022 	    if ( haslrbounds(sc,&left,&right) ) {
2023 		if ( k==1 )
2024 		    tot = 0;
2025 		else if ( k==2 ) {
2026 		    putshort(opbd,offset);
2027 		    offset += 8;
2028 		} else if ( k==3 ) {
2029 		    putshort(opbd,left!=NULL?-left->u.pos.xoff:0);
2030 		    putshort(opbd,0);		/* top */
2031 		    putshort(opbd,right!=NULL?-right->u.pos.h_adv_off:0);
2032 		    putshort(opbd,0);		/* bottom */
2033 		}
2034 		last = i;
2035 		for ( j=i+1, ++tot; j<at->gi.gcnt; ++j ) {
2036 		    if ( at->gi.bygid[i]==-1 || !haslrbounds(_sf->glyphs[at->gi.bygid[j]],&left,&right) )
2037 		break;
2038 		    ++tot;
2039 		    last = j;
2040 		    if ( k==2 ) {
2041 			putshort(opbd,offset);
2042 			offset += 8;
2043 		    } else if ( k==3 ) {
2044 			putshort(opbd,left!=NULL?-left->u.pos.xoff:0);
2045 			putshort(opbd,0);		/* top */
2046 			putshort(opbd,right!=NULL?-right->u.pos.h_adv_off:0);
2047 			putshort(opbd,0);		/* bottom */
2048 		    }
2049 		}
2050 		if ( k==1 ) {
2051 		    putshort(opbd,last);
2052 		    putshort(opbd,i);
2053 		    putshort(opbd,offset);
2054 		    offset += 2*tot;
2055 		}
2056 		++seg_cnt;
2057 		i = j-1;
2058 	    }
2059 	}
2060 	if ( k==0 ) {
2061 	    if ( seg_cnt==0 )
2062 return;
2063 	    opbd = GFileTmpfile();
2064 	    putlong(opbd, 0x00010000);	/* version */
2065 	    putshort(opbd,0);		/* data are distances (not control points) */
2066 
2067 	    putshort(opbd,4);		/* Lookup table format 4 */
2068 		/* Binary search header */
2069 	    putshort(opbd,6);		/* Entry size */
2070 	    putshort(opbd,seg_cnt);	/* Number of segments */
2071 	    for ( j=0,l=1; l<=seg_cnt; l<<=1, ++j );
2072 	    --j; l>>=1;
2073 	    putshort(opbd,6*l);
2074 	    putshort(opbd,j);
2075 	    putshort(opbd,6*(seg_cnt-l));
2076 	    /* offset from start of lookup, not table */
2077 	    offset = 6*2/* format, binsearch*/ + seg_cnt*6 +6 /*flag entry */;
2078 	} else if ( k==1 ) {		/* flag entry */
2079 	    putshort(opbd,0xffff);
2080 	    putshort(opbd,0xffff);
2081 	    putshort(opbd,0);
2082 	}
2083     }
2084     at->opbd = opbd;
2085     at->opbdlen = ftell(at->opbd);
2086     if ( at->opbdlen&2 )
2087 	putshort(at->opbd,0);
2088 }
2089 
2090 /* ************************************************************************** */
2091 /* *************************    The 'prop' table    ************************* */
2092 /* ************************************************************************** */
2093 
props_array(SplineFont * sf,struct glyphinfo * gi)2094 uint16 *props_array(SplineFont *sf,struct glyphinfo *gi) {
2095     uint16 *props;
2096     int i;
2097     SplineChar *sc, *bsc;
2098     int dir, isfloat, isbracket, offset, doit=false;
2099     AnchorPoint *ap;
2100     PST *pst;
2101     int p;
2102 
2103     props = calloc(gi->gcnt+1,sizeof(uint16));
2104     props[gi->gcnt] = -1;
2105 
2106     for ( i=0; i<gi->gcnt; ++i ) if ( (p = gi->bygid==NULL ? i : gi->bygid[i])!=-1 ) {
2107 	sc = sf->glyphs[p];
2108 	if ( sc!=NULL && (gi->bygid==NULL || sc->ttf_glyph!=-1 )) {
2109 	    dir = 0;
2110 	    if ( sc->unicodeenc>=0x10300 && sc->unicodeenc<=0x103ff )
2111 		dir = 0;
2112 	    else if ( sc->unicodeenc>=0x10800 && sc->unicodeenc<=0x10fff )
2113 		dir = 1;
2114 	    else if ( sc->unicodeenc!=-1 && sc->unicodeenc<0x10fff ) {
2115 		if ( iseuronumeric(sc->unicodeenc) )
2116 		    dir = 3;
2117 		else if ( iseuronumsep(sc->unicodeenc))
2118 		    dir = 4;
2119 		else if ( iseuronumterm(sc->unicodeenc))
2120 		    dir = 5;
2121 		else if ( isarabnumeric(sc->unicodeenc))
2122 		    dir = 6;
2123 		else if ( iscommonsep(sc->unicodeenc))
2124 		    dir = 7;
2125 		else if ( isspace(sc->unicodeenc))
2126 		    dir = 10;
2127 		else if ( islefttoright(sc->unicodeenc) )
2128 		    dir = 0;
2129 		else if ( isrighttoleft(sc->unicodeenc) )
2130 		    dir = 1;
2131 		else if ( SCScriptFromUnicode(sc)==CHR('a','r','a','b') )
2132 		    dir = 2;
2133 		else if ( SCScriptFromUnicode(sc)==CHR('h','e','b','r') )
2134 		    dir = 1;
2135 		else
2136 		    dir = 11;		/* Other neutrals */
2137 		/* Not dealing with unicode 3 classes */
2138 		/* nor block seperator/ segment seperator */
2139 	    } else if ( SCScriptFromUnicode(sc)==CHR('a','r','a','b') )
2140 		dir = 2;
2141 	    else if ( SCScriptFromUnicode(sc)==CHR('h','e','b','r') )
2142 		dir = 1;
2143 
2144 	    if ( dir==1 || dir==2 ) doit = true;
2145 	    isfloat = false;
2146 	    if ( sc->width==0 &&
2147 		    ((sc->anchor!=NULL && sc->anchor->type==at_mark) ||
2148 		     (sc->unicodeenc!=-1 && sc->unicodeenc<0x10000 && iscombining(sc->unicodeenc))))
2149 		isfloat = doit = true;
2150 	    isbracket = offset = 0;
2151 	    if ( sc->unicodeenc!=-1 && sc->unicodeenc<0x10000 && tomirror(sc->unicodeenc)!=0 ) {
2152 		bsc = SFGetChar(sf,tomirror(sc->unicodeenc),NULL);
2153 		if ( bsc!=NULL && bsc->ttf_glyph-sc->ttf_glyph>-8 && bsc->ttf_glyph-sc->ttf_glyph<8 ) {
2154 		    isbracket = true;
2155 		    offset = bsc->ttf_glyph-sc->ttf_glyph;
2156 		}
2157 	    }
2158 	    if ( !isbracket ) {
2159 		for ( pst=sc->possub; pst!=NULL && PSTHasTag(pst,CHR('r','t','l','a')); pst=pst->next );
2160 		if ( pst!=NULL && pst->type==pst_substitution &&
2161 			(bsc=SFGetChar(sf,-1,pst->u.subs.variant))!=NULL &&
2162 			bsc->ttf_glyph!=-1 && bsc->ttf_glyph-sc->ttf_glyph>-8 && bsc->ttf_glyph-sc->ttf_glyph<8 ) {
2163 		    isbracket = true;
2164 		    offset = bsc->ttf_glyph-sc->ttf_glyph;
2165 		    doit = true;
2166 		}
2167 	    }
2168 	    if ( SCRightToLeft(sc) ) {
2169 		/* Apple docs say attached right. So for r2l scripts we look for */
2170 		/*  a cursive entry, and for l2r a cursive exit */
2171 		for ( ap=sc->anchor; ap!=NULL && ap->type!=at_centry; ap=ap->next );
2172 	    } else {
2173 		for ( ap=sc->anchor; ap!=NULL && ap->type!=at_cexit; ap=ap->next );
2174 	    }
2175 	    props[sc->ttf_glyph] = dir |
2176 		    (isfloat ? 0x8000 : 0 ) |
2177 		    (isbracket ? 0x1000 : 0 ) |
2178 		    (ap!=NULL ? 0x80 : 0 ) |
2179 		    ((offset&0xf)<<8);
2180 	    /* not dealing with */
2181 	    /*	hang left 0x4000 */
2182 	    /*	hang right 0x2000 */
2183 	}
2184     }
2185 
2186     if ( !doit ) {
2187 	free(props);
2188 return( NULL );
2189     }
2190 
2191 return( props );
2192 }
2193 
aat_dumpprop(struct alltabs * at,SplineFont * sf)2194 void aat_dumpprop(struct alltabs *at, SplineFont *sf) {
2195     uint16 *props = props_array(sf,&at->gi);
2196     uint32 bin_srch_header;
2197     int i, j, cnt;
2198 
2199     if ( props==NULL )
2200 return;
2201 
2202     at->prop = GFileTmpfile();
2203     putlong(at->prop,0x00020000);
2204     putshort(at->prop,1);		/* Lookup data */
2205     putshort(at->prop,0);		/* default property is simple l2r */
2206     putshort(at->prop,2);		/* lookup format 2 => segment single value */
2207 	/* Binsearch header */
2208     bin_srch_header = ftell(at->prop);
2209     putshort(at->prop,6);		/* Entry size */
2210     putshort(at->prop,0);		/* fill in later */
2211     putshort(at->prop,0);
2212     putshort(at->prop,0);
2213     putshort(at->prop,0);
2214 
2215     cnt = 0;
2216     for ( i=0; i<at->gi.gcnt; ++i ) {
2217 	while ( i<at->gi.gcnt && props[i]==0 ) ++i;	/* skip default entries */
2218 	if ( i>=at->gi.gcnt )
2219     break;
2220 	for ( j=i+1; j<at->gi.gcnt && props[j]==props[i]; ++j );
2221 	putshort(at->prop,j-1);
2222 	putshort(at->prop,i);
2223 	putshort(at->prop,props[i]);
2224 	i = j-1;
2225 	++cnt;
2226     }
2227     putshort(at->prop,0xffff);		/* Final eof marker */
2228     putshort(at->prop,0xffff);
2229     putshort(at->prop,0x0000);
2230 
2231     fseek(at->prop,bin_srch_header,SEEK_SET);
2232     putshort(at->prop,6);		/* Entry size */
2233     putshort(at->prop,cnt);		/* Number of segments */
2234     for ( j=0,i=1; i<=cnt; i<<=1, ++j );
2235     --j; i>>=1;
2236     putshort(at->prop,6*i);
2237     putshort(at->prop,j);
2238     putshort(at->prop,6*(cnt-i));
2239 
2240     fseek(at->prop,0,SEEK_END);
2241     at->proplen = ftell(at->prop);
2242     if ( at->proplen&2 )
2243 	putshort(at->prop,0);
2244     free(props);
2245 }
2246 
2247 /* ************************************************************************** */
2248 /* *************************    The 'bsln' table    ************************* */
2249 /* ************************************************************************** */
2250 
BslnFromTag(uint32 tag)2251 static int BslnFromTag(uint32 tag) {
2252     switch ( tag ) {
2253       case CHR('r','o','m','n'):
2254 return( 0 );
2255     /* Apple has a centered ideographic baseline, while OT has a top ideo bsln*/
2256     /* no way to get Apple's baseline #1 */
2257       case CHR('i','d','e','o'):
2258 return( 2 );
2259       case CHR('h','a','n','g'):
2260 return( 3 );
2261       case CHR('m','a','t','h'):
2262 return( 4 );
2263       default:
2264 return( 0xffff );
2265     }
2266 }
2267 
PerGlyphDefBaseline(SplineFont * sf,int * def_baseline)2268 int16 *PerGlyphDefBaseline(SplineFont *sf,int *def_baseline) {
2269     int16 *baselines = malloc(sf->glyphcnt*sizeof(int16));
2270     int gid, bsln, i, any;
2271     SplineChar *sc;
2272     int counts[32];		/* Apple supports a max of 32 baselines, but only 5 are defined */
2273     struct Base *base = sf->horiz_base;
2274     struct basescript *bs;
2275     int bestbsln, bestcnt;
2276 
2277     memset(counts,0,sizeof(counts));
2278 
2279     for ( gid = 0; gid<sf->glyphcnt; ++gid ) if ( (sc = sf->glyphs[gid])!=NULL ) {
2280 	uint32 script = SCScriptFromUnicode(sc);
2281 	for ( bs= base->scripts; bs!=NULL; bs=bs->next )
2282 	    if ( bs->script==script )
2283 	break;
2284 	if ( bs==NULL )
2285 	    bsln = 0xffff;
2286 	else
2287 	    bsln = BslnFromTag( base->baseline_tags[bs->def_baseline] );
2288 /* This if is duplicated (almost) in basedlg.c:Base_FinishEdit */
2289 	if ( bsln==0xffff ) {
2290 	    if ( script==CHR('k','a','n','a') || script==CHR('h','a','n','g') ||
2291 		    script==CHR('h','a','n','i') || script==CHR('b','o','p','o') ||
2292 		    script==CHR('j','a','m','o') || script==CHR('y','i',' ',' '))
2293 		bsln = 2;
2294 	    else if ( script==CHR('t','i','b','t' ) ||
2295 		    script == CHR('b','e','n','g' ) || script == CHR('b','n','g','2') ||
2296 		    script == CHR('d','e','v','a' ) || script == CHR('d','e','v','2') ||
2297 		    script == CHR('g','u','j','r' ) || script == CHR('g','j','r','2') ||
2298 		    script == CHR('g','u','r','u' ) || script == CHR('g','u','r','2') ||
2299 		    script == CHR('k','n','d','a' ) || script == CHR('k','n','d','2') ||
2300 		    script == CHR('m','l','y','m' ) || script == CHR('m','l','m','2') ||
2301 		    script == CHR('o','r','y','a' ) || script == CHR('o','r','y','2') ||
2302 		    script == CHR('t','a','m','l' ) || script == CHR('t','m','l','2') ||
2303 		    script == CHR('t','e','l','u' ) || script == CHR('t','e','l','2'))
2304 		bsln = 3;
2305 	    else if ( script==CHR('m','a','t','h') )
2306 		bsln = 4;
2307 	    else
2308 		bsln = 0;
2309 	}
2310 	baselines[gid] = bsln;
2311 	if ( bsln!=0xffff )
2312 	    ++counts[bsln];
2313     }
2314 
2315     bestbsln = 0;
2316     bestcnt = 0;
2317     any = 0;
2318     for ( i=0; i<32 ; ++i ) {
2319 	if ( counts[i]>bestcnt ) {
2320 	    bestbsln = i;
2321 	    bestcnt = counts[i];
2322 	    ++any;
2323 	}
2324     }
2325     *def_baseline = bestbsln | (any<=1 ? 0x100 : 0 );
2326 return( baselines );
2327 }
2328 
FigureBaseOffsets(SplineFont * sf,int def_bsln,int offsets[32])2329 void FigureBaseOffsets(SplineFont *sf,int def_bsln,int offsets[32]) {
2330     struct Base *base = sf->horiz_base;
2331     struct basescript *bs = base->scripts;
2332     int i;
2333 
2334     memset( offsets,0xff,32*sizeof(int));
2335     for ( i=0; i<base->baseline_cnt; ++i ) {
2336 	int bsln = BslnFromTag(base->baseline_tags[i]);
2337 	if ( bsln!=0xffff )
2338 	    offsets[bsln] = bs->baseline_pos[i];
2339     }
2340     if ( offsets[def_bsln]!=-1 ) {
2341 	for ( i=0; i<32; ++i ) {
2342 	    if ( offsets[i]!=-1 )
2343 		offsets[i] -= offsets[def_bsln];
2344 	}
2345     }
2346     /* I suspect baseline 1 is the standard baseline for CJK glyphs on the mac*/
2347     /*  (because baseline 2 is often the same as baseline 1, which is wrong for 2) */
2348     /* OT doesn't have a centered ideographic baseline, so guestimate */
2349     /* And I don't want to base it on the actual ideo baseline (go up half an em?) */
2350     /*  because in my small sample of 'bsln' tables baseline 2 has been wrong */
2351     /*  most of the time, and it is wrong in the example in the docs. */
2352     /* (I know it is wrong because it has the same value as baseline 1, but */
2353     /*  is supposed to be below baseline 1 ) */
2354     if ( offsets[1]==-1 ) {
2355 	if ( offsets[2]!=-1 )
2356 	    offsets[1] = offsets[2]+(sf->ascent+sf->descent)/2;
2357 	else
2358 	    offsets[1] = (sf->ascent+sf->descent)/2 - sf->descent;
2359     }
2360     for ( i=0; i<32; ++i )
2361 	if ( offsets[i]==-1 )
2362 	    offsets[i] = 0;
2363 }
2364 
aat_dumpbsln(struct alltabs * at,SplineFont * sf)2365 void aat_dumpbsln(struct alltabs *at, SplineFont *sf) {
2366     int def_baseline;
2367     int offsets[32];
2368     int16 *baselines;
2369     int i, gid, j, bsln, cnt;
2370 
2371     if ( sf->horiz_base==NULL || sf->horiz_base->baseline_cnt==0 ||
2372 	    sf->horiz_base->scripts==NULL )
2373 return;
2374 
2375     baselines = PerGlyphDefBaseline(sf,&def_baseline);
2376 
2377     at->bsln = GFileTmpfile();
2378     putlong(at->bsln,0x00010000);	/* Version */
2379     if ( def_baseline & 0x100 )		/* Only one baseline in the font */
2380 	putshort(at->bsln,0);		/* distanced based (no control point), no per-glyph info */
2381     else
2382 	putshort(at->bsln,1);		/* distanced based (no cp info) with per-glyph info */
2383     putshort(at->bsln,def_baseline&0x1f);/* Default baseline when no info specified for glyphs */
2384 
2385     /* table of 32 int16 (the docs say uint16, but that must be wrong) giving */
2386     /*  the offset of the nth baseline from the default baseline. */
2387     /* 0 => Roman, 1=> centered ideo, 2=>low ideo (same as OTF ideo) 3=>hang, 4=>Math */
2388     /* values 5-31 undefined, set to 0 */
2389     FigureBaseOffsets(sf,def_baseline&0x1f,offsets);
2390 
2391     for ( i=0; i<32; ++i )
2392 	putshort(at->bsln,offsets[i]);
2393 
2394     if ( !(def_baseline&0x100) ) {
2395 	def_baseline &= 0x1f;
2396 
2397 	putshort(at->bsln,2);	/* Lookup format 2, segmented array w/ single value */
2398 
2399 	cnt = 0;
2400 	for ( i=0; i<at->gi.gcnt; ++i ) if ( (gid=at->gi.bygid[i])!=-1 ) {
2401 	    if ( baselines[gid]!=-1 && baselines[gid]!=def_baseline ) {
2402 		bsln = baselines[gid];
2403 		for ( j=i; j<at->gi.gcnt && baselines[at->gi.bygid[i]]==bsln; ++j );
2404 		i = j-1;
2405 		++cnt;
2406 	    }
2407 	}
2408 
2409 	/* Dump out a binary search header */
2410 	putshort(at->bsln,6);		/* size of each item */
2411 	putshort(at->bsln,cnt);		/* number of items */
2412 	for ( j=1, i=0; cnt<=j; j<<=1, ++i );
2413 	putshort(at->bsln,6*j/2);	/* j is a power of 2 too big */
2414 	putshort(at->bsln,i-1);
2415 	putshort(at->bsln,6*(cnt-(j>>1)) );
2416 
2417 	for ( i=0; i<at->gi.gcnt; ++i ) if ( (gid=at->gi.bygid[i])!=-1 ) {
2418 	    if ( baselines[gid]!=-1 && baselines[gid]!=def_baseline ) {
2419 		bsln = baselines[gid];
2420 		for ( j=i; j<at->gi.gcnt && baselines[at->gi.bygid[i]]==bsln; ++j );
2421 		putshort(at->bsln,j-1);
2422 		putshort(at->bsln,i);
2423 		putshort(at->bsln,bsln);
2424 		i = j-1;
2425 	    }
2426 	}
2427 
2428 	putshort(at->bsln,0xffff);		/* Final eof marker */
2429 	putshort(at->bsln,0xffff);
2430 	putshort(at->bsln,0x0000);
2431     }
2432 
2433     at->bslnlen = ftell(at->bsln);
2434     /* Only contains 2 & 4 byte quantities, can't have an odd number of bytes */
2435     if ( at->bslnlen&2 )
2436 	putshort(at->bsln,0);
2437     free(baselines);
2438 }
2439 
2440 /* ************************************************************************** */
2441 /* *************************    utility routines    ************************* */
2442 /* ************************************************************************** */
2443 
MacFeatureToOTTag(int featureType,int featureSetting)2444 uint32 MacFeatureToOTTag(int featureType,int featureSetting) {
2445     int i;
2446     struct macsettingname *msn = user_macfeat_otftag ? user_macfeat_otftag : macfeat_otftag;
2447 
2448     for ( i=0; msn[i].otf_tag!=0; ++i )
2449 	if ( msn[i].mac_feature_type == featureType &&
2450 		msn[i].mac_feature_setting == featureSetting )
2451 return( msn[i].otf_tag );
2452 
2453 return( 0 );
2454 }
2455 
OTTagToMacFeature(uint32 tag,int * featureType,int * featureSetting)2456 int OTTagToMacFeature(uint32 tag, int *featureType,int *featureSetting) {
2457     int i;
2458     struct macsettingname *msn = user_macfeat_otftag ? user_macfeat_otftag : macfeat_otftag;
2459 
2460     for ( i=0; msn[i].otf_tag!=0; ++i )
2461 	if ( msn[i].otf_tag == tag ) {
2462 	    *featureType = msn[i].mac_feature_type;
2463 	    *featureSetting = msn[i].mac_feature_setting;
2464 return( true );
2465 	}
2466     *featureType = (tag >> 16);
2467     *featureSetting = (tag & 0xFFFF);
2468 	/* Ranges taken from Apple Font Registry. An OT tag without a
2469     corresponding mac feature should fail this test.*/
2470     if (*featureType >= 0 && *featureType < 105 && *featureSetting < 16)
2471         return ( true );
2472 
2473     *featureType = 0;
2474     *featureSetting = 0;
2475 return( false );
2476 }
2477 
featureFromTag(SplineFont * sf,uint32 tag)2478 static struct feature *featureFromTag(SplineFont *sf, uint32 tag ) {
2479     int ft, fs;
2480     struct feature *feat;
2481 
2482     feat = chunkalloc(sizeof(struct feature));
2483     if (OTTagToMacFeature(tag, &ft, &fs)) {
2484         feat->featureType = ft;
2485         feat->featureSetting = fs;
2486         feat->mf = FindMacFeature(sf,feat->featureType,&feat->smf);
2487         feat->ms = FindMacSetting(sf,feat->featureType,feat->featureSetting,&feat->sms);
2488         feat->needsOff = feat->mf!=NULL && !feat->mf->ismutex;
2489         feat->vertOnly = tag==CHR('v','r','t','2') || tag==CHR('v','k','n','a');
2490     }
2491 
2492     return( feat );
2493 }
2494 
featureFromSubtable(SplineFont * sf,struct lookup_subtable * sub)2495 static struct feature *featureFromSubtable(SplineFont *sf, struct lookup_subtable *sub ) {
2496     FeatureScriptLangList *fl;
2497     int ft, fs;
2498 
2499     for ( fl=sub->lookup->features; fl!=NULL; fl=fl->next ) {
2500 	if ( fl->ismac )
2501     break;
2502     }
2503     if ( fl==NULL ) {
2504 	for ( fl=sub->lookup->features; fl!=NULL; fl=fl->next ) {
2505 	    if ( OTTagToMacFeature(fl->featuretag,&ft,&fs) )
2506 	break;
2507 	}
2508 	  if ( fl==NULL ) {
2509 	    IError("Could not find a mac feature");
2510       return NULL;
2511     }
2512   }
2513   return( featureFromTag(sf,fl->featuretag));
2514 }
2515 
PSTHasTag(PST * pst,uint32 tag)2516 static int PSTHasTag(PST *pst, uint32 tag) {
2517     FeatureScriptLangList *fl;
2518 
2519     if ( pst->subtable==NULL )
2520 return( false );
2521     for ( fl=pst->subtable->lookup->features; fl!=NULL; fl=fl->next )
2522 	if ( fl->featuretag == tag )
2523 return( true );
2524 
2525 return( false );
2526 }
2527 
scriptsHaveDefault(struct scriptlanglist * sl)2528 int scriptsHaveDefault(struct scriptlanglist *sl) {
2529     int i;
2530 
2531     for ( ; sl!=NULL; sl=sl->next ) {
2532 	for ( i=0; i<sl->lang_cnt; ++i ) {
2533 	    if ( (i<MAX_LANG && sl->langs[i]==DEFAULT_LANG) ||
2534 		    (i>=MAX_LANG && sl->morelangs[i-MAX_LANG]==DEFAULT_LANG)) {
2535 return( true );
2536 	    }
2537 	}
2538     }
2539 return( false );
2540 }
2541 
LookupHasDefault(OTLookup * otl)2542 int LookupHasDefault(OTLookup *otl) {
2543     FeatureScriptLangList *feats;
2544 
2545     if ( otl->def_lang_checked )
2546 return( otl->def_lang_found );
2547 
2548     otl->def_lang_checked = true;
2549     for ( feats=otl->features; feats!=NULL; feats = feats->next ) {
2550 	if ( scriptsHaveDefault(feats->scripts) ) {
2551 	    otl->def_lang_found = true;
2552 return( true );
2553 	}
2554     }
2555     otl->def_lang_found = false;
2556 return( false );
2557 }
2558