summaryrefslogtreecommitdiff
path: root/Build/source/texk/dvisvgm/dvisvgm-src/libs/ff-woff/fontforge/asmfpst.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/dvisvgm/dvisvgm-src/libs/ff-woff/fontforge/asmfpst.c')
-rw-r--r--Build/source/texk/dvisvgm/dvisvgm-src/libs/ff-woff/fontforge/asmfpst.c1007
1 files changed, 0 insertions, 1007 deletions
diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/libs/ff-woff/fontforge/asmfpst.c b/Build/source/texk/dvisvgm/dvisvgm-src/libs/ff-woff/fontforge/asmfpst.c
deleted file mode 100644
index 9276f9aeced..00000000000
--- a/Build/source/texk/dvisvgm/dvisvgm-src/libs/ff-woff/fontforge/asmfpst.c
+++ /dev/null
@@ -1,1007 +0,0 @@
-/* Copyright (C) 2003-2007 by George Williams */
-/*
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
-
- * The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
-
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#include "fontforgevw.h"
-#include "ttf.h"
-
-/* ************************************************************************** */
-/* *************** Routines to test conversion from OpenType **************** */
-/* ************************************************************************** */
-
-int ClassesMatch(int cnt1,char **classes1,int cnt2,char **classes2) {
- int i;
-
- if ( cnt1!=cnt2 )
-return( false );
- for ( i=1; i<cnt2; ++i )
- if ( strcmp(classes1[i],classes2[i])!=0 )
-return( false );
-
-return( true );
-}
-
-static char **classcopy(char **names,int nextclass) {
- char **ret;
- int i;
-
- if ( nextclass <= 1 )
-return( NULL );
-
- ret = malloc(nextclass*sizeof(char *));
- ret[0] = NULL;
- for ( i=1; i<nextclass; ++i )
- ret[i] = copy(names[i]);
-return( ret );
-}
-
-FPST *FPSTGlyphToClass(FPST *fpst) {
- FPST *new;
- int nextclass=0, i,j,k, max, cnt, ch;
- char *pt, *end;
- char **names;
-
- if ( fpst->format!=pst_glyphs )
-return( NULL );
-
- new = chunkalloc(sizeof(FPST));
- new->type = fpst->type;
- new->format = pst_class;
- new->subtable = fpst->subtable;
- new->rule_cnt = fpst->rule_cnt;
- new->rules = calloc(fpst->rule_cnt,sizeof(struct fpst_rule));
-
- max = 100; nextclass=1;
- names = malloc(max*sizeof(char *));
- names[0] = NULL;
- for ( i=0; i<fpst->rule_cnt; ++i ) {
- for ( j=0; j<3; ++j ) {
- cnt = 0;
- if ( (&fpst->rules[i].u.glyph.names)[j]!=NULL && *(&fpst->rules[i].u.glyph.names)[j]!='\0' ) {
- for ( pt=(&fpst->rules[i].u.glyph.names)[j]; *pt; ) {
- while ( *pt==' ' ) ++pt;
- if ( *pt=='\0' )
- break;
- while ( *pt!=' ' && *pt!='\0' ) ++pt;
- ++cnt;
- }
- }
- (&new->rules[i].u.class.ncnt)[j] = cnt;
- if ( cnt!=0 ) {
- (&new->rules[i].u.class.nclasses)[j] = malloc(cnt*sizeof(uint16));
- cnt = 0;
- for ( pt=(&fpst->rules[i].u.glyph.names)[j]; *pt; pt=end ) {
- while ( *pt==' ' ) ++pt;
- if ( *pt=='\0' )
- break;
- for ( end=pt ; *end!=' ' && *end!='\0'; ++end );
- ch = *end; *end='\0';
- for ( k=1; k<nextclass; ++k )
- if ( strcmp(pt,names[k])==0 )
- break;
- if ( k==nextclass ) {
- if ( nextclass>=max )
- names = realloc(names,(max+=100)*sizeof(char *));
- names[nextclass++] = copy(pt);
- }
- *end = ch;
- (&new->rules[i].u.class.nclasses)[j][cnt++] = k;
- }
- }
- }
- new->rules[i].lookup_cnt = fpst->rules[i].lookup_cnt;
- new->rules[i].lookups = malloc(fpst->rules[i].lookup_cnt*sizeof(struct seqlookup));
- memcpy(new->rules[i].lookups,fpst->rules[i].lookups,
- fpst->rules[i].lookup_cnt*sizeof(struct seqlookup));
- }
- new->nccnt = nextclass;
- new->nclass = names;
- new->nclassnames = calloc(nextclass,sizeof(char *)); /* Leave as NULL */
- if ( fpst->type==pst_chainpos || fpst->type==pst_chainsub ) {
- /* our class set has one "class" for each glyph used anywhere */
- /* all three class sets are the same */
- new->bccnt = new->fccnt = nextclass;
- new->bclass = classcopy(names,nextclass);
- new->fclass = classcopy(names,nextclass);
- new->bclassnames = calloc(nextclass,sizeof(char *)); /* Leave as NULL */
- new->fclassnames = calloc(nextclass,sizeof(char *)); /* Leave as NULL */
- }
-return( new );
-}
-
-static int ValidSubs(OTLookup *otl ) {
-return( otl->lookup_type == gsub_single );
-}
-
-static void TreeFree(struct contexttree *tree) {
- int i;
-
- if ( tree==NULL )
-return;
-
- for ( i=0; i<tree->branch_cnt; ++i )
- TreeFree(tree->branches[i].branch);
-
- free( tree->branches );
- free( tree->rules );
- chunkfree( tree,sizeof(*tree) );
-}
-
-static int TreeLabelState(struct contexttree *tree, int snum) {
- int i;
-
- if ( tree->branch_cnt==0 && tree->ends_here!=NULL ) {
- tree->state = 0;
-return( snum );
- }
-
- tree->state = snum++;
- for ( i=0; i<tree->branch_cnt; ++i )
- snum = TreeLabelState(tree->branches[i].branch,snum);
- tree->next_state = snum;
-
-return( snum );
-}
-
-static OTLookup *RuleHasSubsHere(struct fpst_rule *rule,int depth) {
- int i,j;
-
- if ( depth<rule->u.class.bcnt )
-return( NULL );
- depth -= rule->u.class.bcnt;
- if ( depth>=rule->u.class.ncnt )
-return( NULL );
- for ( i=0; i<rule->lookup_cnt; ++i ) {
- if ( rule->lookups[i].seq==depth ) {
- /* It is possible to have two substitutions applied at the same */
- /* location. I can't deal with that here */
- for ( j=i+1; j<rule->lookup_cnt; ++j ) {
- if ( rule->lookups[j].seq==depth )
-return( (OTLookup *) 0xffffffff );
- }
-return( rule->lookups[i].lookup );
- }
- }
-
-return( 0 );
-}
-
-static OTLookup *RulesAllSameSubsAt(struct contexttree *me,int pos) {
- int i;
- 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 */
-
- for ( i=0; i<me->rule_cnt; ++i ) {
- newtag = RuleHasSubsHere(me->rules[i].rule,pos);
- if ( tag==(OTLookup *) 0x01 )
- tag=newtag;
- else if ( newtag!=tag )
-return( (OTLookup *) 0xffffffff );
- }
- if ( tag==(OTLookup *) 0x01 )
-return( NULL ); /* Should never happen */
-
-return( tag );
-}
-
-static int TreeFollowBranches(SplineFont *sf,struct contexttree *me,int pending_pos) {
- int i, j;
-
- me->pending_pos = pending_pos;
- if ( me->ends_here!=NULL ) {
- /* If any rule ends here then we have to be able to apply all current */
- /* and pending substitutions */
- if ( pending_pos!=-1 ) {
- me->applymarkedsubs = RulesAllSameSubsAt(me,pending_pos);
- if ( me->applymarkedsubs==(OTLookup *) 0xffffffff )
-return( false );
- if ( !ValidSubs(me->applymarkedsubs))
-return( false );
- }
- me->applycursubs = RulesAllSameSubsAt(me,me->depth);
- if ( me->applycursubs==(OTLookup *) 0xffffffff )
-return( false );
- if ( me->applycursubs!=NULL && !ValidSubs(me->applycursubs))
-return( false );
- for ( i=0; i<me->branch_cnt; ++i ) {
- if ( !TreeFollowBranches(sf,me->branches[i].branch,-1))
-return( false );
- }
- } else {
- for ( i=0; i<me->branch_cnt; ++i ) {
- for ( j=0; j<me->rule_cnt; ++j )
- if ( me->rules[j].branch==me->branches[i].branch &&
- RuleHasSubsHere(me->rules[j].rule,me->depth)!=NULL )
- break;
- if ( j<me->rule_cnt ) {
- if ( pending_pos==-1 ) {
- pending_pos = me->pending_pos = me->depth;
- me->markme = true;
- } else
-return( false );
- }
- if ( !TreeFollowBranches(sf,me->branches[i].branch,pending_pos))
-return( false );
- }
- }
-
-return( true );
-}
-
-static struct contexttree *_FPST2Tree(FPST *fpst,struct contexttree *parent,int class) {
- struct contexttree *me = chunkalloc(sizeof(struct contexttree));
- int i, rcnt, ccnt, k, thisclass;
- uint16 *classes;
-
- if ( fpst!=NULL ) {
- me->depth = -1;
- me->rule_cnt = fpst->rule_cnt;
- me->rules = calloc(me->rule_cnt,sizeof(struct ct_subs));
- for ( i=0; i<me->rule_cnt; ++i )
- me->rules[i].rule = &fpst->rules[i];
- me->parent = NULL;
- } else {
- me->depth = parent->depth+1;
- for ( i=rcnt=0; i<parent->rule_cnt; ++i )
- if ( parent->rules[i].rule->u.class.allclasses[me->depth] == class )
- ++rcnt;
- me->rule_cnt = rcnt;
- me->rules = calloc(me->rule_cnt,sizeof(struct ct_subs));
- for ( i=rcnt=0; i<parent->rule_cnt; ++i )
- if ( parent->rules[i].rule->u.class.allclasses[me->depth] == class )
- me->rules[rcnt++].rule = parent->rules[i].rule;
- me->parent = parent;
- }
- classes = malloc(me->rule_cnt*sizeof(uint16));
- for ( i=ccnt=0; i<me->rule_cnt; ++i ) {
- thisclass = me->rules[i].thisclassnum = me->rules[i].rule->u.class.allclasses[me->depth+1];
- if ( thisclass==0xffff ) {
- if ( me->ends_here==NULL )
- me->ends_here = me->rules[i].rule;
- } else {
- for ( k=0; k<ccnt; ++k )
- if ( classes[k] == thisclass )
- break;
- if ( k==ccnt )
- classes[ccnt++] = thisclass;
- }
- }
- me->branch_cnt = ccnt;
- me->branches = calloc(ccnt,sizeof(struct ct_branch));
- for ( i=0; i<ccnt; ++i )
- me->branches[i].classnum = classes[i];
- for ( i=0; i<ccnt; ++i ) {
- me->branches[i].branch = _FPST2Tree(NULL,me,classes[i]);
- for ( k=0; k<me->rule_cnt; ++k )
- if ( classes[i]==me->rules[k].thisclassnum )
- me->rules[k].branch = me->branches[i].branch;
- }
- free(classes );
-return( me );
-}
-
-static void FPSTBuildAllClasses(FPST *fpst) {
- int i, off,j;
-
- for ( i=0; i<fpst->rule_cnt; ++i ) {
- fpst->rules[i].u.class.allclasses = malloc((fpst->rules[i].u.class.bcnt+
- fpst->rules[i].u.class.ncnt+
- fpst->rules[i].u.class.fcnt+
- 1)*sizeof(uint16));
- off = fpst->rules[i].u.class.bcnt;
- for ( j=0; j<off; ++j )
- fpst->rules[i].u.class.allclasses[j] = fpst->rules[i].u.class.bclasses[off-1-j];
- for ( j=0; j<fpst->rules[i].u.class.ncnt; ++j )
- fpst->rules[i].u.class.allclasses[off+j] = fpst->rules[i].u.class.nclasses[j];
- off += j;
- for ( j=0; j<fpst->rules[i].u.class.fcnt; ++j )
- fpst->rules[i].u.class.allclasses[off+j] = fpst->rules[i].u.class.fclasses[j];
- fpst->rules[i].u.class.allclasses[off+j] = 0xffff; /* End of rule marker */
- }
-}
-
-static void FPSTFreeAllClasses(FPST *fpst) {
- int i;
-
- for ( i=0; i<fpst->rule_cnt; ++i ) {
- free( fpst->rules[i].u.class.allclasses );
- fpst->rules[i].u.class.allclasses = NULL;
- }
-}
-
-static struct contexttree *FPST2Tree(SplineFont *sf,FPST *fpst) {
- struct contexttree *ret;
-
- if ( fpst->format != pst_class )
-return( NULL );
-
- /* I could check for subclasses rather than ClassesMatch, but then I'd have */
- /* to make sure that class 0 was used (if at all) consistently */
- if ( (fpst->bccnt!=0 && !ClassesMatch(fpst->bccnt,fpst->bclass,fpst->nccnt,fpst->nclass)) ||
- (fpst->fccnt!=0 && !ClassesMatch(fpst->fccnt,fpst->fclass,fpst->nccnt,fpst->nclass)))
-return( NULL );
-
- FPSTBuildAllClasses(fpst);
-
- ret = _FPST2Tree(fpst,NULL,0);
-
- if ( !TreeFollowBranches(sf,ret,-1) ) {
- TreeFree(ret);
- ret = NULL;
- }
-
- FPSTFreeAllClasses(fpst);
-
- if ( ret!=NULL )
- TreeLabelState(ret,1); /* actually, it's states 0&1, but this will do */
-
-return( ret );
-}
-
-static struct contexttree *TreeNext(struct contexttree *cur) {
- struct contexttree *p;
- int i;
-
- if ( cur->branch_cnt!=0 )
-return( cur->branches[0].branch );
- else {
- for (;;) {
- p = cur->parent;
- if ( p==NULL )
-return( NULL );
- for ( i=0; i<p->branch_cnt; ++i ) {
- if ( p->branches[i].branch==cur ) {
- ++i;
- break;
- }
- }
- if ( i<p->branch_cnt )
-return( p->branches[i].branch );
- cur = p;
- }
- }
-}
-
-int FPSTisMacable(SplineFont *sf, FPST *fpst) {
- int i;
- int featureType, featureSetting;
- struct contexttree *ret;
- FeatureScriptLangList *fl;
-
- if ( fpst->type!=pst_contextsub && fpst->type!=pst_chainsub )
-return( false );
- for ( fl = fpst->subtable->lookup->features; fl!=NULL; fl=fl->next ) {
- if ( OTTagToMacFeature(fl->featuretag,&featureType,&featureSetting) &&
- scriptsHaveDefault(fl->scripts) )
- break;
- }
- if ( fl==NULL )
-return( false );
-
- if ( fpst->format == pst_glyphs ) {
- FPST *tempfpst = FPSTGlyphToClass(fpst);
- ret = FPST2Tree(sf, tempfpst);
- FPSTFree(tempfpst);
- TreeFree(ret);
-return( ret!=NULL );
- } else if ( fpst->format == pst_class ) {
- ret = FPST2Tree(sf, fpst);
- TreeFree(ret);
-return( ret!=NULL );
- } else if ( fpst->format != pst_coverage )
-return( false );
-
- for ( i=0; i<fpst->rule_cnt; ++i ) {
- if ( fpst->rules[i].u.coverage.ncnt+
- fpst->rules[i].u.coverage.bcnt+
- fpst->rules[i].u.coverage.fcnt>=10 )
-return( false ); /* Let's not make a state machine this complicated */
-
- if ( fpst->rules[i].lookup_cnt==2 ) {
- switch ( fpst->format ) {
- case pst_coverage:
- /* Second substitution must be on the final glyph */
- if ( fpst->rules[i].u.coverage.fcnt!=0 ||
- fpst->rules[i].lookups[0].seq==fpst->rules[i].lookups[1].seq ||
- (fpst->rules[i].lookups[0].seq!=fpst->rules[i].u.coverage.ncnt-1 &&
- fpst->rules[i].lookups[1].seq!=fpst->rules[i].u.coverage.ncnt-1) )
-return( false );
- break;
- default:
-return( false );
- }
- if ( !ValidSubs(fpst->rules[i].lookups[1].lookup) )
-return( false );
-
- } else if ( fpst->rules[i].lookup_cnt!=1 )
-return( false );
- if ( !ValidSubs(fpst->rules[i].lookups[0].lookup) )
-return( false );
- }
-
-return( fpst->rule_cnt>0 );
-}
-
-/* ************************************************************************** */
-/* *************** Conversion from OpenType Context/Chaining **************** */
-/* ************************************************************************** */
-
- /* ********************** From Forms ********************** */
-static int IsMarkChar( SplineChar *sc ) {
- AnchorPoint *ap;
-
- ap=sc->anchor;
- while ( ap!=NULL && (ap->type==at_centry || ap->type==at_cexit) )
- ap = ap->next;
- if ( ap!=NULL && (ap->type==at_mark || ap->type==at_basemark) )
-return( true );
-
-return( false );
-}
-
-static char *GlyphListToNames(SplineChar **classglyphs) {
- int i, len;
- char *ret, *pt;
-
- for ( i=len=0; classglyphs[i]!=NULL; ++i )
- len += strlen(classglyphs[i]->name)+1;
- ret = pt = malloc(len+1);
- for ( i=0; classglyphs[i]!=NULL; ++i ) {
- strcpy(pt,classglyphs[i]->name);
- pt += strlen(pt);
- *pt++ = ' ';
- }
- if ( pt>ret )
- pt[-1] = '\0';
- else
- *ret = '\0';
-return( ret );
-}
-
-static char *BuildMarkClass(SplineFont *sf) {
- SplineChar *sc, **markglyphs;
- int i, mg;
- char *ret;
-
- mg = 0;
- markglyphs = malloc(sf->glyphcnt*sizeof(SplineChar *));
- for ( i=0; i<sf->glyphcnt; ++i ) if ( (sc=sf->glyphs[i])!=NULL ) {
- if ( IsMarkChar(sc)) {
- markglyphs[mg++] = sc;
- }
- }
- markglyphs[mg] = NULL;
- ret = GlyphListToNames(markglyphs);
- free(markglyphs);
-return(ret);
-}
-
-static char *BuildClassNames(SplineChar **glyphs,uint16 *map, int classnum) {
- int i, len;
- char *ret, *pt;
-
- for ( i=len=0; glyphs[i]!=NULL; ++i ) {
- if ( map[i]==classnum )
- len += strlen(glyphs[i]->name)+1;
- }
- ret = pt = malloc(len+1);
- for ( i=len=0; glyphs[i]!=NULL; ++i ) {
- if ( map[i]==classnum ) {
- strcpy(pt,glyphs[i]->name);
- pt += strlen(pt);
- *pt++ = ' ';
- }
- }
- if ( pt>ret )
- pt[-1] = '\0';
- else
- *ret = '\0';
-return( ret );
-}
-
-static int FindFormLookupsForScript(SplineFont *sf,uint32 script,OTLookup *lookups[4]) {
- OTLookup *otl;
- FeatureScriptLangList *fl;
- struct scriptlanglist *sl;
- int which;
-
- memset(lookups,0,4*sizeof(OTLookup *));
- for ( otl=sf->gsub_lookups; otl!=NULL; otl=otl->next ) if ( !otl->unused && otl->lookup_type == gsub_single ) {
- for ( fl=otl->features; fl!=NULL; fl=fl->next ) {
- if ( fl->featuretag== CHR('i','n','i','t') ) which = 0;
- else if ( fl->featuretag== CHR('m','e','d','i') ) which = 1;
- else if ( fl->featuretag== CHR('f','i','n','a') ) which = 2;
- else if ( fl->featuretag== CHR('i','s','o','l') ) which = 3;
- else
- continue;
- if ( lookups[which]!=NULL )
- continue;
- for ( sl=fl->scripts; sl!=NULL && sl->script!=script; sl=sl->next );
- if ( sl==NULL )
- continue;
- lookups[which] = otl;
- break;
- }
- }
- if ( lookups[0]!=NULL || lookups[1]!=NULL || lookups[2]!=NULL || lookups[3]!=NULL )
-return( true );
-
-return( false );
-}
-
-ASM *ASMFromOpenTypeForms(SplineFont *sf,uint32 script) {
- int i, which, cg, mg;
- SplineChar *sc, *rsc, **classglyphs, **markglyphs;
- PST *pst;
- OTLookup *lookups[4];
- ASM *sm;
- int flags;
-
- if ( !FindFormLookupsForScript(sf,script,lookups))
-return( NULL );
- flags = (lookups[0]!=NULL ? lookups[0]->lookup_flags
- :lookups[1]!=NULL ? lookups[1]->lookup_flags
- :lookups[2]!=NULL ? lookups[2]->lookup_flags
- : lookups[3]->lookup_flags);
- classglyphs = calloc((sf->glyphcnt+1),sizeof(SplineChar *));
- markglyphs = malloc((sf->glyphcnt+1)*sizeof(SplineChar *));
-
- mg = 0;
- for ( i=0; i<sf->glyphcnt; ++i ) if ( (sc=sf->glyphs[i])!=NULL ) {
- if ( (flags&pst_ignorecombiningmarks) && IsMarkChar(sc)) {
- markglyphs[mg++] = sc;
- } else if ( SCScriptFromUnicode(sc)==script ) {
- classglyphs[sc->orig_pos] = sc;
- for ( pst = sc->possub; pst!=NULL; pst=pst->next ) if ( pst->subtable!=NULL ) {
- OTLookup *otl = pst->subtable->lookup;
- for ( which=3; which>=0; --which ) {
- if ( otl==lookups[which])
- break;
- }
- if ( which==-1 )
- continue;
- rsc = SFGetChar(sf,-1,pst->u.subs.variant);
- if ( rsc!=NULL )
- classglyphs[rsc->orig_pos] = rsc;
- }
- }
- }
- markglyphs[mg] = NULL;
-
- cg = 0;
- for ( i=0; i<sf->glyphcnt; ++i )
- if ( classglyphs[i]!=NULL )
- classglyphs[cg++] = classglyphs[i];
- classglyphs[cg] = NULL;
-
- sm = chunkalloc(sizeof(ASM));
- sm->type = asm_context;
- sm->flags = (flags&pst_r2l) ? asm_descending : 0;
- /* This is a temporary value. It should be replaced if we will retain */
- /* this state machine */
- sm->subtable = (lookups[3]!=NULL ? lookups[3] : lookups[0]!=NULL ? lookups[0] : lookups[1]!=NULL ? lookups[1] : lookups[2])->subtables;
- /* Only one (or two) classes of any importance: Letter in this script */
- /* might already be formed. Might be a lig. Might be normal */
- /* Oh, if ignoremarks is true, then combining marks merit a class of their own */
- sm->class_cnt = (flags&pst_ignorecombiningmarks) ? 6 : 5;
- sm->classes = calloc(sm->class_cnt,sizeof(char *));
-
- sm->classes[4] = GlyphListToNames(classglyphs);
- if ( flags&pst_ignorecombiningmarks )
- sm->classes[5] = GlyphListToNames(markglyphs);
- free(classglyphs); free(markglyphs);
-
-
- /* State 0,1 are start states */
- /* State 2 means we have found one interesting letter, transformed current to 'init' and marked it (in case we need to make it isolated) */
- /* State 3 means we have found two interesting letters, transformed current to 'medi' and marked (in case we need to make it final) */
- sm->state_cnt = 4;
- sm->state = calloc(sm->state_cnt*sm->class_cnt,sizeof(struct asm_state));
-
- /* State 0,1 (start), Class 4 (char in script) takes us to state 2 */
- sm->state[4].next_state = 2;
- sm->state[4].flags = 0x8000;
-
- sm->state[sm->class_cnt+4] = sm->state[4];
-
- for ( i=0; i<4; ++i ) {
- sm->state[2*sm->class_cnt+i].next_state = 0;
- sm->state[2*sm->class_cnt+i].u.context.mark_lookup = lookups[3];/* Isolated */
- }
-
- sm->state[2*sm->class_cnt+4].next_state = 3;
- sm->state[2*sm->class_cnt+4].flags = 0x8000;
- sm->state[2*sm->class_cnt+4].u.context.mark_lookup = lookups[0]; /* Initial */
-
- for ( i=0; i<4; ++i ) {
- sm->state[3*sm->class_cnt+i].next_state = 0;
- sm->state[3*sm->class_cnt+i].u.context.mark_lookup = lookups[2];/* Final */
- }
-
- sm->state[3*sm->class_cnt+4].next_state = 3;
- sm->state[3*sm->class_cnt+4].flags = 0x8000;
- sm->state[3*sm->class_cnt+4].u.context.mark_lookup = lookups[1]; /* Medial */
-
- /* Deleted glyph retains same state, just eats the glyph */
- for ( i=0; i<sm->state_cnt; ++i ) {
- int pos = i*sm->class_cnt+2, mpos = i*sm->class_cnt+5;
- sm->state[pos].next_state = i;
- sm->state[pos].flags = 0;
- sm->state[pos].u.context.cur_lookup = NULL;
- sm->state[pos].u.context.mark_lookup = NULL;
- /* same for ignored marks */
- if ( flags&pst_ignorecombiningmarks )
- sm->state[mpos].next_state = i;
- }
-
-return( sm );
-}
-
- /* ********************** From Coverage FPST ********************** */
-static SplineChar **morx_cg_FigureClasses(SplineChar ***tables,int match_len,
- int ***classes, int *cc, uint16 **mp, int *gc,
- FPST *fpst,SplineFont *sf,int ordered) {
- int i,j,k, mask, max, class_cnt, gcnt, gtot;
- SplineChar ***temp, *sc, **glyphs, **gall;
- uint16 *map;
- int *nc;
- int *next;
- /* For each glyph used, figure out what coverage tables it gets used in */
- /* then all the glyphs which get used in the same set of coverage tables */
- /* can form one class */
-
- if ( match_len>10 ) /* would need too much space to figure out */
-return( NULL );
-
- gtot = 0;
- for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
- sf->glyphs[i]->lsidebearing = 1;
- if ( !ordered )
- sf->glyphs[i]->ttf_glyph = gtot++;
- else if ( sf->glyphs[i]->ttf_glyph+1>gtot )
- gtot = sf->glyphs[i]->ttf_glyph+1;
- }
-
- max=0;
- for ( i=0; i<match_len; ++i ) {
- for ( k=0; tables[i][k]!=NULL; ++k );
- if ( k>max ) max=k;
- }
- next = calloc(1<<match_len,sizeof(int));
- temp = malloc((1<<match_len)*sizeof(SplineChar **));
-
- for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL ) {
- sf->glyphs[i]->lsidebearing = 0;
- sf->glyphs[i]->ticked = false;
- }
- for ( i=0; i<match_len; ++i ) {
- for ( j=0; tables[i][j]!=NULL ; ++j )
- tables[i][j]->lsidebearing |= 1<<i;
- }
-
- for ( i=0; i<match_len; ++i ) {
- for ( j=0; (sc=tables[i][j])!=NULL ; ++j ) if ( !sc->ticked ) {
- mask = sc->lsidebearing;
- if ( next[mask]==0 )
- temp[mask] = malloc(max*sizeof(SplineChar *));
- temp[mask][next[mask]++] = sc;
- sc->ticked = true;
- }
- }
-
- gall = calloc(gtot+1,sizeof(SplineChar *));
- class_cnt = gcnt = 0;
- for ( i=0; i<(1<<match_len); ++i ) {
- if ( next[i]!=0 ) {
- for ( k=0; k<next[i]; ++k ) {
- gall[temp[i][k]->ttf_glyph] = temp[i][k];
- temp[i][k]->lsidebearing = class_cnt;
- }
- ++class_cnt;
- gcnt += next[i];
- free(temp[i]);
- }
- }
- if ( fpst->subtable->lookup->lookup_flags & pst_ignorecombiningmarks ) {
- for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL && sf->glyphs[i]->ttf_glyph!=-1 ) {
- if ( sf->glyphs[i]->lsidebearing==0 && IsMarkChar(sf->glyphs[i])) {
- sf->glyphs[i]->lsidebearing = class_cnt;
- ++gcnt;
- }
- }
- ++class_cnt; /* Add a class for the marks so we can ignore them */
- }
- *cc = class_cnt+4;
- glyphs = malloc((gcnt+1)*sizeof(SplineChar *));
- map = malloc((gcnt+1)*sizeof(uint16));
- gcnt = 0;
- for ( i=0; i<gtot; ++i ) if ( gall[i]!=NULL ) {
- glyphs[gcnt] = gall[i];
- map[gcnt++] = gall[i]->lsidebearing+4; /* there are 4 standard classes, so our first class starts at 4 */
- }
- glyphs[gcnt] = NULL;
- free(gall);
- free(temp);
- *gc = gcnt;
- *mp = map;
-
- nc = calloc(match_len,sizeof(int));
- *classes = malloc((match_len+1)*sizeof(int *));
- for ( i=0; i<match_len; ++i )
- (*classes)[i] = malloc((class_cnt+1)*sizeof(int));
- (*classes)[i] = NULL;
-
- class_cnt = 0;
- for ( i=0; i<(1<<match_len); ++i ) {
- if ( next[i]!=0 ) {
- for ( j=0; j<match_len; ++j ) if ( i&(1<<j)) {
- (*classes)[j][nc[j]++] = class_cnt+4; /* there are 4 standard classes, so our first class starts at 4 */
- }
- ++class_cnt;
- }
- }
- for ( j=0; j<match_len; ++j )
- (*classes)[j][nc[j]] = 0xffff; /* End marker */
-
- free(next);
- free(nc);
-return( glyphs );
-}
-
-static ASM *ASMFromCoverageFPST(SplineFont *sf,FPST *fpst,int ordered) {
- SplineChar ***tables, **glyphs;
- int **classes, class_cnt, gcnt;
- int i, j, k, match_len;
- struct fpst_rule *r = &fpst->rules[0];
- int subspos = r->u.coverage.bcnt+r->lookups[0].seq;
- OTLookup *substag = r->lookups[0].lookup, *finaltag=NULL;
- uint16 *map;
- ASM *sm;
-
- /* In one very specific case we can support two substitutions */
- if ( r->lookup_cnt==2 ) {
- if ( r->lookups[0].seq==r->u.coverage.ncnt-1 ) {
- finaltag = substag;
- subspos = r->u.coverage.bcnt+r->lookups[1].seq;
- substag = r->lookups[1].lookup;
- } else
- finaltag = r->lookups[1].lookup;
- }
-
- tables = malloc((r->u.coverage.ncnt+r->u.coverage.bcnt+r->u.coverage.fcnt+1)*sizeof(SplineChar **));
- for ( j=0, i=r->u.coverage.bcnt-1; i>=0; --i, ++j )
- tables[j] = SFGlyphsFromNames(sf,r->u.coverage.bcovers[i]);
- for ( i=0; i<r->u.coverage.ncnt; ++i, ++j )
- tables[j] = SFGlyphsFromNames(sf,r->u.coverage.ncovers[i]);
- for ( i=0; i<r->u.coverage.fcnt; ++i, ++j )
- tables[j] = SFGlyphsFromNames(sf,r->u.coverage.fcovers[i]);
- tables[j] = NULL;
- match_len = j;
-
- for ( i=0; i<match_len; ++i )
- if ( tables[i]==NULL || tables[i][0]==NULL )
-return( NULL );
-
- glyphs = morx_cg_FigureClasses(tables,match_len,
- &classes,&class_cnt,&map,&gcnt,fpst,sf,ordered);
- if ( glyphs==NULL )
-return( NULL );
-
- for ( i=0; i<match_len; ++i )
- free(tables[i]);
- free(tables);
-
- sm = chunkalloc(sizeof(ASM));
- sm->type = asm_context;
- sm->flags = (fpst->subtable->lookup->lookup_flags&pst_r2l) ? asm_descending : 0;
- sm->class_cnt = class_cnt;
- sm->classes = malloc(class_cnt*sizeof(char *));
- sm->classes[0] = sm->classes[1] = sm->classes[2] = sm->classes[3] = NULL;
- for ( i=4; i<class_cnt; ++i )
- sm->classes[i] = BuildClassNames(glyphs,map,i);
- free(glyphs); free(map);
-
- /* Now build the state machine */
- /* we have match_len+1 states (there are 2 initial states) */
- /* we transition from the initial state to our first state when we get */
- /* any class which makes up the first coverage table. From the first */
- /* to the second on any class which makes up the second ... */
- sm->state_cnt = match_len+1;
- sm->state = calloc(sm->state_cnt*sm->class_cnt,sizeof(struct asm_state));
- for ( j=0; j<match_len; ++j ) {
- int off = (j+1)*sm->class_cnt;
- for ( i=0; i<class_cnt; ++i ) {
- for ( k=0; classes[j][k]!=0xffff && classes[j][k]!=i; ++k );
- if ( classes[j][k]==i ) {
- sm->state[off+i].next_state = j+2;
- if ( j==match_len-1 ) {
- sm->state[off+i].next_state = 0;
- sm->state[off+i].flags = 0x4000;
- if ( subspos==j )
- sm->state[off+i].u.context.cur_lookup = substag;
- else {
- sm->state[off+i].u.context.mark_lookup = substag;
- sm->state[off+i].u.context.cur_lookup = finaltag;
- }
- } else if ( subspos==j )
- sm->state[off+i].flags = 0x8000;
- } else if ( i==2 || ((fpst->subtable->lookup->lookup_flags&pst_ignorecombiningmarks) && i==class_cnt-1 ) )
- sm->state[off+i].next_state = j+1; /* Deleted glyph is a noop */
- else if ( j!=0 )
- 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 */
- }
- }
- /* Class 0 and class 1 should be the same. We only filled in class 1 above*/
- memcpy(sm->state,sm->state+sm->class_cnt,sm->class_cnt*sizeof(struct asm_state));
- for ( j=0; j<match_len; ++j )
- free(classes[j]);
- free(classes);
-return( sm );
-}
-
- /* ********************** From Class FPST ********************** */
-static void SMSetState(struct asm_state *trans,struct contexttree *cur,int class) {
- int i;
-
- for ( i=0; i<cur->branch_cnt; ++i ) {
- if ( cur->branches[i].classnum==class ) {
- trans->next_state = cur->branches[i].branch->state;
- /* If we go back to state 0, it means we want to start from */
- /* the begining again, and we should check against the */
- /* current glyph (which failed for us, but might be useful */
- /* to start a new operation). Even if we did not fail we */
- /* should still do this (so don't advance the glyph) */
- trans->flags = cur->branches[i].branch->state!=0
- ? cur->branches[i].branch->markme?0x8000:0x0000
- : cur->branches[i].branch->markme?0xc000:0x4000;
- trans->u.context.mark_lookup = cur->branches[i].branch->applymarkedsubs;
- trans->u.context.cur_lookup = cur->branches[i].branch->applycursubs;
-return;
- }
- }
-
- if ( cur->ends_here!=NULL ) {
- trans->next_state = 0;
- trans->flags = 0x4000;
- trans->u.context.mark_lookup = cur->applymarkedsubs;
- trans->u.context.cur_lookup = cur->applycursubs;
- } else
- trans->next_state = 0;
-}
-
-static struct asm_state *AnyActiveSubstrings(struct contexttree *tree,
- struct contexttree *cur,int class, struct asm_state *trans, int classcnt) {
- struct fpc *any = &cur->rules[0].rule->u.class;
- int i,rc,j, b;
-
- for ( i=1; i<=cur->depth; ++i ) {
- for ( rc=0; rc<tree->rule_cnt; ++rc ) {
- struct fpc *r = &tree->rules[rc].rule->u.class;
- int ok = true;
- for ( j=0; j<=cur->depth-i; ++j ) {
- if ( any->allclasses[j+i]!=r->allclasses[j] ) {
- ok = false;
- break;
- }
- }
- if ( ok && r->allclasses[j]==class ) {
- struct contexttree *sub = tree;
- for ( j=0; j<=cur->depth-i; ++j ) {
- for ( b=0; b<sub->branch_cnt; ++b ) {
- if ( sub->branches[b].classnum==r->allclasses[j] ) {
- sub = sub->branches[b].branch;
- break;
- }
- }
- }
- if ( trans[sub->state*classcnt+class+3].next_state!=0 &&
- (sub->pending_pos+i == cur->pending_pos ||
- sub->pending_pos == -1 ))
-return( &trans[sub->state*classcnt+class+3] );
- }
- }
- }
-return( NULL );
-}
-
-static int FailureTrans( struct asm_state *trans ) {
-return( trans->next_state==0 &&
- trans->u.context.mark_lookup==NULL &&
- trans->u.context.cur_lookup==NULL );
-}
-
-static ASM *ASMFromClassFPST(SplineFont *sf,FPST *fpst, struct contexttree *tree) {
- ASM *sm;
- struct contexttree *cur;
- int i;
-
- sm = chunkalloc(sizeof(ASM));
- sm->type = asm_context;
- sm->flags = (fpst->subtable->lookup->lookup_flags&pst_r2l) ? asm_descending : 0;
- /* mac class sets have four magic classes, opentype sets only have one */
- sm->class_cnt = (fpst->subtable->lookup->lookup_flags&pst_ignorecombiningmarks) ? fpst->nccnt+4 : fpst->nccnt+3;
- sm->classes = malloc(sm->class_cnt*sizeof(char *));
- sm->classes[0] = sm->classes[1] = sm->classes[2] = sm->classes[3] = NULL;
- for ( i=1; i<fpst->nccnt; ++i )
- sm->classes[i+3] = copy(fpst->nclass[i]);
- if ( fpst->subtable->lookup->lookup_flags&pst_ignorecombiningmarks )
- sm->classes[sm->class_cnt-1] = BuildMarkClass(sf);
-
- /* Now build the state machine */
- sm->state_cnt = tree->next_state;
- sm->state = calloc(sm->state_cnt*sm->class_cnt,sizeof(struct asm_state));
- for ( cur=tree; cur!=NULL; cur = TreeNext(cur)) if ( cur->state!=0 ) {
- int off = cur->state*sm->class_cnt;
-
- SMSetState(&sm->state[off+1],cur,0); /* Out of bounds state */
- sm->state[off+2].next_state = cur->state; /* Deleted glyph gets eaten and ignored */
- if ( fpst->subtable->lookup->lookup_flags&pst_ignorecombiningmarks )
- sm->state[off+sm->class_cnt-1].next_state = cur->state; /* As do ignored marks */
- for ( i=1; i<fpst->nccnt; ++i )
- SMSetState(&sm->state[off+i+3],cur,i);
- }
- /* Class 0 and class 1 should be the same. We only filled in class 1 above*/
- memcpy(sm->state,sm->state+sm->class_cnt,sm->class_cnt*sizeof(struct asm_state));
- /* Do a sort of transitive closure on states, so if we are looking for */
- /* either "abcd" or "bce", don't lose the "bce" inside "abce" */
- FPSTBuildAllClasses(fpst);
- for ( cur = tree; cur!=NULL; cur = TreeNext(cur)) if ( cur->state>1 ) {
- int off = cur->state*sm->class_cnt;
- for ( i=1; i<fpst->nccnt; ++i ) if ( FailureTrans(&sm->state[off+3+i]) ) {
- struct asm_state *trans =
- AnyActiveSubstrings(tree,cur,i, sm->state,sm->class_cnt);
- if ( trans!=NULL )
- sm->state[off+3+i] = *trans;
- }
- }
- FPSTFreeAllClasses(fpst);
-return( sm );
-}
-
-ASM *ASMFromFPST(SplineFont *sf,FPST *fpst,int ordered) {
- FPST *tempfpst=fpst;
- struct contexttree *tree=NULL;
- ASM *sm;
-
- if ( fpst->format==pst_glyphs )
- tempfpst = FPSTGlyphToClass( fpst );
- if ( tempfpst->format==pst_coverage )
- sm = ASMFromCoverageFPST(sf,fpst,ordered);
- else {
- tree = FPST2Tree(sf, tempfpst);
- if ( tree!=NULL ) {
- sm = ASMFromClassFPST(sf,tempfpst,tree);
- TreeFree(tree);
- } else
- sm = NULL;
- }
-
- if ( tempfpst!=fpst )
- FPSTFree(tempfpst);
- /* This is a temporary value. It should be replaced if we plan to */
- /* retain this state machine */
- if ( sm!=NULL )
- sm->subtable = fpst->subtable;
-return( sm );
-}