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 "sfd1.h"
31 
32 #include "fontforge.h"
33 #include "fvfonts.h"
34 #include "lookups.h"
35 #include "tottfgpos.h"
36 
37 #include <string.h>
38 
39 /* This file contains the routines needed to process an old style sfd file and*/
40 /*  convert it into the new format */
41 
SFGuessScriptList(SplineFont1 * sf)42 static void SFGuessScriptList(SplineFont1 *sf) {
43     uint32 scripts[32], script;
44     int i, scnt=0, j;
45 
46     for ( i=0; i<sf->sf.glyphcnt; ++i ) if ( sf->sf.glyphs[i]!=NULL ) {
47 	script = SCScriptFromUnicode(sf->sf.glyphs[i]);
48 	if ( script!=0 && script!=DEFAULT_SCRIPT ) {
49 	    for ( j=scnt-1; j>=0 ; --j )
50 		if ( scripts[j]==script )
51 	    break;
52 	    if ( j<0 ) {
53 		scripts[scnt++] = script;
54 		if ( scnt>=32 )
55     break;
56 	    }
57 	}
58     }
59     if ( scnt==0 )
60 	scripts[scnt++] = CHR('l','a','t','n');
61 
62     /* order scripts */
63     for ( i=0; i<scnt-1; ++i ) for ( j=i+1; j<scnt; ++j ) {
64 	if ( scripts[i]>scripts[j] ) {
65 	    script = scripts[i];
66 	    scripts[i] = scripts[j];
67 	    scripts[j] = script;
68 	}
69     }
70 
71     if ( sf->sf.cidmaster ) sf = (SplineFont1 *) sf->sf.cidmaster;
72     else if ( sf->sf.mm!=NULL ) sf=(SplineFont1 *) sf->sf.mm->normal;
73     if ( sf->script_lang!=NULL )
74 return;
75     sf->script_lang = calloc(2,sizeof(struct script_record *));
76     sf->script_lang[0] = calloc(scnt+1,sizeof(struct script_record));
77     sf->sli_cnt = 1;
78     for ( j=0; j<scnt; ++j ) {
79 	sf->script_lang[0][j].script = scripts[j];
80 	sf->script_lang[0][j].langs = malloc(2*sizeof(uint32));
81 	sf->script_lang[0][j].langs[0] = DEFAULT_LANG;
82 	sf->script_lang[0][j].langs[1] = 0;
83     }
84     sf->script_lang[1] = NULL;
85 }
86 
SLContains(struct script_record * sr,uint32 script,uint32 lang)87 static int SLContains(struct script_record *sr, uint32 script, uint32 lang) {
88     int i, j;
89 
90     if ( script==DEFAULT_SCRIPT || script == 0 )
91 return( true );
92     for ( i=0; sr[i].script!=0; ++i ) {
93 	if ( sr[i].script==script ) {
94 	    if ( lang==0 )
95 return( true );
96 	    for ( j=0; sr[i].langs[j]!=0; ++j )
97 		if ( sr[i].langs[j]==lang )
98 return( true );
99 
100 return( false );	/* this script entry didn't contain the language. won't be any other scripts to check */
101 	}
102     }
103 return( false );	/* Never found script */
104 }
105 
SFAddScriptIndex(SplineFont1 * sf,uint32 * scripts,int scnt)106 int SFAddScriptIndex(SplineFont1 *sf,uint32 *scripts,int scnt) {
107     int i,j;
108     struct script_record *sr;
109 
110     if ( scnt==0 )
111 	scripts[scnt++] = CHR('l','a','t','n');		/* Need a default script preference */
112     for ( i=0; i<scnt-1; ++i ) for ( j=i+1; j<scnt; ++j ) {
113 	if ( scripts[i]>scripts[j] ) {
114 	    uint32 temp = scripts[i];
115 	    scripts[i] = scripts[j];
116 	    scripts[j] = temp;
117 	}
118     }
119 
120     if ( sf->sf.cidmaster ) sf = (SplineFont1 *) sf->sf.cidmaster;
121     if ( sf->script_lang==NULL )	/* It's an old sfd file */
122 	sf->script_lang = calloc(1,sizeof(struct script_record *));
123     for ( i=0; sf->script_lang[i]!=NULL; ++i ) {
124 	sr = sf->script_lang[i];
125 	for ( j=0; sr[j].script!=0 && j<scnt &&
126 		sr[j].script==scripts[j]; ++j );
127 	if ( sr[j].script==0 && j==scnt )
128 return( i );
129     }
130 
131     sf->script_lang = realloc(sf->script_lang,(i+2)*sizeof(struct script_record *));
132     sf->script_lang[i+1] = NULL;
133     sr = sf->script_lang[i] = calloc(scnt+1,sizeof(struct script_record));
134     for ( j = 0; j<scnt; ++j ) {
135 	sr[j].script = scripts[j];
136 	sr[j].langs = malloc(2*sizeof(uint32));
137 	sr[j].langs[0] = DEFAULT_LANG;
138 	sr[j].langs[1] = 0;
139     }
140 return( i );
141 }
142 
SFAddScriptLangIndex(SplineFont * _sf,uint32 script,uint32 lang)143 static int SFAddScriptLangIndex(SplineFont *_sf,uint32 script,uint32 lang) {
144     int i;
145     SplineFont1 *sf;
146 
147     if ( _sf->cidmaster ) _sf = _sf->cidmaster;
148     else if ( _sf->mm!=NULL ) _sf=_sf->mm->normal;
149 
150     if ( _sf->sfd_version>=2 )
151 	IError( "SFFindBiggestScriptLangIndex called with bad version number.\n" );
152 
153     sf = (SplineFont1 *) _sf;
154 
155     if ( script==0 ) script=DEFAULT_SCRIPT;
156     if ( lang==0 ) lang=DEFAULT_LANG;
157     if ( sf->script_lang==NULL )
158 	sf->script_lang = calloc(2,sizeof(struct script_record *));
159     for ( i=0; sf->script_lang[i]!=NULL; ++i ) {
160 	if ( sf->script_lang[i][0].script==script && sf->script_lang[i][1].script==0 &&
161 		sf->script_lang[i][0].langs[0]==lang &&
162 		sf->script_lang[i][0].langs[1]==0 )
163 return( i );
164     }
165     sf->script_lang = realloc(sf->script_lang,(i+2)*sizeof(struct script_record *));
166     sf->script_lang[i] = calloc(2,sizeof(struct script_record));
167     sf->script_lang[i][0].script = script;
168     sf->script_lang[i][0].langs = malloc(2*sizeof(uint32));
169     sf->script_lang[i][0].langs[0] = lang;
170     sf->script_lang[i][0].langs[1] = 0;
171     sf->script_lang[i+1] = NULL;
172     sf->sli_cnt = i+1;
173 return( i );
174 }
175 
SLCount(struct script_record * sr)176 static int SLCount(struct script_record *sr) {
177     int sl_cnt = 0;
178     int i,j;
179 
180     for ( i=0; sr[i].script!=0; ++i ) {
181 	for ( j=0; sr[i].langs[j]!=0; ++j )
182 	    ++sl_cnt;
183     }
184 return( sl_cnt );
185 }
186 
SFFindBiggestScriptLangIndex(SplineFont * _sf,uint32 script,uint32 lang)187 int SFFindBiggestScriptLangIndex(SplineFont *_sf,uint32 script,uint32 lang) {
188     int i, best_sli= -1, best_cnt= -1, cnt;
189     SplineFont1 *sf = (SplineFont1 *) _sf;
190 
191     if ( _sf->sfd_version>=2 )
192 	IError( "SFFindBiggestScriptLangIndex called with bad version number.\n" );
193 
194     if ( sf->script_lang==NULL )
195 	SFGuessScriptList(sf);
196     for ( i=0; sf->script_lang[i]!=NULL; ++i ) {
197 	if ( SLContains(sf->script_lang[i],script,lang)) {
198 	    cnt = SLCount(sf->script_lang[i]);
199 	    if ( cnt>best_cnt ) {
200 		best_sli = i;
201 		best_cnt = cnt;
202 	    }
203 	}
204     }
205     if ( best_sli==-1 )
206 return( SFAddScriptLangIndex(_sf,script,lang) );
207 
208 return( best_sli );
209 }
210 
FeaturesFromTagSli(uint32 tag,int sli,SplineFont1 * sf)211 static FeatureScriptLangList *FeaturesFromTagSli(uint32 tag,int sli,SplineFont1 *sf) {
212     FeatureScriptLangList *fl;
213     struct script_record *sr;
214     struct scriptlanglist *cur, *last;
215     int i;
216 
217     fl = chunkalloc(sizeof(FeatureScriptLangList));
218     fl->featuretag = tag;
219     if ( sli==SLI_NESTED || sli<0 || sli>=sf->sli_cnt )
220 return( fl );
221     last = NULL;
222     for ( sr = sf->script_lang[sli]; sr->script!=0; ++sr ) {
223 	cur = chunkalloc(sizeof(struct scriptlanglist));
224 	cur->script = sr->script;
225 	for ( i=0; sr->langs[i]!=0; ++i );
226 	cur->lang_cnt = i;
227 	if ( i>MAX_LANG )
228 	    cur->morelangs = malloc((i-MAX_LANG) * sizeof(uint32));
229 	for ( i=0; sr->langs[i]!=0; ++i ) {
230 	    if ( i<MAX_LANG )
231 		cur->langs[i] = sr->langs[i];
232 	    else
233 		cur->morelangs[i-MAX_LANG] = sr->langs[i];
234 	}
235 	if ( last==NULL )
236 	    fl->scripts = cur;
237 	else
238 	    last->next = cur;
239 	last = cur;
240     }
241 return( fl );
242 }
243 
CreateLookup(SplineFont1 * sf,uint32 tag,int sli,int flags,enum possub_type type)244 static OTLookup *CreateLookup(SplineFont1 *sf,uint32 tag, int sli,
245 	int flags,enum possub_type type) {
246     OTLookup *otl = chunkalloc(sizeof(OTLookup));
247 
248     otl->lookup_type =
249 	    type == pst_position ? gpos_single :
250 	    type == pst_pair ? gpos_pair :
251 	    type == pst_contextpos ? gpos_context :
252 	    type == pst_chainpos ? gpos_contextchain :
253 	    type == pst_substitution ? gsub_single :
254 	    type == pst_alternate ? gsub_alternate :
255 	    type == pst_multiple ? gsub_multiple :
256 	    type == pst_ligature ? gsub_ligature :
257 	    type == pst_contextsub ? gsub_context :
258 	    type == pst_chainsub ? gsub_contextchain :
259 		ot_undef;
260     if ( otl->lookup_type == ot_undef )
261 	IError("Unknown lookup type");
262     if ( otl->lookup_type<gpos_single ) {
263 	otl->next = sf->sf.gsub_lookups;
264 	sf->sf.gsub_lookups = otl;
265     } else {
266 	otl->next = sf->sf.gpos_lookups;
267 	sf->sf.gpos_lookups = otl;
268     }
269     otl->lookup_flags = flags;
270     otl->features = FeaturesFromTagSli(tag,sli,sf);
271     /* We will set the lookup_index after we've ordered the list */
272     /* We will set the lookup_name after we've assigned the index */
273     /* We will add subtables as we need them */
274 return( otl );
275 }
276 
CreateACLookup(SplineFont1 * sf,AnchorClass1 * ac)277 static OTLookup *CreateACLookup(SplineFont1 *sf,AnchorClass1 *ac) {
278     OTLookup *otl = chunkalloc(sizeof(OTLookup));
279 
280     otl->lookup_type =
281 	    ac->ac.type == act_mark ? gpos_mark2base :
282 	    ac->ac.type == act_mkmk ? gpos_mark2mark :
283 	    ac->ac.type == act_curs ? gpos_cursive :
284 	    ac->ac.type == act_mklg ? gpos_mark2ligature :
285 		ot_undef;
286     if ( otl->lookup_type == ot_undef )
287 	IError("Unknown AnchorClass type");
288     otl->next = sf->sf.gpos_lookups;
289     sf->sf.gpos_lookups = otl;
290     otl->lookup_flags = ac->flags;
291     otl->features = FeaturesFromTagSli(ac->feature_tag,ac->script_lang_index,sf);
292     /* We will set the lookup_index after we've ordered the list */
293     /* We will set the lookup_name after we've assigned the index */
294     /* We will add one subtable soon */
295 return( otl );
296 }
297 
CreateMacLookup(SplineFont1 * sf,ASM1 * sm)298 static OTLookup *CreateMacLookup(SplineFont1 *sf,ASM1 *sm) {
299     OTLookup *otl = chunkalloc(sizeof(OTLookup));
300     int i, ch;
301     char *pt, *start;
302     SplineChar *sc;
303 
304     otl->features = chunkalloc(sizeof(FeatureScriptLangList));
305     if ( sm->sm.type == asm_kern ) {
306 	otl->lookup_type = kern_statemachine;
307 	otl->next = sf->sf.gpos_lookups;
308 	sf->sf.gpos_lookups = otl;
309 	otl->features->featuretag = (sm->sm.flags&0x8000) ? CHR('v','k','r','n') : CHR('k','e','r','n');
310     } else {
311 	otl->lookup_type = sm->sm.type==asm_indic ? morx_indic : sm->sm.type==asm_context ? morx_context : morx_insert;
312 	otl->next = sf->sf.gsub_lookups;
313 	sf->sf.gsub_lookups = otl;
314 	otl->features->featuretag = (sm->feature<<16) | (sm->setting);
315 	otl->features->ismac = true;
316     }
317     otl->lookup_flags = 0;
318 
319     for ( i=4; i<sm->sm.class_cnt; ++i ) {
320 	for ( start=sm->sm.classes[i]; ; start = pt ) {
321 	    while ( *start==' ' ) ++start;
322 	    if ( *start=='\0' )
323 	break;
324 	    for ( pt=start ; *pt!='\0' && *pt!=' '; ++pt );
325 	    ch = *pt; *pt = '\0';
326 	    sc = SFGetChar(&sf->sf,-1,start);
327 	    if ( sc!=NULL )
328 		FListAppendScriptLang(otl->features,SCScriptFromUnicode(sc),
329 			DEFAULT_LANG);
330 	    *pt = ch;
331 	}
332     }
333 
334     /* We will set the lookup_index after we've ordered the list */
335     /* We will set the lookup_name after we've assigned the index */
336     /* We will add one subtable soon */
337 return( otl );
338 }
339 
CreateSubtable(OTLookup * otl,SplineFont1 * sf)340 static struct lookup_subtable *CreateSubtable(OTLookup *otl,SplineFont1 *sf) {
341     struct lookup_subtable *cur, *prev;
342 
343     cur = chunkalloc(sizeof(struct lookup_subtable));
344     if ( otl->subtables==NULL )
345 	otl->subtables = cur;
346     else {
347 	for ( prev=otl->subtables; prev->next!=NULL; prev=prev->next );
348 	prev->next = cur;
349     }
350     cur->lookup = otl;
351     if ( otl->lookup_type == gsub_single ||
352 	    otl->lookup_type == gsub_multiple ||
353 	    otl->lookup_type == gsub_alternate ||
354 	    otl->lookup_type == gsub_ligature ||
355 	    otl->lookup_type == gpos_single ||
356 	    otl->lookup_type == gpos_pair )
357 	cur->per_glyph_pst_or_kern = true;
358     else if ( otl->lookup_type == gpos_cursive ||
359 	    otl->lookup_type == gpos_mark2base ||
360 	    otl->lookup_type == gpos_mark2ligature ||
361 	    otl->lookup_type == gpos_mark2mark )
362 	cur->anchor_classes = true;
363     if ( otl->lookup_type == gpos_pair ) {
364 	if ( otl->features!=NULL &&
365 		otl->features->featuretag==CHR('v','k','r','n'))
366 	    cur->vertical_kerning = true;
367     }
368 return( cur );
369 }
370 
FindNestedLookupByTag(SplineFont1 * sf,uint32 tag)371 static OTLookup *FindNestedLookupByTag(SplineFont1 *sf,uint32 tag) {
372     int isgpos;
373     OTLookup *otl;
374 
375     for ( isgpos=0; isgpos<2; ++isgpos ) {
376 	for ( otl = isgpos ? sf->sf.gpos_lookups : sf->sf.gsub_lookups; otl!=NULL; otl=otl->next ) {
377 	    if ( otl->features!=NULL && otl->features->scripts==NULL &&
378 		    otl->features->featuretag == tag )
379 return( otl );
380 	}
381     }
382 return( NULL );
383 }
384 
FPSTReplaceTagsWithLookups(FPST * fpst,SplineFont1 * sf)385 static void FPSTReplaceTagsWithLookups(FPST *fpst,SplineFont1 *sf) {
386     int i,j,k;
387 
388     if ( fpst->type == pst_reversesub )
389 return;
390     for ( i=0; i<fpst->rule_cnt; ++i ) {
391 	for ( j=0; j<fpst->rules[i].lookup_cnt; ++j ) {
392 	    OTLookup *otl = FindNestedLookupByTag(sf,(uint32) (intpt) (fpst->rules[i].lookups[j].lookup) );
393 	    if ( otl!=NULL )
394 		fpst->rules[i].lookups[j].lookup = otl;
395 	    else {
396 		for ( k=j+1; k<fpst->rules[i].lookup_cnt; ++k )
397 		    fpst->rules[i].lookups[k-1] = fpst->rules[i].lookups[k];
398 		--fpst->rules[i].lookup_cnt;
399 	    }
400 	}
401     }
402 }
403 
ASMReplaceTagsWithLookups(ASM * sm,SplineFont1 * sf)404 static void ASMReplaceTagsWithLookups(ASM *sm,SplineFont1 *sf) {
405     int i;
406 
407     if ( sm->type != asm_context )
408 return;
409     for ( i=0; i<sm->class_cnt*sm->state_cnt; ++i ) {
410 	if ( sm->state[i].u.context.mark_lookup!=NULL )
411 	    sm->state[i].u.context.mark_lookup = FindNestedLookupByTag(sf,(uint32) (intpt) (sm->state[i].u.context.mark_lookup) );
412 	if ( sm->state[i].u.context.cur_lookup!=NULL )
413 	    sm->state[i].u.context.cur_lookup = FindNestedLookupByTag(sf,(uint32) (intpt) (sm->state[i].u.context.cur_lookup) );
414     }
415 }
416 
ACHasBaseLig(SplineFont1 * sf,AnchorClass1 * ac)417 static void ACHasBaseLig(SplineFont1 *sf,AnchorClass1 *ac) {
418     int gid,k;
419     SplineFont1 *subsf;
420     SplineChar *sc;
421     AnchorPoint *ap;
422 
423     ac->has_bases = ac->has_ligatures = false;
424     if ( ac->ac.type==act_mkmk || ac->ac.type==act_curs )
425 return;
426     k=0;
427     do {
428 	subsf = sf->sf.subfontcnt==0 ? sf : (SplineFont1 *) (sf->sf.subfonts[k]);
429 	for ( gid=0; gid<subsf->sf.glyphcnt; ++gid ) if ( (sc=subsf->sf.glyphs[gid])!=NULL ) {
430 	    for ( ap=sc->anchor; ap!=NULL; ap=ap->next ) {
431 		if ( ap->anchor!=(AnchorClass *) ac )
432 	    continue;
433 		if ( ap->type==at_basechar ) {
434 		    ac->has_bases = true;
435 		    if ( ac->has_ligatures )
436 return;
437 		} else if ( ap->type==at_baselig ) {
438 		    ac->has_ligatures = true;
439 		    if ( ac->has_bases )
440 return;
441 		}
442 	    }
443 	}
444 	++k;
445     } while ( k<sf->sf.subfontcnt );
446 }
447 
ACDisassociateLigatures(SplineFont1 * sf,AnchorClass1 * ac)448 static void ACDisassociateLigatures(SplineFont1 *sf,AnchorClass1 *ac) {
449     int gid,k;
450     SplineFont1 *subsf;
451     SplineChar *sc;
452     AnchorPoint *ap, *lap;
453     AnchorClass1 *lac;
454     char *format;
455 
456     lac = chunkalloc(sizeof(AnchorClass1));
457     *lac = *ac;
458     lac->ac.type = act_mklg;
459     ac->ac.next = (AnchorClass *) lac;
460 
461   /* GT: Need to split some AnchorClasses into two classes, one for normal */
462   /* GT:  base letters, and one for ligatures. So create a new AnchorClass */
463   /* GT:  name for the ligature version */
464     format = _("Ligature %s");
465     lac->ac.name = malloc(strlen(ac->ac.name)+strlen(format)+1);
466     sprintf( lac->ac.name, format, ac->ac.name );
467 
468     k=0;
469     do {
470 	subsf = sf->sf.subfontcnt==0 ? sf : (SplineFont1 *) (sf->sf.subfonts[k]);
471 	for ( gid=0; gid<subsf->sf.glyphcnt; ++gid ) if ( (sc=subsf->sf.glyphs[gid])!=NULL ) {
472 	    for ( ap=sc->anchor; ap!=NULL; ap=ap->next ) {
473 		if ( ap->anchor!=(AnchorClass *) ac )
474 	    continue;
475 		if ( ap->type==at_mark ) {
476 		    lap = chunkalloc(sizeof(AnchorPoint));
477 		    *lap = *ap;
478 		    ap->next = lap;
479 		    lap->anchor = (AnchorClass *) lac;
480 		} else if ( ap->type==at_baselig ) {
481 		    ap->anchor = (AnchorClass *) lac;
482 		}
483 	    }
484 	}
485 	++k;
486     } while ( k<sf->sf.subfontcnt );
487 }
488 
TTFFeatureIndex(uint32 tag,struct table_ordering * ord)489 static int TTFFeatureIndex( uint32 tag, struct table_ordering *ord ) {
490     /* This is the order in which features should be executed */
491     int cnt = 0;
492 
493     if ( ord!=NULL ) {
494 	for ( cnt=0; ord->ordered_features[cnt]!=0; ++cnt )
495 	    if ( ord->ordered_features[cnt]==tag )
496 	break;
497 return( cnt );
498     }
499 
500     cnt+=2;
501 
502     switch ( tag ) {
503 /* GSUB ordering */
504       case CHR('c','c','m','p'):	/* Must be first? */
505 return( cnt-2 );
506       case CHR('l','o','c','l'):	/* Language dependent letter forms (serbian uses some different glyphs than russian) */
507 return( cnt-1 );
508       case CHR('i','s','o','l'):
509 return( cnt );
510       case CHR('j','a','l','t'):		/* must come after 'isol' */
511 return( cnt+1 );
512       case CHR('f','i','n','a'):
513 return( cnt+2 );
514       case CHR('f','i','n','2'):
515       case CHR('f','a','l','t'):		/* must come after 'fina' */
516 return( cnt+3 );
517       case CHR('f','i','n','3'):
518 return( cnt+4 );
519       case CHR('m','e','d','i'):
520 return( cnt+5 );
521       case CHR('m','e','d','2'):
522 return( cnt+6 );
523       case CHR('i','n','i','t'):
524 return( cnt+7 );
525 
526       case CHR('r','t','l','a'):
527 return( cnt+100 );
528       case CHR('s','m','c','p'): case CHR('c','2','s','c'):
529 return( cnt+200 );
530 
531       case CHR('r','l','i','g'):
532 return( cnt+300 );
533       case CHR('c','a','l','t'):
534 return( cnt+301 );
535       case CHR('l','i','g','a'):
536 return( cnt+302 );
537       case CHR('d','l','i','g'): case CHR('h','l','i','g'):
538 return( cnt+303 );
539       case CHR('c','s','w','h'):
540 return( cnt+304 );
541       case CHR('m','s','e','t'):
542 return( cnt+305 );
543 
544       case CHR('f','r','a','c'):
545 return( cnt+306 );
546 
547 /* Indic processing */
548       case CHR('n','u','k','t'):
549       case CHR('p','r','e','f'):
550 return( cnt+301 );
551       case CHR('a','k','h','n'):
552 return( cnt+302 );
553       case CHR('r','p','h','f'):
554 return( cnt+303 );
555       case CHR('b','l','w','f'):
556 return( cnt+304 );
557       case CHR('h','a','l','f'):
558       case CHR('a','b','v','f'):
559 return( cnt+305 );
560       case CHR('p','s','t','f'):
561 return( cnt+306 );
562       case CHR('v','a','t','u'):
563 return( cnt+307 );
564 
565       case CHR('p','r','e','s'):
566 return( cnt+310 );
567       case CHR('b','l','w','s'):
568 return( cnt+311 );
569       case CHR('a','b','v','s'):
570 return( cnt+312 );
571       case CHR('p','s','t','s'):
572 return( cnt+313 );
573       case CHR('c','l','i','g'):
574 return( cnt+314 );
575 
576       case CHR('h','a','l','n'):
577 return( cnt+320 );
578 /* end indic ordering */
579 
580       case CHR('a','f','r','c'):
581       case CHR('l','j','m','o'):
582       case CHR('v','j','m','o'):
583 return( cnt+350 );
584       case CHR('v','r','t','2'): case CHR('v','e','r','t'):
585 return( cnt+1010 );		/* Documented to come last */
586 
587 /* Unknown things come after everything but vert/vrt2 */
588       default:
589 return( cnt+1000 );
590 
591     }
592 }
593 
GSubOrder(SplineFont1 * sf,FeatureScriptLangList * fl)594 static int GSubOrder(SplineFont1 *sf,FeatureScriptLangList *fl) {
595     struct table_ordering *ord;
596     int sofar = 30000, temp;
597 
598     for ( ord=sf->orders; ord!=NULL && ord->table_tag!=CHR('G','S','U','B');
599 	    ord = ord->next );
600     for ( ; fl!=NULL; fl=fl->next ) {
601 	temp = TTFFeatureIndex(fl->featuretag,ord);
602 	if ( temp<sofar )
603 	    sofar = temp;
604     }
605 return( sofar );
606 }
607 
order_lookups(const void * _otl1,const void * _otl2)608 static int order_lookups(const void *_otl1, const void *_otl2) {
609     const OTLookup *otl1 = *(const OTLookup **) _otl1, *otl2 = *(const OTLookup **) _otl2;
610 return( otl1->lookup_index - otl2->lookup_index );
611 }
612 
SFDCleanupAnchorClasses(SplineFont * sf)613 static void SFDCleanupAnchorClasses(SplineFont *sf) {
614     AnchorClass *ac;
615     AnchorPoint *ap;
616     int i, j, scnt;
617 #define S_MAX	100
618     uint32 scripts[S_MAX];
619     int merge=0;
620 
621     for ( ac = sf->anchor; ac!=NULL; ac=ac->next ) {
622 	if ( ((AnchorClass1 *) ac)->script_lang_index==0xffff ) {
623 	    scnt = 0;
624 	    for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
625 		for ( ap = sf->glyphs[i]->anchor; ap!=NULL && ap->anchor!=ac; ap=ap->next );
626 		if ( ap!=NULL && scnt<S_MAX ) {
627 		    uint32 script = SCScriptFromUnicode(sf->glyphs[i]);
628 		    if ( script==0 )
629 	    continue;
630 		    for ( j=0; j<scnt; ++j )
631 			if ( scripts[j]==script )
632 		    break;
633 		    if ( j==scnt )
634 			scripts[scnt++] = script;
635 		}
636 	    }
637 	    ((AnchorClass1 *) ac)->script_lang_index = SFAddScriptIndex((SplineFont1 *) sf,scripts,scnt);
638 	}
639 	if ( ((AnchorClass1 *) ac)->merge_with == 0xffff )
640 	    ((AnchorClass1 *) ac)->merge_with = ++merge;
641     }
642 #undef S_MAX
643 }
644 
interp_from_encoding(Encoding * enc,enum uni_interp interp)645 enum uni_interp interp_from_encoding(Encoding *enc,enum uni_interp interp) {
646 
647     if ( enc==NULL )
648 return( interp );
649 
650     if ( enc->is_japanese )
651 	interp = ui_japanese;
652     else if ( enc->is_korean )
653 	interp = ui_korean;
654     else if ( enc->is_tradchinese )
655 	interp = ui_trad_chinese;
656     else if ( enc->is_simplechinese )
657 	interp = ui_simp_chinese;
658 return( interp );
659 }
660 
SFD_AssignLookups(SplineFont1 * sf)661 void SFD_AssignLookups(SplineFont1 *sf) {
662     PST1 *pst, *pst2;
663     int isv;
664     KernPair1 *kp, *kp2;
665     KernClass1 *kc, *kc2;
666     FPST1 *fpst;
667     ASM1 *sm;
668     AnchorClass1 *ac, *ac2;
669     int gid, gid2, cnt, i, k, isgpos;
670     SplineFont1 *subsf;
671     SplineChar *sc, *sc2;
672     OTLookup *otl, **all;
673     struct lookup_subtable *sub;
674 
675     /* Fix up some gunk from really old versions of the sfd format */
676     SFDCleanupAnchorClasses(&sf->sf);
677     if ( sf->sf.uni_interp==ui_unset && sf->sf.map!=NULL )
678 	sf->sf.uni_interp = interp_from_encoding(sf->sf.map->enc,ui_none);
679 
680     /* Fixup for an old bug */
681     if ( sf->sf.pfminfo.os2_winascent < sf->sf.ascent/4 && !sf->sf.pfminfo.winascent_add ) {
682 	sf->sf.pfminfo.winascent_add = true;
683 	sf->sf.pfminfo.os2_winascent = 0;
684 	sf->sf.pfminfo.windescent_add = true;
685 	sf->sf.pfminfo.os2_windescent = 0;
686     }
687 
688     /* First handle the PSTs, no complications here */
689     k=0;
690     do {
691 	subsf = sf->sf.subfontcnt==0 ? sf : (SplineFont1 *) (sf->sf.subfonts[k]);
692 	for ( gid=0; gid<subsf->sf.glyphcnt; ++gid ) if ( (sc=subsf->sf.glyphs[gid])!=NULL ) {
693 	    for ( pst = (PST1 *) (sc->possub); pst!=NULL; pst = (PST1*) (pst->pst.next) ) {
694 		if ( pst->pst.type == pst_lcaret || pst->pst.subtable!=NULL )
695 	    continue;		/* Nothing to do, or already done */
696 		otl = CreateLookup(sf,pst->tag,pst->script_lang_index,pst->flags,pst->pst.type);
697 		sub = CreateSubtable(otl,sf);
698 		/* There might be another PST with the same flags on this glyph */
699 		/* And we must fixup the current pst */
700 		for ( pst2=pst ; pst2!=NULL; pst2 = (PST1 *) (pst2->pst.next) ) {
701 		    if ( pst2->tag==pst->tag &&
702 			    pst2->script_lang_index==pst->script_lang_index &&
703 			    pst2->flags==pst->flags &&
704 			    pst2->pst.type==pst->pst.type )
705 			pst2->pst.subtable = sub;
706 		}
707 		for ( gid2=gid+1; gid2<subsf->sf.glyphcnt; ++gid2 ) if ( (sc2=subsf->sf.glyphs[gid2])!=NULL ) {
708 		    for ( pst2 = (PST1 *) (sc2->possub); pst2!=NULL; pst2 = (PST1 *) (pst2->pst.next) ) {
709 			if ( pst2->tag==pst->tag &&
710 				pst2->script_lang_index==pst->script_lang_index &&
711 				pst2->flags==pst->flags &&
712 				pst2->pst.type==pst->pst.type )
713 			    pst2->pst.subtable = sub;
714 		    }
715 		}
716 	    }
717 	}
718 	++k;
719     } while ( k<sf->sf.subfontcnt );
720 
721 	/* Now kerns. May need to merge kernclasses to kernpair lookups (different subtables, of course */
722     for ( isv=0; isv<2; ++isv ) {
723 	k=0;
724 	do {
725 	    subsf = sf->sf.subfontcnt==0 ? sf : (SplineFont1 *) (sf->sf.subfonts[k]);
726 	    for ( gid=0; gid<subsf->sf.glyphcnt; ++gid ) if ( (sc=subsf->sf.glyphs[gid])!=NULL ) {
727 		for ( kp = (KernPair1 *) (isv ? sc->vkerns : sc->kerns); kp!=NULL; kp = (KernPair1 *) (kp->kp.next) ) {
728 		    if ( kp->kp.subtable!=NULL )
729 		continue;		/* already done */
730 		    otl = CreateLookup(sf,isv ? CHR('v','k','r','n') : CHR('k','e','r','n'),
731 			    kp->sli,kp->flags,pst_pair);
732 		    sub = CreateSubtable(otl,sf);
733 		    /* There might be another kp with the same flags on this glyph */
734 		    /* And we must fixup the current kp */
735 		    for ( kp2=kp ; kp2!=NULL; kp2 = (KernPair1 *) (kp2->kp.next) ) {
736 			if ( kp2->sli==kp->sli && kp2->flags==kp->flags )
737 			    kp2->kp.subtable = sub;
738 		    }
739 		    for ( gid2=gid+1; gid2<subsf->sf.glyphcnt; ++gid2 ) if ( (sc2=subsf->sf.glyphs[gid2])!=NULL ) {
740 			for ( kp2 = (KernPair1 *) (isv ? sc2->vkerns : sc2->kerns); kp2!=NULL; kp2 = (KernPair1 *) (kp2->kp.next) ) {
741 			    if ( kp2->sli==kp->sli && kp2->flags==kp->flags )
742 				kp2->kp.subtable = sub;
743 			}
744 		    }
745 		    /* And there might be a kerning class... */
746 		    for ( kc=(KernClass1 *) (isv ? sf->sf.vkerns : sf->sf.kerns); kc!=NULL;
747 			    kc = (KernClass1 *) (kc->kc.next) ) {
748 			if ( kc->sli == kp->sli && kc->flags == kp->flags && kc->kc.subtable==NULL) {
749 			    sub = CreateSubtable(otl,sf);
750 			    sub->per_glyph_pst_or_kern = false;
751 			    sub->kc = &kc->kc;
752 			    kc->kc.subtable = sub;
753 			}
754 		    }
755 		}
756 	    }
757 	    ++k;
758 	} while ( k<sf->sf.subfontcnt );
759 	/* Or there might be a kerning class all by its lonesome */
760 	for ( kc=(KernClass1 *) (isv ? sf->sf.vkerns : sf->sf.kerns); kc!=NULL;
761 		kc = (KernClass1 *) (kc->kc.next) ) {
762 	    if ( kc->kc.subtable==NULL) {
763 		otl = CreateLookup(sf,isv ? CHR('v','k','r','n') : CHR('k','e','r','n'),
764 			kc->sli,kc->flags,pst_pair);
765 		for ( kc2=kc; kc2!=NULL; kc2=(KernClass1 *) (kc2->kc.next) ) {
766 		    if ( kc->sli == kc2->sli && kc->flags == kc2->flags && kc2->kc.subtable==NULL) {
767 			sub = CreateSubtable(otl,sf);
768 			sub->per_glyph_pst_or_kern = false;
769 			sub->kc = &kc2->kc;
770 			kc2->kc.subtable = sub;
771 		    }
772 		}
773 	    }
774 	}
775     }
776 
777     /* Every FPST and ASM lives in its own lookup with one subtable */
778     /* But the old format refered to nested lookups by tag, and now we refer */
779     /*  to the lookup itself, so fix that up */
780     for ( fpst=(FPST1 *) sf->sf.possub; fpst!=NULL; fpst=((FPST1 *) fpst->fpst.next) ) {
781 	otl = CreateLookup(sf,fpst->tag, fpst->script_lang_index,
782 		fpst->flags,fpst->fpst.type);
783 	sub = CreateSubtable(otl,sf);
784 	sub->per_glyph_pst_or_kern = false;
785 	sub->fpst = &fpst->fpst;
786 	fpst->fpst.subtable = sub;
787 	FPSTReplaceTagsWithLookups(&fpst->fpst,sf);
788     }
789     for ( sm=(ASM1 *) sf->sf.sm; sm!=NULL; sm=((ASM1 *) sm->sm.next) ) {
790 	otl = CreateMacLookup(sf,sm);
791 	sub = CreateSubtable(otl,sf);
792 	sub->per_glyph_pst_or_kern = false;
793 	sub->sm = &sm->sm;
794 	sm->sm.subtable = sub;
795 	if ( sm->sm.type==asm_context )
796 	    ASMReplaceTagsWithLookups(&sm->sm,sf);
797     }
798 
799     /* We retained the old nested feature tags so we could do the above conversion */
800     /*  of tag to lookup. Get rid of them now */
801     for ( isgpos=0; isgpos<2; ++isgpos ) {
802 	for ( otl = isgpos ? sf->sf.gpos_lookups : sf->sf.gsub_lookups ;
803 		otl != NULL; otl=otl->next ) {
804 	    if ( otl->features!=NULL && otl->features->scripts==NULL ) {
805 		chunkfree(otl->features,sizeof(FeatureScriptLangList));
806 		otl->features = NULL;
807 	    }
808 	}
809     }
810 
811     /* Anchor classes are complicated, because I foolishly failed to distinguish */
812     /*  between mark to base and mark to ligature classes. So one AC might have */
813     /*  both. If so we need to turn it into two ACs, and have separate lookups */
814     /*  for each */
815     for ( ac=(AnchorClass1 *) (sf->sf.anchor); ac!=NULL; ac=(AnchorClass1 *) ac->ac.next ) {
816 	ACHasBaseLig(sf,ac);
817 	if ( ac->has_ligatures && !ac->has_bases )
818 	    ac->ac.type = act_mklg;
819 	else if ( ac->has_ligatures && ac->has_bases )
820 	    ACDisassociateLigatures(sf,ac);
821     }
822     for ( ac=(AnchorClass1 *) (sf->sf.anchor); ac!=NULL; ac=(AnchorClass1 *) ac->ac.next ) {
823 	if ( ac->ac.subtable==NULL ) {
824 	    otl = CreateACLookup(sf,ac);
825 	    sub = CreateSubtable(otl,sf);
826 	    for ( ac2=ac; ac2!=NULL; ac2 = (AnchorClass1 *) ac2->ac.next ) {
827 		if ( ac2->feature_tag == ac->feature_tag &&
828 			ac2->script_lang_index == ac->script_lang_index &&
829 			ac2->flags == ac->flags &&
830 			ac2->ac.type == ac->ac.type &&
831 			ac2->merge_with == ac->merge_with )
832 		    ac2->ac.subtable = sub;
833 	    }
834 	}
835     }
836 
837     /* Now I want to order the gsub lookups. I shan't bother with the gpos */
838     /*  lookups because I didn't before */
839     for ( otl=sf->sf.gsub_lookups, cnt=0; otl!=NULL; otl=otl->next, ++cnt );
840     if ( cnt!=0 ) {
841 	all = malloc(cnt*sizeof(OTLookup *));
842 	for ( otl=sf->sf.gsub_lookups, cnt=0; otl!=NULL; otl=otl->next, ++cnt ) {
843 	    all[cnt] = otl;
844 	    otl->lookup_index = GSubOrder(sf,otl->features);
845 	}
846 	qsort(all,cnt,sizeof(OTLookup *),order_lookups);
847 	sf->sf.gsub_lookups = all[0];
848 	for ( i=1; i<cnt; ++i )
849 	    all[i-1]->next = all[i];
850 	all[cnt-1]->next = NULL;
851 	free( all );
852     }
853 
854     for ( isgpos=0; isgpos<2; ++isgpos ) {
855 	for ( otl = isgpos ? sf->sf.gpos_lookups : sf->sf.gsub_lookups , cnt=0;
856 		otl!=NULL; otl = otl->next ) {
857 	    otl->lookup_index = cnt++;
858 	    NameOTLookup(otl,&sf->sf);
859 	}
860     }
861 }
862