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