diff options
Diffstat (limited to 'Build/source/texk/web2c/luatexdir/luafontloader/fontforge/fontforge/parsettfatt.c')
-rw-r--r-- | Build/source/texk/web2c/luatexdir/luafontloader/fontforge/fontforge/parsettfatt.c | 1926 |
1 files changed, 24 insertions, 1902 deletions
diff --git a/Build/source/texk/web2c/luatexdir/luafontloader/fontforge/fontforge/parsettfatt.c b/Build/source/texk/web2c/luatexdir/luafontloader/fontforge/fontforge/parsettfatt.c index b6c45fe956f..97974e3baf5 100644 --- a/Build/source/texk/web2c/luatexdir/luafontloader/fontforge/fontforge/parsettfatt.c +++ b/Build/source/texk/web2c/luatexdir/luafontloader/fontforge/fontforge/parsettfatt.c @@ -31,7 +31,6 @@ #include <math.h> #include <locale.h> #include <stdlib.h> -#include <ggadget.h> /* For GTextInfo */ #include "ttf.h" static uint16 *getAppleClassTable(FILE *ttf, int classdef_offset, int cnt, int sub, int div, struct ttfinfo *info) { @@ -1770,6 +1769,7 @@ static struct { uint32 tag; char *str; } tagstr[] = { { 0, NULL } }; + static void gsubSimpleSubTable(FILE *ttf, int stoffset, struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable, int justinuse) { int coverage, cnt, i, j, which; @@ -2928,113 +2928,6 @@ return; info->g_bounds = 0; } -static void readttf_applelookup(FILE *ttf,struct ttfinfo *info, - void (*apply_values)(struct ttfinfo *info, int gfirst, int glast,FILE *ttf), - void (*apply_value)(struct ttfinfo *info, int gfirst, int glast,FILE *ttf), - void (*apply_default)(struct ttfinfo *info, int gfirst, int glast,void *def), - void *def, int allow_out_of_bounds) { - int format, i, first, last, data_off, cnt, prev; - uint32 here; - uint32 base = ftell(ttf); - - format = getushort(ttf); - switch ( format ) { - case 0: /* Simple array */ - apply_values(info,0,info->glyph_cnt-1,ttf); - break; - case 2: /* Segment Single */ - /* Entry size */ getushort(ttf); - cnt = getushort(ttf); - /* search range */ getushort(ttf); - /* log2(cnt) */ getushort(ttf); - /* range shift */ getushort(ttf); - prev = 0; - for ( i=0; i<cnt; ++i ) { - last = getushort(ttf); - first = getushort(ttf); - if ( last<first || last>=0xffff || - (!allow_out_of_bounds && last>=info->glyph_cnt )) { - LogError( _("Bad lookup table: format=2 (%d/%d), first=%d last=%d total glyphs in font=%d\n"), - i,cnt,first,last,info->glyph_cnt ); - info->bad_gx = true; - } else { - if ( apply_default!=NULL ) - apply_default(info,prev,first-1,def); - apply_value(info,first,last,ttf); - prev = last+1; - } - } - break; - case 4: /* Segment multiple */ - /* Entry size */ getushort(ttf); - cnt = getushort(ttf); - /* search range */ getushort(ttf); - /* log2(cnt) */ getushort(ttf); - /* range shift */ getushort(ttf); - prev = 0; - for ( i=0; i<cnt; ++i ) { - last = getushort(ttf); - first = getushort(ttf); - data_off = getushort(ttf); - if ( last<first || last>=0xffff || - (!allow_out_of_bounds && last>=info->glyph_cnt )) { - LogError( _("Bad lookup table: format=4 (%d/%d), first=%d last=%d total glyphs in font=%d\n"), - i,cnt,first,last,info->glyph_cnt ); - info->bad_gx = true; - } else { - here = ftell(ttf); - if ( apply_default!=NULL ) - apply_default(info,prev,first-1,def); - fseek(ttf,base+data_off,SEEK_SET); - apply_values(info,first,last,ttf); - fseek(ttf,here,SEEK_SET); - prev = last+1; - } - } - break; - case 6: /* Single table */ - /* Entry size */ getushort(ttf); - cnt = getushort(ttf); - /* search range */ getushort(ttf); - /* log2(cnt) */ getushort(ttf); - /* range shift */ getushort(ttf); - prev = 0; - for ( i=0; i<cnt; ++i ) { - first = getushort(ttf); - if ( first>=0xffff || (!allow_out_of_bounds && first>=info->glyph_cnt )) { - LogError( _("Bad lookup table: format=6, first=%d total glyphs in font=%d\n"), - first,info->glyph_cnt ); - info->bad_gx = true; - } else { - if ( apply_default!=NULL ) - apply_default(info,prev,first-1,def); - apply_value(info,first,first,ttf); - prev = first+1; - } - } - break; - case 8: /* Simple array */ - first = getushort(ttf); - cnt = getushort(ttf); - if ( first+cnt>=0xffff || (!allow_out_of_bounds && first+cnt>=info->glyph_cnt )) { - LogError( _("Bad lookup table: format=8, first=%d cnt=%d total glyphs in font=%d\n"), - first,cnt,info->glyph_cnt ); - info->bad_gx = true; - } else { - if ( apply_default!=NULL ) { - apply_default(info,0,first-1,def); - apply_default(info,first+cnt,info->glyph_cnt-1,def); - } - apply_values(info,first,first+cnt-1,ttf); - } - break; - default: - LogError( _("Invalid lookup table format. %d\n"), format ); - info->bad_gx = true; - break; - } -} - static void OTLAppend(struct ttfinfo *info,OTLookup *otl,int gpos) { OTLookup *prev; int pos=0; @@ -3069,1544 +2962,13 @@ static void OTLRemove(struct ttfinfo *info,OTLookup *otl,int gpos) { OTLookupFree(otl); } -static OTLookup *NewMacLookup(struct ttfinfo *info,int gpos) { - OTLookup *otl; - - otl = chunkalloc(sizeof(OTLookup)); - otl->lookup_type = gpos ? kern_statemachine : morx_context; - otl->subtables = chunkalloc(sizeof(struct lookup_subtable)); - otl->subtables->lookup = otl; - otl->features = chunkalloc(sizeof(FeatureScriptLangList)); - if ( gpos ) - otl->features->featuretag = CHR('k','e','r','n'); - else { - otl->features->featuretag = (info->mort_feat<<16) | (info->mort_setting); - otl->features->ismac = true; - } - OTLAppend(info,otl,gpos); -return( otl ); -} - -static OTLookup *NewMacSubsLookup(struct ttfinfo *info,OTLookup *parent, - int nest_index, OTLookup **subs) { - OTLookup *otl; - char *name, *format; - - if ( subs[nest_index]!=NULL ) -return( subs[nest_index] ); - - /* These are nested lookups, only to be activated by a state machine */ - /* as such they have no feature tags nor scripts of their own. */ - otl = chunkalloc(sizeof(OTLookup)); - otl->lookup_type = gsub_single; - otl->subtables = chunkalloc(sizeof(struct lookup_subtable)); - otl->subtables->lookup = otl; -/* GT: This is to give the name to a nested substitution lookup invoked by */ -/* GT: a statemachine. The %s is the name of the statemachine('s lookup) */ -/* GT: and the %d is n, where this lookup is the n'th defined for this state */ -/* GT: machine */ -#ifdef LUA_FF_LIB - format = _("%s_ns_%d"); -#else - format = _("%s nested-substitutions %d"); -#endif - name = galloc(strlen(parent->lookup_name)+strlen(format)+10); - sprintf( name, format, parent->lookup_name, nest_index ); - otl->lookup_name = name; -#ifdef LUA_FF_LIB - otl->subtables->subtable_name = strconcat(name,"_s"); -#else - otl->subtables->subtable_name = strconcat3(name," ",_("subtable")); -#endif - OTLAppend(info,otl,false); - subs[nest_index] = otl; -return( otl ); -} - static void InfoNameOTLookup(OTLookup *otl,struct ttfinfo *info) { SplineFont sf; memset(&sf,0,sizeof(sf)); - sf.features = info->features; NameOTLookup(otl,&sf); } -static void TTF_SetProp(struct ttfinfo *info,int gnum, int prop) { - int offset; - PST *pst; - - if ( gnum<0 || gnum>=info->glyph_cnt ) { - LogError( _("Glyph out of bounds in 'prop' table %d\n"), gnum ); - info->bad_gx = true; -return; - } - - if ( prop&0x1000 ) { /* Mirror */ - offset = (prop<<20)>>28; - if ( gnum+offset>=0 && gnum+offset<info->glyph_cnt && - info->chars[gnum+offset]->name!=NULL ) { - pst = chunkalloc(sizeof(PST)); - pst->type = pst_substitution; - pst->subtable = info->mort_subs_lookup->subtables; - FListAppendScriptLang(info->mort_subs_lookup->features,SCScriptFromUnicode(info->chars[gnum]), - DEFAULT_LANG); - pst->next = info->chars[gnum]->possub; - info->chars[gnum]->possub = pst; - pst->u.subs.variant = copy(info->chars[gnum+offset]->name); - } - } -} - -static void prop_apply_values(struct ttfinfo *info, int gfirst, int glast,FILE *ttf) { - int i; - - for ( i=gfirst; i<=glast; ++i ) - TTF_SetProp(info,i, getushort(ttf)); -} - -static void prop_apply_value(struct ttfinfo *info, int gfirst, int glast,FILE *ttf) { - int i; - int prop; - - prop = getushort(ttf); - for ( i=gfirst; i<=glast; ++i ) - TTF_SetProp(info,i, prop); -} - -static void prop_apply_default(struct ttfinfo *info, int gfirst, int glast,void *def) { - int def_prop, i; - - def_prop = (intpt) def; - for ( i=gfirst; i<=glast; ++i ) - TTF_SetProp(info,i, def_prop); -} - -void readttfprop(FILE *ttf,struct ttfinfo *info) { - int def; - - fseek(ttf,info->prop_start,SEEK_SET); - /* The one example that I've got has a wierd version, so I don't check it */ - /* the three versions that I know about are all pretty much the same, just a few extra flags */ - /* version = */ getlong(ttf); - /* format = */ getushort(ttf); - def = getushort(ttf); - info->mort_subs_lookup = NewMacLookup(info,false); - info->mort_subs_lookup->lookup_type = gsub_single; - info->mort_subs_lookup->features->featuretag = CHR('r','t','l','a'); - info->mort_subs_lookup->features->ismac = false; - info->mort_subs_lookup->subtables->per_glyph_pst_or_kern = true; - readttf_applelookup(ttf,info, - prop_apply_values,prop_apply_value, - prop_apply_default,(void *) (intpt) def, false); - InfoNameOTLookup(info->mort_subs_lookup,info); -} - -static void TTF_SetLcaret(struct ttfinfo *info, int gnum, int offset, FILE *ttf) { - uint32 here = ftell(ttf); - PST *pst; - SplineChar *sc; - int cnt, i; - - if ( gnum<0 || gnum>=info->glyph_cnt ) { - LogError( _("Glyph out of bounds in 'lcar' table %d\n"), gnum ); - info->bad_gx = true; -return; - } else if ( (sc=info->chars[gnum])==NULL ) -return; - - fseek(ttf,info->lcar_start+offset,SEEK_SET); - cnt = getushort(ttf); - pst = chunkalloc(sizeof(PST)); - pst->type = pst_lcaret; - pst->subtable = NULL; - pst->next = sc->possub; - sc->possub = pst; - sc->lig_caret_cnt_fixed = true; - pst->u.lcaret.cnt = cnt; - pst->u.lcaret.carets = galloc(cnt*sizeof(uint16)); - for ( i=0; i<cnt; ++i ) - pst->u.lcaret.carets[i] = getushort(ttf); - fseek(ttf,here,SEEK_SET); -} - -static void lcar_apply_values(struct ttfinfo *info, int gfirst, int glast,FILE *ttf) { - int i; - - for ( i=gfirst; i<=glast; ++i ) - TTF_SetLcaret(info,i, getushort(ttf), ttf); -} - -static void lcar_apply_value(struct ttfinfo *info, int gfirst, int glast,FILE *ttf) { - int i; - int offset; - - offset = getushort(ttf); - for ( i=gfirst; i<=glast; ++i ) - TTF_SetLcaret(info,i, offset, ttf); -} - -void readttflcar(FILE *ttf,struct ttfinfo *info) { - - fseek(ttf,info->lcar_start,SEEK_SET); - /* version = */ getlong(ttf); - if ( getushort(ttf)!=0 ) /* A format type of 1 has the caret locations */ -return; /* indicated by points */ - readttf_applelookup(ttf,info, - lcar_apply_values,lcar_apply_value,NULL,NULL,false); -} - -static void TTF_SetOpticalBounds(struct ttfinfo *info, int gnum, int left, int right) { - PST *pst; - SplineChar *sc; - - if ( left==0 && right==0 ) -return; - - if ( gnum<0 || gnum>=info->glyph_cnt ) { - LogError( _("Glyph out of bounds in 'opbd' table %d\n"), gnum ); - info->bad_gx = true; -return; - } else if ( (sc=info->chars[gnum])==NULL ) -return; - - if ( left!=0 ) { - pst = chunkalloc(sizeof(PST)); - pst->type = pst_position; - pst->subtable = info->mort_subs_lookup->subtables; - FListAppendScriptLang(info->mort_subs_lookup->features,SCScriptFromUnicode(sc), - DEFAULT_LANG); - pst->next = sc->possub; - sc->possub = pst; - pst->u.pos.xoff = left; - pst->u.pos.h_adv_off = left; - } - if ( right!=0 ) { - pst = chunkalloc(sizeof(PST)); - pst->type = pst_position; - pst->subtable = info->mort_pos_lookup2->subtables; - FListAppendScriptLang(info->mort_pos_lookup2->features,SCScriptFromUnicode(sc), - DEFAULT_LANG); - pst->next = sc->possub; - sc->possub = pst; - pst->u.pos.h_adv_off = -right; - } -} - -static void opbd_apply_values(struct ttfinfo *info, int gfirst, int glast,FILE *ttf) { - int i, left, right, offset; - uint32 here; - - for ( i=gfirst; i<=glast; ++i ) { - offset = getushort(ttf); - here = ftell(ttf); - fseek(ttf,info->opbd_start+6/*opbd header*/+offset,SEEK_SET); - left = (int16) getushort(ttf); - /* top = (int16) */ getushort(ttf); - right = (int16) getushort(ttf); - /* bottom = (int16) */ getushort(ttf); - fseek(ttf,here,SEEK_SET); - TTF_SetOpticalBounds(info,i, left, right); - } -} - -static void opbd_apply_value(struct ttfinfo *info, int gfirst, int glast,FILE *ttf) { - int i, left, right, offset; - uint32 here; - - offset = getushort(ttf); - here = ftell(ttf); - fseek(ttf,info->opbd_start+offset,SEEK_SET); - left = (int16) getushort(ttf); - /* top = (int16) */ getushort(ttf); - right = (int16) getushort(ttf); - /* bottom = (int16) */ getushort(ttf); - fseek(ttf,here,SEEK_SET); - - for ( i=gfirst; i<=glast; ++i ) - TTF_SetOpticalBounds(info,i, left, right); -} - -void readttfopbd(FILE *ttf,struct ttfinfo *info) { - - fseek(ttf,info->opbd_start,SEEK_SET); - /* version = */ getlong(ttf); - if ( getushort(ttf)!=0 ) /* A format type of 1 has the bounds */ -return; /* indicated by points */ - info->mort_subs_lookup = NewMacLookup(info,true); - info->mort_subs_lookup->lookup_type = gpos_single; - info->mort_subs_lookup->features->featuretag = CHR('l','f','b','d'); - info->mort_subs_lookup->features->ismac = false; - info->mort_subs_lookup->subtables->per_glyph_pst_or_kern = true; - - info->mort_pos_lookup2 = NewMacLookup(info,true); - info->mort_pos_lookup2->lookup_type = gpos_single; - info->mort_pos_lookup2->features->featuretag = CHR('r','t','b','d'); - info->mort_pos_lookup2->features->ismac = false; - info->mort_pos_lookup2->subtables->per_glyph_pst_or_kern = true; - - readttf_applelookup(ttf,info, - opbd_apply_values,opbd_apply_value,NULL,NULL,false); - InfoNameOTLookup(info->mort_subs_lookup,info); - InfoNameOTLookup(info->mort_pos_lookup2,info); -} - -/* Interesting. The mac allows the creation of temporary gids beyond the */ -/* range specified by the font, as long as the user never sees them. So */ -/* it seems perfectly legal for one substitution to use a gid of 1111 */ -/* if that gid never reaches output but will be converted into a real gid */ -/* by a subsequent substitution. I saw this used in a conditional situation */ -/* to provide a temporary context for a later match. */ -static SplineChar *CreateBadGid(struct ttfinfo *info,int badgid) { - int i; - SplineChar *fake; - char name[60]; - - if ( badgid<0 || badgid>=0xffff ) /* <0 should never happen, 0xffff is the special "deleted" glyph, >0xffff should never happen */ -return( NULL ); - - for ( i=0; i<info->badgid_cnt; ++i ) - if ( info->badgids[i]->orig_pos == badgid ) -return( info->badgids[i] ); - - if ( info->badgid_cnt>=info->badgid_max ) - info->badgids = grealloc(info->badgids,(info->badgid_max += 20)*sizeof(SplineChar *)); - fake = SplineCharCreate(2); - fake->orig_pos = badgid; - sprintf( name, "Out-Of-Range-GID-%d", badgid ); - fake->name = copy(name); - fake->widthset = true; /* So it doesn't just vanish on us */ - fake->width = fake->vwidth = info->emsize; - info->badgids[info->badgid_cnt++] = fake; -return( fake ); -} - -static void TTF_SetMortSubs(struct ttfinfo *info, int gnum, int gsubs) { - PST *pst; - SplineChar *sc, *ssc; - - if ( gsubs==0 ) -return; - - if ( gnum<0 || gnum>=info->glyph_cnt ) { - if ( !info->warned_morx_out_of_bounds_glyph ) { - LogError( _("Glyph out of bounds in 'mort'/'morx' table %d\n"), gnum ); - info->bad_gx = true; - info->warned_morx_out_of_bounds_glyph = true; - } - sc = CreateBadGid(info,gnum); - } else - sc = info->chars[gnum]; - ssc = NULL; - if ( gsubs<0 || (gsubs>=info->glyph_cnt && gsubs!=0xffff)) { - if ( !info->warned_morx_out_of_bounds_glyph ) { - LogError( _("Substitute glyph out of bounds in 'mort'/'morx' table %d\n"), gsubs ); - info->bad_gx = true; - info->warned_morx_out_of_bounds_glyph = true; - } - ssc = CreateBadGid(info,gsubs); - } else if ( gsubs!=0xffff ) - ssc=info->chars[gsubs]; - if ( sc==NULL || (gsubs!=0xffff && ssc==NULL) ) -return; - - pst = chunkalloc(sizeof(PST)); - pst->type = pst_substitution; - pst->subtable = info->mort_subs_lookup->subtables; - if ( info->mort_subs_lookup->features!=NULL ) - FListsAppendScriptLang(info->mort_subs_lookup->features,SCScriptFromUnicode(sc), - DEFAULT_LANG); - pst->next = sc->possub; - sc->possub = pst; - pst->u.subs.variant = gsubs!=0xffff ? copy(ssc->name) : copy(MAC_DELETED_GLYPH_NAME); -} - -static void mort_apply_values(struct ttfinfo *info, int gfirst, int glast,FILE *ttf) { - uint16 gnum; - int i; - - for ( i=gfirst; i<=glast; ++i ) { - gnum = getushort(ttf); - TTF_SetMortSubs(info,i, gnum); - } -} - -static void mort_apply_value(struct ttfinfo *info, int gfirst, int glast,FILE *ttf) { - uint16 gnum; - int i; - - gnum = getushort(ttf); - - for ( i=gfirst; i<=glast; ++i ) - TTF_SetMortSubs(info,i, gnum ); -} - -static void mortclass_apply_values(struct ttfinfo *info, int gfirst, int glast,FILE *ttf) { - int i; - - for ( i=gfirst; i<=glast; ++i ) - info->morx_classes[i] = getushort(ttf); -} - -static void mortclass_apply_value(struct ttfinfo *info, int gfirst, int glast,FILE *ttf) { - uint16 class; - int i; - - class = getushort(ttf); - - for ( i=gfirst; i<=glast; ++i ) - info->morx_classes[i] = class; -} - -int32 memlong(uint8 *data,int len, int offset) { - if ( offset>=0 && offset+3<len ) { - int ch1 = data[offset], ch2 = data[offset+1], ch3 = data[offset+2], ch4 = data[offset+3]; -return( (ch1<<24)|(ch2<<16)|(ch3<<8)|ch4 ); - } else { - LogError( _("Bad font, offset out of bounds.\n") ); -return( 0 ); - } -} - -int memushort(uint8 *data,int len, int offset) { - if ( offset>=0 && offset+1<len ) { - int ch1 = data[offset], ch2 = data[offset+1]; -return( (ch1<<8)|ch2 ); - } else { - LogError( _("Bad font, offset out of bounds.\n") ); -return( 0 ); - } -} - -void memputshort(uint8 *data,int offset,uint16 val) { - data[offset] = (val>>8); - data[offset+1] = val&0xff; -} - -#define MAX_LIG_COMP 16 -struct statemachine { - uint8 *data; - int length; - uint32 nClasses; - uint32 classOffset, stateOffset, entryOffset, ligActOff, compOff, ligOff; - uint16 *classes; - uint16 lig_comp_classes[MAX_LIG_COMP]; - uint16 lig_comp_glyphs[MAX_LIG_COMP]; - int lcp; - uint8 *states_in_use; - int smax; - struct ttfinfo *info; - int cnt; -}; - -static void mort_figure_ligatures(struct statemachine *sm, int lcp, int off, int32 lig_offset, - struct ttfinfo *info) { - uint32 lig; - int i, j, lig_glyph; - PST *pst; - int len; - - if ( lcp<0 || off+3>sm->length ) -return; - - lig = memlong(sm->data,sm->length, off); - off += sizeof(int32); - - for ( i=0; i<sm->info->glyph_cnt; ++i ) if ( sm->classes[i]==sm->lig_comp_classes[lcp] ) { - sm->lig_comp_glyphs[lcp] = i; - lig_offset += memushort(sm->data,sm->length,2*( ((((int32) lig)<<2)>>2) + i ) ); - if ( lig&0xc0000000 ) { - if ( lig_offset+1 > sm->length ) { - LogError( _("Invalid ligature offset\n") ); - info->bad_gx = true; - break; - } - lig_glyph = memushort(sm->data,sm->length,lig_offset); - if ( lig_glyph>=sm->info->glyph_cnt ) { - LogError( _("Attempt to make a ligature for glyph %d out of "), - lig_glyph ); - for ( j=lcp; j<sm->lcp; ++j ) - LogError("%d ",sm->lig_comp_glyphs[j]); - LogError("\n"); - info->bad_gx = true; - } else { - char *comp; - for ( len=0, j=lcp; j<sm->lcp; ++j ) - if ( sm->lig_comp_glyphs[j]<sm->info->glyph_cnt && - sm->info->chars[sm->lig_comp_glyphs[j]]!=NULL ) - len += strlen(sm->info->chars[sm->lig_comp_glyphs[j]]->name)+1; - comp = galloc(len+1); - *comp = '\0'; - for ( j=lcp; j<sm->lcp; ++j ) { - if ( sm->lig_comp_glyphs[j]<sm->info->glyph_cnt && - sm->info->chars[sm->lig_comp_glyphs[j]]!=NULL ) { - if ( *comp!='\0' ) - strcat(comp," "); - strcat(comp,sm->info->chars[sm->lig_comp_glyphs[j]]->name); - } - } - if ( lig_glyph<sm->info->glyph_cnt && sm->info->chars[lig_glyph]!=NULL ) { - for ( pst=sm->info->chars[lig_glyph]->possub; pst!=NULL; pst=pst->next ) - if ( pst->type==pst_ligature && pst->subtable==sm->info->mort_subs_lookup->subtables && - strcmp(comp,pst->u.lig.components)==0 ) - break; - /* There are cases where there will be multiple entries for */ - /* the same lig. ie. if we have "ff" and "ffl" then there */ - /* will be multiple entries for "ff" */ - if ( pst == NULL ) { - pst = chunkalloc(sizeof(PST)); - pst->type = pst_ligature; - pst->subtable = sm->info->mort_subs_lookup->subtables; - if ( sm->info->mort_subs_lookup->features!=NULL ) - FListsAppendScriptLang(sm->info->mort_subs_lookup->features, - SCScriptFromUnicode(sm->info->chars[lig_glyph]), - DEFAULT_LANG); - pst->u.lig.components = comp; - pst->u.lig.lig = sm->info->chars[lig_glyph]; - pst->next = sm->info->chars[lig_glyph]->possub; - sm->info->chars[lig_glyph]->possub = pst; - } else - free(comp); - } else { - LogError( _("Bad font: Ligature glyph %d is missing\n"), lig_glyph ); - info->bad_gx = true; - } - } - } else - mort_figure_ligatures(sm,lcp-1,off,lig_offset,info); - lig_offset -= memushort(sm->data,sm->length,2*( ((((int32) lig)<<2)>>2) + i ) ); - } -} - -static void follow_mort_state(struct statemachine *sm,int offset,int class, - struct ttfinfo *info) { - int state = (offset-sm->stateOffset)/sm->nClasses; - int class_top, class_bottom; - - if ( state<0 || state>=sm->smax || sm->states_in_use[state] || sm->lcp>=MAX_LIG_COMP ) -return; - ++ sm->cnt; - if ( sm->cnt>=10000 ) { - if ( sm->cnt==10000 ) -/* GT: This is a reference to "Much Ado About Nothing". The string should read */ -/* GT: "A ligature sub-table in Apple's 'mort'/'morx' table is too\ncomplex for me to understand. I shall give up on it.\nYour ligatures may not be complete." */ - LogError(_("In an attempt to process the ligatures of this font, I've concluded\nthat the state machine in Apple's mort/morx table is\n(like the learned constable) too cunning to be understood.\nI shall give up on it. Your ligatures may be incomplete.\n") ); - info->bad_gx = true; -return; - } - sm->states_in_use[state] = true; - - if ( class==-1 ) { class_bottom = 0; class_top = sm->nClasses; } - else { class_bottom = class; class_top = class+1; } - for ( class=class_bottom; class<class_top; ++class ) { - int ent = sm->data[offset+class]; - int newState = memushort(sm->data,sm->length,sm->entryOffset+4*ent); - int flags = memushort(sm->data,sm->length,sm->entryOffset+4*ent+2); - /* If we have the same entry as state 0, then presumably we are */ - /* ignoring the components read so far and starting over with a new */ - /* lig (similarly for state 1) */ - if (( state!=0 && sm->data[sm->stateOffset+class] == ent ) || - (state>1 && sm->data[sm->stateOffset+sm->nClasses+class]==ent )) - continue; - if ( flags&0x8000 ) /* Set component */ - sm->lig_comp_classes[sm->lcp++] = class; - if ( flags&0x3fff ) { - mort_figure_ligatures(sm, sm->lcp-1, flags & 0x3fff, 0,info); - } else if ( flags&0x8000 ) - follow_mort_state(sm,newState,(flags&0x4000)?class:-1,info); - if ( flags&0x8000 ) - --sm->lcp; - } - sm->states_in_use[state] = false; -} - -static void morx_figure_ligatures(struct statemachine *sm, int lcp, int ligindex, int32 lig_offset, - struct ttfinfo *info) { - uint32 lig; - int i, j, lig_glyph; - PST *pst; - int len; - - if ( lcp<0 || sm->ligActOff+4*ligindex+3>(unsigned)sm->length ) -return; - - lig = memlong(sm->data,sm->length, sm->ligActOff+4*ligindex); - ++ligindex; - - for ( i=0; i<sm->info->glyph_cnt; ++i ) if ( sm->classes[i]==sm->lig_comp_classes[lcp] ) { - sm->lig_comp_glyphs[lcp] = i; - lig_offset += memushort(sm->data,sm->length,sm->compOff + 2*( ((((int32) lig)<<2)>>2) + i ) ); - if ( lig&0xc0000000 ) { - if ( sm->ligOff+2*lig_offset+1 > (unsigned)sm->length ) { - LogError( _("Invalid ligature offset\n") ); - info->bad_gx = true; - break; - } - lig_glyph = memushort(sm->data,sm->length,sm->ligOff+2*lig_offset); - if ( lig_glyph>=sm->info->glyph_cnt || sm->info->chars[lig_glyph]==NULL ) { - LogError( _("Attempt to make a ligature for (non-existent) glyph %d out of "), - lig_glyph ); - info->bad_gx = true; - for ( j=lcp; j<sm->lcp; ++j ) - LogError("%d ",sm->lig_comp_glyphs[j]); - LogError("\n"); - } else { - char *comp; - for ( len=0, j=lcp; j<sm->lcp; ++j ) - len += strlen(sm->info->chars[sm->lig_comp_glyphs[j]]->name)+1; - comp = galloc(len); - *comp = '\0'; - for ( j=lcp; j<sm->lcp; ++j ) { - if ( *comp!='\0' ) - strcat(comp," "); - strcat(comp,sm->info->chars[sm->lig_comp_glyphs[j]]->name); - } - for ( pst=sm->info->chars[lig_glyph]->possub; pst!=NULL; pst=pst->next ) - if ( pst->type==pst_ligature && pst->subtable==sm->info->mort_subs_lookup->subtables && - strcmp(comp,pst->u.lig.components)==0 ) - break; - /* There are cases where there will be multiple entries for */ - /* the same lig. ie. if we have "ff" and "ffl" then there */ - /* will be multiple entries for "ff" */ - if ( pst == NULL ) { - pst = chunkalloc(sizeof(PST)); - pst->type = pst_ligature; - pst->subtable = sm->info->mort_subs_lookup->subtables; - if ( sm->info->mort_subs_lookup->features!=NULL ) - FListsAppendScriptLang(sm->info->mort_subs_lookup->features, - SCScriptFromUnicode(sm->info->chars[lig_glyph]), - DEFAULT_LANG); - pst->u.lig.components = comp; - pst->u.lig.lig = sm->info->chars[lig_glyph]; - pst->next = sm->info->chars[lig_glyph]->possub; - sm->info->chars[lig_glyph]->possub = pst; - } else - free(comp); - } - } else - morx_figure_ligatures(sm,lcp-1,ligindex,lig_offset,info); - lig_offset -= memushort(sm->data,sm->length,sm->compOff + 2*( ((((int32) lig)<<2)>>2) + i ) ); - } -} - -static void follow_morx_state(struct statemachine *sm,int state,int class, - struct ttfinfo *info) { - int class_top, class_bottom; - - if ( state<0 || state>=sm->smax || sm->states_in_use[state] || sm->lcp>=MAX_LIG_COMP ) -return; - ++ sm->cnt; - if ( sm->cnt>=10000 ) { - if ( sm->cnt==10000 ) - LogError(_("In an attempt to process the ligatures of this font, I've concluded\nthat the state machine in Apple's mort/morx table is\n(like the learned constable) too cunning to be understood.\nI shall give up on it. Your ligatures may be incomplete.\n") ); - info->bad_gx = true; -return; - } - sm->states_in_use[state] = true; - - if ( class==-1 ) { class_bottom = 0; class_top = sm->nClasses; } - else { class_bottom = class; class_top = class+1; } - for ( class=class_bottom; class<class_top; ++class ) { - int ent = memushort(sm->data, sm->length,sm->stateOffset + 2*(state*sm->nClasses+class) ); - int newState = memushort(sm->data,sm->length,sm->entryOffset+6*ent); - int flags = memushort(sm->data,sm->length,sm->entryOffset+6*ent+2); - int ligindex = memushort(sm->data,sm->length,sm->entryOffset+6*ent+4); - /* If we have the same entry as state 0, then presumably we are */ - /* ignoring the components read so far and starting over with a new */ - /* lig (similarly for state 1) */ - if (( state!=0 && memushort(sm->data, sm->length,sm->stateOffset + 2*class) == ent ) || - (state>1 && memushort(sm->data,sm->length, sm->stateOffset + 2*(sm->nClasses+class))==ent )) - continue; - if ( flags&0x8000 ) /* Set component */ - sm->lig_comp_classes[sm->lcp++] = class; - if ( flags&0x2000 ) { - morx_figure_ligatures(sm, sm->lcp-1, ligindex, 0,info); - } else if ( flags&0x8000 ) - follow_morx_state(sm,newState,(flags&0x4000)?class:-1,info); - if ( flags&0x8000 ) - --sm->lcp; - } - sm->states_in_use[state] = false; -} - -static void readttf_mortx_lig(FILE *ttf,struct ttfinfo *info,int ismorx,uint32 base,uint32 length) { - uint32 here; - struct statemachine sm; - int first, cnt, i; - - memset(&sm,0,sizeof(sm)); - sm.info = info; - here = ftell(ttf); - length -= here-base; - sm.data = galloc(length); - sm.length = length; - if ( fread(sm.data,1,length,ttf)!=length ) { - free(sm.data); - LogError( _("Bad mort ligature table. Not long enough\n")); - info->bad_gx = true; -return; - } - fseek(ttf,here,SEEK_SET); - if ( ismorx ) { - sm.nClasses = memlong(sm.data,sm.length, 0); - sm.classOffset = memlong(sm.data,sm.length, sizeof(int32)); - sm.stateOffset = memlong(sm.data,sm.length, 2*sizeof(int32)); - sm.entryOffset = memlong(sm.data,sm.length, 3*sizeof(int32)); - sm.ligActOff = memlong(sm.data,sm.length, 4*sizeof(int32)); - sm.compOff = memlong(sm.data,sm.length, 5*sizeof(int32)); - sm.ligOff = memlong(sm.data,sm.length, 6*sizeof(int32)); - fseek(ttf,here+sm.classOffset,SEEK_SET); - /* I used only to allocate space for info->glyph_cnt entries */ - /* but some fonts use out of bounds gids as flags to contextual */ - /* morx subtables, so allocate a full 65536 */ - sm.classes = info->morx_classes = galloc(65536*sizeof(uint16)); - for ( i=0; i<65536; ++i ) - sm.classes[i] = 1; /* Out of bounds */ - readttf_applelookup(ttf,info, - mortclass_apply_values,mortclass_apply_value,NULL,NULL,true); - sm.smax = length/(2*sm.nClasses); - sm.states_in_use = gcalloc(sm.smax,sizeof(uint8)); - follow_morx_state(&sm,0,-1,info); - } else { - sm.nClasses = memushort(sm.data,sm.length, 0); - sm.classOffset = memushort(sm.data,sm.length, sizeof(uint16)); - sm.stateOffset = memushort(sm.data,sm.length, 2*sizeof(uint16)); - sm.entryOffset = memushort(sm.data,sm.length, 3*sizeof(uint16)); - sm.ligActOff = memushort(sm.data,sm.length, 4*sizeof(uint16)); - sm.compOff = memushort(sm.data,sm.length, 5*sizeof(uint16)); - sm.ligOff = memushort(sm.data,sm.length, 6*sizeof(uint16)); - sm.classes = galloc(info->glyph_cnt*sizeof(uint16)); - for ( i=0; i<info->glyph_cnt; ++i ) - sm.classes[i] = 1; /* Out of bounds */ - first = memushort(sm.data,sm.length, sm.classOffset); - cnt = memushort(sm.data,sm.length, sm.classOffset+sizeof(uint16)); - for ( i=0; i<cnt; ++i ) - sm.classes[first+i] = sm.data[sm.classOffset+2*sizeof(uint16)+i]; - sm.smax = length/sm.nClasses; - sm.states_in_use = gcalloc(sm.smax,sizeof(uint8)); - follow_mort_state(&sm,sm.stateOffset,-1,info); - } - free(sm.data); - free(sm.states_in_use); - free(sm.classes); -} - -struct statetable { - uint32 state_start; - int nclasses; - int nstates; - int nentries; - int state_offset; - int entry_size; /* size of individual entry */ - int entry_extras; /* Number of extra glyph offsets */ - int first_glyph; /* that's classifyable */ - int nglyphs; - uint8 *classes; - uint8 *state_table; /* state_table[nstates][nclasses], each entry is an */ - /* index into the following array */ - uint16 *state_table2; /* morx version. States are have 2 byte entries */ - uint16 *classes2; - uint8 *transitions; - uint32 extra_offsets[3]; -}; - -static struct statetable *read_statetable(FILE *ttf, int ent_extras, int ismorx, struct ttfinfo *info) { - struct statetable *st = gcalloc(1,sizeof(struct statetable)); - uint32 here = ftell(ttf); - int nclasses, class_off, state_off, entry_off; - int state_max, ent_max, old_state_max, old_ent_max; - int i, j, ent, new_state, ent_size; - int error; - - st->state_start = here; - - if ( ismorx ) { - nclasses = getlong(ttf); - class_off = getlong(ttf); - state_off = getlong(ttf); - entry_off = getlong(ttf); - st->extra_offsets[0] = getlong(ttf); - st->extra_offsets[1] = getlong(ttf); - st->extra_offsets[2] = getlong(ttf); - } else { - nclasses = getushort(ttf); /* Number of bytes per state in state subtable, equal to number of classes */ - class_off = getushort(ttf); - state_off = getushort(ttf); - entry_off = getushort(ttf); - st->extra_offsets[0] = getushort(ttf); - st->extra_offsets[1] = getushort(ttf); - st->extra_offsets[2] = getushort(ttf); - } - st->nclasses = nclasses; - st->state_offset = state_off; - - /* parse class subtable */ - fseek(ttf,here+class_off,SEEK_SET); - error = 0; - if ( ismorx ) { - /* I used only to allocate space for info->glyph_cnt entries */ - /* but some fonts use out of bounds gids as flags to contextual */ - /* morx subtables, so allocate a full 65536 */ - st->classes2 = info->morx_classes = galloc(65536*sizeof(uint16)); - for ( i=0; i<65536; ++i ) - st->classes2[i] = 1; /* Out of bounds */ - readttf_applelookup(ttf,info, - mortclass_apply_values,mortclass_apply_value,NULL,NULL,true); - for ( i=0; i<65536; ++i ) { - if ( /*st->classes2[i]<0 ||*/ st->classes2[i]>=st->nclasses ) { - if ( !error ) - LogError( _("Bad class in state machine.\n" )); - info->bad_gx = true; - error = true; - st->classes2[i] = 1; /* Out of bounds */ - } - } - } else { - st->first_glyph = getushort(ttf); - st->nglyphs = getushort(ttf); - if ( feof(ttf)) { - LogError(_("Bad glyph count in mort table.\n")); - info->bad_gx = true; - st->nglyphs = 0; - } - st->classes = galloc(st->nglyphs); - fread(st->classes,1,st->nglyphs,ttf); - for ( i=0; i<st->nglyphs; ++i ) { - if ( /*st->classes[i]<0 ||*/ st->classes[i]>=st->nclasses ) { - if ( !error ) - LogError( _("Bad class in state machine.\n" )); - info->bad_gx = true; - error = true; - st->classes[i] = 1; /* Out of bounds */ - } - } - } - - - /* The size of an entry is variable. There are 2 uint16 fields at the begin-*/ - /* ning of all entries. There may be some number of shorts following these*/ - /* used for indexing special tables. */ - ent_size = 4 + 2*ent_extras; - st->entry_size = ent_size; - st->entry_extras = ent_extras; - - /* Apple does not provide a way of figuring out the size of either of the */ - /* state or entry tables, so we must parse both as we go and try to work */ - /* out the maximum values... */ - /* There are always at least 2 states defined. Parse them and find what */ - /* is the biggest entry they use, then parse those entries and find what */ - /* is the biggest state they use, and then repeat until we don't find any*/ - /* more states or entries */ - old_state_max = 0; old_ent_max = 0; - state_max = 2; ent_max = 0; - while ( old_state_max!=state_max ) { - i = old_state_max*nclasses; - fseek(ttf,here+state_off+(ismorx?(int)(i*sizeof(uint16)):i),SEEK_SET); - old_state_max = state_max; - for ( ; i<state_max*nclasses; ++i ) { - ent = ismorx ? getushort(ttf) : getc(ttf); - if ( ent+1 > ent_max ) - ent_max = ent+1; - } - if ( ent_max==old_ent_max ) /* Nothing more */ - break; - if ( ent_max>1000 ) { - LogError( _("It looks to me as though there's a morx sub-table with more than 1000\n transitions. Which makes me think there's probably an error\n" )); - info->bad_gx = true; - free(st); -return( NULL ); - } - fseek(ttf,here+entry_off+old_ent_max*ent_size,SEEK_SET); - i = old_ent_max; - old_ent_max = ent_max; - for ( ; i<ent_max; ++i ) { - new_state = getushort(ttf); - if ( !ismorx ) - new_state = (new_state-state_off)/nclasses; - /* flags = */ getushort(ttf); - for ( j=0; j<ent_extras; ++j ) - /* glyphOffsets[j] = */ getushort(ttf); - if ( new_state+1>state_max ) - state_max = new_state+1; - } - if ( state_max>1000 ) { - LogError( _("It looks to me as though there's a morx sub-table with more than 1000\n states. Which makes me think there's probably an error\n" )); - info->bad_gx = true; - free(st); -return( NULL ); - } - } - - st->nstates = state_max; - st->nentries = ent_max; - - fseek(ttf,here+state_off,SEEK_SET); - /* an array of arrays of state transitions, each represented by one byte */ - /* which is an index into the Entry subtable, which comes next. */ - /* One dimension is the number of states, and the other the */ - /* number of classes (classes vary faster than states) */ - /* The first two states are predefined, 0 is start of text, 1 start of line*/ - if ( ismorx ) { - st->state_table2 = galloc(st->nstates*st->nclasses*sizeof(uint16)); - for ( i=0; i<st->nstates*st->nclasses; ++i ) - st->state_table2[i] = getushort(ttf); - } else { - st->state_table = galloc(st->nstates*st->nclasses); - fread(st->state_table,1,st->nstates*st->nclasses,ttf); - } - - /* parse the entry subtable */ - fseek(ttf,here+entry_off,SEEK_SET); - st->transitions = galloc(st->nentries*st->entry_size); - fread(st->transitions,1,st->nentries*st->entry_size,ttf); -return( st ); -} - -static void statetablefree(struct statetable *st) { - free( st->classes ); - free( st->state_table ); - free( st->classes2 ); - free( st->state_table2 ); - free( st->transitions ); - free( st ); -} - -static void tagSMWithScriptLang(FeatureScriptLangList *fl, - struct statetable *st,int ismorx,struct ttfinfo *info) { - int i; - - if ( ismorx ) { - for ( i=0; i<info->glyph_cnt; ++i ) - if ( st->classes2[i]>=4 && info->chars[i]!=NULL ) - FListsAppendScriptLang(fl,SCScriptFromUnicode(info->chars[i]), - DEFAULT_LANG); - } else { - for ( i=st->first_glyph; i<st->first_glyph+st->nglyphs && i<info->glyph_cnt; ++i ) - if ( info->chars[i]!=NULL ) - FListsAppendScriptLang(fl,SCScriptFromUnicode(info->chars[i]), - DEFAULT_LANG); - } -} - -static char **ClassesFromStateTable(struct statetable *st,int ismorx,struct ttfinfo *info) { - /* On the mac the first four classes should be left blank. only class 1 */ - /* (out of bounds) is supposed to be used in the class array anyway */ - char **classes = galloc(st->nclasses*sizeof(char *)); - int *lens = gcalloc(st->nclasses,sizeof(int)); - int i; - - - if ( ismorx ) { - for ( i=0; i<info->glyph_cnt; ++i ) if ( info->chars[i]!=NULL ) - lens[st->classes2[i]] += strlen( info->chars[i]->name )+1; - if ( info->badgids!=NULL ) - for ( i=0; i<info->badgid_cnt; ++i ) if ( info->badgids[i]!=NULL ) - lens[st->classes2[info->badgids[i]->orig_pos]] += strlen( info->badgids[i]->name )+1; - } else { - for ( i=st->first_glyph; i<st->first_glyph+st->nglyphs && i<info->glyph_cnt; ++i ) - if ( info->chars[i]!=NULL ) - lens[st->classes[i-st->first_glyph]] += strlen( info->chars[i]->name )+1; - } - classes[0] = classes[1] = classes[2] = classes[3] = NULL; - for ( i=4; i<st->nclasses; ++i ) { - classes[i] = galloc(lens[i]+1); - *classes[i] = '\0'; - } - if ( ismorx ) { - for ( i=0; i<info->glyph_cnt; ++i ) if ( st->classes2[i]>=4 && info->chars[i]!=NULL ) { - strcat(classes[st->classes2[i]],info->chars[i]->name ); - strcat(classes[st->classes2[i]]," "); - } - if ( info->badgids!=NULL ) - for ( i=0; i<info->badgid_cnt; ++i ) if ( info->badgids[i]!=NULL && st->classes2[info->badgids[i]->orig_pos]>=4) { - strcat(classes[st->classes2[info->badgids[i]->orig_pos]],info->badgids[i]->name ); - strcat(classes[st->classes2[info->badgids[i]->orig_pos]]," "); - } - } else { - for ( i=st->first_glyph; i<st->first_glyph+st->nglyphs && i<info->glyph_cnt; ++i ) if ( st->classes[i-st->first_glyph]>=4 && info->chars[i]!=NULL ) { - strcat(classes[st->classes[i-st->first_glyph]],info->chars[i]->name ); - strcat(classes[st->classes[i-st->first_glyph]]," " ); - } - } - for ( i=4; i<st->nclasses; ++i ) { - int len = strlen(classes[i]); - if ( len!=0 ) - classes[i][len-1] = '\0'; /* Remove trailing space */ - } - free(lens); -return( classes ); -} - -static char *NamesOfList(uint32 pos,int cnt, FILE *ttf, struct ttfinfo *info) { - int i, len, glyph; - char *str; - - if ( cnt==0 ) -return(NULL); - - fseek(ttf,pos,SEEK_SET); - for ( i=len=0; i<cnt; ++i ) { - glyph = getushort(ttf); - if ( glyph<info->glyph_cnt ) - len += strlen(info->chars[glyph]->name)+1; - } - if ( len==0 ) -return( NULL ); - str = galloc(len+1); - fseek(ttf,pos,SEEK_SET); - for ( i=len=0; i<cnt; ++i ) { - glyph = getushort(ttf); - if ( glyph<info->glyph_cnt ) { - strcpy(str+len,info->chars[glyph]->name); - len += strlen(info->chars[glyph]->name); - str[len++] = ' '; - } - } - str[len-1] = '\0'; -return( str ); -} - -#if 0 -static void RunStateFindKernDepth_(ASM *as,int state,int kdepth,uint8 *used) { - int j, kd; - - if ( used[state] ) -return; - used[state] = true; - - for ( j=0; j<as->class_cnt; ++j ) { - kd = kdepth; - flags = as->state[state*as->class_cnt+j]; - if ( flags&0x8000 ) - ++kd; - if ( (flags&0x3fff)!=0 ) { - as->state[state*as->class_cnt+j].u.kern.kcnt = kd; - kd = 0; - } - RunStateFindKernDepth_(as,as->state[state*as->class_cnt+j].next_state,kd,used); - } -} - -static void RunStateFindKernDepth(ASM *as) { - uint8 *used = gcalloc(as->class_cnt); - int i; - - for ( i=0; i<as->class_cnt*as->state_cnt; ++i ) { - as->state[i].u.kern.kerns = NULL; - as->state[i].u.kern.kcnt = (as->state[i].flags&0x3fff)==0 ? 0 : -1; - } - RunStateFindKernDepth_(as,0,0,used); - RunStateFindKernDepth_(as,1,0,used); -} -#endif - -static void KernReadKernList(FILE *ttf,uint32 pos, struct asm_state *trans) { -/* Apple does not document how to detect the end of the list */ -/* They say "an odd value that depends on coverage" */ -/* They should say "an odd value". Any odd value terminates the list. */ -/* coverage is irrelevant */ -/* Note: List is backwards (glyphs are popped of LIFO so last glyph on */ -/* in stack gets first kern value) */ -/* There are at most 8 glyphs */ - int i,j,k; - int16 buffer[8]; /* At most 8 kerns are supported */ - - fseek(ttf,pos,SEEK_SET); - for ( i=0; i<8; ++i ) { - buffer[i]=(int16) getushort(ttf); - if ( buffer[i]&1 ) { - buffer[i] &= ~1; - ++i; - break; - } - } - if ( i==0 ) { - trans->u.kern.kerns = NULL; - } else { - trans->u.kern.kerns = galloc(i*sizeof(int16)); - for ( j=i-1, k=0; k<i; ++k, --j ) - trans->u.kern.kerns[k] = buffer[j]; - } - trans->u.kern.kcnt = i; -} - -static void read_perglyph_subs(FILE *ttf,struct ttfinfo *info, - int subs_base,int subs_end,struct statetable *st, - uint8 *classes_subbed, int evermarked, uint8 *used) { - /* The file is positioned at the start of a per-glyph substitution table */ - /* Sadly great chunks of this table have been omitted. We are where glyph */ - /* 0 would be if it were present. We've no idea what has been omitted */ - /* Simple checks: if the file pointer is outside of the area devoted to */ - /* substitutions then we know it is ignorable. */ - /* If the current glyph is not in the list of glyphs which could ever */ - /* be substituted then we know it is ignorable. */ - /* Note: the above list is easily figured for substitutions on the current*/ - /* glyph, but if a substitution ever happens to a marked glyph then we */ - /* can't guess. We could check for all classes that get marked, but that*/ - /* doesn't work if there is a current substitution before the class is */ - /* marked, after that we don't know what class the glyph might have */ - /* Instead, for marked subs, we keep track of all locations which were */ - /* used in a current-only sub, and assume that they aren't valid for us */ - /* If the putative substitution glyph is not a valid glyph then we know */ - /* it is ignorable */ - int i, subs, was = info->mort_tag_mac; - uint32 here; - - info->mort_tag_mac = false; - for ( i=0; i<info->glyph_cnt; ++i ) { - here = ftell(ttf); - subs = getushort(ttf); - if ( subs>=info->glyph_cnt && subs!=0xffff ) /* 0xffff means delete the substituted glyph */ - continue; - if ( subs==0 ) /* A little risky, one could substitute notdef */ - continue; /* but they shouldn't */ - if ( here<(unsigned)subs_base ) - continue; - if ( here>=(unsigned)subs_end ) - break; - if ( evermarked ) { - if ( used[(here-subs_base)/2] ) - continue; - } else if ( i<st->first_glyph || i>=st->first_glyph+st->nglyphs ) { - if ( !classes_subbed[1]) { /* Out of bounds class */ - if ( i>=st->first_glyph+st->nglyphs ) - break; - continue; - } - } else { - if ( !classes_subbed[st->classes[i-st->first_glyph]] ) - continue; - } - - if ( !evermarked ) - used[(here-subs_base)/2] = true; - TTF_SetMortSubs(info, i, subs); - } - info->mort_tag_mac = was; -} - -static int sm_lookupfind(int32 *lookups,int *_lm,int off) { - int lm = *_lm, i; - for ( i=0; i<=lm; ++i ) - if ( lookups[i]==off ) -return( i ); - (*_lm)++; - lookups[i] = off; -return( i ); -} - -static ASM *readttf_mortx_asm(FILE *ttf,struct ttfinfo *info,int ismorx, - uint32 subtab_len,enum asm_type type,int extras, - uint32 coverage, OTLookup *otl) { - struct statetable *st; - ASM *as; - int i,j; - uint32 here = ftell(ttf); - - st = read_statetable(ttf,extras,ismorx,info); - if ( st==NULL ) -return(NULL); - - as = chunkalloc(sizeof(ASM)); - as->type = type; - as->flags = coverage>>16; - as->class_cnt = st->nclasses; - as->state_cnt = st->nstates; - as->classes = ClassesFromStateTable(st,ismorx,info); - as->state = galloc(st->nclasses*st->nstates*sizeof(struct asm_state)); - if ( otl==NULL ) - otl = NewMacLookup(info,false); - otl->lookup_type = type==asm_indic ? morx_indic : type==asm_context ? morx_context : morx_insert; - as->subtable = otl->subtables; otl->subtables->sm = as; - tagSMWithScriptLang(otl->features,st,ismorx,info); - InfoNameOTLookup(otl,info); - for ( i=0; i<st->nclasses*st->nstates; ++i ) { - int trans; - if ( ismorx ) { - trans = st->state_table2[i]; - as->state[i].next_state = memushort(st->transitions,st->nentries*st->entry_size,trans*st->entry_size); - } else { - trans = st->state_table[i]; - as->state[i].next_state = (memushort(st->transitions,st->nentries*st->entry_size,trans*st->entry_size)-st->state_offset)/st->nclasses; - } - as->state[i].flags = memushort(st->transitions,st->nentries*st->entry_size,trans*st->entry_size+2); - if ( extras>0 ) - as->state[i].u.context.mark_lookup = (void *) (intpt) memushort(st->transitions,st->nentries*st->entry_size, trans*st->entry_size+2+2); - if ( extras>1 ) - as->state[i].u.context.cur_lookup = (void *) (intpt) memushort(st->transitions,st->nentries*st->entry_size, trans*st->entry_size+2+2+2); - } - /* Indic tables have no attached subtables, just a verb in the flag field */ - /* so for them we are done. For the others... */ - if ( !ismorx && type==asm_insert ) { - for ( i=0; i<st->nclasses*st->nstates; ++i ) { - char *cur=NULL, *mark=NULL; - if ( (as->state[i].flags&0x3e0)!=0 && as->state[i].u.context.mark_lookup!=NULL ) { - cur = NamesOfList(here+(intpt) as->state[i].u.context.mark_lookup, - (as->state[i].flags&0x3e0)>>5,ttf,info); - } - if ( (as->state[i].flags&0x01f)!=0 && as->state[i].u.context.cur_lookup!=NULL ) { - mark = NamesOfList(here+(intpt) as->state[i].u.context.cur_lookup, - as->state[i].flags&0x01f,ttf,info); - } - as->state[i].u.insert.cur_ins=cur; - as->state[i].u.insert.mark_ins=mark; - } - } else if ( ismorx && type == asm_insert ) { - for ( i=0; i<st->nclasses*st->nstates; ++i ) { - char *cur=NULL, *mark=NULL; - if ( (as->state[i].flags&0x3e0)!=0 && (intpt) as->state[i].u.context.mark_lookup!=0xffff ) { - cur = NamesOfList(here+st->extra_offsets[0]+((intpt) as->state[i].u.context.mark_lookup)*2, - (as->state[i].flags&0x3e0)>>5,ttf,info); - } - if ( (as->state[i].flags&0x01f)!=0 && ((intpt) as->state[i].u.context.cur_lookup)!=0xffff ) { - mark = NamesOfList(here+st->extra_offsets[0]+((intpt) as->state[i].u.context.cur_lookup)*2, - as->state[i].flags&0x01f,ttf,info); - } - as->state[i].u.insert.cur_ins=cur; - as->state[i].u.insert.mark_ins=mark; - } - } else if ( !ismorx && type == asm_context ) { - /* I don't see any good way to parse a per-glyph substitution table */ - /* the problem being that most of the per-glyph table is missing */ - /* but I don't know which bits. The offsets I'm given point to */ - /* where glyph 0 would be if it were present in the table, but */ - /* mostly only the bit used is present... */ - /* I could walk though the state machine and find all classes that */ - /* go to a specific substitution (which would tell me what glyphs */ - /* were active). That's not hard for substitutions of the current */ - /* glyph, but it is intractibable for marked glyphs. And I can't */ - /* do one without the other. So I do neither. */ - /* One thing I could test fairly easily would be to see whether */ - /* class 1 (out of bounds) is ever available for a substitution */ - /* (if it ever has a mark set on it or has a current substitution)*/ - /* if not, then I can ignore any putative substitutions for class */ - /* 1 glyphs (actually I should do this for all classes)*/ - /* Damn. That doesn't work for marks. Because a current substitution*/ - /* may be applied, and then the glyph gets marked. So we've no idea*/ - /* what class the newly marked glyph might live in */ - /* Apple's docs say the substitutions are offset from the "state */ - /* subtable", but it seems much more likely that they are offset */ - /* from the substitution table (given that Apple's docs are often */ - /* wrong */ /* Apple's docs are right. not clear why that offset */ - /* is there */ - uint8 *classes_subbed = gcalloc(st->nclasses,1); - int lookup_max = -1, index, index_max; - int32 *lookups = galloc(st->nclasses*st->nstates*sizeof(int32)); - uint8 *evermarked = gcalloc(st->nclasses*st->nstates,sizeof(uint8)); - uint8 *used; - OTLookup **subs; - - index_max = 0; - for ( i=0; i<st->nclasses*st->nstates; ++i ) { - if ( as->state[i].u.context.mark_lookup!=NULL ) { - index = sm_lookupfind(lookups,&lookup_max,(int16) (intpt) as->state[i].u.context.mark_lookup); - if ( index>index_max ) index_max = index; - } - if ( as->state[i].u.context.cur_lookup!=NULL ) { - index = sm_lookupfind(lookups,&lookup_max,(int16) (intpt) as->state[i].u.context.cur_lookup); - if ( index>index_max ) index_max = index; - } - } - subs = gcalloc(index_max+1,sizeof(OTLookup *)); - - for ( i=0; i<st->nclasses*st->nstates; ++i ) { - if ( as->state[i].u.context.mark_lookup!=NULL ) { - index = sm_lookupfind(lookups,&lookup_max,(int16) (intpt) as->state[i].u.context.mark_lookup); - evermarked[index] = true; - as->state[i].u.context.mark_lookup = NewMacSubsLookup(info,otl,index,subs); - } - if ( as->state[i].u.context.cur_lookup!=NULL ) { - index = sm_lookupfind(lookups,&lookup_max,(int16) (intpt) as->state[i].u.context.cur_lookup); - as->state[i].u.context.cur_lookup = NewMacSubsLookup(info,otl,index,subs); - } - } - used = gcalloc((subtab_len-st->extra_offsets[0]+1)/2,sizeof(uint8)); - /* first figure things that only appear in current subs */ - /* then go back and work on things that apply to things which are also in marked subs */ - for ( j=0; j<2; ++j ) for ( i=0; i<=lookup_max; ++i ) if ( evermarked[i]==j ) { - info->mort_subs_lookup = NewMacSubsLookup(info,otl,i,subs); - info->mort_is_nested = true; - if ( !evermarked[i] ) { int k,l; - memset(classes_subbed,0,st->nclasses); - for ( k=0; k<st->nstates; ++k ) for ( l=0; l<st->nclasses; ++l ) { - if ( as->state[k*st->nclasses+l].u.context.cur_lookup == info->mort_subs_lookup ) - classes_subbed[l] = true; - } - } - fseek(ttf,here/*+st->extra_offsets[0]*/+lookups[i]*2,SEEK_SET); - read_perglyph_subs(ttf,info,here+st->extra_offsets[0],here+subtab_len, - st,classes_subbed,evermarked[i],used); - } - info->mort_is_nested = false; - free(classes_subbed); - free(lookups); - free(used); - free(evermarked); - free(subs); - } else if ( ismorx && type == asm_context ) { - int lookup_max= -1; - uint32 *lookups; - OTLookup **subs; - - for ( i=0; i<st->nclasses*st->nstates; ++i ) { - if ( (intpt) as->state[i].u.context.mark_lookup!=0xffff ) { - if ( ((int) (intpt) as->state[i].u.context.mark_lookup)>lookup_max ) - lookup_max = (intpt) as->state[i].u.context.mark_lookup; - } - if ( (intpt) as->state[i].u.context.cur_lookup!=0xffff ) { - if ( ((int) (intpt) as->state[i].u.context.cur_lookup)>lookup_max ) - lookup_max = (intpt) as->state[i].u.context.cur_lookup; - } - } - ++lookup_max; - subs = gcalloc(lookup_max,sizeof(OTLookup *)); - for ( i=0; i<st->nclasses*st->nstates; ++i ) { - if ( (intpt) as->state[i].u.context.mark_lookup!=0xffff ) { - as->state[i].u.context.mark_lookup = NewMacSubsLookup(info,otl,(intpt) as->state[i].u.context.mark_lookup,subs); - } else - as->state[i].u.context.mark_lookup = NULL; - if ( (intpt) as->state[i].u.context.cur_lookup!=0xffff ) { - as->state[i].u.context.cur_lookup = NewMacSubsLookup(info,otl,(intpt) as->state[i].u.context.cur_lookup,subs); - } else - as->state[i].u.context.cur_lookup = NULL; - } - lookups = galloc(lookup_max*sizeof(uint32)); - fseek(ttf,here+st->extra_offsets[0],SEEK_SET); - for ( i=0; i<lookup_max; ++i ) - lookups[i] = getlong(ttf) + here+st->extra_offsets[0]; - for ( i=0; i<lookup_max; ++i ) { - fseek(ttf,lookups[i],SEEK_SET); - info->mort_subs_lookup = NewMacSubsLookup(info,otl,i,subs); - info->mort_is_nested = true; - readttf_applelookup(ttf,info, - mort_apply_values,mort_apply_value,NULL,NULL,true); - } - info->mort_is_nested = false; - free(subs); - free(lookups); - } else if ( type == asm_kern ) { - for ( i=0; i<st->nclasses*st->nstates; ++i ) { - if ( (as->state[i].flags&0x3fff)!=0 ) { - KernReadKernList(ttf,here+(as->state[i].flags&0x3fff), - &as->state[i]); - as->state[i].flags &= ~0x3fff; - } else { - as->state[i].u.kern.kcnt = 0; - as->state[i].u.kern.kerns = NULL; - } - } - } - as->next = info->sm; - info->sm = as; - statetablefree(st); -return( as ); -} - -static int InfoHasGSUBTag(struct ttfinfo *info, uint32 tag, int apple_lookup_type) { - OTLookup *otl; - FeatureScriptLangList *feat; - - if ( apple_lookup_type==0 || /* Indic rearrangement */ - apple_lookup_type==1 || /* Contextual substitution */ - apple_lookup_type==5 ) /* Contextual insertion */ -return( false ); /* These types can either not be represented in OT */ - /* or not converted to AAT -- so we'd better read them */ - /* We can't really do contextual ligatures either, but we parse that table*/ - /* for the non-contextual ligs (which is most of them) */ - - for ( otl = info->gsub_lookups; otl!=NULL; otl=otl->next ) { - for ( feat = otl->features; feat!=NULL; feat=feat->next ) { - if ( feat->featuretag == tag && - Macable(NULL,otl)) -return( true ); - } - } -return( false ); -} - -static void FeatMarkAsEnabled(struct ttfinfo *info,int featureType, - int featureSetting); - -static uint32 readmortchain(FILE *ttf,struct ttfinfo *info, uint32 base, int ismorx) { - uint32 chain_len, nfeatures, nsubtables, default_flags; - uint32 enable_flags, disable_flags, flags; - int featureType, featureSetting; - int i,j,k; - uint32 length, coverage; - uint32 here; - uint32 tag; - struct tagmaskfeature { uint32 tag, enable_flags; uint16 ismac, feat, set; } tmf[32]; - int r2l; - (void)base; /* for -Wall */ - default_flags = getlong(ttf); - chain_len = getlong(ttf); - if ( ismorx ) { - nfeatures = getlong(ttf); - nsubtables = getlong(ttf); - } else { - nfeatures = getushort(ttf); - nsubtables = getushort(ttf); - } - - k = 0; - for ( i=0; i<(int)nfeatures; ++i ) { - featureType = getushort(ttf); - featureSetting = getushort(ttf); - enable_flags = getlong(ttf); - disable_flags = getlong(ttf); - if ( feof(ttf)) -return( chain_len ); - if ( enable_flags & default_flags ) - FeatMarkAsEnabled(info,featureType,featureSetting); - tag = MacFeatureToOTTag(featureType,featureSetting); - if ( enable_flags!=0 && k<32 ) { - if ( tag==0 ) { - tmf[k].tag = (featureType<<16) | featureSetting; - tmf[k].ismac = true; - } else { - tmf[k].tag = tag; - tmf[k].ismac = false; - } - tmf[k].feat = featureType; - tmf[k].set = featureSetting; - tmf[k++].enable_flags = enable_flags; - } - } - if ( k==0 ) -return( chain_len ); - - for ( i=0; i<(int)nsubtables; ++i ) { - here = ftell(ttf); - if ( ismorx ) { - length = getlong(ttf); - coverage = getlong(ttf); - } else { - length = getushort(ttf); - coverage = getushort(ttf); - coverage = ((coverage&0xe000)<<16) | (coverage&7); /* convert to morx format */ - } - r2l = (coverage & 0x40000000)? 1 : 0; - flags = getlong(ttf); - for ( j=k-1; j>=0 && (!(flags&tmf[j].enable_flags) || (tmf[j].enable_flags&~flags)!=0); --j ); - if ( j==-1 ) - for ( j=k-1; j>=0 && (!(flags&tmf[j].enable_flags) || tmf[j].feat==0); --j ); - if ( j>=0 ) { - if ( !tmf[j].ismac && - ((coverage&0xff)==0 || - (coverage&0xff)==1 || - (coverage&0xff)==5 )) { - /* Only do the opentype tag conversion if we've got a format */ - /* we can convert to opentype. Otherwise it is useless and */ - /* confusing */ - tmf[j].ismac = true; - tmf[j].tag = (tmf[j].feat<<16) | tmf[j].set; - } - info->mort_r2l = r2l; - info->mort_tag_mac = tmf[j].ismac; - info->mort_feat = tmf[j].feat; info->mort_setting = tmf[j].set; - /* If we've already read gsub. And this feature setting matches */ - /* and opentype feature tag. And we've got an OpenType lookup */ - /* attached to that feature tag. And it's a lookup type we can */ - /* convert... Then don't parse this sub-table, we shall assume */ - /* it is simply a duplicate of the OT version */ - if ( info->gsub_start!=0 && - (tag = MacFeatureToOTTag(tmf[j].feat,tmf[j].set))!=0 && - InfoHasGSUBTag(info,tag,coverage&0xff)) - /* Skip it */; - else switch( coverage&0xff ) { - case 0: /* Indic rearangement */ - readttf_mortx_asm(ttf,info,ismorx,length,asm_indic,0, - coverage,NULL); - break; - case 1: /* contextual glyph substitution */ - readttf_mortx_asm(ttf,info,ismorx,length,asm_context,2, - coverage,NULL); - break; - case 2: /* ligature substitution */ - /* Apple's ligature state machines are too weird to be */ - /* represented easily, but I can parse them into a set */ - /* of ligatures -- assuming they are unconditional */ - info->mort_subs_lookup = NewMacLookup(info,false); - info->mort_subs_lookup->lookup_type = gsub_ligature; - if ( !tmf[j].ismac ) { - info->mort_subs_lookup->features->next = chunkalloc(sizeof(FeatureScriptLangList)); - info->mort_subs_lookup->features->next->featuretag = tmf[j].tag; - info->mort_subs_lookup->features->next->ismac = false; - } - info->mort_subs_lookup->subtables->per_glyph_pst_or_kern = true; - readttf_mortx_lig(ttf,info,ismorx,here,length); - InfoNameOTLookup(info->mort_subs_lookup,info); - /* We can give the lookup a better name after we've made a */ - /* guess at what scripts it involves => substitutions first */ - break; - case 4: /* non-contextual glyph substitutions */ - info->mort_subs_lookup = NewMacLookup(info,false); - info->mort_subs_lookup->lookup_type = gsub_single; - if ( !tmf[j].ismac ) { - info->mort_subs_lookup->features->next = chunkalloc(sizeof(FeatureScriptLangList)); - info->mort_subs_lookup->features->next->featuretag = tmf[j].tag; - info->mort_subs_lookup->features->next->ismac = false; - } - info->mort_subs_lookup->subtables->per_glyph_pst_or_kern = true; - readttf_applelookup(ttf,info, - mort_apply_values,mort_apply_value,NULL,NULL,true); - InfoNameOTLookup(info->mort_subs_lookup,info); - break; - case 5: /* contextual glyph insertion */ - readttf_mortx_asm(ttf,info,ismorx,length,asm_insert,2, - coverage,NULL); - break; - } - } - fseek(ttf, here+length, SEEK_SET ); - } - -return( chain_len ); -} - -void readttfmort(FILE *ttf,struct ttfinfo *info) { - uint32 base = info->morx_start!=0 ? info->morx_start : info->mort_start; - uint32 here, len; - int ismorx; - int32 version; - int i, nchains; - - fseek(ttf,base,SEEK_SET); - version = getlong(ttf); - ismorx = version == 0x00020000; - if ( version!=0x00010000 && version != 0x00020000 ) -return; - nchains = getlong(ttf); - if ( feof(ttf)) { - LogError( _("Unexpected end of file found in morx chain.\n" )); - info->bad_gx = true; -return; - } - info->mort_max = nchains*33; /* Maximum of one feature per bit ? */ - for ( i=0; i<nchains; ++i ) { - here = ftell(ttf); - len = readmortchain(ttf,info,base,ismorx); - if ( feof(ttf)) { - LogError( _("Unexpected end of file found in morx chain.\n")); - info->bad_gx = true; - break; - } - fseek(ttf,here+len,SEEK_SET); - } - /* Some Apple fonts use out of range gids as flags in conditional substitutions */ - /* generally to pass information from one sub-table to another which then */ - /* removes the flag */ - if ( info->badgid_cnt!=0 ) { - /* Merge the fake glyphs in with the real ones */ - info->chars = grealloc(info->chars,(info->glyph_cnt+info->badgid_cnt)*sizeof(SplineChar *)); - for ( i=0; i<info->badgid_cnt; ++i ) { - info->chars[info->glyph_cnt+i] = info->badgids[i]; - info->badgids[i]->orig_pos = info->glyph_cnt+i; - } - info->glyph_cnt += info->badgid_cnt; - free(info->badgids); - } -} - /* Apple's docs imply that kerning info is always provided left to right, even*/ /* for right to left scripts. My guess is that their docs are wrong, as they */ /* often are, but if that be so then we need code in here to reverse */ @@ -4620,63 +2982,46 @@ void readttfkerns(FILE *ttf,struct ttfinfo *info) { KernClass *kc; uint32 begin_table; uint16 *class1, *class2; - int tupleIndex; int isv; - SplineChar **chars; OTLookup *otl; fseek(ttf,info->kern_start,SEEK_SET); version = getushort(ttf); tabcnt = getushort(ttf); if ( version!=0 ) { - fseek(ttf,info->kern_start,SEEK_SET); - version = getlong(ttf); - tabcnt = getlong(ttf); + LogError(_("Invalid or unsupported version (0x%x) for 'kern' table"), version ); + info->bad_gx = true; +return; } for ( tab=0; tab<tabcnt; ++tab ) { begin_table = ftell(ttf); - if ( version==0 ) { - /* version = */ getushort(ttf); - len = getushort(ttf); - coverage = getushort(ttf); - format = coverage>>8; - flags_good = ((coverage&7)<=1); - isv = !(coverage&1); - tupleIndex = -1; - header_size = 6; - } else { - len = getlong(ttf); - coverage = getushort(ttf); - /* Apple has reordered the bits */ - format = (coverage&0xff); - flags_good = ((coverage&0xdf00)==0 || (coverage&0xdf00)==0x8000); - isv = coverage&0x8000? 1 : 0; - tupleIndex = getushort(ttf); - if ( coverage&0x2000 ) { - if ( info->variations==NULL ) - flags_good = false; /* Ignore if we failed to load the tuple data */ - else if ( tupleIndex>=info->variations->tuple_count ) - flags_good = false; /* Bad tuple */ - } else - tupleIndex = -1; - header_size = 8; - } + /* version = */ getushort(ttf); + len = getushort(ttf); + coverage = getushort(ttf); + format = coverage>>8; + flags_good = ((coverage&7)<=1); + isv = !(coverage&1); + header_size = 6; otl = NULL; if ( flags_good ) { - otl = NewMacLookup(info,true); + otl = chunkalloc(sizeof(OTLookup)); otl->lookup_type = gpos_pair; - if ( isv ) { - otl->features->featuretag = CHR('v','k','r','n'); - otl->features->ismac = false; - } + otl->subtables = chunkalloc(sizeof(struct lookup_subtable)); + otl->subtables->lookup = otl; otl->subtables->per_glyph_pst_or_kern = true; otl->subtables->vertical_kerning = isv; + otl->features = chunkalloc(sizeof(FeatureScriptLangList)); + if (isv) + otl->features->featuretag = CHR('v','k','r','n'); + else + otl->features->featuretag = CHR('k','e','r','n'); + OTLAppend(info,otl,true); } if ( flags_good && format==0 ) { /* format 0, horizontal kerning data (as pairs) not perpendicular */ - chars = tupleIndex==-1 ? info->chars : info->variations->tuples[tupleIndex].chars; + SplineChar **chars = info->chars; npairs = getushort(ttf); - if ( version==0 && (len-14 != 6*npairs || npairs>10920 )) { + if ( len-14 != 6*npairs || npairs>10920 ) { LogError( _("In the 'kern' table, a subtable's length does not match the number of kerning pairs.") ); info->bad_gx = true; } @@ -4720,32 +3065,15 @@ void readttfkerns(FILE *ttf,struct ttfinfo *info) { } } InfoNameOTLookup(otl,info); - } else if ( flags_good && format==1 ) { - /* format 1 is an apple state machine which can handle weird cases */ - /* OpenType's spec doesn't document this */ - /* Apple's docs are wrong about this table, they claim */ - /* there is a special value which marks the end of the kerning */ - /* lists. In fact there is no such value, the list is as long */ - /* as there are things on the kern stack */ - otl->lookup_type = kern_statemachine; - readttf_mortx_asm(ttf,info,false,len-header_size,asm_kern,0, - isv ? 0x80000000 : 0 /* coverage doesn't really apply */,otl); - fseek(ttf,begin_table+len,SEEK_SET); } else if ( flags_good && (format==2 || format==3 )) { /* two class based formats */ KernClass **khead, **klast; - if ( isv && tupleIndex==-1 ) { + if ( isv ) { khead = &info->vkhead; klast = &info->vklast; - } else if ( tupleIndex==-1 ) { + } else { khead = &info->khead; klast = &info->klast; - } else if ( isv ) { - khead = &info->variations->tuples[tupleIndex].vkhead; - klast = &info->variations->tuples[tupleIndex].vklast; - } else { - khead = &info->variations->tuples[tupleIndex].khead; - klast = &info->variations->tuples[tupleIndex].klast; } if ( *khead==NULL ) *khead = kc = chunkalloc(sizeof(KernClass)); @@ -4826,92 +3154,6 @@ void readttfkerns(FILE *ttf,struct ttfinfo *info) { } } -void readmacfeaturemap(FILE *ttf,struct ttfinfo *info) { - MacFeat *last=NULL, *cur; - struct macsetting *slast, *scur; - struct fs { int n; int off; } *fs; - int featcnt, i, j, flags; - - fseek(ttf,info->feat_start,SEEK_SET); - /* version =*/ getfixed(ttf); - featcnt = getushort(ttf); - /* reserved */ getushort(ttf); - /* reserved */ getlong(ttf); - if ( feof(ttf)) { - LogError( _("End of file in feat table.\n" )); - info->bad_gx = true; -return; - } - - fs = galloc(featcnt*sizeof(struct fs)); - for ( i=0; i<featcnt; ++i ) { - cur = chunkalloc(sizeof(MacFeat)); - if ( last==NULL ) - info->features = cur; - else - last->next = cur; - last = cur; - - cur->feature = getushort(ttf); - fs[i].n = getushort(ttf); - fs[i].off = getlong(ttf); - flags = getushort(ttf); - cur->strid = getushort(ttf); - if ( flags&0x8000 ) cur->ismutex = true; - if ( flags&0x4000 ) - cur->default_setting = flags&0xff; - if ( feof(ttf)) { - free(fs); - LogError( _("End of file in feat table.\n" )); - info->bad_gx = true; -return; - } - } - - for ( i=0, cur=info->features; i<featcnt; ++i, cur = cur->next ) { - fseek(ttf,info->feat_start+fs[i].off,SEEK_SET); - slast = NULL; - for ( j=0; j<fs[i].n; ++j ) { - scur = chunkalloc(sizeof(struct macsetting)); - if ( slast==NULL ) - cur->settings = scur; - else - slast->next = scur; - slast = scur; - - scur->setting = getushort(ttf); - scur->strid = getushort(ttf); - if ( feof(ttf)) { - free(fs); - LogError( _("End of file in feat table.\n") ); - info->bad_gx = true; -return; - } - } - } - free(fs); -} - -static void FeatMarkAsEnabled(struct ttfinfo *info,int featureType, - int featureSetting) { - MacFeat *f; - struct macsetting *s; - - for ( f = info->features; f!=NULL && f->feature!=featureType; f=f->next ); - if ( f==NULL ) -return; - if ( f->ismutex ) { - for ( s=f->settings ; s!=NULL; s=s->next ) - s->initially_enabled = ( s->setting==featureSetting ); - f->default_setting = featureSetting; - } else { - for ( s=f->settings ; s!=NULL && s->setting!=featureSetting; s=s->next ); - if ( s!=NULL ) - s->initially_enabled = true; - } -return; -} - /******************************************************************************/ /* ******************************* MATH Table ******************************* */ /* ********************** (Not strictly OpenType yet) *********************** */ @@ -5486,123 +3728,3 @@ return; } } } - -static void bsln_apply_values(struct ttfinfo *info, int gfirst, int glast,FILE *ttf) { - int i; - - for ( i=gfirst; i<=glast; ++i ) - info->bsln_values[i]= getushort(ttf); -} - -static void bsln_apply_value(struct ttfinfo *info, int gfirst, int glast,FILE *ttf) { - int i; - int bsln; - - bsln = getushort(ttf); - for ( i=gfirst; i<=glast; ++i ) - info->bsln_values[i]= bsln; -} - -static void bsln_apply_default(struct ttfinfo *info, int gfirst, int glast,void *def) { - int def_bsln, i; - - def_bsln = (intpt) def; - for ( i=gfirst; i<=glast; ++i ) - info->bsln_values[i]= def_bsln; -} - -void readttfbsln(FILE *ttf,struct ttfinfo *info) { - int def, ap_def, version, format; - uint16 *values; - int offsets[32]; - SplineChar *sc; - BasePoint pos; - int mapping[32]; - int i; - struct Base *base; - struct basescript *bs; - - fseek(ttf,info->bsln_start,SEEK_SET); - version = getlong(ttf); - if ( version!=0x00010000 ) -return; - format = getushort(ttf); - def = getushort(ttf); - if ( format==0 || format==1 ) { - for ( i=0; i<32; ++i ) - offsets[i] = (int16) getushort(ttf); - } else if ( format==2 || format==3 ) { - int stdGID = getushort(ttf); - int ptnum; - if ( stdGID>=info->glyph_cnt || (sc = info->chars[stdGID])==NULL ) -return; - for ( i=0; i<32; ++i ) { - ptnum = getushort(ttf); - if ( ttfFindPointInSC(sc,ly_fore,ptnum,&pos,NULL)!=-1 ) -return; - offsets[i] = pos.y; - } - } - - if ( format&1 ) { - info->bsln_values = values = gcalloc(info->glyph_cnt,sizeof(uint16)); - readttf_applelookup(ttf,info, - bsln_apply_values,bsln_apply_value, - bsln_apply_default,(void *) (intpt) def, false); - } else - values = NULL; - - for ( i=1; i<32; ++i ) mapping[i] = 3; /* Roman */ - - info->horiz_base = base = chunkalloc(sizeof(struct Base)); - base->baseline_cnt = 4; - base->baseline_tags = galloc(4*sizeof(uint32)); - base->baseline_tags[0] = CHR('h','a','n','g'); /* Apple 3 */ - if ( offsets[1]!= offsets[2] ) { - base->baseline_tags[1] = CHR('i','d','e','o'); /* Apple 2 */ - base->baseline_tags[2] = CHR('m','a','t','h'); /* Apple 4 */ - base->baseline_tags[3] = CHR('r','o','m','n'); /* Apple 0 */ - - /* Map from Apple's baseline indeces, to OT tag positions */ - mapping[3] = 0; - mapping[2] = 1; - mapping[4] = 2; - mapping[0] = 3; - /* Apple baseline 1 does not map to an OT tag */ - /* I assume baseline 1 is the normal baseline for CJK on Macs */ - /* (because baseline 2 often (and wrongly) contains the same value */ - } else { - /* baseline 1 (centered ideographic) and baseline 2 (low ideographic) */ - /* are documented to be different. Yet most of the fonts I have looked*/ - /* at (and I've only got about 4 test cases) have the low ideographic*/ - /* baseline set to the centered baseline. If I were to copy that to */ - /* OT it would be really bad. So even though baseline data is provided*/ - /* I shall ignore it if it looks WRONG! */ - base->baseline_cnt = 3; - base->baseline_tags[1] = CHR('m','a','t','h'); /* Apple 4 */ - base->baseline_tags[2] = CHR('r','o','m','n'); /* Apple 0 */ - mapping[3] = 0; - mapping[4] = 1; - mapping[0] = 2; - } - - for ( i=0; i<info->glyph_cnt; ++i ) if ( (sc=info->chars[i])!=NULL ) { - uint32 script = SCScriptFromUnicode(sc); - if ( script==DEFAULT_SCRIPT ) - continue; - for ( bs=base->scripts; bs!=NULL && bs->script!=script; bs=bs->next ); - if ( bs!=NULL ) - continue; - bs = chunkalloc(sizeof(struct basescript)); - bs->script = script; - ap_def = def; - if ( values!=NULL ) - ap_def = values[i]; - bs->def_baseline = mapping[ap_def]; - bs->baseline_pos = galloc(4*sizeof(int16)); - for ( i=0; i<5; ++i ) if ( i!=1 ) - bs->baseline_pos[mapping[i]] = offsets[i] - offsets[ap_def]; - bs->next = base->scripts; - base->scripts = bs; - } -} |