1 /* Copyright (C) 2003-2007 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 "asmfpst.h"
31 
32 #include "chardata.h"
33 #include "fontforgevw.h"
34 #include "fvfonts.h"
35 #include "splineutil.h"
36 #include "tottfaat.h"
37 #include "tottfgpos.h"
38 #include "ttf.h"
39 #include "ustring.h"
40 #include "utype.h"
41 
42 /* ************************************************************************** */
43 /* *************** Routines to test conversion from OpenType **************** */
44 /* ************************************************************************** */
45 
ClassesMatch(int cnt1,char ** classes1,int cnt2,char ** classes2)46 int ClassesMatch(int cnt1,char **classes1,int cnt2,char **classes2) {
47     int i;
48 
49     if ( cnt1!=cnt2 )
50 return( false );
51     for ( i=1; i<cnt2; ++i )
52 	if ( strcmp(classes1[i],classes2[i])!=0 )
53 return( false );
54 
55 return( true );
56 }
57 
classcopy(char ** names,int nextclass)58 static char **classcopy(char **names,int nextclass) {
59     char **ret;
60     int i;
61 
62     if ( nextclass <= 1 )
63 return( NULL );
64 
65     ret = malloc(nextclass*sizeof(char *));
66     ret[0] = NULL;
67     for ( i=1; i<nextclass; ++i )
68 	ret[i] = copy(names[i]);
69 return( ret );
70 }
71 
FPSTGlyphToClass(FPST * fpst)72 FPST *FPSTGlyphToClass(FPST *fpst) {
73     FPST *new;
74     int nextclass=0, i,j,k, max, cnt, ch;
75     char *pt, *end;
76     char **names;
77 
78     if ( fpst->format!=pst_glyphs )
79 return( NULL );
80 
81     new = chunkalloc(sizeof(FPST));
82     new->type = fpst->type;
83     new->format = pst_class;
84     new->subtable = fpst->subtable;
85     new->rule_cnt = fpst->rule_cnt;
86     new->rules = calloc(fpst->rule_cnt,sizeof(struct fpst_rule));
87 
88     max = 100; nextclass=1;
89     names = malloc(max*sizeof(char *));
90     names[0] = NULL;
91     for ( i=0; i<fpst->rule_cnt; ++i ) {
92 	for ( j=0; j<3; ++j ) {
93 	    cnt = 0;
94 	    if ( (&fpst->rules[i].u.glyph.names)[j]!=NULL && *(&fpst->rules[i].u.glyph.names)[j]!='\0' ) {
95 		for ( pt=(&fpst->rules[i].u.glyph.names)[j]; *pt; ) {
96 		    while ( *pt==' ' ) ++pt;
97 		    if ( *pt=='\0' )
98 		break;
99 		    while ( *pt!=' ' && *pt!='\0' ) ++pt;
100 		    ++cnt;
101 		}
102 	    }
103 	    (&new->rules[i].u.class.ncnt)[j] = cnt;
104 	    if ( cnt!=0 ) {
105 		(&new->rules[i].u.class.nclasses)[j] = malloc(cnt*sizeof(uint16));
106 		cnt = 0;
107 		for ( pt=(&fpst->rules[i].u.glyph.names)[j]; *pt; pt=end ) {
108 		    while ( *pt==' ' ) ++pt;
109 		    if ( *pt=='\0' )
110 		break;
111 		    for ( end=pt ; *end!=' ' && *end!='\0'; ++end );
112 		    ch = *end; *end='\0';
113 		    for ( k=1; k<nextclass; ++k )
114 			if ( strcmp(pt,names[k])==0 )
115 		    break;
116 		    if ( k==nextclass ) {
117 			if ( nextclass>=max )
118 			    names = realloc(names,(max+=100)*sizeof(char *));
119 			names[nextclass++] = copy(pt);
120 		    }
121 		    *end = ch;
122 		    (&new->rules[i].u.class.nclasses)[j][cnt++] = k;
123 		}
124 	    }
125 	}
126 	new->rules[i].lookup_cnt = fpst->rules[i].lookup_cnt;
127 	new->rules[i].lookups = malloc(fpst->rules[i].lookup_cnt*sizeof(struct seqlookup));
128 	memcpy(new->rules[i].lookups,fpst->rules[i].lookups,
129 		fpst->rules[i].lookup_cnt*sizeof(struct seqlookup));
130     }
131     new->nccnt = nextclass;
132     new->nclass = names;
133     new->nclassnames = calloc(nextclass,sizeof(char *));	/* Leave as NULL */
134     if ( fpst->type==pst_chainpos || fpst->type==pst_chainsub ) {
135 	/* our class set has one "class" for each glyph used anywhere */
136 	/*  all three class sets are the same */
137 	new->bccnt = new->fccnt = nextclass;
138 	new->bclass = classcopy(names,nextclass);
139 	new->fclass = classcopy(names,nextclass);
140 	new->bclassnames = calloc(nextclass,sizeof(char *));	/* Leave as NULL */
141 	new->fclassnames = calloc(nextclass,sizeof(char *));	/* Leave as NULL */
142     }
143 return( new );
144 }
145 
ValidSubs(OTLookup * otl)146 static int ValidSubs(OTLookup *otl ) {
147 return( otl->lookup_type == gsub_single );
148 }
149 
TreeFree(struct contexttree * tree)150 static void TreeFree(struct contexttree *tree) {
151     int i;
152 
153     if ( tree==NULL )
154 return;
155 
156     for ( i=0; i<tree->branch_cnt; ++i )
157 	TreeFree(tree->branches[i].branch);
158 
159     free( tree->branches );
160     free( tree->rules );
161     chunkfree( tree,sizeof(*tree) );
162 }
163 
TreeLabelState(struct contexttree * tree,int snum)164 static int TreeLabelState(struct contexttree *tree, int snum) {
165     int i;
166 
167     if ( tree->branch_cnt==0 && tree->ends_here!=NULL ) {
168 	tree->state = 0;
169 return( snum );
170     }
171 
172     tree->state = snum++;
173     for ( i=0; i<tree->branch_cnt; ++i )
174 	snum = TreeLabelState(tree->branches[i].branch,snum);
175     tree->next_state = snum;
176 
177 return( snum );
178 }
179 
RuleHasSubsHere(struct fpst_rule * rule,int depth)180 static OTLookup *RuleHasSubsHere(struct fpst_rule *rule,int depth) {
181     int i,j;
182 
183     if ( depth<rule->u.class.bcnt )
184 return( NULL );
185     depth -= rule->u.class.bcnt;
186     if ( depth>=rule->u.class.ncnt )
187 return( NULL );
188     for ( i=0; i<rule->lookup_cnt; ++i ) {
189 	if ( rule->lookups[i].seq==depth ) {
190 	    /* It is possible to have two substitutions applied at the same */
191 	    /*  location. I can't deal with that here */
192 	    for ( j=i+1; j<rule->lookup_cnt; ++j ) {
193 		if ( rule->lookups[j].seq==depth )
194 return( (OTLookup *) 0xffffffff );
195 	    }
196 return( rule->lookups[i].lookup );
197 	}
198     }
199 
200 return( 0 );
201 }
202 
RulesAllSameSubsAt(struct contexttree * me,int pos)203 static OTLookup *RulesAllSameSubsAt(struct contexttree *me,int pos) {
204     int i;
205     OTLookup *tag=(OTLookup *) 0x01, *newtag;	/* Can't use 0 as an "unused" flag because it is perfectly valid for there to be no substititution. But then all rules must have no subs */
206 
207     for ( i=0; i<me->rule_cnt; ++i ) {
208 	newtag = RuleHasSubsHere(me->rules[i].rule,pos);
209 	if ( tag==(OTLookup *) 0x01 )
210 	    tag=newtag;
211 	else if ( newtag!=tag )
212 return( (OTLookup *) 0xffffffff );
213     }
214     if ( tag==(OTLookup *) 0x01 )
215 return( NULL );		/* Should never happen */
216 
217 return( tag );
218 }
219 
TreeFollowBranches(SplineFont * sf,struct contexttree * me,int pending_pos)220 static int TreeFollowBranches(SplineFont *sf,struct contexttree *me,int pending_pos) {
221     int i, j;
222 
223     me->pending_pos = pending_pos;
224     if ( me->ends_here!=NULL ) {
225 	/* If any rule ends here then we have to be able to apply all current */
226 	/*  and pending substitutions */
227 	if ( pending_pos!=-1 ) {
228 	    me->applymarkedsubs = RulesAllSameSubsAt(me,pending_pos);
229 	    if ( me->applymarkedsubs==(OTLookup *) 0xffffffff )
230 return( false );
231 	    if ( !ValidSubs(me->applymarkedsubs))
232 return( false );
233 	}
234 	me->applycursubs = RulesAllSameSubsAt(me,me->depth);
235 	if ( me->applycursubs==(OTLookup *) 0xffffffff )
236 return( false );
237 	if ( me->applycursubs!=NULL && !ValidSubs(me->applycursubs))
238 return( false );
239 	for ( i=0; i<me->branch_cnt; ++i ) {
240 	    if ( !TreeFollowBranches(sf,me->branches[i].branch,-1))
241 return( false );
242 	}
243     } else {
244 	for ( i=0; i<me->branch_cnt; ++i ) {
245 	    for ( j=0; j<me->rule_cnt; ++j )
246 		if ( me->rules[j].branch==me->branches[i].branch &&
247 			RuleHasSubsHere(me->rules[j].rule,me->depth)!=NULL )
248 	    break;
249 	    if ( j<me->rule_cnt ) {
250 		if ( pending_pos==-1 ) {
251 		    pending_pos = me->pending_pos = me->depth;
252 		    me->markme = true;
253 		} else
254 return( false );
255 	    }
256 	    if ( !TreeFollowBranches(sf,me->branches[i].branch,pending_pos))
257 return( false );
258 	}
259     }
260 
261 return( true );
262 }
263 
_FPST2Tree(FPST * fpst,struct contexttree * parent,int class)264 static struct contexttree *_FPST2Tree(FPST *fpst,struct contexttree *parent,int class) {
265     struct contexttree *me = chunkalloc(sizeof(struct contexttree));
266     int i, rcnt, ccnt, k, thisclass;
267     uint16 *classes;
268 
269     if ( fpst!=NULL ) {
270 	me->depth = -1;
271 	me->rule_cnt = fpst->rule_cnt;
272 	me->rules = calloc(me->rule_cnt,sizeof(struct ct_subs));
273 	for ( i=0; i<me->rule_cnt; ++i )
274 	    me->rules[i].rule = &fpst->rules[i];
275 	me->parent = NULL;
276     } else {
277 	me->depth = parent->depth+1;
278 	for ( i=rcnt=0; i<parent->rule_cnt; ++i )
279 	    if ( parent->rules[i].rule->u.class.allclasses[me->depth] == class )
280 		++rcnt;
281 	me->rule_cnt = rcnt;
282 	me->rules = calloc(me->rule_cnt,sizeof(struct ct_subs));
283 	for ( i=rcnt=0; i<parent->rule_cnt; ++i )
284 	    if ( parent->rules[i].rule->u.class.allclasses[me->depth] == class )
285 		me->rules[rcnt++].rule = parent->rules[i].rule;
286 	me->parent = parent;
287     }
288     classes = malloc(me->rule_cnt*sizeof(uint16));
289     for ( i=ccnt=0; i<me->rule_cnt; ++i ) {
290 	thisclass = me->rules[i].thisclassnum = me->rules[i].rule->u.class.allclasses[me->depth+1];
291 	if ( thisclass==0xffff ) {
292 	    if ( me->ends_here==NULL )
293 		me->ends_here = me->rules[i].rule;
294 	} else {
295 	    for ( k=0; k<ccnt; ++k )
296 		if ( classes[k] == thisclass )
297 	    break;
298 	    if ( k==ccnt )
299 		classes[ccnt++] = thisclass;
300 	}
301     }
302     me->branch_cnt = ccnt;
303     me->branches = calloc(ccnt,sizeof(struct ct_branch));
304     for ( i=0; i<ccnt; ++i )
305 	me->branches[i].classnum = classes[i];
306     for ( i=0; i<ccnt; ++i ) {
307 	me->branches[i].branch = _FPST2Tree(NULL,me,classes[i]);
308 	for ( k=0; k<me->rule_cnt; ++k )
309 	    if ( classes[i]==me->rules[k].thisclassnum )
310 		me->rules[k].branch = me->branches[i].branch;
311     }
312     free(classes );
313 return( me );
314 }
315 
FPSTBuildAllClasses(FPST * fpst)316 static void FPSTBuildAllClasses(FPST *fpst) {
317     int i, off,j;
318 
319     for ( i=0; i<fpst->rule_cnt; ++i ) {
320 	fpst->rules[i].u.class.allclasses = malloc((fpst->rules[i].u.class.bcnt+
321 						    fpst->rules[i].u.class.ncnt+
322 			                            fpst->rules[i].u.class.fcnt+
323 			                            1)*sizeof(uint16));
324 	off = fpst->rules[i].u.class.bcnt;
325 	for ( j=0; j<off; ++j )
326 	    fpst->rules[i].u.class.allclasses[j] = fpst->rules[i].u.class.bclasses[off-1-j];
327 	for ( j=0; j<fpst->rules[i].u.class.ncnt; ++j )
328 	    fpst->rules[i].u.class.allclasses[off+j] = fpst->rules[i].u.class.nclasses[j];
329 	off += j;
330 	for ( j=0; j<fpst->rules[i].u.class.fcnt; ++j )
331 	    fpst->rules[i].u.class.allclasses[off+j] = fpst->rules[i].u.class.fclasses[j];
332 	fpst->rules[i].u.class.allclasses[off+j] = 0xffff;	/* End of rule marker */
333     }
334 }
335 
FPSTFreeAllClasses(FPST * fpst)336 static void FPSTFreeAllClasses(FPST *fpst) {
337     int i;
338 
339     for ( i=0; i<fpst->rule_cnt; ++i ) {
340 	free( fpst->rules[i].u.class.allclasses );
341 	fpst->rules[i].u.class.allclasses = NULL;
342     }
343 }
344 
FPST2Tree(SplineFont * sf,FPST * fpst)345 static struct contexttree *FPST2Tree(SplineFont *sf,FPST *fpst) {
346     struct contexttree *ret;
347 
348     if ( fpst->format != pst_class )
349 return( NULL );
350 
351     /* I could check for subclasses rather than ClassesMatch, but then I'd have */
352     /* to make sure that class 0 was used (if at all) consistently */
353     if ( (fpst->bccnt!=0 && !ClassesMatch(fpst->bccnt,fpst->bclass,fpst->nccnt,fpst->nclass)) ||
354 	    (fpst->fccnt!=0 && !ClassesMatch(fpst->fccnt,fpst->fclass,fpst->nccnt,fpst->nclass)))
355 return( NULL );
356 
357     FPSTBuildAllClasses(fpst);
358 
359     ret = _FPST2Tree(fpst,NULL,0);
360 
361     if ( !TreeFollowBranches(sf,ret,-1) ) {
362 	TreeFree(ret);
363 	ret = NULL;
364     }
365 
366     FPSTFreeAllClasses(fpst);
367 
368     if ( ret!=NULL )
369 	TreeLabelState(ret,1);	/* actually, it's states 0&1, but this will do */
370 
371 return( ret );
372 }
373 
TreeNext(struct contexttree * cur)374 static struct contexttree *TreeNext(struct contexttree *cur) {
375     struct contexttree *p;
376     int i;
377 
378     if ( cur->branch_cnt!=0 )
379 return( cur->branches[0].branch );
380     else {
381 	for (;;) {
382 	    p = cur->parent;
383 	    if ( p==NULL )
384 return( NULL );
385 	    for ( i=0; i<p->branch_cnt; ++i ) {
386 		if ( p->branches[i].branch==cur ) {
387 		    ++i;
388 	    break;
389 		}
390 	    }
391 	    if ( i<p->branch_cnt )
392 return( p->branches[i].branch );
393 	    cur = p;
394 	}
395     }
396 }
397 
FPSTisMacable(SplineFont * sf,FPST * fpst)398 int FPSTisMacable(SplineFont *sf, FPST *fpst) {
399     int i;
400     int featureType, featureSetting;
401     struct contexttree *ret;
402     FeatureScriptLangList *fl;
403 
404     if ( fpst->type!=pst_contextsub && fpst->type!=pst_chainsub )
405 return( false );
406     for ( fl = fpst->subtable->lookup->features; fl!=NULL; fl=fl->next ) {
407 	if ( OTTagToMacFeature(fl->featuretag,&featureType,&featureSetting) &&
408 		scriptsHaveDefault(fl->scripts) )
409     break;
410     }
411     if ( fl==NULL )
412 return( false );
413 
414     if ( fpst->format == pst_glyphs ) {
415 	FPST *tempfpst = FPSTGlyphToClass(fpst);
416 	ret = FPST2Tree(sf, tempfpst);
417 	FPSTFree(tempfpst);
418 	TreeFree(ret);
419 return( ret!=NULL );
420     } else if ( fpst->format == pst_class ) {
421 	ret = FPST2Tree(sf, fpst);
422 	TreeFree(ret);
423 return( ret!=NULL );
424     } else if ( fpst->format != pst_coverage )
425 return( false );
426 
427     for ( i=0; i<fpst->rule_cnt; ++i ) {
428 	if ( fpst->rules[i].u.coverage.ncnt+
429 		fpst->rules[i].u.coverage.bcnt+
430 		fpst->rules[i].u.coverage.fcnt>=10 )
431 return( false );			/* Let's not make a state machine this complicated */
432 
433 	if ( fpst->rules[i].lookup_cnt==2 ) {
434 	    switch ( fpst->format ) {
435 	      case pst_coverage:
436 		/* Second substitution must be on the final glyph */
437 		if ( fpst->rules[i].u.coverage.fcnt!=0 ||
438 			fpst->rules[i].lookups[0].seq==fpst->rules[i].lookups[1].seq ||
439 			(fpst->rules[i].lookups[0].seq!=fpst->rules[i].u.coverage.ncnt-1 &&
440 			 fpst->rules[i].lookups[1].seq!=fpst->rules[i].u.coverage.ncnt-1) )
441 return( false );
442 	      break;
443 	      default:
444 return( false );
445 	    }
446 	    if ( !ValidSubs(fpst->rules[i].lookups[1].lookup) )
447 return( false );
448 
449 	} else if ( fpst->rules[i].lookup_cnt!=1 )
450 return( false );
451 	if ( !ValidSubs(fpst->rules[i].lookups[0].lookup) )
452 return( false );
453     }
454 
455 return( fpst->rule_cnt>0 );
456 }
457 
458 /* ************************************************************************** */
459 /* *************** Conversion from OpenType Context/Chaining **************** */
460 /* ************************************************************************** */
461 
462 	/* ********************** From Forms ********************** */
IsMarkChar(SplineChar * sc)463 static int IsMarkChar( SplineChar *sc ) {
464     AnchorPoint *ap;
465 
466     ap=sc->anchor;
467     while ( ap!=NULL && (ap->type==at_centry || ap->type==at_cexit) )
468 	ap = ap->next;
469     if ( ap!=NULL && (ap->type==at_mark || ap->type==at_basemark) )
470 return( true );
471 
472 return( false );
473 }
474 
GlyphListToNames(SplineChar ** classglyphs)475 static char *GlyphListToNames(SplineChar **classglyphs) {
476     int i, len;
477     char *ret, *pt;
478 
479     for ( i=len=0; classglyphs[i]!=NULL; ++i )
480 	len += strlen(classglyphs[i]->name)+1;
481     ret = pt = malloc(len+1);
482     for ( i=0; classglyphs[i]!=NULL; ++i ) {
483 	strcpy(pt,classglyphs[i]->name);
484 	pt += strlen(pt);
485 	*pt++ = ' ';
486     }
487     if ( pt>ret )
488 	pt[-1] = '\0';
489     else
490 	*ret = '\0';
491 return( ret );
492 }
493 
BuildMarkClass(SplineFont * sf)494 static char *BuildMarkClass(SplineFont *sf) {
495     SplineChar *sc, **markglyphs;
496     int i, mg;
497     char *ret;
498 
499     mg = 0;
500     markglyphs = malloc(sf->glyphcnt*sizeof(SplineChar *));
501     for ( i=0; i<sf->glyphcnt; ++i ) if ( (sc=sf->glyphs[i])!=NULL ) {
502 	if ( IsMarkChar(sc)) {
503 	    markglyphs[mg++] = sc;
504 	}
505     }
506     markglyphs[mg] = NULL;
507     ret = GlyphListToNames(markglyphs);
508     free(markglyphs);
509 return(ret);
510 }
511 
BuildClassNames(SplineChar ** glyphs,uint16 * map,int classnum)512 static char *BuildClassNames(SplineChar **glyphs,uint16 *map, int classnum) {
513     int i, len;
514     char *ret, *pt;
515 
516     for ( i=len=0; glyphs[i]!=NULL; ++i ) {
517 	if ( map[i]==classnum )
518 	    len += strlen(glyphs[i]->name)+1;
519     }
520     ret = pt = malloc(len+1);
521     for ( i=len=0; glyphs[i]!=NULL; ++i ) {
522 	if ( map[i]==classnum ) {
523 	    strcpy(pt,glyphs[i]->name);
524 	    pt += strlen(pt);
525 	    *pt++ = ' ';
526 	}
527     }
528     if ( pt>ret )
529 	pt[-1] = '\0';
530     else
531 	*ret = '\0';
532 return( ret );
533 }
534 
FindFormLookupsForScript(SplineFont * sf,uint32 script,OTLookup * lookups[4])535 static int FindFormLookupsForScript(SplineFont *sf,uint32 script,OTLookup *lookups[4]) {
536     OTLookup *otl;
537     FeatureScriptLangList *fl;
538     struct scriptlanglist *sl;
539     int which;
540 
541     memset(lookups,0,4*sizeof(OTLookup *));
542     for ( otl=sf->gsub_lookups; otl!=NULL; otl=otl->next ) if ( !otl->unused && otl->lookup_type == gsub_single ) {
543 	for ( fl=otl->features; fl!=NULL; fl=fl->next ) {
544 	    if ( fl->featuretag== CHR('i','n','i','t') ) which = 0;
545 	    else if ( fl->featuretag== CHR('m','e','d','i') ) which = 1;
546 	    else if ( fl->featuretag== CHR('f','i','n','a') ) which = 2;
547 	    else if ( fl->featuretag== CHR('i','s','o','l') ) which = 3;
548 	    else
549 	continue;
550 	    if ( lookups[which]!=NULL )
551 	continue;
552 	    for ( sl=fl->scripts; sl!=NULL && sl->script!=script; sl=sl->next );
553 	    if ( sl==NULL )
554 	continue;
555 	    lookups[which] = otl;
556 	break;
557 	}
558     }
559     if ( lookups[0]!=NULL || lookups[1]!=NULL || lookups[2]!=NULL || lookups[3]!=NULL )
560 return( true );
561 
562 return( false );
563 }
564 
ASMFromOpenTypeForms(SplineFont * sf,uint32 script)565 ASM *ASMFromOpenTypeForms(SplineFont *sf,uint32 script) {
566     int i, which, cg, mg;
567     SplineChar *sc, *rsc, **classglyphs, **markglyphs;
568     PST *pst;
569     OTLookup *lookups[4];
570     ASM *sm;
571     int flags;
572 
573     if ( !FindFormLookupsForScript(sf,script,lookups))
574 return( NULL );
575     flags = (lookups[0]!=NULL ? lookups[0]->lookup_flags
576 	    :lookups[1]!=NULL ? lookups[1]->lookup_flags
577 	    :lookups[2]!=NULL ? lookups[2]->lookup_flags
578 	    :                   lookups[3]->lookup_flags);
579     classglyphs = calloc((sf->glyphcnt+1),sizeof(SplineChar *));
580     markglyphs = malloc((sf->glyphcnt+1)*sizeof(SplineChar *));
581 
582     mg = 0;
583     for ( i=0; i<sf->glyphcnt; ++i ) if ( (sc=sf->glyphs[i])!=NULL ) {
584 	if ( (flags&pst_ignorecombiningmarks) && IsMarkChar(sc)) {
585 	    markglyphs[mg++] = sc;
586 	} else if ( SCScriptFromUnicode(sc)==script ) {
587 	    classglyphs[sc->orig_pos] = sc;
588 	    for ( pst = sc->possub; pst!=NULL; pst=pst->next ) if ( pst->subtable!=NULL ) {
589 		OTLookup *otl = pst->subtable->lookup;
590 		for ( which=3; which>=0; --which ) {
591 		    if ( otl==lookups[which])
592 		break;
593 		}
594 		if ( which==-1 )
595 	    continue;
596 		rsc = SFGetChar(sf,-1,pst->u.subs.variant);
597 		if ( rsc!=NULL )
598 		    classglyphs[rsc->orig_pos] = rsc;
599 	    }
600 	}
601     }
602     markglyphs[mg] = NULL;
603 
604     cg = 0;
605     for ( i=0; i<sf->glyphcnt; ++i )
606 	if ( classglyphs[i]!=NULL )
607 	    classglyphs[cg++] = classglyphs[i];
608     classglyphs[cg] = NULL;
609 
610     sm = chunkalloc(sizeof(ASM));
611     sm->type = asm_context;
612     sm->flags = (flags&pst_r2l) ? asm_descending : 0;
613 	/* This is a temporary value. It should be replaced if we will retain */
614 	/*  this state machine */
615     sm->subtable = (lookups[3]!=NULL ? lookups[3] : lookups[0]!=NULL ? lookups[0] : lookups[1]!=NULL ? lookups[1] : lookups[2])->subtables;
616     /* Only one (or two) classes of any importance: Letter in this script */
617     /* might already be formed. Might be a lig. Might be normal */
618     /* Oh, if ignoremarks is true, then combining marks merit a class of their own */
619     sm->class_cnt = (flags&pst_ignorecombiningmarks) ? 6 : 5;
620     sm->classes = calloc(sm->class_cnt,sizeof(char *));
621 
622     sm->classes[4] = GlyphListToNames(classglyphs);
623     if ( flags&pst_ignorecombiningmarks )
624 	sm->classes[5] = GlyphListToNames(markglyphs);
625     free(classglyphs); free(markglyphs);
626 
627 
628     /* State 0,1 are start states */
629     /* State 2 means we have found one interesting letter, transformed current to 'init' and marked it (in case we need to make it isolated) */
630     /* State 3 means we have found two interesting letters, transformed current to 'medi' and marked (in case we need to make it final) */
631     sm->state_cnt = 4;
632     sm->state = calloc(sm->state_cnt*sm->class_cnt,sizeof(struct asm_state));
633 
634     /* State 0,1 (start), Class 4 (char in script) takes us to state 2 */
635     sm->state[4].next_state = 2;
636     sm->state[4].flags = 0x8000;
637 
638     sm->state[sm->class_cnt+4] = sm->state[4];
639 
640     for ( i=0; i<4; ++i ) {
641 	sm->state[2*sm->class_cnt+i].next_state = 0;
642 	sm->state[2*sm->class_cnt+i].u.context.mark_lookup = lookups[3];/* Isolated */
643     }
644 
645     sm->state[2*sm->class_cnt+4].next_state = 3;
646     sm->state[2*sm->class_cnt+4].flags = 0x8000;
647     sm->state[2*sm->class_cnt+4].u.context.mark_lookup = lookups[0];	/* Initial */
648 
649     for ( i=0; i<4; ++i ) {
650 	sm->state[3*sm->class_cnt+i].next_state = 0;
651 	sm->state[3*sm->class_cnt+i].u.context.mark_lookup = lookups[2];/* Final */
652     }
653 
654     sm->state[3*sm->class_cnt+4].next_state = 3;
655     sm->state[3*sm->class_cnt+4].flags = 0x8000;
656     sm->state[3*sm->class_cnt+4].u.context.mark_lookup = lookups[1];	/* Medial */
657 
658     /* Deleted glyph retains same state, just eats the glyph */
659     for ( i=0; i<sm->state_cnt; ++i ) {
660 	int pos = i*sm->class_cnt+2, mpos = i*sm->class_cnt+5;
661 	sm->state[pos].next_state = i;
662 	sm->state[pos].flags = 0;
663 	sm->state[pos].u.context.cur_lookup = NULL;
664 	sm->state[pos].u.context.mark_lookup = NULL;
665 	/* same for ignored marks */
666 	if ( flags&pst_ignorecombiningmarks )
667 	    sm->state[mpos].next_state = i;
668     }
669 
670 return( sm );
671 }
672 
673 	/* ********************** From Coverage FPST ********************** */
morx_cg_FigureClasses(SplineChar *** tables,int match_len,int *** classes,int * cc,uint16 ** mp,int * gc,FPST * fpst,SplineFont * sf,int ordered)674 static SplineChar **morx_cg_FigureClasses(SplineChar ***tables,int match_len,
675 	int ***classes, int *cc, uint16 **mp, int *gc,
676 	FPST *fpst,SplineFont *sf,int ordered) {
677     int i,j,k, mask, max, class_cnt, gcnt, gtot;
678     SplineChar ***temp, *sc, **glyphs, **gall;
679     uint16 *map;
680     int *nc;
681     int *next;
682     /* For each glyph used, figure out what coverage tables it gets used in */
683     /*  then all the glyphs which get used in the same set of coverage tables */
684     /*  can form one class */
685 
686     if ( match_len>10 )		/* would need too much space to figure out */
687 return( NULL );
688 
689     gtot = 0;
690     for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
691 	sf->glyphs[i]->lsidebearing = 1;
692 	if ( !ordered )
693 	    sf->glyphs[i]->ttf_glyph = gtot++;
694 	else if ( sf->glyphs[i]->ttf_glyph+1>gtot )
695 	    gtot = sf->glyphs[i]->ttf_glyph+1;
696     }
697 
698     max=0;
699     for ( i=0; i<match_len; ++i ) {
700 	for ( k=0; tables[i][k]!=NULL; ++k );
701 	if ( k>max ) max=k;
702     }
703     next = calloc(1<<match_len,sizeof(int));
704     temp = malloc((1<<match_len)*sizeof(SplineChar **));
705 
706     for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
707 	sf->glyphs[i]->lsidebearing = 0;
708 	sf->glyphs[i]->ticked = false;
709     }
710     for ( i=0; i<match_len; ++i ) {
711 	for ( j=0; tables[i][j]!=NULL ; ++j )
712 	    tables[i][j]->lsidebearing |= 1<<i;
713     }
714 
715     for ( i=0; i<match_len; ++i ) {
716 	for ( j=0; (sc=tables[i][j])!=NULL ; ++j ) if ( !sc->ticked ) {
717 	    mask = sc->lsidebearing;
718 	    if ( next[mask]==0 )
719 		temp[mask] = malloc(max*sizeof(SplineChar *));
720 	    temp[mask][next[mask]++] = sc;
721 	    sc->ticked = true;
722 	}
723     }
724 
725     gall = calloc(gtot+1,sizeof(SplineChar *));
726     class_cnt = gcnt = 0;
727     for ( i=0; i<(1<<match_len); ++i ) {
728 	if ( next[i]!=0 ) {
729 	    for ( k=0; k<next[i]; ++k ) {
730 		gall[temp[i][k]->ttf_glyph] = temp[i][k];
731 		temp[i][k]->lsidebearing = class_cnt;
732 	    }
733 	    ++class_cnt;
734 	    gcnt += next[i];
735 	    free(temp[i]);
736 	}
737     }
738     if ( fpst->subtable->lookup->lookup_flags & pst_ignorecombiningmarks ) {
739 	for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL && sf->glyphs[i]->ttf_glyph!=-1 ) {
740 	    if ( sf->glyphs[i]->lsidebearing==0 && IsMarkChar(sf->glyphs[i])) {
741 		sf->glyphs[i]->lsidebearing = class_cnt;
742 		++gcnt;
743 	    }
744 	}
745 	++class_cnt;			/* Add a class for the marks so we can ignore them */
746     }
747     *cc = class_cnt+4;
748     glyphs = malloc((gcnt+1)*sizeof(SplineChar *));
749     map = malloc((gcnt+1)*sizeof(uint16));
750     gcnt = 0;
751     for ( i=0; i<gtot; ++i ) if ( gall[i]!=NULL ) {
752 	glyphs[gcnt] = gall[i];
753 	map[gcnt++] = gall[i]->lsidebearing+4;	/* there are 4 standard classes, so our first class starts at 4 */
754     }
755     glyphs[gcnt] = NULL;
756     free(gall);
757     free(temp);
758     *gc = gcnt;
759     *mp = map;
760 
761     nc = calloc(match_len,sizeof(int));
762     *classes = malloc((match_len+1)*sizeof(int *));
763     for ( i=0; i<match_len; ++i )
764 	(*classes)[i] = malloc((class_cnt+1)*sizeof(int));
765     (*classes)[i] = NULL;
766 
767     class_cnt = 0;
768     for ( i=0; i<(1<<match_len); ++i ) {
769 	if ( next[i]!=0 ) {
770 	    for ( j=0; j<match_len; ++j ) if ( i&(1<<j)) {
771 		(*classes)[j][nc[j]++] = class_cnt+4;	/* there are 4 standard classes, so our first class starts at 4 */
772 	    }
773 	    ++class_cnt;
774 	}
775     }
776     for ( j=0; j<match_len; ++j )
777 	(*classes)[j][nc[j]] = 0xffff;		/* End marker */
778 
779     free(next);
780     free(nc);
781 return( glyphs );
782 }
783 
ASMFromCoverageFPST(SplineFont * sf,FPST * fpst,int ordered)784 static ASM *ASMFromCoverageFPST(SplineFont *sf,FPST *fpst,int ordered) {
785     SplineChar ***tables, **glyphs;
786     int **classes, class_cnt, gcnt;
787     int i, j, k, match_len;
788     struct fpst_rule *r = &fpst->rules[0];
789     int subspos = r->u.coverage.bcnt+r->lookups[0].seq;
790     OTLookup *substag = r->lookups[0].lookup, *finaltag=NULL;
791     uint16 *map;
792     ASM *sm;
793 
794     /* In one very specific case we can support two substitutions */
795     if ( r->lookup_cnt==2 ) {
796 	if ( r->lookups[0].seq==r->u.coverage.ncnt-1 ) {
797 	    finaltag = substag;
798 	    subspos = r->u.coverage.bcnt+r->lookups[1].seq;
799 	    substag = r->lookups[1].lookup;
800 	} else
801 	    finaltag = r->lookups[1].lookup;
802     }
803 
804     tables = malloc((r->u.coverage.ncnt+r->u.coverage.bcnt+r->u.coverage.fcnt+1)*sizeof(SplineChar **));
805     for ( j=0, i=r->u.coverage.bcnt-1; i>=0; --i, ++j )
806 	tables[j] = SFGlyphsFromNames(sf,r->u.coverage.bcovers[i]);
807     for ( i=0; i<r->u.coverage.ncnt; ++i, ++j )
808 	tables[j] = SFGlyphsFromNames(sf,r->u.coverage.ncovers[i]);
809     for ( i=0; i<r->u.coverage.fcnt; ++i, ++j )
810 	tables[j] = SFGlyphsFromNames(sf,r->u.coverage.fcovers[i]);
811     tables[j] = NULL;
812     match_len = j;
813 
814     for ( i=0; i<match_len; ++i )
815 	if ( tables[i]==NULL || tables[i][0]==NULL ) {
816             for ( i=0; i<match_len; ++i )
817 	        free(tables[i]);
818             free(tables);
819 return( NULL );
820        }
821 
822     glyphs = morx_cg_FigureClasses(tables,match_len,
823 	    &classes,&class_cnt,&map,&gcnt,fpst,sf,ordered);
824     if ( glyphs==NULL ) {
825         for ( i=0; i<match_len; ++i )
826 	    free(tables[i]);
827         free(tables);
828 return( NULL );
829     }
830 
831     for ( i=0; i<match_len; ++i )
832 	free(tables[i]);
833     free(tables);
834 
835     sm = chunkalloc(sizeof(ASM));
836     sm->type = asm_context;
837     sm->flags = (fpst->subtable->lookup->lookup_flags&pst_r2l) ? asm_descending : 0;
838     sm->class_cnt = class_cnt;
839     sm->classes = malloc(class_cnt*sizeof(char *));
840     sm->classes[0] = sm->classes[1] = sm->classes[2] = sm->classes[3] = NULL;
841     for ( i=4; i<class_cnt; ++i )
842 	sm->classes[i] = BuildClassNames(glyphs,map,i);
843     free(glyphs); free(map);
844 
845     /* Now build the state machine */
846     /* we have match_len+1 states (there are 2 initial states) */
847     /*  we transition from the initial state to our first state when we get */
848     /*  any class which makes up the first coverage table. From the first */
849     /*  to the second on any class which makes up the second ... */
850     sm->state_cnt = match_len+1;
851     sm->state = calloc(sm->state_cnt*sm->class_cnt,sizeof(struct asm_state));
852     for ( j=0; j<match_len; ++j ) {
853 	int off = (j+1)*sm->class_cnt;
854 	for ( i=0; i<class_cnt; ++i ) {
855 	    for ( k=0; classes[j][k]!=0xffff && classes[j][k]!=i; ++k );
856 	    if ( classes[j][k]==i ) {
857 		sm->state[off+i].next_state = j+2;
858 		if ( j==match_len-1 ) {
859 		    sm->state[off+i].next_state = 0;
860 		    sm->state[off+i].flags = 0x4000;
861 		    if ( subspos==j )
862 			sm->state[off+i].u.context.cur_lookup = substag;
863 		    else {
864 			sm->state[off+i].u.context.mark_lookup = substag;
865 			sm->state[off+i].u.context.cur_lookup = finaltag;
866 		    }
867 		} else if ( subspos==j )
868 		    sm->state[off+i].flags = 0x8000;
869 	    } else if ( i==2 || ((fpst->subtable->lookup->lookup_flags&pst_ignorecombiningmarks) && i==class_cnt-1 ) )
870 		sm->state[off+i].next_state = j+1;	/* Deleted glyph is a noop */
871 	    else if ( j!=0 )
872 		sm->state[off+i].flags = 0x4000;	/* Don't eat the current glyph, go back to state 0 and see if it will start the sequence over again */
873 	}
874     }
875     /* Class 0 and class 1 should be the same. We only filled in class 1 above*/
876     memcpy(sm->state,sm->state+sm->class_cnt,sm->class_cnt*sizeof(struct asm_state));
877     for ( j=0; j<match_len; ++j )
878 	free(classes[j]);
879     free(classes);
880 return( sm );
881 }
882 
883 	/* ********************** From Class FPST ********************** */
SMSetState(struct asm_state * trans,struct contexttree * cur,int class)884 static void SMSetState(struct asm_state *trans,struct contexttree *cur,int class) {
885     int i;
886 
887     for ( i=0; i<cur->branch_cnt; ++i ) {
888 	if ( cur->branches[i].classnum==class ) {
889 	    trans->next_state = cur->branches[i].branch->state;
890 	    /* If we go back to state 0, it means we want to start from */
891 	    /*  the begining again, and we should check against the */
892 	    /*  current glyph (which failed for us, but might be useful */
893 	    /*  to start a new operation).  Even if we did not fail we */
894 	    /*  should still do this (so don't advance the glyph) */
895 	    trans->flags = cur->branches[i].branch->state!=0
896 		    ? cur->branches[i].branch->markme?0x8000:0x0000
897 		    : cur->branches[i].branch->markme?0xc000:0x4000;
898 	    trans->u.context.mark_lookup = cur->branches[i].branch->applymarkedsubs;
899 	    trans->u.context.cur_lookup = cur->branches[i].branch->applycursubs;
900 return;
901 	}
902     }
903 
904     if ( cur->ends_here!=NULL ) {
905 	trans->next_state = 0;
906 	trans->flags = 0x4000;
907 	trans->u.context.mark_lookup = cur->applymarkedsubs;
908 	trans->u.context.cur_lookup = cur->applycursubs;
909     } else
910 	trans->next_state = 0;
911 }
912 
AnyActiveSubstrings(struct contexttree * tree,struct contexttree * cur,int class,struct asm_state * trans,int classcnt)913 static struct asm_state *AnyActiveSubstrings(struct contexttree *tree,
914 	struct contexttree *cur,int class, struct asm_state *trans, int classcnt) {
915     struct fpc *any = &cur->rules[0].rule->u.class;
916     int i,rc,j, b;
917 
918     for ( i=1; i<=cur->depth; ++i ) {
919 	for ( rc=0; rc<tree->rule_cnt; ++rc ) {
920 	    struct fpc *r = &tree->rules[rc].rule->u.class;
921 	    int ok = true;
922 	    for ( j=0; j<=cur->depth-i; ++j ) {
923 		if ( any->allclasses[j+i]!=r->allclasses[j] ) {
924 		    ok = false;
925 	    break;
926 		}
927 	    }
928 	    if ( ok && r->allclasses[j]==class ) {
929 		struct contexttree *sub = tree;
930 		for ( j=0; j<=cur->depth-i; ++j ) {
931 		    for ( b=0; b<sub->branch_cnt; ++b ) {
932 			if ( sub->branches[b].classnum==r->allclasses[j] ) {
933 			    sub = sub->branches[b].branch;
934 		    break;
935 			}
936 		    }
937 		}
938 		if ( trans[sub->state*classcnt+class+3].next_state!=0 &&
939 			(sub->pending_pos+i == cur->pending_pos ||
940 			 sub->pending_pos == -1 ))
941 return( &trans[sub->state*classcnt+class+3] );
942 	    }
943 	}
944     }
945 return( NULL );
946 }
947 
FailureTrans(struct asm_state * trans)948 static int FailureTrans( struct asm_state *trans ) {
949 return( trans->next_state==0 &&
950 	    trans->u.context.mark_lookup==NULL &&
951 	    trans->u.context.cur_lookup==NULL );
952 }
953 
ASMFromClassFPST(SplineFont * sf,FPST * fpst,struct contexttree * tree)954 static ASM *ASMFromClassFPST(SplineFont *sf,FPST *fpst, struct contexttree *tree) {
955     ASM *sm;
956     struct contexttree *cur;
957     int i;
958 
959     sm = chunkalloc(sizeof(ASM));
960     sm->type = asm_context;
961     sm->flags = (fpst->subtable->lookup->lookup_flags&pst_r2l) ? asm_descending : 0;
962     /* mac class sets have four magic classes, opentype sets only have one */
963     sm->class_cnt = (fpst->subtable->lookup->lookup_flags&pst_ignorecombiningmarks) ? fpst->nccnt+4 : fpst->nccnt+3;
964     sm->classes = malloc(sm->class_cnt*sizeof(char *));
965     sm->classes[0] = sm->classes[1] = sm->classes[2] = sm->classes[3] = NULL;
966     for ( i=1; i<fpst->nccnt; ++i )
967 	sm->classes[i+3] = copy(fpst->nclass[i]);
968     if ( fpst->subtable->lookup->lookup_flags&pst_ignorecombiningmarks )
969 	sm->classes[sm->class_cnt-1] = BuildMarkClass(sf);
970 
971     /* Now build the state machine */
972     sm->state_cnt = tree->next_state;
973     sm->state = calloc(sm->state_cnt*sm->class_cnt,sizeof(struct asm_state));
974     for ( cur=tree; cur!=NULL; cur = TreeNext(cur)) if ( cur->state!=0 ) {
975 	int off = cur->state*sm->class_cnt;
976 
977 	SMSetState(&sm->state[off+1],cur,0);		/* Out of bounds state */
978 	sm->state[off+2].next_state = cur->state;	/* Deleted glyph gets eaten and ignored */
979 	if ( fpst->subtable->lookup->lookup_flags&pst_ignorecombiningmarks )
980 	    sm->state[off+sm->class_cnt-1].next_state = cur->state;	/* As do ignored marks */
981 	for ( i=1; i<fpst->nccnt; ++i )
982 	    SMSetState(&sm->state[off+i+3],cur,i);
983     }
984     /* Class 0 and class 1 should be the same. We only filled in class 1 above*/
985     memcpy(sm->state,sm->state+sm->class_cnt,sm->class_cnt*sizeof(struct asm_state));
986     /* Do a sort of transitive closure on states, so if we are looking for */
987     /*  either "abcd" or "bce", don't lose the "bce" inside "abce" */
988     FPSTBuildAllClasses(fpst);
989     for ( cur = tree; cur!=NULL; cur = TreeNext(cur)) if ( cur->state>1 ) {
990 	int off = cur->state*sm->class_cnt;
991 	for ( i=1; i<fpst->nccnt; ++i ) if ( FailureTrans(&sm->state[off+3+i]) ) {
992 	    struct asm_state *trans =
993 		    AnyActiveSubstrings(tree,cur,i, sm->state,sm->class_cnt);
994 	    if ( trans!=NULL )
995 		sm->state[off+3+i] = *trans;
996 	}
997     }
998     FPSTFreeAllClasses(fpst);
999 return( sm );
1000 }
1001 
ASMFromFPST(SplineFont * sf,FPST * fpst,int ordered)1002 ASM *ASMFromFPST(SplineFont *sf,FPST *fpst,int ordered) {
1003     FPST *tempfpst=fpst;
1004     struct contexttree *tree=NULL;
1005     ASM *sm;
1006 
1007     if ( fpst->format==pst_glyphs )
1008 	tempfpst = FPSTGlyphToClass( fpst );
1009     if ( tempfpst->format==pst_coverage )
1010 	sm = ASMFromCoverageFPST(sf,fpst,ordered);
1011     else {
1012 	tree = FPST2Tree(sf, tempfpst);
1013 	if ( tree!=NULL ) {
1014 	    sm = ASMFromClassFPST(sf,tempfpst,tree);
1015 	    TreeFree(tree);
1016 	} else
1017 	    sm = NULL;
1018     }
1019 
1020     if ( tempfpst!=fpst )
1021 	FPSTFree(tempfpst);
1022 	/* This is a temporary value. It should be replaced if we plan to */
1023 	/*  retain this state machine */
1024     if ( sm!=NULL )
1025 	sm->subtable = fpst->subtable;
1026 return( sm );
1027 }
1028