diff options
Diffstat (limited to 'Build/source/texk/dvisvgm/dvisvgm-src/libs/ff-woff/fontforge/tottfgpos.c')
-rw-r--r-- | Build/source/texk/dvisvgm/dvisvgm-src/libs/ff-woff/fontforge/tottfgpos.c | 4613 |
1 files changed, 0 insertions, 4613 deletions
diff --git a/Build/source/texk/dvisvgm/dvisvgm-src/libs/ff-woff/fontforge/tottfgpos.c b/Build/source/texk/dvisvgm/dvisvgm-src/libs/ff-woff/fontforge/tottfgpos.c deleted file mode 100644 index 607214a7ef9..00000000000 --- a/Build/source/texk/dvisvgm/dvisvgm-src/libs/ff-woff/fontforge/tottfgpos.c +++ /dev/null @@ -1,4613 +0,0 @@ -/* Copyright (C) 2000-2012 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 <utype.h> - -int coverageformatsallowed=3; -int use_second_indic_scripts = false; - -#include "ttf.h" - -/* This file contains routines to create the otf gpos and gsub tables and their */ -/* attendant subtables */ - -/* Undocumented fact: ATM (which does kerning for otf fonts in Word) can't handle features with multiple lookups */ - -/* Undocumented fact: Only one feature with a given tag allowed per script/lang */ -/* So if we have multiple lookups with the same tag they must be merged into */ -/* one feature with many lookups */ - -/* scripts (for opentype) that I understand */ - /* see also list in lookups.c mapping script tags to friendly names */ - -static uint32 scripts[][15] = { -/* Arabic */ { CHR('a','r','a','b'), 0x0600, 0x06ff, 0xfb50, 0xfdff, 0xfe70, 0xfefe }, -/* Aramaic */ { CHR('a','r','a','m'), 0x820, 0x83f }, -/* Armenian */ { CHR('a','r','m','n'), 0x0530, 0x058f, 0xfb13, 0xfb17 }, -/* Balinese */ { CHR('b','a','l','i'), 0x1b00, 0x1b7f }, -/* Bengali */ { CHR('b','e','n','g'), 0x0980, 0x09ff }, -/* Bliss symb */{ CHR('b','l','i','s'), 0x12200, 0x124ff }, -/* Bopomofo */ { CHR('b','o','p','o'), 0x3100, 0x312f, 0x31a0, 0x31bf }, -/* Braille */ { CHR('b','r','a','i'), 0x2800, 0x28ff }, -/* Buginese */ { CHR('b','u','g','i'), 0x1a00, 0x1a1f }, -/* Buhid */ { CHR('b','u','h','d'), 0x1740, 0x1753 }, -/* Byzantine M*/{ CHR('b','y','z','m'), 0x1d000, 0x1d0ff }, -/* Canadian Syl*/{CHR('c','a','n','s'), 0x1400, 0x167f }, -/* Carian */ {CHR('c','a','r','i'), 0x0, 0x0 }, -/* Cham */ {CHR('c','h','a','m'), 0x0, 0x0 }, -/* Cherokee */ { CHR('c','h','e','r'), 0x13a0, 0x13ff }, -/* Cirth */ { CHR('c','i','r','t'), 0x12080, 0x120ff }, -/* CJKIdeogra */{ CHR('h','a','n','i'), 0x3300, 0x9fff, 0xf900, 0xfaff, 0x020000, 0x02ffff }, -/* Coptic */ { CHR('c','o','p','t'), 0x2c80, 0x2cff }, -/* Cypriot */ { CHR('c','p','m','n'), 0x10800, 0x1083f }, -/* Cyrillic */ { CHR('c','y','r','l'), 0x0400, 0x052f, 0x1d2b, 0x1d2b, 0x1d78, 0x1d78, - 0x2de0, 0x2dff, 0xa640, 0xa6ff }, -/* Deseret */ { CHR('d','s','r','t'), 0x10400, 0x1044f }, -/* Devanagari */{ CHR('d','e','v','a'), 0x0900, 0x097f }, -/* Ethiopic */ { CHR('e','t','h','i'), 0x1200, 0x139f }, -/* Georgian */ { CHR('g','e','o','r'), 0x1080, 0x10ff }, -/* Glagolitic */{ CHR('g','l','a','g'), 0x1080, 0x10ff }, -/* Gothic */ { CHR('g','o','t','h'), 0x10330, 0x1034a }, -/* Greek */ { CHR('g','r','e','k'), 0x0370, 0x03ff, 0x1f00, 0x1fff }, -/* Gujarati */ { CHR('g','u','j','r'), 0x0a80, 0x0aff }, -/* Gurmukhi */ { CHR('g','u','r','u'), 0x0a00, 0x0a7f }, -/* Hangul */ { CHR('h','a','n','g'), 0xac00, 0xd7af, 0x3130, 0x319f, 0xffa0, 0xff9f }, -/* Hanunoo */ { CHR('h','a','n','o'), 0x1720, 0x1734 }, - /* I'm not sure what the difference is between the 'hang' tag and the 'jamo' */ - /* tag. 'Jamo' is said to be the precomposed forms, but what's 'hang'? */ -/* Hebrew */ { CHR('h','e','b','r'), 0x0590, 0x05ff, 0xfb1e, 0xfb4f }, -/* Hiragana used to have its own tag 'hira', but has since been merged with katakana */ -/* Hangul Jamo*/{ CHR('j','a','m','o'), 0x1100, 0x11ff, 0x3130, 0x319f, 0xffa0, 0xffdf }, -/* Javanese */ { CHR('j','a','v','a'), 0 }, /* MS has a tag, but there is no unicode range */ -/* Katakana */ { CHR('k','a','n','a'), 0x3040, 0x30ff, 0xff60, 0xff9f }, -/* Kayah Li */ { CHR('k','a','l','i'), 0 }, -/* Kannada */ { CHR('k','n','d','a'), 0x0c80, 0x0cff }, -/* Kharosthi */ { CHR('k','h','a','r'), 0x10a00, 0x10a5f }, -/* Khmer */ { CHR('k','h','m','r'), 0x1780, 0x17ff }, -/* Latin */ { CHR('l','a','t','n'), 0x0041, 0x005a, 0x0061, 0x007a, - 0x00c0, 0x02af, 0x1d00, 0x1eff, 0xfb00, 0xfb0f, 0xff00, 0xff5f, 0xa770, 0xa7ff }, -/* Lao */ { CHR('l','a','o',' '), 0x0e80, 0x0eff }, -/* Lepcha */ { CHR('l','e','p','c'), 0 }, -/* Limbu */ { CHR('l','i','m','b'), 0x1900, 0x194f }, -/* Linear A */ /*{ CHR('l','i','n','a'), 0x10180, 0x102cf },*/ /* What happened to linear A? */ -/* Linear B */ { CHR('l','i','n','b'), 0x10000, 0x100fa }, -/* Lycian */ { CHR('l','y','c','i'), 0 }, -/* Lydian */ { CHR('l','y','d','i'), 0 }, -/* Malayalam */ { CHR('m','l','y','m'), 0x0d00, 0x0d7f }, -/* Mathematical Alphanumeric Symbols */ - { CHR('m','a','t','h'), 0x1d400, 0x1d7ff }, -/* Mongolian */ { CHR('m','o','n','g'), 0x1800, 0x18af }, -/* Musical */ { CHR('m','u','s','c'), 0x1d100, 0x1d1ff }, -/* Myanmar */ { CHR('m','y','m','r'), 0x1000, 0x107f }, -/* New Tai Lue*/{ CHR('t','a','l','u'), 0 }, -/* N'Ko */ { CHR('n','k','o',' '), 0x07c0, 0x07fa }, -/* Ogham */ { CHR('o','g','a','m'), 0x1680, 0x169f }, -/* Ol Chiki */ { CHR('o','l','c','k'), 0 }, -/* Old Italic */{ CHR('i','t','a','l'), 0x10300, 0x1031e }, -/* Old Permic */{ CHR('p','e','r','m'), 0x10350, 0x1037f }, -/* Old Persian cuneiform */ - { CHR('x','p','e','o'), 0x103a0, 0x103df }, -/* Oriya */ { CHR('o','r','y','a'), 0x0b00, 0x0b7f }, -/* Osmanya */ { CHR('o','s','m','a'), 0x10480, 0x104a9 }, -/* Phags-pa */ { CHR('p','h','a','g'), 0xa840, 0xa87f }, -/* Phoenician */{ CHR('p','h','n','x'), 0x10900, 0x1091f }, -/* Pollard */ { CHR('p','l','r','d'), 0x104b0, 0x104d9 }, -/* Rejang */ { CHR('r','j','n','g'), 0 }, -/* Rongorongo */{ CHR('r','o','r','o'), 0 }, -/* Runic */ { CHR('r','u','n','r'), 0x16a0, 0x16ff }, -/* Saurashtra*/ { CHR('s','a','u','r'), 0 }, -/* Shavian */ { CHR('s','h','a','w'), 0x10450, 0x1047f }, -/* Sinhala */ { CHR('s','i','n','h'), 0x0d80, 0x0dff }, -/* Sumero-Akkadian Cuneiform */ - { CHR('x','s','u','x'), 0x12000, 0x1236e }, -/* Sundanese */ { CHR('s','u','n','d'), 0 }, -/* Syloti Nagri */ - { CHR('s','y','l','o'), 0xa800, 0xa82f }, -/* Syriac */ { CHR('s','y','r','c'), 0x0700, 0x074f }, -/* Tagalog */ { CHR('t','a','g','l'), 0x1700, 0x1714 }, -/* Tagbanwa */ { CHR('t','a','g','b'), 0x1760, 0x1773 }, -/* Tai Le */ { CHR('t','a','l','e'), 0x1950, 0x1974 }, -/* Tai Lu */ { CHR('t','a','l','u'), 0x1980, 0x19df }, -/* Tamil */ { CHR('t','a','m','l'), 0x0b80, 0x0bff }, -/* Telugu */ { CHR('t','e','l','u'), 0x0c00, 0x0c7f }, -/* Tengwar */ { CHR('t','e','n','g'), 0x12000, 0x1207f }, -/* Thaana */ { CHR('t','h','a','a'), 0x0780, 0x07bf }, -/* Thai */ { CHR('t','h','a','i'), 0x0e00, 0x0e7f }, -/* Tibetan */ { CHR('t','i','b','t'), 0x0f00, 0x0fff }, -/* Tifinagh */ { CHR('t','f','n','g'), 0x2d30, 0x2d7f }, -/* Ugaritic */ { CHR('u','g','a','r'), 0x10380, 0x1039d }, -/* Yi */ { CHR('y','i',' ',' '), 0xa000, 0xa4c6 }, - { 0 } -}; - -static SplineChar **SFOrderedGlyphs(SplineChar **glyphs); - -int ScriptIsRightToLeft(uint32 script) { - if ( script==CHR('a','r','a','b') || script==CHR('h','e','b','r') || - script==CHR('c','p','m','n') || script==CHR('k','h','a','r') || - script==CHR('s','y','r','c') || script==CHR('t','h','a','a') || - script==CHR('n','k','o',' ')) -return( true ); - -return( false ); -} - -uint32 ScriptFromUnicode(uint32 u,SplineFont *sf) { - int s, k; - - if ( (int32)u!=-1 ) { - for ( s=0; scripts[s][0]!=0; ++s ) { - for ( k=1; scripts[s][k+1]!=0; k += 2 ) - if ( u>=scripts[s][k] && u<=scripts[s][k+1] ) - break; - if ( scripts[s][k+1]!=0 ) - break; - } - if ( scripts[s][0]!=0 ) { - uint32 script = scripts[s][0]; - if ( use_second_indic_scripts ) { - /* MS has a parallel set of script tags for their new */ - /* Indic font shaper */ - if ( script == CHR('b','e','n','g' )) script = CHR('b','n','g','2'); - else if ( script == CHR('d','e','v','a' )) script = CHR('d','e','v','2'); - else if ( script == CHR('g','u','j','r' )) script = CHR('g','j','r','2'); - else if ( script == CHR('g','u','r','u' )) script = CHR('g','u','r','2'); - else if ( script == CHR('k','n','d','a' )) script = CHR('k','n','d','2'); - else if ( script == CHR('m','l','y','m' )) script = CHR('m','l','m','2'); - else if ( script == CHR('o','r','y','a' )) script = CHR('o','r','y','2'); - else if ( script == CHR('t','a','m','l' )) script = CHR('t','m','l','2'); - else if ( script == CHR('t','e','l','u' )) script = CHR('t','e','l','2'); - } -return( script ); - } - } else if ( sf!=NULL ) { - if ( sf->cidmaster!=NULL || sf->subfontcnt!=0 ) { - if ( sf->cidmaster!=NULL ) sf = sf->cidmaster; - if ( strmatch(sf->ordering,"Identity")==0 ) -return( DEFAULT_SCRIPT ); - else if ( strmatch(sf->ordering,"Korean")==0 ) -return( CHR('h','a','n','g')); - else -return( CHR('h','a','n','i') ); - } - } - -return( DEFAULT_SCRIPT ); -} - -uint32 SCScriptFromUnicode(SplineChar *sc) { - const char *pt; - PST *pst; - SplineFont *sf; - int i; unsigned uni; - FeatureScriptLangList *features; - - if ( sc==NULL ) -return( DEFAULT_SCRIPT ); - - sf = sc->parent; - if ( sc->unicodeenc!=-1 && - !(sc->unicodeenc>=0xe000 && sc->unicodeenc<0xf8ff) && - !(sc->unicodeenc>=0xf0000 && sc->unicodeenc<0x10ffff)) -return( ScriptFromUnicode( sc->unicodeenc,sf )); - - pt = sc->name; - if ( *pt ) for ( ++pt; *pt!='\0' && *pt!='_' && *pt!='.'; ++pt ); - if ( *pt!='\0' ) { - char *str = copyn(sc->name,pt-sc->name); - int uni = UniFromName(str,ui_none,&custom); - free(str); - if ( uni!=-1 ) -return( ScriptFromUnicode( uni,sf )); - } - /* Adobe ligature uniXXXXXXXX */ - if ( strncmp(sc->name,"uni",3)==0 && sscanf(sc->name+3,"%4x", &uni)==1 ) -return( ScriptFromUnicode( uni,sf )); - - if ( sf==NULL ) -return( DEFAULT_SCRIPT ); - - if ( sf->cidmaster ) sf=sf->cidmaster; - else if ( sf->mm!=NULL ) sf=sf->mm->normal; - for ( i=0; i<2; ++i ) { - for ( pst=sc->possub; pst!=NULL; pst=pst->next ) { - if ( pst->type == pst_lcaret ) - continue; - for ( features = pst->subtable->lookup->features; features!=NULL; features=features->next ) { - if ( features->scripts!=NULL ) -return( features->scripts->script ); - } - } - } -return( ScriptFromUnicode( sc->unicodeenc,sf )); -} - -int SCRightToLeft(SplineChar *sc) { - - if ( sc->unicodeenc>=0x10800 && sc->unicodeenc<=0x10fff ) -return( true ); /* Supplemental Multilingual Plane, RTL scripts */ - if ( sc->unicodeenc!=-1 && sc->unicodeenc<0x10000 ) -return( isrighttoleft(sc->unicodeenc )); - -return( ScriptIsRightToLeft(SCScriptFromUnicode(sc))); -} - -static void GlyphMapFree(SplineChar ***map) { - int i; - - if ( map==NULL ) - return; - for ( i=0; map[i]!=NULL; ++i ) - free(map[i]); - free(map); -} - -static SplineChar **FindSubs(SplineChar *sc,struct lookup_subtable *sub) { - SplineChar *spc[30], **space = spc; - int max = sizeof(spc)/sizeof(spc[0]); - int cnt=0; - char *pt, *start; - SplineChar *subssc, **ret; - PST *pst; - - for ( pst=sc->possub; pst!=NULL; pst=pst->next ) { - if ( pst->subtable==sub ) { - pt = pst->u.subs.variant; - while ( 1 ) { - while ( *pt==' ' ) ++pt; // Burn leading spaces. - // Start tokenizing the space-delimited list of references. - start = pt; // Note the beginning of the current item. - pt = strchr(start,' '); // Find the end of the current item. - if ( pt!=NULL ) - *pt = '\0'; // Temporarily terminate the item. - subssc = SFGetChar(sc->parent,-1,start); // Find the corresponding SplineChar. - if ( subssc!=NULL && subssc->ttf_glyph!=-1 ) { - // Extend the list if necessary. - if ( cnt>=max ) { - if ( spc==space ) { - space = malloc((max+=30)*sizeof(SplineChar *)); - memcpy(space,spc,(max-30)*sizeof(SplineChar *)); - } else - space = realloc(space,(max+=30)*sizeof(SplineChar *)); - } - // Write the SplineChar to the list. - space[cnt++] = subssc; - } - if ( pt==NULL ) - break; // No more items. - *pt=' '; // Repair the string from the tokenization process. - } - } - } - // Returning NULL causes problems and seems to be unnecessary for now. - ret = malloc((cnt+1)*sizeof(SplineChar *)); - memcpy(ret,space,cnt*sizeof(SplineChar *)); - ret[cnt] = NULL; - if ( space!=spc ) - free(space); // Free the temp space only if it is dynamically allocated. - return( ret ); -} - -static SplineChar ***generateMapList(SplineChar **glyphs, struct lookup_subtable *sub) { - int cnt; - SplineChar *sc; - int i; - SplineChar ***maps=NULL; - - for ( cnt=0; glyphs[cnt]!=NULL; ++cnt ); - maps = malloc((cnt+1)*sizeof(SplineChar **)); - for ( i=0; i<cnt; ++i ) { - sc = glyphs[i]; - maps[i] = FindSubs(sc,sub); - if (maps[i] == NULL) { - fprintf( stderr, "maps[%d] is null; glyphs[%d] is \"%s\"; lookup name is \"%s\".\n" , i , i , (glyphs[i]->name ? glyphs[i]->name : ""), sub->subtable_name) ; - } - } - maps[cnt] = NULL; -return( maps ); -} - -void AnchorClassDecompose(SplineFont *sf,AnchorClass *_ac, int classcnt, int *subcnts, - SplineChar ***marks,SplineChar ***base, - SplineChar ***lig,SplineChar ***mkmk, - struct glyphinfo *gi) { - /* Run through the font finding all characters with this anchor class */ - /* (and the cnt-1 classes after it) */ - /* and distributing in the four possible anchor types */ - int i,j,k,gid, gmax; - struct sclist { int cnt; SplineChar **glyphs; } heads[at_max]; - AnchorPoint *test; - AnchorClass *ac; - - memset(heads,0,sizeof(heads)); - memset(subcnts,0,classcnt*sizeof(int)); - memset(marks,0,classcnt*sizeof(SplineChar **)); - gmax = gi==NULL ? sf->glyphcnt : gi->gcnt; - for ( j=0; j<2; ++j ) { - for ( i=0; i<gmax; ++i ) if ( (gid = gi==NULL ? i : gi->bygid[i])!=-1 && gid < sf->glyphcnt && sf->glyphs[gid]!=NULL ) { - for ( ac = _ac, k=0; k<classcnt; ac=ac->next ) if ( ac->matches ) { - for ( test=sf->glyphs[gid]->anchor; test!=NULL ; test=test->next ) { - if ( test->anchor==ac ) { - if ( test->type==at_mark ) { - if ( j ) - marks[k][subcnts[k]] = sf->glyphs[gid]; - ++subcnts[k]; - if ( ac->type!=act_mkmk ) - break; - } else if ( test->type!=at_centry && test->type!=at_cexit ) { - if ( heads[test->type].glyphs!=NULL ) { - /* If we have multiple mark classes, we may use the same base glyph */ - /* with more than one mark class. But it should only appear once in */ - /* the output */ - if ( heads[test->type].cnt==0 || - heads[test->type].glyphs[heads[test->type].cnt-1]!=sf->glyphs[gid] ) { - heads[test->type].glyphs[heads[test->type].cnt] = sf->glyphs[gid]; - ++heads[test->type].cnt; - } - } else - ++heads[test->type].cnt; - if ( ac->type!=act_mkmk ) - break; - } - } - } - ++k; - } - } - if ( j==1 ) - break; - for ( i=0; i<4; ++i ) - if ( heads[i].cnt!=0 ) { - heads[i].glyphs = malloc((heads[i].cnt+1)*sizeof(SplineChar *)); - /* I used to set glyphs[cnt] to NULL here. But it turns out */ - /* cnt may be an overestimate on the first pass. So we can */ - /* only set it at the end of the second pass */ - heads[i].cnt = 0; - } - for ( k=0; k<classcnt; ++k ) if ( subcnts[k]!=0 ) { - marks[k] = malloc((subcnts[k]+1)*sizeof(SplineChar *)); - marks[k][subcnts[k]] = NULL; - subcnts[k] = 0; - } - } - for ( i=0; i<4; ++i ) { - if ( heads[i].glyphs!=NULL ) - heads[i].glyphs[heads[i].cnt] = NULL; - } - for ( i=0; i<classcnt; ++i ) { - if ( subcnts[k]!=0 ) - SFOrderedGlyphs(marks[i]); - } - - *base = SFOrderedGlyphs(heads[at_basechar].glyphs); - *lig = SFOrderedGlyphs(heads[at_baselig].glyphs); - *mkmk = SFOrderedGlyphs(heads[at_basemark].glyphs); -} - -SplineChar **EntryExitDecompose(SplineFont *sf,AnchorClass *ac,struct glyphinfo *gi) { - /* Run through the font finding all characters with this anchor class */ - int i,j, cnt, gmax, gid; - SplineChar **array; - AnchorPoint *test; - - array=NULL; - gmax = gi==NULL ? sf->glyphcnt : gi->gcnt; - for ( j=0; j<2; ++j ) { - cnt = 0; - for ( i=0; i<gmax; ++i ) if ( (gid = gi==NULL ? i : gi->bygid[i])!=-1 && sf->glyphs[gid]!=NULL ) { - for ( test=sf->glyphs[gid]->anchor; test!=NULL && test->anchor!=ac; test=test->next ); - if ( test!=NULL && (test->type==at_centry || test->type==at_cexit )) { - if ( array!=NULL ) - array[cnt] = sf->glyphs[gid]; - ++cnt; - } - } - if ( cnt==0 ) -return( NULL ); - if ( j==1 ) - break; - array = malloc((cnt+1)*sizeof(SplineChar *)); - array[cnt] = NULL; - } -return( array ); -} - -static void AnchorGuessContext(SplineFont *sf,struct alltabs *at) { - int i; - int maxbase=0, maxmark=0, basec, markc; - AnchorPoint *ap; - int hascursive = 0; - - /* the order in which we examine the glyphs does not matter here, so */ - /* we needn't add the complexity running though in gid order */ - for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i] ) { - basec = markc = 0; - for ( ap = sf->glyphs[i]->anchor; ap!=NULL; ap=ap->next ) - if ( ap->type==at_basemark ) - ++markc; - else if ( ap->type==at_basechar || ap->type==at_baselig ) - ++basec; - else if ( ap->type==at_centry ) - hascursive = true; - if ( basec>maxbase ) maxbase = basec; - if ( markc>maxmark ) maxmark = markc; - } - - if ( maxbase*(maxmark+1)>at->os2.maxContext ) - at->os2.maxContext = maxbase*(maxmark+1); - if ( hascursive && at->os2.maxContext<2 ) - at->os2.maxContext=2; -} - -static void dumpcoveragetable(FILE *gpos,SplineChar **glyphs) { - int i, last = -2, range_cnt=0, start, r; - /* the glyph list should already be sorted */ - /* figure out whether it is better (smaller) to use an array of glyph ids */ - /* or a set of glyph id ranges */ - - for ( i=0; glyphs[i]!=NULL; ++i ) { - if ( glyphs[i]->ttf_glyph<=last ) - IError("Glyphs must be ordered when creating coverage table"); - if ( glyphs[i]->ttf_glyph!=last+1 ) - ++range_cnt; - last = glyphs[i]->ttf_glyph; - } - /* I think Windows will only accept format 2 coverage tables? */ - if ( !(coverageformatsallowed&2) || ((coverageformatsallowed&1) && i<=3*range_cnt )) { - /* We use less space with a list of glyphs than with a set of ranges */ - putshort(gpos,1); /* Coverage format=1 => glyph list */ - putshort(gpos,i); /* count of glyphs */ - for ( i=0; glyphs[i]!=NULL; ++i ) - putshort(gpos,glyphs[i]->ttf_glyph); /* array of glyph IDs */ - } else { - putshort(gpos,2); /* Coverage format=2 => range list */ - putshort(gpos,range_cnt); /* count of ranges */ - last = -2; start = -2; /* start is a index in our glyph array, last is ttf_glyph */ - r = 0; - for ( i=0; glyphs[i]!=NULL; ++i ) { - if ( glyphs[i]->ttf_glyph!=last+1 ) { - if ( last!=-2 ) { - putshort(gpos,glyphs[start]->ttf_glyph); /* start glyph ID */ - putshort(gpos,last); /* end glyph ID */ - putshort(gpos,start); /* coverage index of start glyph */ - ++r; - } - start = i; - } - last = glyphs[i]->ttf_glyph; - } - if ( last!=-2 ) { - putshort(gpos,glyphs[start]->ttf_glyph); /* start glyph ID */ - putshort(gpos,last); /* end glyph ID */ - putshort(gpos,start); /* coverage index of start glyph */ - ++r; - } - if ( r!=range_cnt ) - IError("Miscounted ranges in format 2 coverage table output"); - } -} - -static int sc_ttf_order( const void *_sc1, const void *_sc2) { - const SplineChar *sc1 = *(const SplineChar **) _sc1, *sc2 = *(const SplineChar **) _sc2; -return( sc1->ttf_glyph - sc2->ttf_glyph ); -} - -static SplineChar **SFOrderedGlyphs(SplineChar **glyphs) { - int cnt, i, k; - if ( glyphs==NULL ) -return( NULL ); - for ( cnt=0; glyphs[cnt]!=NULL; ++cnt); - qsort(glyphs,cnt,sizeof(SplineChar *),sc_ttf_order); - if ( glyphs[0]->ttf_glyph==-1 ) { - /* Not sure if this can happen, but it's easy to fix */ - for ( k=0; k<cnt && glyphs[k]->ttf_glyph==-1; ++k); - for ( i=0; i<=cnt-k; ++i ) - glyphs[i] = glyphs[i+k]; - } - for ( i=0; i<cnt-1; ++i ) - if (glyphs[i]->ttf_glyph==glyphs[i+1]->ttf_glyph) { - memmove(glyphs+i, glyphs+i+1, (cnt-i)*sizeof(SplineChar *)); - --cnt; - } -return( glyphs ); -} - -static SplineChar **SFOrderedGlyphsWithPSTinSubtable(SplineFont *sf,struct lookup_subtable *sub) { - SplineChar **glyphs = SFGlyphsWithPSTinSubtable(sf,sub); - return SFOrderedGlyphs(glyphs); -} - -SplineChar **SFGlyphsFromNames(SplineFont *sf,char *names) { - int cnt, ch; - char *pt, *end; - SplineChar *sc, **glyphs; - - if ( names==NULL ) -return( calloc(1,sizeof(SplineChar *)) ); - - cnt = 0; - for ( pt = names; *pt; pt = end+1 ) { - ++cnt; - end = strchr(pt,' '); - if ( end==NULL ) - break; - } - - glyphs = malloc((cnt+1)*sizeof(SplineChar *)); - cnt = 0; - for ( pt = names; *pt; pt = end+1 ) { - end = strchr(pt,' '); - if ( end==NULL ) - end = pt+strlen(pt); - ch = *end; - *end = '\0'; - sc = SFGetChar(sf,-1,pt); - if ( sc!=NULL && sc->ttf_glyph!=-1 ) - glyphs[cnt++] = sc; - *end = ch; - if ( ch=='\0' ) - break; - } - glyphs[cnt] = NULL; -return( glyphs ); -} - -static SplineChar **OrderedGlyphsFromNames(SplineFont *sf,char *names) { - SplineChar **glyphs = SFGlyphsFromNames(sf,names); - int i,j; - - if ( glyphs==NULL || glyphs[0]==NULL ) -return( glyphs ); - - for ( i=0; glyphs[i+1]!=NULL; ++i ) for ( j=i+1; glyphs[j]!=NULL; ++j ) { - if ( glyphs[i]->ttf_glyph > glyphs[j]->ttf_glyph ) { - SplineChar *sc = glyphs[i]; - glyphs[i] = glyphs[j]; - glyphs[j] = sc; - } - } - if ( glyphs[0]!=NULL ) { /* Glyphs should not appear twice in the name list, just just in case they do... */ - for ( i=0; glyphs[i+1]!=NULL; ++i ) { - if ( glyphs[i]==glyphs[i+1] ) { - for ( j=i+1; glyphs[j]!=NULL; ++j ) - glyphs[j] = glyphs[j+1]; - } - } - } -return( glyphs ); -} - -static void gposvrmaskeddump(FILE *gpos,int vf1,int mask,int offset) { - if ( vf1&1 ) putshort(gpos,mask&1 ? offset : 0 ); - if ( vf1&2 ) putshort(gpos,mask&2 ? offset : 0 ); - if ( vf1&4 ) putshort(gpos,mask&4 ? offset : 0 ); - if ( vf1&8 ) putshort(gpos,mask&8 ? offset : 0 ); -} - -static int devtaboffsetsize(DeviceTable *dt) { - int type = 1, i; - - for ( i=dt->last_pixel_size-dt->first_pixel_size; i>=0; --i ) { - if ( dt->corrections[i]>=8 || dt->corrections[i]<-8 ) -return( 3 ); - else if ( dt->corrections[i]>=2 || dt->corrections[i]<-2 ) - type = 2; - } -return( type ); -} - -static void dumpgposdevicetable(FILE *gpos,DeviceTable *dt) { - int type; - int i,cnt,b; - - if ( dt==NULL || dt->corrections==NULL ) -return; - type = devtaboffsetsize(dt); - putshort(gpos,dt->first_pixel_size); - putshort(gpos,dt->last_pixel_size ); - putshort(gpos,type); - cnt = dt->last_pixel_size - dt->first_pixel_size + 1; - if ( type==3 ) { - for ( i=0; i<cnt; ++i ) - putc(dt->corrections[i],gpos); - if ( cnt&1 ) - putc(0,gpos); - } else if ( type==2 ) { - for ( i=0; i<cnt; i+=4 ) { - int val = 0; - for ( b=0; b<4 && i+b<cnt; ++b ) - val |= (dt->corrections[i+b]&0x000f)<<(12-b*4); - putshort(gpos,val); - } - } else { - for ( i=0; i<cnt; i+=8 ) { - int val = 0; - for ( b=0; b<8 && i+b<cnt; ++b ) - val |= (dt->corrections[i+b]&0x0003)<<(14-b*2); - putshort(gpos,val); - } - } -} - -static int DevTabLen(DeviceTable *dt) { - int type; - int cnt; - - if ( dt==NULL || dt->corrections==NULL ) -return( 0 ); - cnt = dt->last_pixel_size - dt->first_pixel_size + 1; - type = devtaboffsetsize(dt); - if ( type==3 ) - cnt = (cnt+1)/2; - else if ( type==2 ) - cnt = (cnt+3)/4; - else - cnt = (cnt+7)/8; - cnt += 3; /* first, last, type */ -return( sizeof(uint16)*cnt ); -} - -static int ValDevTabLen(ValDevTab *vdt) { - - if ( vdt==NULL ) -return( 0 ); - -return( DevTabLen(&vdt->xadjust) + DevTabLen(&vdt->yadjust) + - DevTabLen(&vdt->xadv) + DevTabLen(&vdt->yadv) ); -} - -static int gposdumpvaldevtab(FILE *gpos,ValDevTab *vdt,int bits,int next_dev_tab ) { - - if ( bits&0x10 ) { - if ( vdt==NULL || vdt->xadjust.corrections==NULL ) - putshort(gpos,0); - else { - putshort(gpos,next_dev_tab); - next_dev_tab += DevTabLen(&vdt->xadjust); - } - } - if ( bits&0x20 ) { - if ( vdt==NULL || vdt->yadjust.corrections==NULL ) - putshort(gpos,0); - else { - putshort(gpos,next_dev_tab); - next_dev_tab += DevTabLen(&vdt->yadjust); - } - } - if ( bits&0x40 ) { - if ( vdt==NULL || vdt->xadv.corrections==NULL ) - putshort(gpos,0); - else { - putshort(gpos,next_dev_tab); - next_dev_tab += DevTabLen(&vdt->xadv); - } - } - if ( bits&0x80 ) { - if ( vdt==NULL || vdt->yadv.corrections==NULL ) - putshort(gpos,0); - else { - putshort(gpos,next_dev_tab); - next_dev_tab += DevTabLen(&vdt->yadv); - } - } -return( next_dev_tab ); -} - -static int gposmaskeddumpdevtab(FILE *gpos,DeviceTable *dt,int bits,int mask, - int next_dev_tab ) { - - if ( bits&0x10 ) { - if ( !(mask&0x10) || dt==NULL ) - putshort(gpos,0); - else { - putshort(gpos,next_dev_tab); - next_dev_tab += DevTabLen(dt); - } - } - if ( bits&0x20 ) { - if ( !(mask&0x20) || dt==NULL ) - putshort(gpos,0); - else { - putshort(gpos,next_dev_tab); - next_dev_tab += DevTabLen(dt); - } - } - if ( bits&0x40 ) { - if ( !(mask&0x40) || dt==NULL ) - putshort(gpos,0); - else { - putshort(gpos,next_dev_tab); - next_dev_tab += DevTabLen(dt); - } - } - if ( bits&0x80 ) { - if ( !(mask&0x80) || dt==NULL ) - putshort(gpos,0); - else { - putshort(gpos,next_dev_tab); - next_dev_tab += DevTabLen(dt); - } - } -return( next_dev_tab ); -} - -static int DevTabsSame(DeviceTable *dt1, DeviceTable *dt2) { - DeviceTable _dt; - int i; - - if ( dt1==NULL && dt2==NULL ) -return( true ); - if ( dt1==NULL ) { - memset(&_dt,0,sizeof(_dt)); - dt1 = &_dt; - } - if ( dt2==NULL ) { - memset(&_dt,0,sizeof(_dt)); - dt2 = &_dt; - } - if ( dt1->corrections==NULL && dt2->corrections==NULL ) -return( true ); - if ( dt1->corrections==NULL || dt2->corrections==NULL ) -return( false ); - if ( dt1->first_pixel_size!=dt2->first_pixel_size || - dt1->last_pixel_size!=dt2->last_pixel_size ) -return( false ); - for ( i=dt2->last_pixel_size-dt1->first_pixel_size; i>=0; --i ) - if ( dt1->corrections[i]!=dt2->corrections[i] ) -return( false ); - -return( true ); -} - -static int ValDevTabsSame(ValDevTab *vdt1, ValDevTab *vdt2) { - ValDevTab _vdt; - - if ( vdt1==NULL && vdt2==NULL ) -return( true ); - if ( vdt1==NULL ) { - memset(&_vdt,0,sizeof(_vdt)); - vdt1 = &_vdt; - } - if ( vdt2==NULL ) { - memset(&_vdt,0,sizeof(_vdt)); - vdt2 = &_vdt; - } -return( DevTabsSame(&vdt1->xadjust,&vdt2->xadjust) && - DevTabsSame(&vdt1->yadjust,&vdt2->yadjust) && - DevTabsSame(&vdt1->xadv,&vdt2->xadv) && - DevTabsSame(&vdt1->yadv,&vdt2->yadv) ); -} - -static void dumpGPOSsimplepos(FILE *gpos,SplineFont *sf,struct lookup_subtable *sub ) { - int cnt, cnt2; - int32 coverage_pos, end; - PST *pst, *first=NULL; - int bits = 0, same=true; - SplineChar **glyphs; - - glyphs = SFOrderedGlyphsWithPSTinSubtable(sf,sub); - for ( cnt=cnt2=0; glyphs[cnt]!=NULL; ++cnt) { - for ( pst=glyphs[cnt]->possub; pst!=NULL; pst=pst->next ) { - if ( pst->subtable==sub && pst->type==pst_position ) { - if ( first==NULL ) first = pst; - else if ( same ) { - if ( first->u.pos.xoff!=pst->u.pos.xoff || - first->u.pos.yoff!=pst->u.pos.yoff || - first->u.pos.h_adv_off!=pst->u.pos.h_adv_off || - first->u.pos.v_adv_off!=pst->u.pos.v_adv_off ) - same = false; - if ( !ValDevTabsSame(pst->u.pos.adjust,first->u.pos.adjust)) - same = false; - } - if ( pst->u.pos.xoff!=0 ) bits |= 1; - if ( pst->u.pos.yoff!=0 ) bits |= 2; - if ( pst->u.pos.h_adv_off!=0 ) bits |= 4; - if ( pst->u.pos.v_adv_off!=0 ) bits |= 8; - if ( pst->u.pos.adjust!=NULL ) { - if ( pst->u.pos.adjust->xadjust.corrections!=NULL ) bits |= 0x10; - if ( pst->u.pos.adjust->yadjust.corrections!=NULL ) bits |= 0x20; - if ( pst->u.pos.adjust->xadv.corrections!=NULL ) bits |= 0x40; - if ( pst->u.pos.adjust->yadv.corrections!=NULL ) bits |= 0x80; - } - ++cnt2; - break; - } - } - } - if ( bits==0 ) bits=1; - if ( cnt!=cnt2 ) - IError( "Count mismatch in dumpGPOSsimplepos#1 %d vs %d\n", cnt, cnt2 ); - - putshort(gpos,same?1:2); /* 1 means all value records same */ - coverage_pos = ftell(gpos); - putshort(gpos,0); /* offset to coverage table */ - putshort(gpos,bits); - if ( same ) { - if ( bits&1 ) putshort(gpos,first->u.pos.xoff); - if ( bits&2 ) putshort(gpos,first->u.pos.yoff); - if ( bits&4 ) putshort(gpos,first->u.pos.h_adv_off); - if ( bits&8 ) putshort(gpos,first->u.pos.v_adv_off); - if ( bits&0xf0 ) { - int next_dev_tab = ftell(gpos)-coverage_pos+2+ - sizeof(int16)*((bits&0x10?1:0) + (bits&0x20?1:0) + (bits&0x40?1:0) + (bits&0x80?1:0)); - if ( bits&0x10 ) { putshort(gpos,next_dev_tab); next_dev_tab += DevTabLen(&first->u.pos.adjust->xadjust); } - if ( bits&0x20 ) { putshort(gpos,next_dev_tab); next_dev_tab += DevTabLen(&first->u.pos.adjust->yadjust); } - if ( bits&0x40 ) { putshort(gpos,next_dev_tab); next_dev_tab += DevTabLen(&first->u.pos.adjust->xadv); } - if ( bits&0x80 ) { putshort(gpos,next_dev_tab); next_dev_tab += DevTabLen(&first->u.pos.adjust->yadv); } - if ( bits&0x10 ) dumpgposdevicetable(gpos,&first->u.pos.adjust->xadjust); - if ( bits&0x20 ) dumpgposdevicetable(gpos,&first->u.pos.adjust->yadjust); - if ( bits&0x40 ) dumpgposdevicetable(gpos,&first->u.pos.adjust->xadv); - if ( bits&0x80 ) dumpgposdevicetable(gpos,&first->u.pos.adjust->yadv); - if ( next_dev_tab!=ftell(gpos)-coverage_pos+2 ) - IError( "Device Table offsets wrong in simple positioning 2"); - } - } else { - int vr_size = - sizeof(int16)*((bits&0x1?1:0) + (bits&0x2?1:0) + (bits&0x4?1:0) + (bits&0x8?1:0) + - (bits&0x10?1:0) + (bits&0x20?1:0) + (bits&0x40?1:0) + (bits&0x80?1:0)); - int next_dev_tab = ftell(gpos)-coverage_pos+2+2+vr_size*cnt; - putshort(gpos,cnt); - for ( cnt2 = 0; glyphs[cnt2]!=NULL; ++cnt2 ) { - for ( pst=glyphs[cnt2]->possub; pst!=NULL; pst=pst->next ) { - if ( pst->subtable==sub && pst->type==pst_position ) { - if ( bits&1 ) putshort(gpos,pst->u.pos.xoff); - if ( bits&2 ) putshort(gpos,pst->u.pos.yoff); - if ( bits&4 ) putshort(gpos,pst->u.pos.h_adv_off); - if ( bits&8 ) putshort(gpos,pst->u.pos.v_adv_off); - next_dev_tab = gposdumpvaldevtab(gpos,pst->u.pos.adjust,bits, - next_dev_tab); - break; - } - } - } - if ( cnt!=cnt2 ) - IError( "Count mismatch in dumpGPOSsimplepos#3 %d vs %d\n", cnt, cnt2 ); - if ( bits&0xf0 ) { - for ( cnt2 = 0; glyphs[cnt2]!=NULL; ++cnt2 ) { - for ( pst=glyphs[cnt2]->possub; pst!=NULL; pst=pst->next ) { - if ( pst->subtable==sub && pst->type==pst_position ) { - if ( bits&0x10 ) dumpgposdevicetable(gpos,&first->u.pos.adjust->xadjust); - if ( bits&0x20 ) dumpgposdevicetable(gpos,&first->u.pos.adjust->yadjust); - if ( bits&0x40 ) dumpgposdevicetable(gpos,&first->u.pos.adjust->xadv); - if ( bits&0x80 ) dumpgposdevicetable(gpos,&first->u.pos.adjust->yadv); - } - } - } - } - if ( next_dev_tab!=ftell(gpos)-coverage_pos+2 ) - IError( "Device Table offsets wrong in simple positioning 2"); - } - end = ftell(gpos); - fseek(gpos,coverage_pos,SEEK_SET); - putshort(gpos,end-coverage_pos+2); - fseek(gpos,end,SEEK_SET); - dumpcoveragetable(gpos,glyphs); - fseek(gpos,0,SEEK_END); - free(glyphs); -} - -struct sckppst { - uint16 samewas; - uint16 devtablen; - uint16 tot; - uint8 isv; - uint8 subtable_too_big; -/* The first few fields are only meaningful in the first structure in the array*/ -/* and provide information about the entire rest of the array */ - uint16 other_gid; - SplineChar *sc; - KernPair *kp; - PST *pst; -}; - -static int cmp_gid( const void *_s1, const void *_s2 ) { - const struct sckppst *s1 = _s1, *s2 = _s2; -return( ((int) s1->other_gid) - ((int) s2->other_gid) ); -} - -static void dumpGPOSpairpos(FILE *gpos,SplineFont *sf,struct lookup_subtable *sub) { - int cnt; - int32 coverage_pos, offset_pos, end, start, pos; - PST *pst; - KernPair *kp; - int vf1 = 0, vf2=0, i, j, k, tot, bit_cnt, v; - int start_cnt, end_cnt; - int chunk_cnt, chunk_max; - SplineChar *sc, **glyphs, *gtemp; - struct sckppst **seconds; - int devtablen; - int next_dev_tab; - - /* Figure out all the data we need. First the glyphs with kerning info */ - /* then the glyphs to which they kern, and by how much */ - glyphs = SFOrderedGlyphsWithPSTinSubtable(sf,sub); - for ( cnt=0; glyphs[cnt]!=NULL; ++cnt); - seconds = malloc(cnt*sizeof(struct sckppst *)); - for ( cnt=0; glyphs[cnt]!=NULL; ++cnt) { - for ( k=0; k<2; ++k ) { - devtablen = 0; - tot = 0; - for ( pst=glyphs[cnt]->possub; pst!=NULL; pst=pst->next ) { - if ( pst->subtable==sub && pst->type==pst_pair && - (sc = SFGetChar(sf,-1,pst->u.pair.paired))!=NULL && - sc->ttf_glyph!=-1 ) { - if ( k ) { - seconds[cnt][tot].sc = sc; - seconds[cnt][tot].other_gid = sc->ttf_glyph; - seconds[cnt][tot].pst = pst; - devtablen += ValDevTabLen(pst->u.pair.vr[0].adjust) + - ValDevTabLen(pst->u.pair.vr[1].adjust); - - } - ++tot; - } - } - for ( v=0; v<2; ++v ) { - for ( kp = v ? glyphs[cnt]->vkerns : glyphs[cnt]->kerns; kp!=NULL; kp=kp->next ) { - if( kp->subtable!=sub ) continue; // process only glyphs from the current subtable - if ( kp->sc->ttf_glyph!=-1 ) { - if ( k ) { - seconds[cnt][tot].other_gid = kp->sc->ttf_glyph; - seconds[cnt][tot].sc = kp->sc; - seconds[cnt][tot].kp = kp; - seconds[cnt][tot].isv = v; - devtablen += DevTabLen(kp->adjust); - } - ++tot; - } - } - } - if ( k==0 ) { - seconds[cnt] = calloc(tot+1,sizeof(struct sckppst)); - } else { - qsort(seconds[cnt],tot,sizeof(struct sckppst),cmp_gid); - seconds[cnt][0].tot = tot; - /* Devtablen is 0 unless we are configured for device tables */ - seconds[cnt][0].devtablen = devtablen; - seconds[cnt][0].samewas = 0xffff; - } - } - } - - /* Some fonts do a primitive form of class based kerning, several glyphs */ - /* can share the same list of second glyphs & offsets */ - for ( cnt=0; glyphs[cnt]!=NULL; ++cnt) { - struct sckppst *test = seconds[cnt], *test2; - for ( i=cnt-1; i>=0; --i ) { - test2 = seconds[i]; - if ( test[0].tot != test2[0].tot || test2[0].samewas!=0xffff ) - continue; - for ( j=test[0].tot-1; j>=0; --j ) { - if ( test[j].other_gid != test2[j].other_gid ) - break; - if ( test[j].kp!=NULL && test2[j].kp!=NULL && - test[j].kp->off == test2[j].kp->off - && DevTabsSame(test[j].kp->adjust,test2[j].kp->adjust) - ) - /* So far, so good */; - else if ( test[j].pst!=NULL && test2[j].pst!=NULL && - test[j].pst->u.pair.vr[0].xoff == test2[j].pst->u.pair.vr[0].xoff && - test[j].pst->u.pair.vr[0].yoff == test2[j].pst->u.pair.vr[0].yoff && - test[j].pst->u.pair.vr[0].h_adv_off == test2[j].pst->u.pair.vr[0].h_adv_off && - test[j].pst->u.pair.vr[0].v_adv_off == test2[j].pst->u.pair.vr[0].v_adv_off && - test[j].pst->u.pair.vr[1].xoff == test2[j].pst->u.pair.vr[1].xoff && - test[j].pst->u.pair.vr[1].yoff == test2[j].pst->u.pair.vr[1].yoff && - test[j].pst->u.pair.vr[1].h_adv_off == test2[j].pst->u.pair.vr[1].h_adv_off && - test[j].pst->u.pair.vr[1].v_adv_off == test2[j].pst->u.pair.vr[1].v_adv_off - && ValDevTabsSame(test[j].pst->u.pair.vr[0].adjust,test2[j].pst->u.pair.vr[0].adjust) - && ValDevTabsSame(test[j].pst->u.pair.vr[1].adjust,test2[j].pst->u.pair.vr[1].adjust) - ) - /* That's ok too. */; - else - break; - } - if ( j>=0 ) - continue; - test[0].samewas = i; - break; - } - } - - /* Ok, how many offsets must we output? Normal kerning will just use */ - /* one offset (with perhaps a device table), but the standard allows */ - /* us to adjust 8 different values (with 8 different device tables) */ - /* Find out which we need */ - for ( cnt=0; glyphs[cnt]!=NULL; ++cnt) { - for ( tot=0 ; tot<seconds[cnt][0].tot; ++tot ) { - if ( (pst=seconds[cnt][tot].pst)!=NULL ) { - if ( pst->subtable==sub && pst->type==pst_pair ) { - if ( pst->u.pair.vr[0].xoff!=0 ) vf1 |= 1; - if ( pst->u.pair.vr[0].yoff!=0 ) vf1 |= 2; - if ( pst->u.pair.vr[0].h_adv_off!=0 ) vf1 |= 4; - if ( pst->u.pair.vr[0].v_adv_off!=0 ) vf1 |= 8; - if ( pst->u.pair.vr[0].adjust!=NULL ) { - if ( pst->u.pair.vr[0].adjust->xadjust.corrections!=NULL ) vf1 |= 0x10; - if ( pst->u.pair.vr[0].adjust->yadjust.corrections!=NULL ) vf1 |= 0x20; - if ( pst->u.pair.vr[0].adjust->xadv.corrections!=NULL ) vf1 |= 0x40; - if ( pst->u.pair.vr[0].adjust->yadv.corrections!=NULL ) vf1 |= 0x80; - } - if ( pst->u.pair.vr[1].xoff!=0 ) vf2 |= 1; - if ( pst->u.pair.vr[1].yoff!=0 ) vf2 |= 2; - if ( pst->u.pair.vr[1].h_adv_off!=0 ) vf2 |= 4; - if ( pst->u.pair.vr[1].v_adv_off!=0 ) vf2 |= 8; - if ( pst->u.pair.vr[1].adjust!=NULL ) { - if ( pst->u.pair.vr[1].adjust->xadjust.corrections!=NULL ) vf2 |= 0x10; - if ( pst->u.pair.vr[1].adjust->yadjust.corrections!=NULL ) vf2 |= 0x20; - if ( pst->u.pair.vr[1].adjust->xadv.corrections!=NULL ) vf2 |= 0x40; - if ( pst->u.pair.vr[1].adjust->yadv.corrections!=NULL ) vf2 |= 0x80; - } - } - } - if ( (kp = seconds[cnt][tot].kp)!=NULL ) { - int mask = 0, mask2=0; - if ( seconds[cnt][tot].isv ) - mask = 0x0008; - else - mask = 0x0004; - if ( kp->adjust!=NULL ) { - mask |= mask<<4; - mask2 |= mask2<<4; - } - vf1 |= mask; - vf2 |= mask2; - } - } - } - if ( vf1==0 && vf2==0 ) vf1=1; - bit_cnt = 0; - for ( i=0; i<8; ++i ) { - if ( vf1&(1<<i) ) ++bit_cnt; - if ( vf2&(1<<i) ) ++bit_cnt; - } - - chunk_max = chunk_cnt = 0; - for ( start_cnt=0; start_cnt<cnt; start_cnt=end_cnt ) { - int len = 5*2; /* Subtable header */ - for ( end_cnt=start_cnt; end_cnt<cnt; ++end_cnt ) { - int glyph_len = 2; /* For the glyph's offset */ - if ( seconds[end_cnt][0].samewas==0xffff || seconds[end_cnt][0].samewas<start_cnt ) - glyph_len += (bit_cnt*2+2)*seconds[end_cnt][0].tot + - seconds[end_cnt][0].devtablen + - 2; /* Number of secondary glyphs */ - if ( glyph_len>65535 && end_cnt==start_cnt ) { - LogError(_("Lookup subtable %s contains a glyph %s whose kerning information takes up more than 64k bytes\n"), - sub->subtable_name, glyphs[start_cnt]->name ); - len += glyph_len; - } else if ( len+glyph_len>65535 ) { - if( start_cnt==0 ) - LogError(_("Lookup subtable %s had to be split into several subtables\nbecause it was too big.\n"), - sub->subtable_name ); - break; - } else - len += glyph_len; - } - if ( start_cnt!=0 || end_cnt!=cnt ) { - if ( chunk_cnt>=chunk_max ) - sub->extra_subtables = realloc(sub->extra_subtables,((chunk_max+=10)+1)*sizeof(uint32)); - sub->extra_subtables[chunk_cnt++] = ftell(gpos); - sub->extra_subtables[chunk_cnt] = -1; - } - - start = ftell(gpos); - putshort(gpos,1); /* 1 means char pairs (ie. not classes) */ - coverage_pos = ftell(gpos); - putshort(gpos,0); /* offset to coverage table */ - putshort(gpos,vf1); - putshort(gpos,vf2); - putshort(gpos,end_cnt-start_cnt); - offset_pos = ftell(gpos); - for ( i=start_cnt; i<end_cnt; ++i ) - putshort(gpos,0); /* Fill in later */ - for ( i=start_cnt; i<end_cnt; ++i ) { - if ( seconds[i][0].samewas>= start_cnt && seconds[i][0].samewas!=0xffff ) { - /* It's the same as the glyph at samewas, so just copy the */ - /* offset from there. We don't need to do anything else */ - int offset; - fseek(gpos,offset_pos+(seconds[i][0].samewas-start_cnt)*sizeof(uint16),SEEK_SET); - offset = getushort(gpos); - fseek(gpos,offset_pos+(i-start_cnt)*sizeof(uint16),SEEK_SET); - putshort(gpos,offset); - fseek(gpos,0,SEEK_END); - continue; - } - next_dev_tab = ftell(gpos)-start; - if ( (vf1&0xf0) || (vf2&0xf0) ) { - for ( tot=0 ; tot<seconds[i][0].tot; ++tot ) { - if ( (pst=seconds[i][tot].pst)!=NULL ) { - if ( pst->u.pair.vr[0].adjust!=NULL ) { - dumpgposdevicetable(gpos,&pst->u.pair.vr[0].adjust->xadjust); - dumpgposdevicetable(gpos,&pst->u.pair.vr[0].adjust->yadjust); - dumpgposdevicetable(gpos,&pst->u.pair.vr[0].adjust->xadv); - dumpgposdevicetable(gpos,&pst->u.pair.vr[0].adjust->yadv); - } - if ( pst->u.pair.vr[1].adjust!=NULL ) { - dumpgposdevicetable(gpos,&pst->u.pair.vr[1].adjust->xadjust); - dumpgposdevicetable(gpos,&pst->u.pair.vr[1].adjust->yadjust); - dumpgposdevicetable(gpos,&pst->u.pair.vr[1].adjust->xadv); - dumpgposdevicetable(gpos,&pst->u.pair.vr[1].adjust->yadv); - } - } - if ( (kp=seconds[i][tot].kp)!=NULL && kp->adjust!=NULL ) - dumpgposdevicetable(gpos,kp->adjust); - } - } - pos = ftell(gpos); - fseek(gpos,offset_pos+(i-start_cnt)*sizeof(uint16),SEEK_SET); - putshort(gpos,pos-start); - fseek(gpos,pos,SEEK_SET); - - putshort(gpos,seconds[i][0].tot); - for ( tot=0 ; tot<seconds[i][0].tot; ++tot ) { - putshort(gpos,seconds[i][tot].other_gid); - if ( (pst=seconds[i][tot].pst)!=NULL ) { - if ( vf1&1 ) putshort(gpos,pst->u.pair.vr[0].xoff); - if ( vf1&2 ) putshort(gpos,pst->u.pair.vr[0].yoff); - if ( vf1&4 ) putshort(gpos,pst->u.pair.vr[0].h_adv_off); - if ( vf1&8 ) putshort(gpos,pst->u.pair.vr[0].v_adv_off); - next_dev_tab = gposdumpvaldevtab(gpos,pst->u.pair.vr[0].adjust,vf1, - next_dev_tab); - if ( vf2&1 ) putshort(gpos,pst->u.pair.vr[1].xoff); - if ( vf2&2 ) putshort(gpos,pst->u.pair.vr[1].yoff); - if ( vf2&4 ) putshort(gpos,pst->u.pair.vr[1].h_adv_off); - if ( vf2&8 ) putshort(gpos,pst->u.pair.vr[1].v_adv_off); - next_dev_tab = gposdumpvaldevtab(gpos,pst->u.pair.vr[1].adjust,vf2, - next_dev_tab); - } else if ( (kp=seconds[i][tot].kp)!=NULL ) { - int mask=0, mask2=0; - if ( seconds[i][tot].isv ) - mask = 0x8; - else - mask = 0x4; - gposvrmaskeddump(gpos,vf1,mask,kp->off); - next_dev_tab = gposmaskeddumpdevtab(gpos,kp->adjust,vf1,mask<<4, - next_dev_tab); - gposvrmaskeddump(gpos,vf2,mask2,kp->off); - next_dev_tab = gposmaskeddumpdevtab(gpos,kp->adjust,vf2,mask2<<4, - next_dev_tab); - } - } - } - end = ftell(gpos); - fseek(gpos,coverage_pos,SEEK_SET); - if ( end-start>65535 ) - IError(_("I miscalculated the size of subtable %s, this means the kerning output is wrong."), sub->subtable_name ); - putshort(gpos,end-start); - fseek(gpos,end,SEEK_SET); - gtemp = glyphs[end_cnt]; glyphs[end_cnt] = NULL; - dumpcoveragetable(gpos,glyphs+start_cnt); - glyphs[end_cnt] = gtemp; - } - for ( i=0; i<cnt; ++i ) - free(seconds[i]); - free(seconds); - free(glyphs); -} - -uint16 *ClassesFromNames(SplineFont *sf,char **classnames,int class_cnt, - int numGlyphs, SplineChar ***glyphs, int apple_kc) { - uint16 *class; - int i; - char *pt, *end, ch; - SplineChar *sc, **gs=NULL; - int offset = (apple_kc && classnames[0]!=NULL); - - class = calloc(numGlyphs,sizeof(uint16)); - if ( glyphs ) *glyphs = gs = calloc(numGlyphs,sizeof(SplineChar *)); - for ( i=0; i<class_cnt; ++i ) { - if ( i==0 && classnames[0]==NULL ) - continue; - for ( pt = classnames[i]; *pt; pt = end+1 ) { - while ( *pt==' ' ) ++pt; - if ( *pt=='\0' ) - break; - end = strchr(pt,' '); - if ( end==NULL ) - end = pt+strlen(pt); - ch = *end; - *end = '\0'; - sc = SFGetChar(sf,-1,pt); - if ( sc!=NULL && sc->ttf_glyph!=-1 ) { - class[sc->ttf_glyph] = i+offset; - if ( gs!=NULL ) - gs[sc->ttf_glyph] = sc; - } - *end = ch; - if ( ch=='\0' ) - break; - } - } -return( class ); -} - -static SplineChar **GlyphsFromClasses(SplineChar **gs, int numGlyphs) { - int i, cnt; - SplineChar **glyphs; - - for ( i=cnt=0; i<numGlyphs; ++i ) - if ( gs[i]!=NULL ) ++cnt; - glyphs = malloc((cnt+1)*sizeof(SplineChar *)); - for ( i=cnt=0; i<numGlyphs; ++i ) - if ( gs[i]!=NULL ) - glyphs[cnt++] = gs[i]; - glyphs[cnt++] = NULL; - free(gs); -return( glyphs ); -} - -static SplineChar **GlyphsFromInitialClasses(SplineChar **gs, int numGlyphs, uint16 *classes, uint16 *initial) { - int i, j, cnt; - SplineChar **glyphs; - - for ( i=cnt=0; i<numGlyphs; ++i ) { - for ( j=0; initial[j]!=0xffff; ++j ) - if ( initial[j]==classes[i]) - break; - if ( initial[j]!=0xffff && gs[i]!=NULL ) ++cnt; - } - glyphs = malloc((cnt+1)*sizeof(SplineChar *)); - for ( i=cnt=0; i<numGlyphs; ++i ) { - for ( j=0; initial[j]!=0xffff; ++j ) - if ( initial[j]==classes[i]) - break; - if ( initial[j]!=0xffff && gs[i]!=NULL ) - glyphs[cnt++] = gs[i]; - } - glyphs[cnt++] = NULL; -return( glyphs ); -} - -static void DumpClass(FILE *gpos,uint16 *class,int numGlyphs) { - int ranges, i, cur, first= -1, last=-1, istart; - - for ( i=ranges=0; i<numGlyphs; ) { - istart = i; - cur = class[i]; - while ( i<numGlyphs && class[i]==cur ) - ++i; - if ( cur!=0 ) { - ++ranges; - if ( first==-1 ) first = istart; - last = i-1; - } - } - if ( ranges*3+1>last-first+1+2 || first==-1 ) { - if ( first==-1 ) first = last = 0; - putshort(gpos,1); /* Format 1, list of all posibilities */ - putshort(gpos,first); - putshort(gpos,last-first+1); - for ( i=first; i<=last ; ++i ) - putshort(gpos,class[i]); - } else { - putshort(gpos,2); /* Format 2, series of ranges */ - putshort(gpos,ranges); - for ( i=0; i<numGlyphs; ) { - istart = i; - cur = class[i]; - while ( i<numGlyphs && class[i]==cur ) - ++i; - if ( cur!=0 ) { - putshort(gpos,istart); - putshort(gpos,i-1); - putshort(gpos,cur); - } - } - } -} - -static void dumpgposkernclass(FILE *gpos,SplineFont *sf, - struct lookup_subtable *sub, struct alltabs *at) { - uint32 begin_off = ftell(gpos), pos; - uint16 *class1, *class2; - KernClass *kc = sub->kc, *test; - SplineChar **glyphs; - int i, isv; - int anydevtab = false; - int next_devtab; - - putshort(gpos,2); /* format 2 of the pair adjustment subtable */ - putshort(gpos,0); /* offset to coverage table */ - for ( i=0; i<kc->first_cnt*kc->second_cnt; ++i ) { - if ( kc->adjusts[i].corrections!=NULL ) { - anydevtab = true; - break; - } - } - - for ( test=sf->vkerns; test!=NULL && test!=kc; test=test->next ); - isv = test==kc; - - if ( isv ) { - /* As far as I know there is no "bottom to top" writing direction */ - /* Oh. There is. Ogham, Runic */ - putshort(gpos,anydevtab?0x0088:0x0008); /* Alter YAdvance of first character */ - putshort(gpos,0x0000); /* leave second char alone */ - } else { - putshort(gpos,anydevtab?0x0044:0x0004); /* Alter XAdvance of first character */ - putshort(gpos,0x0000); /* leave second char alone */ - } - class1 = ClassesFromNames(sf,kc->firsts,kc->first_cnt,at->maxp.numGlyphs,&glyphs,false); - glyphs = GlyphsFromClasses(glyphs,at->maxp.numGlyphs); - class2 = ClassesFromNames(sf,kc->seconds,kc->second_cnt,at->maxp.numGlyphs,NULL,false); - putshort(gpos,0); /* offset to first glyph classes */ - putshort(gpos,0); /* offset to second glyph classes */ - putshort(gpos,kc->first_cnt); - putshort(gpos,kc->second_cnt); - next_devtab = ftell(gpos)-begin_off + kc->first_cnt*kc->second_cnt*2*sizeof(uint16); - for ( i=0; i<kc->first_cnt*kc->second_cnt; ++i ) { - putshort(gpos,kc->offsets[i]); - if ( anydevtab && kc->adjusts[i].corrections!=NULL ) { - putshort(gpos,next_devtab); - next_devtab += DevTabLen(&kc->adjusts[i]); - } else if ( anydevtab ) - putshort(gpos,0); - } - if ( anydevtab ) { - for ( i=0; i<kc->first_cnt*kc->second_cnt; ++i ) { - if ( kc->adjusts[i].corrections!=NULL ) - dumpgposdevicetable(gpos,&kc->adjusts[i]); - } - if ( next_devtab!=ftell(gpos)-begin_off ) - IError("Device table offsets screwed up in kerning class"); - } - pos = ftell(gpos); - fseek(gpos,begin_off+4*sizeof(uint16),SEEK_SET); - putshort(gpos,pos-begin_off); - fseek(gpos,pos,SEEK_SET); - DumpClass(gpos,class1,at->maxp.numGlyphs); - - pos = ftell(gpos); - fseek(gpos,begin_off+5*sizeof(uint16),SEEK_SET); - putshort(gpos,pos-begin_off); - fseek(gpos,pos,SEEK_SET); - DumpClass(gpos,class2,at->maxp.numGlyphs); - - pos = ftell(gpos); - fseek(gpos,begin_off+sizeof(uint16),SEEK_SET); - putshort(gpos,pos-begin_off); - fseek(gpos,pos,SEEK_SET); - dumpcoveragetable(gpos,glyphs); - - free(glyphs); - free(class1); - free(class2); -} - -static void dumpanchor(FILE *gpos,AnchorPoint *ap, int is_ttf ) { - int base = ftell(gpos); - - if ( ap->xadjust.corrections!=NULL || ap->yadjust.corrections!=NULL ) - putshort(gpos,3); /* format 3 w/ device tables */ - else - if ( ap->has_ttf_pt && is_ttf ) - putshort(gpos,2); /* format 2 w/ a matching ttf point index */ - else - putshort(gpos,1); /* Anchor format 1 just location*/ - putshort(gpos,ap->me.x); /* X coord of attachment */ - putshort(gpos,ap->me.y); /* Y coord of attachment */ - if ( ap->xadjust.corrections!=NULL || ap->yadjust.corrections!=NULL ) { - putshort(gpos,ap->xadjust.corrections==NULL?0: - ftell(gpos)-base+4); - putshort(gpos,ap->yadjust.corrections==NULL?0: - ftell(gpos)-base+2+DevTabLen(&ap->xadjust)); - dumpgposdevicetable(gpos,&ap->xadjust); - dumpgposdevicetable(gpos,&ap->yadjust); - } else - if ( ap->has_ttf_pt && is_ttf ) - putshort(gpos,ap->ttf_pt_index); -} - -static void dumpgposCursiveAttach(FILE *gpos, SplineFont *sf, - struct lookup_subtable *sub,struct glyphinfo *gi) { - AnchorClass *ac, *testac; - SplineChar **entryexit; - int cnt, offset,j; - AnchorPoint *ap, *entry, *exit; - uint32 coverage_offset, start; - - ac = NULL; - for ( testac=sf->anchor; testac!=NULL; testac = testac->next ) { - if ( testac->subtable == sub ) { - if ( ac==NULL ) - ac = testac; - else { - ff_post_error(_("Two cursive anchor classes"),_("Two cursive anchor classes in the same subtable, %s"), - sub->subtable_name); - break; - } - } - } - if ( ac==NULL ) { - IError( "Missing anchor class for %s", sub->subtable_name ); -return; - } - entryexit = EntryExitDecompose(sf,ac,gi); - if ( entryexit==NULL ) -return; - - for ( cnt=0; entryexit[cnt]!=NULL; ++cnt ); - - start = ftell(gpos); - putshort(gpos,1); /* format 1 for this subtable */ - putshort(gpos,0); /* Fill in later, offset to coverage table */ - putshort(gpos,cnt); /* number of glyphs */ - - offset = 6+2*2*cnt; - for ( j=0; j<cnt; ++j ) { - entry = exit = NULL; - for ( ap=entryexit[j]->anchor; ap!=NULL; ap=ap->next ) { - if ( ap->anchor==ac && ap->type==at_centry ) entry = ap; - if ( ap->anchor==ac && ap->type==at_cexit ) exit = ap; - } - if ( entry!=NULL ) { - putshort(gpos,offset); - offset += 6; - if ( entry->xadjust.corrections!=NULL || entry->yadjust.corrections!=NULL ) - offset += 4 + DevTabLen(&entry->xadjust) + DevTabLen(&entry->yadjust); - if ( gi->is_ttf && entry->has_ttf_pt ) - offset += 2; - } else - putshort(gpos,0); - if ( exit!=NULL ) { - putshort(gpos,offset); - offset += 6; - if ( exit->xadjust.corrections!=NULL || exit->yadjust.corrections!=NULL ) - offset += 4 + DevTabLen(&exit->xadjust) + DevTabLen(&exit->yadjust); - else - if ( gi->is_ttf && exit->has_ttf_pt ) - offset += 2; - } else - putshort(gpos,0); - } - for ( j=0; j<cnt; ++j ) { - entry = exit = NULL; - for ( ap=entryexit[j]->anchor; ap!=NULL; ap=ap->next ) { - if ( ap->anchor==ac && ap->type==at_centry ) entry = ap; - if ( ap->anchor==ac && ap->type==at_cexit ) exit = ap; - } - if ( entry!=NULL ) - dumpanchor(gpos,entry,gi->is_ttf); - if ( exit!=NULL ) - dumpanchor(gpos,exit,gi->is_ttf); - } - coverage_offset = ftell(gpos); - dumpcoveragetable(gpos,entryexit); - fseek(gpos,start+2,SEEK_SET); - putshort(gpos,coverage_offset-start); - fseek(gpos,0,SEEK_END); - - free(entryexit); -} - -static int orderglyph(const void *_sc1,const void *_sc2) { - SplineChar * const *sc1 = _sc1, * const *sc2 = _sc2; - -return( (*sc1)->ttf_glyph - (*sc2)->ttf_glyph ); -} - -static SplineChar **allmarkglyphs(SplineChar ***glyphlist, int classcnt) { - SplineChar **glyphs; - int i, tot, k; - - if ( classcnt==1 ) -return( SFOrderedGlyphs(glyphlist[0])); - - for ( i=tot=0; i<classcnt; ++i ) { - for ( k=0; glyphlist[i][k]!=NULL; ++k ); - tot += k; - } - glyphs = malloc((tot+1)*sizeof(SplineChar *)); - for ( i=tot=0; i<classcnt; ++i ) { - for ( k=0; glyphlist[i][k]!=NULL; ++k ) - glyphs[tot++] = glyphlist[i][k]; - } - qsort(glyphs,tot,sizeof(SplineChar *),orderglyph); - for ( i=k=0; i<tot; ++i ) { - while ( i+1<tot && glyphs[i]==glyphs[i+1]) ++i; - glyphs[k++] = glyphs[i]; - } - glyphs[k] = NULL; -return( glyphs ); -} - -static void dumpgposAnchorData(FILE *gpos,AnchorClass *_ac, - enum anchor_type at, - SplineChar ***marks,SplineChar **base, - int classcnt, struct glyphinfo *gi) { - AnchorClass *ac=NULL; - int j,cnt,k,l, pos, offset, tot, max; - uint32 coverage_offset, markarray_offset, subtable_start; - AnchorPoint *ap, **aps; - SplineChar **markglyphs; - - for ( cnt=0; base[cnt]!=NULL; ++cnt ); - - subtable_start = ftell(gpos); - putshort(gpos,1); /* format 1 for this subtable */ - putshort(gpos,0); /* Fill in later, offset to mark coverage table */ - putshort(gpos,0); /* Fill in later, offset to base coverage table */ - putshort(gpos,classcnt); - putshort(gpos,0); /* Fill in later, offset to mark array */ - putshort(gpos,12); /* Offset to base array */ - /* Base array */ - putshort(gpos,cnt); /* Number of entries in array */ - if ( at==at_basechar || at==at_basemark ) { - offset = 2; - for ( l=0; l<3; ++l ) { - for ( j=0; j<cnt; ++j ) { - for ( k=0, ac=_ac; k<classcnt; ac=ac->next ) if ( ac->matches ) { - if ( !ac->has_mark || !ac->has_base ) - continue; - for ( ap=base[j]->anchor; ap!=NULL && (ap->anchor!=ac || ap->type!=at); - ap=ap->next ); - switch ( l ) { - case 0: - offset += 2; - break; - case 1: - if ( ap==NULL ) - putshort(gpos,0); - else { - putshort(gpos,offset); - offset += 6; - if ( ap->xadjust.corrections!=NULL || ap->yadjust.corrections!=NULL ) - offset += 4 + DevTabLen(&ap->xadjust) + DevTabLen(&ap->yadjust); - else - if ( gi->is_ttf && ap->has_ttf_pt ) - offset += 2; - } - break; - case 2: - if ( ap!=NULL ) - dumpanchor(gpos,ap,gi->is_ttf); - break; - } - ++k; - } - } - } - } else { - offset = 2+2*cnt; - max = 0; - for ( j=0; j<cnt; ++j ) { - putshort(gpos,offset); - pos = tot = 0; - for ( ap=base[j]->anchor; ap!=NULL ; ap=ap->next ) - for ( k=0, ac=_ac; k<classcnt; ac=ac->next ) if ( ac->matches ) { - if ( ap->anchor==ac ) { - if ( ap->lig_index>pos ) pos = ap->lig_index; - ++tot; - } - ++k; - } - if ( pos>max ) max = pos; - offset += 2+(pos+1)*classcnt*2+tot*6; - /* 2 for component count, for each component an offset to an offset to an anchor record */ - } - ++max; - int special_ceiling = classcnt*max; - aps = malloc((classcnt*max+max)*sizeof(AnchorPoint *)); - for ( j=0; j<cnt; ++j ) { - memset(aps,0,(classcnt*max+max)*sizeof(AnchorPoint *)); - pos = 0; - for ( ap=base[j]->anchor; ap!=NULL ; ap=ap->next ) - for ( k=0, ac=_ac; k<classcnt; ac=ac->next ) if ( ac->matches ) { - if ( ap->anchor==ac ) { - if ( ap->lig_index>pos ) pos = ap->lig_index; - if (k*max+ap->lig_index > special_ceiling || k*max+ap->lig_index < 0) { - fprintf(stderr, "A ligature index is invalid.\n"); - } else { - aps[k*max+ap->lig_index] = ap; - } - } - ++k; - } - ++pos; - putshort(gpos,pos); - offset = 2+2*pos*classcnt; - for ( l=0; l<pos; ++l ) { - for ( k=0; k<classcnt; ++k ) { - if ( aps[k*max+l]==NULL ) - putshort(gpos,0); - else { - putshort(gpos,offset); - offset += 6; - if ( aps[k*max+l]->xadjust.corrections!=NULL || aps[k*max+l]->yadjust.corrections!=NULL ) - offset += 4 + DevTabLen(&aps[k*max+l]->xadjust) + - DevTabLen(&aps[k*max+l]->yadjust); - else - if ( gi->is_ttf && aps[k*max+l]->has_ttf_pt ) - offset += 2; - } - } - } - for ( l=0; l<pos; ++l ) { - for ( k=0; k<classcnt; ++k ) { - if ( aps[k*max+l]!=NULL ) { - dumpanchor(gpos,aps[k*max+l],gi->is_ttf); - } - } - } - } - free(aps); aps = NULL; - } - coverage_offset = ftell(gpos); - fseek(gpos,subtable_start+4,SEEK_SET); - putshort(gpos,coverage_offset-subtable_start); - fseek(gpos,0,SEEK_END); - dumpcoveragetable(gpos,base); - - /* We tried sharing the mark table, (among all these sub-tables) but */ - /* that doesn't work because we need to be able to reorder the sub-tables */ - markglyphs = allmarkglyphs(marks,classcnt); - coverage_offset = ftell(gpos); - dumpcoveragetable(gpos,markglyphs); - markarray_offset = ftell(gpos); - for ( cnt=0; markglyphs[cnt]!=NULL; ++cnt ); - putshort(gpos,cnt); - offset = 2+4*cnt; - for ( j=0; j<cnt; ++j ) { - if ( classcnt==0 ) { - putshort(gpos,0); /* Only one class */ - ap = NULL; - } else { - for ( k=0, ac=_ac; k<classcnt; ac=ac->next ) { - if ( ac->matches ) { - for ( ap = markglyphs[j]->anchor; ap!=NULL && (ap->anchor!=ac || ap->type!=at_mark); - ap=ap->next ); - if ( ap!=NULL ) - break; - ++k; - } - } - putshort(gpos,k); - } - putshort(gpos,offset); - offset += 6; - if ( ap!=NULL && (ap->xadjust.corrections!=NULL || ap->yadjust.corrections!=NULL )) - offset += 4 + DevTabLen(&ap->xadjust) + DevTabLen(&ap->yadjust); - else - if ( gi->is_ttf && ap->has_ttf_pt ) - offset += 2; - } - for ( j=0; j<cnt; ++j ) { - for ( k=0, ac=_ac; k<classcnt; ac=ac->next ) { - if ( ac->matches ) { - for ( ap = markglyphs[j]->anchor; ap!=NULL && (ap->anchor!=ac || ap->type!=at_mark); - ap=ap->next ); - if ( ap!=NULL ) - break; - ++k; - } - } - dumpanchor(gpos,ap,gi->is_ttf); - } - if ( markglyphs!=marks[0] ) - free(markglyphs); - - fseek(gpos,subtable_start+2,SEEK_SET); /* mark coverage table offset */ - putshort(gpos,coverage_offset-subtable_start); - fseek(gpos,4,SEEK_CUR); - putshort(gpos,markarray_offset-subtable_start); - - fseek(gpos,0,SEEK_END); -} - -static void dumpGSUBsimplesubs(FILE *gsub,SplineFont *sf,struct lookup_subtable *sub) { - int cnt, diff, ok = true; - int32 coverage_pos, end; - SplineChar **glyphs, ***maps; - - glyphs = SFOrderedGlyphsWithPSTinSubtable(sf,sub); - maps = generateMapList(glyphs,sub); - - diff = (*maps[0])->ttf_glyph - glyphs[0]->ttf_glyph; - for ( cnt=0; glyphs[cnt]!=NULL; ++cnt) - if ( diff!= maps[cnt][0]->ttf_glyph-glyphs[cnt]->ttf_glyph ) ok = false; - - if ( ok ) { - putshort(gsub,1); /* delta format */ - coverage_pos = ftell(gsub); - putshort(gsub,0); /* offset to coverage table */ - putshort(gsub,diff); - } else { - putshort(gsub,2); /* glyph list format */ - coverage_pos = ftell(gsub); - putshort(gsub,0); /* offset to coverage table */ - putshort(gsub,cnt); - for ( cnt = 0; glyphs[cnt]!=NULL; ++cnt ) - putshort(gsub,(*maps[cnt])->ttf_glyph); - } - end = ftell(gsub); - fseek(gsub,coverage_pos,SEEK_SET); - putshort(gsub,end-coverage_pos+2); - fseek(gsub,end,SEEK_SET); - dumpcoveragetable(gsub,glyphs); - - free(glyphs); - GlyphMapFree(maps); -} - -static void dumpGSUBmultiplesubs(FILE *gsub,SplineFont *sf,struct lookup_subtable *sub) { - int cnt, offset; - int32 coverage_pos, end; - int gc; - SplineChar **glyphs, ***maps; - - glyphs = SFOrderedGlyphsWithPSTinSubtable(sf,sub); - maps = generateMapList(glyphs,sub); - for ( cnt=0; glyphs[cnt]!=NULL; ++cnt); - - putshort(gsub,1); /* glyph list format */ - coverage_pos = ftell(gsub); - putshort(gsub,0); /* offset to coverage table */ - putshort(gsub,cnt); - offset = 6+2*cnt; - for ( cnt = 0; glyphs[cnt]!=NULL; ++cnt ) { - putshort(gsub,offset); - if (maps[cnt] == NULL) { - fprintf( stderr, "maps[%d] is null; glyphs[%d] is \"%s\"; lookup name is \"%s\".\n" , cnt , cnt , (glyphs[cnt]->name ? glyphs[cnt]->name : ""), sub->subtable_name) ; - } - for ( gc=0; maps[cnt][gc]!=NULL; ++gc ); - offset += 2+2*gc; - } - for ( cnt = 0; glyphs[cnt]!=NULL; ++cnt ) { - for ( gc=0; maps[cnt][gc]!=NULL; ++gc ); - putshort(gsub,gc); - for ( gc=0; maps[cnt][gc]!=NULL; ++gc ) - putshort(gsub,maps[cnt][gc]->ttf_glyph); - } - end = ftell(gsub); - fseek(gsub,coverage_pos,SEEK_SET); - putshort(gsub,end-coverage_pos+2); - fseek(gsub,end,SEEK_SET); - dumpcoveragetable(gsub,glyphs); - - free(glyphs); - GlyphMapFree(maps); -} - -static int AllToBeOutput(LigList *lig) { - struct splinecharlist *cmp; - - if ( lig->lig->u.lig.lig->ttf_glyph==-1 || - lig->first->ttf_glyph==-1 ) -return( 0 ); - for ( cmp=lig->components; cmp!=NULL; cmp=cmp->next ) - if ( cmp->sc->ttf_glyph==-1 ) -return( 0 ); -return( true ); -} - -static void dumpGSUBligdata(FILE *gsub,SplineFont *sf, - struct lookup_subtable *sub, struct alltabs *at) { - int32 coverage_pos, next_val_pos, here, lig_list_start; - int cnt, i, pcnt, lcnt, max=100, j; - uint16 *offsets=NULL, *ligoffsets=malloc(max*sizeof(uint16)); - SplineChar **glyphs; - LigList *ll; - struct splinecharlist *scl; - - glyphs = SFOrderedGlyphsWithPSTinSubtable(sf,sub); - cnt=0; - if ( glyphs!=NULL ) for ( ; glyphs[cnt]!=NULL; ++cnt ); - - putshort(gsub,1); /* only one format for ligatures */ - coverage_pos = ftell(gsub); - putshort(gsub,0); /* offset to coverage table */ - putshort(gsub,cnt); - next_val_pos = ftell(gsub); - if ( glyphs!=NULL ) - offsets = malloc(cnt*sizeof(int16)); - for ( i=0; i<cnt; ++i ) - putshort(gsub,0); - for ( i=0; i<cnt; ++i ) { - offsets[i] = ftell(gsub)-coverage_pos+2; - for ( pcnt = 0, ll = glyphs[i]->ligofme; ll!=NULL; ll=ll->next ) - if ( ll->lig->subtable==sub && AllToBeOutput(ll)) - ++pcnt; - putshort(gsub,pcnt); - if ( pcnt>=max ) { - max = pcnt+100; - ligoffsets = realloc(ligoffsets,max*sizeof(int)); - } - lig_list_start = ftell(gsub); - for ( j=0; j<pcnt; ++j ) - putshort(gsub,0); /* Place holders */ - for ( pcnt=0, ll = glyphs[i]->ligofme; ll!=NULL; ll=ll->next ) { - if ( ll->lig->subtable==sub && AllToBeOutput(ll)) { - ligoffsets[pcnt] = ftell(gsub)-lig_list_start+2; - putshort(gsub,ll->lig->u.lig.lig->ttf_glyph); - for ( lcnt=0, scl=ll->components; scl!=NULL; scl=scl->next ) ++lcnt; - putshort(gsub, lcnt+1); - if ( lcnt+1>at->os2.maxContext ) - at->os2.maxContext = lcnt+1; - for ( scl=ll->components; scl!=NULL; scl=scl->next ) - putshort(gsub, scl->sc->ttf_glyph ); - ++pcnt; - } - } - fseek(gsub,lig_list_start,SEEK_SET); - for ( j=0; j<pcnt; ++j ) - putshort(gsub,ligoffsets[j]); - fseek(gsub,0,SEEK_END); - } - free(ligoffsets); - if ( glyphs!=NULL ) { - here = ftell(gsub); - fseek(gsub,coverage_pos,SEEK_SET); - putshort(gsub,here-coverage_pos+2); - fseek(gsub,next_val_pos,SEEK_SET); - for ( i=0; i<cnt; ++i ) - putshort(gsub,offsets[i]); - fseek(gsub,here,SEEK_SET); - dumpcoveragetable(gsub,glyphs); - free(glyphs); - free(offsets); - } -} - -static int ui16cmp(const void *_i1, const void *_i2) { - if ( *(const uint16 *) _i1 > *(const uint16 *) _i2 ) -return( 1 ); - if ( *(const uint16 *) _i1 < *(const uint16 *) _i2 ) -return( -1 ); - -return( 0 ); -} - -static uint16 *FigureInitialClasses(FPST *fpst) { - uint16 *initial = malloc((fpst->nccnt+1)*sizeof(uint16)); - int i, cnt, j; - - initial[fpst->nccnt] = 0xffff; - for ( i=cnt=0; i<fpst->rule_cnt; ++i ) { - for ( j=0; j<cnt ; ++j ) - if ( initial[j] == fpst->rules[i].u.class.nclasses[0] ) - break; - if ( j==cnt ) - initial[cnt++] = fpst->rules[i].u.class.nclasses[0]; - } - qsort(initial,cnt,sizeof(uint16),ui16cmp); - initial[cnt] = 0xffff; -return( initial ); -} - -static SplineChar **OrderedInitialGlyphs(SplineFont *sf,FPST *fpst) { - SplineChar **glyphs, *sc; - int i, j, cnt, ch; - char *pt, *names; - - glyphs = malloc((fpst->rule_cnt+1)*sizeof(SplineChar *)); - for ( i=cnt=0; i<fpst->rule_cnt; ++i ) { - names = fpst->rules[i].u.glyph.names; - pt = strchr(names,' '); - if ( pt==NULL ) pt = names+strlen(names); - ch = *pt; *pt = '\0'; - sc = SFGetChar(sf,-1,names); - *pt = ch; - for ( j=0; j<cnt; ++j ) - if ( glyphs[j]==sc ) - break; - if ( j==cnt && sc!=NULL ) - glyphs[cnt++] = sc; - } - glyphs[cnt] = NULL; - if ( cnt==0 ) -return( glyphs ); - - for ( i=0; glyphs[i+1]!=NULL; ++i ) for ( j=i+1; glyphs[j]!=NULL; ++j ) { - if ( glyphs[i]->ttf_glyph > glyphs[j]->ttf_glyph ) { - sc = glyphs[i]; - glyphs[i] = glyphs[j]; - glyphs[j] = sc; - } - } -return( glyphs ); -} - -static int NamesStartWith(SplineChar *sc,char *names ) { - char *pt; - - pt = strchr(names,' '); - if ( pt==NULL ) pt = names+strlen(names); - if ( pt-names!=strlen(sc->name)) -return( false ); - -return( strncmp(sc->name,names,pt-names)==0 ); -} - -static int CntRulesStartingWith(FPST *fpst,SplineChar *sc) { - int i, cnt; - - for ( i=cnt=0; i<fpst->rule_cnt; ++i ) { - if ( NamesStartWith(sc,fpst->rules[i].u.glyph.names)) - ++cnt; - } -return( cnt ); -} - -static int CntRulesStartingWithClass(FPST *fpst,uint16 cval) { - int i, cnt; - - for ( i=cnt=0; i<fpst->rule_cnt; ++i ) { - if ( fpst->rules[i].u.class.nclasses[0]==cval ) - ++cnt; - } -return( cnt ); -} - -static void dumpg___ContextChainGlyphs(FILE *lfile,SplineFont *sf, - struct lookup_subtable *sub, struct alltabs *at) { - FPST *fpst = sub->fpst; - int iscontext = fpst->type==pst_contextpos || fpst->type==pst_contextsub; - uint32 base = ftell(lfile); - int i,cnt, subcnt, j,k,l, maxcontext,curcontext; - SplineChar **glyphs, **subglyphs; - int lc; - - glyphs = OrderedInitialGlyphs(sf,fpst); - for ( cnt=0; glyphs[cnt]!=NULL; ++cnt ); - - putshort(lfile,1); /* Sub format 1 => glyph lists */ - putshort(lfile,(3+cnt)*sizeof(short)); /* offset to coverage */ - putshort(lfile,cnt); - for ( i=0; i<cnt; ++i ) - putshort(lfile,0); /* Offset to rule */ - dumpcoveragetable(lfile,glyphs); - - maxcontext = 0; - - for ( i=0; i<cnt; ++i ) { - uint32 pos = ftell(lfile); - fseek(lfile,base+(3+i)*sizeof(short),SEEK_SET); - putshort(lfile,pos-base); - fseek(lfile,pos,SEEK_SET); - subcnt = CntRulesStartingWith(fpst,glyphs[i]); - putshort(lfile,subcnt); - for ( j=0; j<subcnt; ++j ) - putshort(lfile,0); - for ( j=k=0; k<fpst->rule_cnt; ++k ) if ( NamesStartWith(glyphs[i],fpst->rules[k].u.glyph.names )) { - uint32 subpos = ftell(lfile); - fseek(lfile,pos+(1+j)*sizeof(short),SEEK_SET); - putshort(lfile,subpos-pos); - fseek(lfile,subpos,SEEK_SET); - - for ( l=lc=0; l<fpst->rules[k].lookup_cnt; ++l ) - if ( fpst->rules[k].lookups[l].lookup->lookup_index!=-1 ) - ++lc; - if ( iscontext ) { - subglyphs = SFGlyphsFromNames(sf,fpst->rules[k].u.glyph.names); - for ( l=0; subglyphs[l]!=NULL; ++l ); - putshort(lfile,l); - curcontext = l; - putshort(lfile,lc); - for ( l=1; subglyphs[l]!=NULL; ++l ) - putshort(lfile,subglyphs[l]->ttf_glyph); - free(subglyphs); - } else { - subglyphs = SFGlyphsFromNames(sf,fpst->rules[k].u.glyph.back); - for ( l=0; subglyphs[l]!=NULL; ++l ); - putshort(lfile,l); - curcontext = l; - for ( l=0; subglyphs[l]!=NULL; ++l ) - putshort(lfile,subglyphs[l]->ttf_glyph); - free(subglyphs); - subglyphs = SFGlyphsFromNames(sf,fpst->rules[k].u.glyph.names); - for ( l=0; subglyphs[l]!=NULL; ++l ); - putshort(lfile,l); - curcontext += l; - for ( l=1; subglyphs[l]!=NULL; ++l ) - putshort(lfile,subglyphs[l]->ttf_glyph); - free(subglyphs); - subglyphs = SFGlyphsFromNames(sf,fpst->rules[k].u.glyph.fore); - for ( l=0; subglyphs[l]!=NULL; ++l ); - putshort(lfile,l); - curcontext += l; - for ( l=0; subglyphs[l]!=NULL; ++l ) - putshort(lfile,subglyphs[l]->ttf_glyph); - free(subglyphs); - putshort(lfile,lc); - } - for ( l=0; l<fpst->rules[k].lookup_cnt; ++l ) - if ( fpst->rules[k].lookups[l].lookup->lookup_index!=-1 ) { - putshort(lfile,fpst->rules[k].lookups[l].seq); - putshort(lfile,fpst->rules[k].lookups[l].lookup->lookup_index); - } - ++j; - if ( curcontext>maxcontext ) maxcontext = curcontext; - } - } - free(glyphs); - - if ( maxcontext>at->os2.maxContext ) - at->os2.maxContext = maxcontext; -} - -static void dumpg___ContextChainClass(FILE *lfile,SplineFont *sf, - struct lookup_subtable *sub, struct alltabs *at) { - FPST *fpst = sub->fpst; - int iscontext = fpst->type==pst_contextpos || fpst->type==pst_contextsub; - uint32 base = ftell(lfile), rulebase, pos, subpos, npos; - uint16 *initialclasses, *iclass, *bclass, *lclass; - SplineChar **iglyphs, **bglyphs, **lglyphs, **glyphs; - int i,ii,cnt, subcnt, j,k,l , maxcontext,curcontext; - int lc; - - putshort(lfile,2); /* Sub format 2 => class */ - putshort(lfile,0); /* offset to coverage table */ - if ( iscontext ) - putshort(lfile,0); /* offset to input classdef */ - else { - putshort(lfile,0); /* offset to backtrack classdef */ - putshort(lfile,0); /* offset to input classdef */ - putshort(lfile,0); /* offset to lookahead classdef */ - } - initialclasses = FigureInitialClasses(fpst); - putshort(lfile,fpst->nccnt); - rulebase = ftell(lfile); - for ( cnt=0; cnt<fpst->nccnt; ++cnt ) - putshort(lfile,0); - - iclass = ClassesFromNames(sf,fpst->nclass,fpst->nccnt,at->maxp.numGlyphs,&iglyphs,false); - lglyphs = bglyphs = NULL; bclass = lclass = NULL; - if ( !iscontext ) { - bclass = ClassesFromNames(sf,fpst->bclass,fpst->bccnt,at->maxp.numGlyphs,&bglyphs,false); - lclass = ClassesFromNames(sf,fpst->fclass,fpst->fccnt,at->maxp.numGlyphs,&lglyphs,false); - } - pos = ftell(lfile); - fseek(lfile,base+sizeof(uint16),SEEK_SET); - putshort(lfile,pos-base); - fseek(lfile,pos,SEEK_SET); - glyphs = GlyphsFromInitialClasses(iglyphs,at->maxp.numGlyphs,iclass,initialclasses); - dumpcoveragetable(lfile,glyphs); - free(glyphs); - free(iglyphs); free(bglyphs); free(lglyphs); - - if ( iscontext ) { - pos = ftell(lfile); - fseek(lfile,base+2*sizeof(uint16),SEEK_SET); - putshort(lfile,pos-base); - fseek(lfile,pos,SEEK_SET); - DumpClass(lfile,iclass,at->maxp.numGlyphs); - free(iclass); - } else { - pos = ftell(lfile); - fseek(lfile,base+2*sizeof(uint16),SEEK_SET); - putshort(lfile,pos-base); - fseek(lfile,pos,SEEK_SET); - DumpClass(lfile,bclass,at->maxp.numGlyphs); - if ( ClassesMatch(fpst->bccnt,fpst->bclass,fpst->nccnt,fpst->nclass)) { - npos = pos; - fseek(lfile,base+3*sizeof(uint16),SEEK_SET); - putshort(lfile,npos-base); - fseek(lfile,0,SEEK_END); - } else { - npos = ftell(lfile); - fseek(lfile,base+3*sizeof(uint16),SEEK_SET); - putshort(lfile,npos-base); - fseek(lfile,npos,SEEK_SET); - DumpClass(lfile,iclass,at->maxp.numGlyphs); - } - if ( ClassesMatch(fpst->fccnt,fpst->fclass,fpst->bccnt,fpst->bclass)) { - fseek(lfile,base+4*sizeof(uint16),SEEK_SET); - putshort(lfile,pos-base); - fseek(lfile,0,SEEK_END); - } else if ( ClassesMatch(fpst->fccnt,fpst->fclass,fpst->nccnt,fpst->nclass)) { - fseek(lfile,base+4*sizeof(uint16),SEEK_SET); - putshort(lfile,npos-base); - fseek(lfile,0,SEEK_END); - } else { - pos = ftell(lfile); - fseek(lfile,base+4*sizeof(uint16),SEEK_SET); - putshort(lfile,pos-base); - fseek(lfile,pos,SEEK_SET); - DumpClass(lfile,lclass,at->maxp.numGlyphs); - } - free(iclass); free(bclass); free(lclass); - } - - ii=0; - for ( i=0; i<fpst->nccnt; ++i ) { - if ( initialclasses[ii]!=i ) { - /* This class isn't an initial one, so leave it's rule pointer NULL */ - } else { - ++ii; - pos = ftell(lfile); - fseek(lfile,rulebase+i*sizeof(short),SEEK_SET); - putshort(lfile,pos-base); - fseek(lfile,pos,SEEK_SET); - subcnt = CntRulesStartingWithClass(fpst,i); - putshort(lfile,subcnt); - for ( j=0; j<subcnt; ++j ) - putshort(lfile,0); - for ( j=k=0; k<fpst->rule_cnt; ++k ) if ( i==fpst->rules[k].u.class.nclasses[0] ) { - subpos = ftell(lfile); - fseek(lfile,pos+(1+j)*sizeof(short),SEEK_SET); - putshort(lfile,subpos-pos); - fseek(lfile,subpos,SEEK_SET); - - for ( l=lc=0; l<fpst->rules[k].lookup_cnt; ++l ) - if ( fpst->rules[k].lookups[l].lookup->lookup_index!=-1 ) - ++lc; - if ( iscontext ) { - putshort(lfile,fpst->rules[k].u.class.ncnt); - putshort(lfile,lc); - for ( l=1; l<fpst->rules[k].u.class.ncnt; ++l ) - putshort(lfile,fpst->rules[k].u.class.nclasses[l]); - } else { - putshort(lfile,fpst->rules[k].u.class.bcnt); - for ( l=0; l<fpst->rules[k].u.class.bcnt; ++l ) - putshort(lfile,fpst->rules[k].u.class.bclasses[l]); - putshort(lfile,fpst->rules[k].u.class.ncnt); - for ( l=1; l<fpst->rules[k].u.class.ncnt; ++l ) - putshort(lfile,fpst->rules[k].u.class.nclasses[l]); - putshort(lfile,fpst->rules[k].u.class.fcnt); - for ( l=0; l<fpst->rules[k].u.class.fcnt; ++l ) - putshort(lfile,fpst->rules[k].u.class.fclasses[l]); - putshort(lfile,lc); - } - for ( l=0; l<fpst->rules[k].lookup_cnt; ++l ) - if ( fpst->rules[k].lookups[l].lookup->lookup_index!=-1 ) { - putshort(lfile,fpst->rules[k].lookups[l].seq); - putshort(lfile,fpst->rules[k].lookups[l].lookup->lookup_index); - } - ++j; - } - } - } - free(initialclasses); - - maxcontext = 0; - for ( i=0; i<fpst->rule_cnt; ++i ) { - curcontext = fpst->rules[i].u.class.ncnt+fpst->rules[i].u.class.bcnt+fpst->rules[i].u.class.fcnt; - if ( curcontext>maxcontext ) maxcontext = curcontext; - } - if ( maxcontext>at->os2.maxContext ) - at->os2.maxContext = maxcontext; -} - -static void dumpg___ContextChainCoverage(FILE *lfile,SplineFont *sf, - struct lookup_subtable *sub, struct alltabs *at) { - FPST *fpst = sub->fpst; - int iscontext = fpst->type==pst_contextpos || fpst->type==pst_contextsub; - uint32 base = ftell(lfile), ibase, lbase, bbase; - int i, l; - SplineChar **glyphs; - int curcontext; - int lc; - - if ( fpst->rule_cnt!=1 ) - IError("Bad rule cnt in coverage context lookup"); - if ( fpst->format==pst_reversecoverage && fpst->rules[0].u.rcoverage.always1!=1 ) - IError("Bad input count in reverse coverage lookup" ); - - putshort(lfile,3); /* Sub format 3 => coverage */ - for ( l=lc=0; l<fpst->rules[0].lookup_cnt; ++l ) - if ( fpst->rules[0].lookups[l].lookup->lookup_index!=-1 ) - ++lc; - if ( iscontext ) { - putshort(lfile,fpst->rules[0].u.coverage.ncnt); - putshort(lfile,lc); - for ( i=0; i<fpst->rules[0].u.coverage.ncnt; ++i ) - putshort(lfile,0); - for ( i=0; i<fpst->rules[0].lookup_cnt; ++i ) - if ( fpst->rules[0].lookups[i].lookup->lookup_index!=-1 ) { - putshort(lfile,fpst->rules[0].lookups[i].seq); - putshort(lfile,fpst->rules[0].lookups[i].lookup->lookup_index); - } - for ( i=0; i<fpst->rules[0].u.coverage.ncnt; ++i ) { - uint32 pos = ftell(lfile); - fseek(lfile,base+6+2*i,SEEK_SET); - putshort(lfile,pos-base); - fseek(lfile,pos,SEEK_SET); - glyphs = OrderedGlyphsFromNames(sf,fpst->rules[0].u.coverage.ncovers[i]); - dumpcoveragetable(lfile,glyphs); - free(glyphs); - } - } else { - if ( fpst->format==pst_reversecoverage ) { - ibase = ftell(lfile); - putshort(lfile,0); - } - putshort(lfile,fpst->rules[0].u.coverage.bcnt); - bbase = ftell(lfile); - for ( i=0; i<fpst->rules[0].u.coverage.bcnt; ++i ) - putshort(lfile,0); - if ( fpst->format==pst_coverage ) { - putshort(lfile,fpst->rules[0].u.coverage.ncnt); - ibase = ftell(lfile); - for ( i=0; i<fpst->rules[0].u.coverage.ncnt; ++i ) - putshort(lfile,0); - } - putshort(lfile,fpst->rules[0].u.coverage.fcnt); - lbase = ftell(lfile); - for ( i=0; i<fpst->rules[0].u.coverage.fcnt; ++i ) - putshort(lfile,0); - if ( fpst->format==pst_coverage ) { - putshort(lfile,lc); - for ( i=0; i<fpst->rules[0].lookup_cnt; ++i ) - if ( fpst->rules[0].lookups[i].lookup->lookup_index!=-1 ) { - putshort(lfile,fpst->rules[0].lookups[i].seq); - putshort(lfile,fpst->rules[0].lookups[i].lookup->lookup_index); - } - } else { /* reverse coverage */ - glyphs = SFGlyphsFromNames(sf,fpst->rules[0].u.rcoverage.replacements); - for ( i=0; glyphs[i]!=0; ++i ); - putshort(lfile,i); - for ( i=0; glyphs[i]!=0; ++i ) - putshort(lfile,glyphs[i]->ttf_glyph); - } - for ( i=0; i<fpst->rules[0].u.coverage.ncnt; ++i ) { - uint32 pos = ftell(lfile); - fseek(lfile,ibase+2*i,SEEK_SET); - putshort(lfile,pos-base); - fseek(lfile,pos,SEEK_SET); - glyphs = OrderedGlyphsFromNames(sf,fpst->rules[0].u.coverage.ncovers[i]); - dumpcoveragetable(lfile,glyphs); - free(glyphs); - } - for ( i=0; i<fpst->rules[0].u.coverage.bcnt; ++i ) { - uint32 pos = ftell(lfile); - fseek(lfile,bbase+2*i,SEEK_SET); - putshort(lfile,pos-base); - fseek(lfile,pos,SEEK_SET); - glyphs = OrderedGlyphsFromNames(sf,fpst->rules[0].u.coverage.bcovers[i]); - dumpcoveragetable(lfile,glyphs); - free(glyphs); - } - for ( i=0; i<fpst->rules[0].u.coverage.fcnt; ++i ) { - uint32 pos = ftell(lfile); - fseek(lfile,lbase+2*i,SEEK_SET); - putshort(lfile,pos-base); - fseek(lfile,pos,SEEK_SET); - glyphs = OrderedGlyphsFromNames(sf,fpst->rules[0].u.coverage.fcovers[i]); - dumpcoveragetable(lfile,glyphs); - free(glyphs); - } - } - - curcontext = fpst->rules[0].u.coverage.ncnt+fpst->rules[0].u.coverage.bcnt+fpst->rules[0].u.coverage.fcnt; - if ( curcontext>at->os2.maxContext ) - at->os2.maxContext = curcontext; -} - -static void dumpg___ContextChain(FILE *lfile,SplineFont *sf, - struct lookup_subtable *sub, struct alltabs *at) { - FPST *fpst = sub->fpst; - - switch ( fpst->format ) { - case pst_glyphs: - dumpg___ContextChainGlyphs(lfile,sf,sub,at); - break; - case pst_class: - dumpg___ContextChainClass(lfile,sf,sub,at); - break; - case pst_coverage: - case pst_reversecoverage: - dumpg___ContextChainCoverage(lfile,sf,sub,at); - break; - } - - fseek(lfile,0,SEEK_END); - -} - -static void AnchorsAway(FILE *lfile,SplineFont *sf, - struct lookup_subtable *sub, struct glyphinfo *gi ) { - SplineChar **base, **lig, **mkmk; - AnchorClass *ac, *acfirst; - SplineChar ***marks; - int *subcnts; - int cmax, classcnt; - int i; - - marks = malloc((cmax=20)*sizeof(SplineChar **)); - subcnts = malloc(cmax*sizeof(int)); - - classcnt = 0; - acfirst = NULL; - for ( ac=sf->anchor; ac!=NULL; ac = ac->next ) { - ac->matches = false; - if ( ac->subtable==sub && !ac->processed ) { - if ( acfirst == NULL ) - acfirst = ac; - if ( ac->type==act_curs ) - continue; - else if ( ac->has_mark && ac->has_base ) { - ac->matches = ac->processed = true; - ++classcnt; - } - } - } - if ( classcnt>cmax ) { - marks = realloc(marks,(cmax=classcnt+10)*sizeof(SplineChar **)); - subcnts = realloc(subcnts,cmax*sizeof(int)); - } - AnchorClassDecompose(sf,acfirst,classcnt,subcnts,marks,&base,&lig,&mkmk,gi); - switch ( sub->lookup->lookup_type ) { - case gpos_mark2base: - if ( marks[0]!=NULL && base!=NULL ) - dumpgposAnchorData(lfile,acfirst,at_basechar,marks,base,classcnt,gi); - break; - case gpos_mark2ligature: - if ( marks[0]!=NULL && lig!=NULL ) - dumpgposAnchorData(lfile,acfirst,at_baselig,marks,lig,classcnt,gi); - break; - case gpos_mark2mark: - if ( marks[0]!=NULL && mkmk!=NULL ) - dumpgposAnchorData(lfile,acfirst,at_basemark,marks,mkmk,classcnt,gi); - break; - default:; - } - for ( i=0; i<classcnt; ++i ) - free(marks[i]); - free(base); - free(lig); - free(mkmk); - free(marks); - free(subcnts); -} - -static int lookup_size_cmp(const void *_l1, const void *_l2) { - const OTLookup *l1 = *(OTLookup **) _l1, *l2 = *(OTLookup **) _l2; -return( l1->lookup_length-l2->lookup_length ); -} - -static int FPSTRefersToOTL(FPST *fpst,OTLookup *otl) { - int i, j; - - if ( fpst==NULL || fpst->type == pst_reversesub ) -return( false ); - for ( i=0; i<fpst->rule_cnt; ++i ) { - for ( j=0; j< fpst->rules[i].lookup_cnt; ++j ) - if ( fpst->rules[i].lookups[j].lookup == otl ) -return( true ); - } -return( false ); -} - -static int OnlyMac(OTLookup *otl, OTLookup *all) { - FeatureScriptLangList *features = otl->features; - int anymac = 0; - struct lookup_subtable *sub; - - switch ( otl->lookup_type ) { - /* These two lookup types are mac only */ - case kern_statemachine: case morx_indic: case morx_context: case morx_insert: - return( true ); - /* These lookup types are OpenType only */ - case gsub_multiple: case gsub_alternate: case gsub_context: - case gsub_contextchain: case gsub_reversecchain: - case gpos_single: case gpos_cursive: case gpos_mark2base: - case gpos_mark2ligature: case gpos_mark2mark: - case gpos_context: case gpos_contextchain: - return( false ); - /* These two can be expressed in both, and might be either */ - case gpos_pair: case gsub_single: case gsub_ligature: - for ( features = otl->features; features!=NULL; features = features->next ) { - if ( !features->ismac ) - return( false ); - else - anymac = true; - } - /* Either it has no features at all (nested), or all its features */ - /* are mac feature settings. Even if all are mac feature settings it */ - /* might still be used as under control of a contextual feature */ - /* so in both cases check for nested */ - while ( all!=NULL ) { - if ( all!=otl && !all->unused && - (all->lookup_type==gpos_context || - all->lookup_type==gpos_contextchain || - all->lookup_type==gsub_context || - all->lookup_type==gsub_contextchain /*|| - all->lookup_type==gsub_reversecchain*/ )) { - for ( sub=all->subtables; sub!=NULL; sub=sub->next ) if ( !sub->unused && sub->fpst!=NULL ) { - if ( FPSTRefersToOTL(sub->fpst,otl) ) - return( false ); - } - } - all = all->next; - } - if ( anymac ) - return( true ); - /* As far as I can tell, this lookup isn't used at all */ - /* Let's output it anyway, just in case we ever support some other */ - /* table that uses GPOS/GSUB lookups (I think JUST) */ - return( false ); - default:; - } - /* Should never get here, but gcc probably thinks we might */ -return( true ); -} - -static void otf_dumpALookup(FILE *lfile, OTLookup *otl, SplineFont *sf, - struct alltabs *at) { - struct lookup_subtable *sub; - int lookup_sub_table_contains_no_data_count = 0; - int lookup_sub_table_is_too_big_count = 0; - - otl->lookup_offset = ftell(lfile); - for ( sub = otl->subtables; sub!=NULL; sub=sub->next ) { - sub->extra_subtables = NULL; - if ( sub->unused ) - sub->subtable_offset = -1; - else { - sub->subtable_offset = ftell(lfile); - switch ( otl->lookup_type ) { - /* GPOS lookup types */ - case gpos_single: - dumpGPOSsimplepos(lfile,sf,sub); - break; - - case gpos_pair: - if ( at->os2.maxContext<2 ) - at->os2.maxContext = 2; - if ( sub->kc!=NULL ) - dumpgposkernclass(lfile,sf,sub,at); - else - dumpGPOSpairpos(lfile,sf,sub); - break; - - case gpos_cursive: - dumpgposCursiveAttach(lfile,sf,sub,&at->gi); - break; - - case gpos_mark2base: - case gpos_mark2ligature: - case gpos_mark2mark: - AnchorsAway(lfile,sf,sub,&at->gi); - break; - - case gpos_contextchain: - case gpos_context: - dumpg___ContextChain(lfile,sf,sub,at); - break; - - /* GSUB lookup types */ - case gsub_single: - dumpGSUBsimplesubs(lfile,sf,sub); - break; - - case gsub_multiple: - case gsub_alternate: - dumpGSUBmultiplesubs(lfile,sf,sub); - break; - - case gsub_ligature: - dumpGSUBligdata(lfile,sf,sub,at); - break; - - case gsub_contextchain: - case gsub_context: - case gsub_reversecchain: - dumpg___ContextChain(lfile,sf,sub,at); - break; - default:; - } - if ( ftell(lfile)-sub->subtable_offset==0 ) { - if ( lookup_sub_table_contains_no_data_count < 32 ) { - IError( "Lookup sub table, %s in %s, contains no data.\n", - sub->subtable_name, sub->lookup->lookup_name ); - lookup_sub_table_contains_no_data_count ++; - } - sub->unused = true; - sub->subtable_offset = -1; - } else if ( sub->extra_subtables==NULL && - ftell(lfile)-sub->subtable_offset>65535 ) - if ( lookup_sub_table_is_too_big_count < 32 ) { - IError( "Lookup sub table, %s in %s, is too big. Will not be useable.\n", - sub->subtable_name, sub->lookup->lookup_name ); - lookup_sub_table_is_too_big_count ++; - } - } - } - otl->lookup_length = ftell(lfile)-otl->lookup_offset; -} - -static FILE *G___figureLookups(SplineFont *sf,int is_gpos, - struct alltabs *at) { - OTLookup *otl; - struct lookup_subtable *sub; - int index, i,j; - FILE *final; - FILE *lfile = tmpfile2(); - OTLookup **sizeordered; - OTLookup *all = is_gpos ? sf->gpos_lookups : sf->gsub_lookups; - char *buffer; - int len; - - index = 0; - for ( otl=all; otl!=NULL; otl=otl->next ) { - if ( otl->unused || OnlyMac(otl,all) || otl->only_jstf || otl->temporary_kern ) - otl->lookup_index = -1; - else - otl->lookup_index = index++; - } - for ( otl=all; otl!=NULL; otl=otl->next ) { - if ( otl->lookup_index!=-1 ) { - otf_dumpALookup(lfile, otl, sf, at ); - } - } - if ( is_gpos ) - AnchorGuessContext(sf,at); - - /* We don't need to reorder short files */ - if ( ftell(lfile)<65536 ) -return( lfile ); - - /* Order the lookups so that the smallest ones come first */ - /* thus we are less likely to need extension tables */ - /* I think it's better to order the entire lookup rather than ordering the*/ - /* subtables -- since the extension subtable would be required for all */ - /* subtables in the lookup, so might as well keep them all together */ - sizeordered = malloc(index*sizeof(OTLookup *)); - for ( otl=is_gpos ? sf->gpos_lookups : sf->gsub_lookups; otl!=NULL; otl=otl->next ) - if ( otl->lookup_index!=-1 ) - sizeordered[ otl->lookup_index ] = otl; - qsort(sizeordered,index,sizeof(OTLookup *),lookup_size_cmp); - - final = tmpfile2(); - buffer = malloc(32768); - for ( i=0; i<index; ++i ) { - uint32 diff; - otl = sizeordered[i]; - fseek(lfile,otl->lookup_offset,SEEK_SET); - diff = ftell(final) - otl->lookup_offset; - otl->lookup_offset = ftell(final); - len = otl->lookup_length; - while ( len>=32768 ) { - int done = fread(buffer,1,32768,lfile); - if ( done==0 ) /* fread returns 0 on error, not EOF */ - break; - fwrite(buffer,1,done,final); - len -= done; - } - if ( len>0 && len<=32768 ) { - int done = fread(buffer,1,len,lfile); - if ( done==0 ) - break; - fwrite(buffer,1,done,final); - } - for ( sub = otl->subtables; sub!=NULL; sub=sub->next ) { - if ( !sub->unused ) { - sub->subtable_offset += diff; - if ( sub->extra_subtables!=NULL ) { - for ( j=0; sub->extra_subtables[j]!=-1; ++j ) - sub->extra_subtables[j] += diff; - } - } - } - } - free(buffer); - free(sizeordered); - fclose(lfile); -return( final ); -} - -struct feat_lookups { - uint32 tag; - int lcnt; - OTLookup **lookups; - int feature_id; /* Initially consecutive, but may be rearranged by sorting */ - uint32 name_param_ptr; -}; - -struct langsys { - uint32 lang; - int fc; - int *feature_id; - int same_as; - int32 offset; -}; - -struct scriptset { - uint32 script; - int lc; - struct langsys *langsys; -}; - -struct ginfo { - int fmax, fcnt; - struct feat_lookups *feat_lookups; - int sc; - struct scriptset *scripts; -}; - -static int FindOrMakeNewFeatureLookup(struct ginfo *ginfo,OTLookup **lookups, - uint32 tag) { - int i, j; - - for ( i=0; i<ginfo->fcnt; ++i ) { - if ( ginfo->feat_lookups[i].tag!= tag ) - continue; - if ( lookups==NULL && ginfo->feat_lookups[i].lookups==NULL ) /* 'size' feature */ -return( i ); - if ( lookups==NULL || ginfo->feat_lookups[i].lookups==NULL ) - continue; - for ( j=0; lookups[j]!=NULL && ginfo->feat_lookups[i].lookups[j]!=NULL; ++j ) - if ( ginfo->feat_lookups[i].lookups[j]!=lookups[j] ) - break; - if ( ginfo->feat_lookups[i].lookups[j]==lookups[j] ) { - free(lookups); -return( i ); - } - } - if ( ginfo->fcnt>=ginfo->fmax ) - ginfo->feat_lookups = realloc(ginfo->feat_lookups,(ginfo->fmax+=20)*sizeof(struct feat_lookups)); - ginfo->feat_lookups[i].feature_id = i; - ginfo->feat_lookups[i].tag = tag; - ginfo->feat_lookups[i].lookups = lookups; - j=0; - if ( lookups!=NULL ) for ( ; lookups[j]!=NULL; ++j ); - ginfo->feat_lookups[i].lcnt = j; - ++ginfo->fcnt; -return( i ); -} - -static int feat_alphabetize(const void *_fl1, const void *_fl2) { - const struct feat_lookups *fl1 = _fl1, *fl2 = _fl2; - - if ( fl1->tag<fl2->tag ) -return( -1 ); - if ( fl1->tag>fl2->tag ) -return( 1 ); - -return( 0 ); -} - -static int numeric_order(const void *_i1, const void *_i2) { - int i1 = *(const int *) _i1, i2 = *(const int *) _i2; - - if ( i1<i2 ) -return( -1 ); - if ( i1>i2 ) -return( 1 ); - -return( 0 ); -} - -static int LangSysMatch(struct scriptset *s,int ils1, int ils2 ) { - struct langsys *ls1 = &s->langsys[ils1], *ls2 = &s->langsys[ils2]; - int i; - - if ( ls1->fc!=ls2->fc ) -return( false ); - for ( i=0; i<ls1->fc; ++i ) - if ( ls1->feature_id[i]!=ls2->feature_id[i] ) -return( false ); - -return( true ); -} - -static void FindFeatures(SplineFont *sf,int is_gpos,struct ginfo *ginfo) { - uint32 *scripts, *langs, *features; - OTLookup **lookups; - int sc, lc, fc, j; - - memset(ginfo,0,sizeof(struct ginfo)); - - scripts = SFScriptsInLookups(sf,is_gpos); - if ( scripts==NULL ) /* All lookups unused */ -return; - for ( sc=0; scripts[sc]!=0; ++sc ); - ginfo->scripts = malloc(sc*sizeof(struct scriptset)); - ginfo->sc = sc; - for ( sc=0; scripts[sc]!=0; ++sc ) { - langs = SFLangsInScript(sf,is_gpos,scripts[sc]); - for ( lc=0; langs[lc]!=0; ++lc ); - ginfo->scripts[sc].script = scripts[sc]; - ginfo->scripts[sc].lc = lc; - ginfo->scripts[sc].langsys = malloc(lc*sizeof(struct langsys)); - for ( lc=0; langs[lc]!=0; ++lc ) { - features = SFFeaturesInScriptLang(sf,is_gpos,scripts[sc],langs[lc]); - for ( fc=0; features[fc]!=0; ++fc ); - ginfo->scripts[sc].langsys[lc].lang = langs[lc]; - ginfo->scripts[sc].langsys[lc].fc = fc; - ginfo->scripts[sc].langsys[lc].feature_id = malloc(fc*sizeof(int)); - ginfo->scripts[sc].langsys[lc].same_as = -1; - for ( fc=0; features[fc]!=0; ++fc ) { - lookups = SFLookupsInScriptLangFeature(sf,is_gpos,scripts[sc],langs[lc],features[fc]); - ginfo->scripts[sc].langsys[lc].feature_id[fc] = - FindOrMakeNewFeatureLookup(ginfo,lookups,features[fc]); - /* lookups is freed or used by FindOrMakeNewFeatureLookup */ - } - free(features); - } - free(langs); - } - free(scripts); - - qsort(ginfo->feat_lookups,ginfo->fcnt,sizeof(struct feat_lookups),feat_alphabetize); - - /* Now we've disordered the features. Find each feature_id and turn it back*/ - /* into a feature number */ - for ( sc=0; sc<ginfo->sc; ++sc ) { - for ( lc=0; lc<ginfo->scripts[sc].lc; ++lc ) { - int fcmax = ginfo->scripts[sc].langsys[lc].fc; - int *feature_id = ginfo->scripts[sc].langsys[lc].feature_id; - for ( fc=0; fc<fcmax; ++fc ) { - int id = feature_id[fc]; - for ( j=0; j<ginfo->fcnt; ++j ) - if ( id==ginfo->feat_lookups[j].feature_id ) - break; - feature_id[fc] = j; - } - qsort(feature_id,fcmax,sizeof(int),numeric_order); - } - /* See if there are langsys tables which use exactly the same features*/ - /* They can use the same entry in the file. This optimization seems */ - /* to be required for Japanese vertical writing to work in Uniscribe.*/ - for ( lc=0; lc<ginfo->scripts[sc].lc; ++lc ) { - for ( j=0; j<lc; ++j ) - if ( LangSysMatch(&ginfo->scripts[sc],j,lc) ) { - ginfo->scripts[sc].langsys[lc].same_as = j; - break; - } - } - } -} - - -static void dump_script_table(FILE *g___,struct scriptset *ss,struct ginfo *ginfo) { - int i, lcnt, dflt_lang = -1; - uint32 base; - int j, req_index; - uint32 offset; - - /* Count the languages, and find default */ - for ( lcnt=0; lcnt<ss->lc; ++lcnt ) - if ( ss->langsys[lcnt].lang==DEFAULT_LANG ) - dflt_lang = lcnt; - if ( dflt_lang != -1 ) - --lcnt; - - base = ftell(g___); - putshort(g___, 0 ); /* fill in later, Default Lang Sys */ - putshort(g___,lcnt); - for ( i=0; i<ss->lc; ++i ) if ( i!=dflt_lang ) { - putlong(g___,ss->langsys[i].lang); /* Language tag */ - putshort(g___,0); /* Fill in later, offset to langsys */ - } - - for ( lcnt=0; lcnt<ss->lc; ++lcnt ) { - if ( ss->langsys[lcnt].same_as!=-1 ) - offset = ss->langsys[ ss->langsys[lcnt].same_as ].offset; - else { - offset = ftell(g___); - ss->langsys[lcnt].offset = offset; - } - fseek(g___,lcnt==dflt_lang ? base : - lcnt<dflt_lang || dflt_lang==-1 ? base + 4 + lcnt*6 +4 : - base + 4 + (lcnt-1)*6 +4 , - SEEK_SET ); - putshort(g___,offset-base); - fseek(g___,0,SEEK_END); - if ( ss->langsys[lcnt].same_as==-1 ) { - req_index = -1; - for ( j=0; j<ss->langsys[lcnt].fc; ++j ) { - if ( ginfo->feat_lookups[ ss->langsys[lcnt].feature_id[j] ].tag == REQUIRED_FEATURE ) { - req_index = ss->langsys[lcnt].feature_id[j]; - break; - } - } - putshort(g___,0); /* LookupOrder, always NULL */ - putshort(g___,req_index); /* index of required feature, if any */ - putshort(g___,ss->langsys[lcnt].fc - (req_index!=-1)); - /* count of non-required features */ - for ( j=0; j<ss->langsys[lcnt].fc; ++j ) if (ss->langsys[lcnt].feature_id[j]!=req_index ) - putshort(g___,ss->langsys[lcnt].feature_id[j]); - } - } -} - -static FILE *g___FigureExtensionSubTables(OTLookup *all,int startoffset,int is_gpos) { - OTLookup *otf; - struct lookup_subtable *sub; - int len, len2, gotmore; - FILE *efile; - int i, offset, cnt; - int any= false; - - if ( all==NULL ) -return( NULL ); - gotmore = true; cnt=len=0; - while ( gotmore ) { - gotmore = false; - offset = startoffset + 8*cnt; - for ( otf=all; otf!=NULL; otf=otf->next ) if ( otf->lookup_index!=-1 ) { - if ( otf->needs_extension ) - continue; - for ( sub = otf->subtables; sub!=NULL; sub=sub->next ) { - if ( sub->subtable_offset==-1 ) - continue; - if ( sub->extra_subtables!=NULL ) { - for ( i=0; sub->extra_subtables[i]!=-1; ++i ) { - if ( sub->extra_subtables[i]+offset>65535 ) - break; - } - if ( sub->extra_subtables[i]!=-1 ) - break; - } else if ( sub->subtable_offset+offset>65535 ) - break; - } - if ( sub!=NULL ) { - if ( !any ) { - ff_post_notice(_("Lookup potentially too big"), - _("Lookup %s has an\noffset bigger than 65535 bytes. This means\nFontForge must use an extension lookup to output it.\nNot all applications support extension lookups."), - otf->lookup_name ); - any = true; - } - otf->needs_extension = true; - gotmore = true; - len += 8*otf->subcnt; - ++cnt; - } - offset -= 6+2*otf->subcnt; - } - } - - if ( cnt==0 ) /* No offset overflows */ -return( NULL ); - - /* Now we've worked out which lookups need extension tables and marked them*/ - /* Generate the extension tables, and update the offsets to reflect the size */ - /* of the extensions */ - efile = tmpfile2(); - - len2 = 0; - for ( otf=all; otf!=NULL; otf=otf->next ) if ( otf->lookup_index!=-1 ) { - for ( sub = otf->subtables; sub!=NULL; sub=sub->next ) { - if ( sub->subtable_offset==-1 ) - continue; - if ( sub->extra_subtables!=NULL ) { - for ( i=0; sub->extra_subtables[i]!=-1; ++i ) { - sub->extra_subtables[i] += len; - if ( otf->needs_extension ) { - int off = ftell(efile); - putshort(efile,1); /* exten subtable format (there's only one) */ - putshort(efile,otf->lookup_type&0xff); - putlong(efile,sub->extra_subtables[i]-len2); - sub->extra_subtables[i] = off; - len2+=8; - } - } - } else { - sub->subtable_offset += len; - if ( otf->needs_extension ) { - int off = ftell(efile); - putshort(efile,1); /* exten subtable format (there's only one) */ - putshort(efile,otf->lookup_type&0xff); - putlong(efile,sub->subtable_offset-len2); - sub->subtable_offset = off; - len2+=8; - } - } - } - } - -return( efile ); -} - -struct otffeatname *findotffeatname(uint32 tag,SplineFont *sf) { - struct otffeatname *fn; - - for ( fn=sf->feat_names; fn!=NULL && fn->tag!=tag; fn=fn->next ); -return( fn ); -} - -static FILE *dumpg___info(struct alltabs *at, SplineFont *sf,int is_gpos) { - /* Dump out either a gpos or a gsub table. gpos handles kerns, gsub ligs */ - /* we assume that SFFindUnusedLookups has been called */ - FILE *lfile, *g___, *efile; - uint32 lookup_list_table_start, feature_list_table_start, here, scripts_start_offset; - struct ginfo ginfo; - int32 size_params_loc, size_params_ptr; - int i,j, cnt, scnt, offset; - OTLookup *otf, *all; - struct lookup_subtable *sub; - char *buf; - struct otffeatname *fn; - - for ( fn=sf->feat_names; fn!=NULL; fn=fn->next ) - fn->nid = 0; - - FindFeatures(sf,is_gpos,&ginfo); - if ( ginfo.sc==0 ) -return( NULL ); - lfile = G___figureLookups(sf,is_gpos,at); - - if ( ginfo.sc==0 && ftell(lfile)==0 ) { - /* ftell(lfile)==0 => There are no lookups for this table */ - /* ginfo.sc==0 => There are no scripts. */ - /* If both are true then we don't need to output the table */ - /* It is perfectly possible to have lookups without scripts */ - /* (if some other table refered to them -- we don't currently */ - /* support this, but we might some day). */ - /* It is also possible to have scripts without lookups (to get */ - /* around a bug in Uniscribe which only processes some scripts */ - /* if both GPOS and GSUB entries are present. So we share scripts */ - /* between the two tables */ - fclose(lfile); - /* if ginfo.sc==0 then there will be nothing to free in the ginfo struct*/ -return( NULL ); - } - - g___ = tmpfile2(); - - putlong(g___,0x10000); /* version number */ - putshort(g___,10); /* offset to script table */ - putshort(g___,0); /* offset to features. Come back for this */ - putshort(g___,0); /* offset to lookups. Come back for this */ -/* Now the scripts */ - scripts_start_offset = ftell(g___); - putshort(g___,ginfo.sc); - for ( i=0; i<ginfo.sc; ++i ) { - putlong(g___,ginfo.scripts[i].script); - putshort(g___,0); /* fix up later */ - } - - /* Ok, that was the script_list_table which gives each script an offset */ - /* Now for each script we provide a Script table which contains an */ - /* offset to a bunch of features for the default language, and a */ - /* a more complex situation for non-default languages. */ - offset=2+4; /* To the script pointer at the start of table */ - for ( i=0; i<ginfo.sc; ++i ) { - here = ftell(g___); - fseek(g___,scripts_start_offset+offset,SEEK_SET); - putshort(g___,here-scripts_start_offset); - offset+=6; - fseek(g___,here,SEEK_SET); - dump_script_table(g___,&ginfo.scripts[i],&ginfo); - } - /* And that should finish all the scripts/languages */ - - /* so free the ginfo script/lang data */ - for ( i=0; i<ginfo.sc; ++i ) { - for ( j=0; j<ginfo.scripts[i].lc; ++j ) { - free( ginfo.scripts[i].langsys[j].feature_id ); - } - free( ginfo.scripts[i].langsys ); - } - free( ginfo.scripts ); - -/* Now the features */ - feature_list_table_start = ftell(g___); - fseek(g___,6,SEEK_SET); - putshort(g___,feature_list_table_start); - fseek(g___,0,SEEK_END); - putshort(g___,ginfo.fcnt); /* Number of features */ - offset = 2+6*ginfo.fcnt; /* Offset to start of first feature table from beginning of feature_list */ - for ( i=0; i<ginfo.fcnt; ++i ) { - putlong(g___,ginfo.feat_lookups[i].tag); - putshort(g___,offset); - offset += 4+2*ginfo.feat_lookups[i].lcnt; - } - /* for each feature, one feature table */ - size_params_ptr = 0; - for ( i=0; i<ginfo.fcnt; ++i ) { - ginfo.feat_lookups[i].name_param_ptr = 0; - if ( ginfo.feat_lookups[i].tag==CHR('s','i','z','e') ) - size_params_ptr = ftell(g___); - else if ( ginfo.feat_lookups[i].tag>=CHR('s','s','0','1') && ginfo.feat_lookups[i].tag<=CHR('s','s','2','0')) - ginfo.feat_lookups[i].name_param_ptr = ftell(g___); - putshort(g___,0); /* No feature params (we'll come back for 'size') */ - putshort(g___,ginfo.feat_lookups[i].lcnt);/* this many lookups */ - for ( j=0; j<ginfo.feat_lookups[i].lcnt; ++j ) - putshort(g___,ginfo.feat_lookups[i].lookups[j]->lookup_index ); - /* index of each lookup */ - } - if ( size_params_ptr!=0 ) { - size_params_loc = ftell(g___); - fseek(g___,size_params_ptr,SEEK_SET); - putshort(g___,size_params_loc-size_params_ptr); - fseek(g___,size_params_loc,SEEK_SET); - putshort(g___,sf->design_size); - if ( sf->fontstyle_id!=0 || sf->fontstyle_name!=NULL ) { - putshort(g___,sf->fontstyle_id); - at->fontstyle_name_strid = at->next_strid++; - putshort(g___,at->fontstyle_name_strid); - } else { - putshort(g___,0); - putshort(g___,0); - } - putshort(g___,sf->design_range_bottom); - putshort(g___,sf->design_range_top); - } - for ( i=0; i<ginfo.fcnt; ++i ) { - if ( ginfo.feat_lookups[i].name_param_ptr!=0 && - (fn = findotffeatname(ginfo.feat_lookups[i].tag,sf))!=NULL ) { - if ( fn->nid==0 ) - fn->nid = at->next_strid++; - uint32 name_param_loc = ftell(g___); - fseek(g___,ginfo.feat_lookups[i].name_param_ptr,SEEK_SET); - putshort(g___,name_param_loc-ginfo.feat_lookups[i].name_param_ptr); - fseek(g___,name_param_loc,SEEK_SET); - putshort(g___,0); /* Minor version number */ - putshort(g___,fn->nid); - } - } - /* And that should finish all the features */ - - /* so free the ginfo feature data */ - for ( i=0; i<ginfo.fcnt; ++i ) - free( ginfo.feat_lookups[i].lookups ); - free( ginfo.feat_lookups ); - -/* Now the lookups */ - all = is_gpos ? sf->gpos_lookups : sf->gsub_lookups; - for ( cnt=0, otf = all; otf!=NULL; otf=otf->next ) { - if ( otf->lookup_index!=-1 ) - ++cnt; - } - lookup_list_table_start = ftell(g___); - fseek(g___,8,SEEK_SET); - putshort(g___,lookup_list_table_start); - fseek(g___,0,SEEK_END); - putshort(g___,cnt); - offset = 2+2*cnt; /* Offset to start of first lookup table from beginning of lookup list */ - for ( otf = all; otf!=NULL; otf=otf->next ) if ( otf->lookup_index!=-1 ) { - putshort(g___,offset); - for ( scnt=0, sub = otf->subtables; sub!=NULL; sub=sub->next ) { - if ( sub->subtable_offset==-1 ) - continue; - else if ( sub->extra_subtables!=NULL ) { - for ( i=0; sub->extra_subtables[i]!=-1; ++i ) - ++scnt; - } else - ++scnt; - } - otf->subcnt = scnt; - offset += 6+2*scnt; /* 6 bytes header +2 per lookup */ - if ( otf->lookup_flags & pst_usemarkfilteringset ) - offset += 2; /* For mark filtering set, if used */ - } - offset -= 2+2*cnt; - /* now the lookup tables */ - /* do we need any extension sub-tables? */ - efile=g___FigureExtensionSubTables(all,offset,is_gpos); - for ( otf = all; otf!=NULL; otf=otf->next ) if ( otf->lookup_index!=-1 ) { - putshort(g___,!otf->needs_extension ? (otf->lookup_type&0xff) - : is_gpos ? 9 : 7); - putshort(g___,(otf->lookup_flags&0xffff)); - putshort(g___,otf->subcnt); - for ( sub = otf->subtables; sub!=NULL; sub=sub->next ) { - if ( sub->subtable_offset==-1 ) - continue; - else if ( sub->extra_subtables!=NULL ) { - for ( i=0; sub->extra_subtables[i]!=-1; ++i ) - putshort(g___,offset+sub->extra_subtables[i]); - } else - putshort(g___,offset+sub->subtable_offset); - - /* Offset to lookup data which is in the temp file */ - /* we keep adjusting offset so it reflects the distance between */ - /* here and the place where the temp file will start, and then */ - /* we need to skip l->offset bytes in the temp file */ - /* If it's a big GPOS/SUB table we may also need some extension */ - /* pointers, but FigureExtension will adjust for that */ - } - offset -= 6+2*otf->subcnt; - if ( otf->lookup_flags & pst_usemarkfilteringset ) { - putshort(g___,otf->lookup_flags>>16); - offset -= 2; - } - } - - buf = malloc(8096); - if ( efile!=NULL ) { - rewind(efile); - while ( (i=fread(buf,1,8096,efile))>0 ) - fwrite(buf,1,i,g___); - fclose(efile); - } - rewind(lfile); - while ( (i=fread(buf,1,8096,lfile))>0 ) - fwrite(buf,1,i,g___); - fclose(lfile); - free(buf); - for ( otf = all; otf!=NULL; otf=otf->next ) if ( otf->lookup_index!=-1 ) { - for ( sub = otf->subtables; sub!=NULL; sub=sub->next ) { - free(sub->extra_subtables); - sub->extra_subtables = NULL; - } - otf->needs_extension = false; - } -return( g___ ); -} - -void otf_dumpgpos(struct alltabs *at, SplineFont *sf) { - /* Open Type, bless its annoying little heart, doesn't store kern info */ - /* in the kern table. Of course not, how silly of me to think it might */ - /* be consistent. It stores it in the much more complicated gpos table */ - AnchorClass *ac; - - for ( ac=sf->anchor; ac!=NULL; ac=ac->next ) - ac->processed = false; - - at->gpos = dumpg___info(at, sf,true); - if ( at->gpos!=NULL ) { - at->gposlen = ftell(at->gpos); - if ( at->gposlen&1 ) putc('\0',at->gpos); - if ( (at->gposlen+1)&2 ) putshort(at->gpos,0); - } -} - -void otf_dumpgsub(struct alltabs *at, SplineFont *sf) { - /* substitutions such as: Ligatures, cjk vertical rotation replacement, */ - /* arabic forms, small caps, ... */ - SFLigaturePrepare(sf); - at->gsub = dumpg___info(at, sf, false); - if ( at->gsub!=NULL ) { - at->gsublen = ftell(at->gsub); - if ( at->gsublen&1 ) putc('\0',at->gsub); - if ( (at->gsublen+1)&2 ) putshort(at->gsub,0); - } - SFLigatureCleanup(sf); -} - -int LigCaretCnt(SplineChar *sc) { - PST *pst; - int j, cnt; - - for ( pst=sc->possub; pst!=NULL; pst=pst->next ) { - if ( pst->type == pst_lcaret ) { - if ( sc->lig_caret_cnt_fixed ) -return( pst->u.lcaret.cnt ); - else { - /* only output non-zero carets */ - cnt=0; - for ( j=pst->u.lcaret.cnt-1; j>=0 ; --j ) - if ( pst->u.lcaret.carets[j]!=0 ) - ++cnt; -return( cnt ); - } - } - } -return( 0 ); -} - -static void DumpLigCarets(FILE *gdef,SplineChar *sc) { - PST *pst; - int i, j, offset, cnt; - - for ( pst=sc->possub; pst!=NULL; pst=pst->next ) { - if ( pst->type == pst_lcaret ) - break; - } - if ( pst==NULL ) -return; - cnt = LigCaretCnt(sc); - if ( cnt==0 ) -return; - - if ( SCRightToLeft(sc) ) { - for ( i=0; i<pst->u.lcaret.cnt-1; ++i ) - for ( j=i+1; j<pst->u.lcaret.cnt; ++j ) - if ( pst->u.lcaret.carets[i]<pst->u.lcaret.carets[j] ) { - int16 temp = pst->u.lcaret.carets[i]; - pst->u.lcaret.carets[i] = pst->u.lcaret.carets[j]; - pst->u.lcaret.carets[j] = temp; - } - } else { - for ( i=0; i<pst->u.lcaret.cnt-1; ++i ) - for ( j=i+1; j<pst->u.lcaret.cnt; ++j ) - if ( pst->u.lcaret.carets[i]>pst->u.lcaret.carets[j] ) { - int16 temp = pst->u.lcaret.carets[i]; - pst->u.lcaret.carets[i] = pst->u.lcaret.carets[j]; - pst->u.lcaret.carets[j] = temp; - } - } - - putshort(gdef,cnt); /* this many carets */ - offset = sizeof(uint16) + sizeof(uint16)*cnt; - for ( i=0; i<cnt; ++i ) { - putshort(gdef,offset); - offset+=4; - } - for ( i=0; i<pst->u.lcaret.cnt; ++i ) { - if ( sc->lig_caret_cnt_fixed || pst->u.lcaret.carets[i]!=0 ) { - putshort(gdef,1); /* Format 1 */ - putshort(gdef,pst->u.lcaret.carets[i]); - } - } -} - -static int glyphnameinlist(char *haystack,char *name) { - char *start, *pt; - int ch, match, slen = strlen(name); - - for ( pt=haystack ; ; ) { - while ( *pt==' ' ) ++pt; - if ( *pt=='\0' ) -return( false ); - start=pt; - while ( *pt!=' ' && *pt!='\0' ) ++pt; - if ( pt-start==slen ) { - ch = *pt; *pt='\0'; - match = strcmp(start,name); - *pt = ch; - if ( match==0 ) -return( true ); - } - } -} - -static int ReferencedByGSUB(SplineChar *sc) { - PST *pst; - SplineFont *sf = sc->parent; - int gid; - SplineChar *testsc; - char *name = sc->name; - - /* If it is itself a ligature it will be referenced by GSUB */ - /* (because we store ligatures on the glyph generated) */ - for ( pst=sc->possub; pst!=NULL; pst=pst->next ) - if ( pst->type == pst_ligature ) -return( true ); - - for ( gid=0; gid<sf->glyphcnt; ++gid ) if ( (testsc=sf->glyphs[gid])!=NULL ) { - for ( pst=testsc->possub; pst!=NULL; pst=pst->next ) { - if ( pst->type==pst_substitution || pst->type==pst_alternate || - pst->type==pst_multiple ) { - if ( glyphnameinlist(pst->u.mult.components,name) ) -return( true ); - } - } - } -return( false ); -} - -int gdefclass(SplineChar *sc) { - PST *pst; - AnchorPoint *ap; - - if ( sc->glyph_class!=0 ) -return( sc->glyph_class-1 ); - - if ( strcmp(sc->name,".notdef")==0 ) -return( 0 ); - - /* It isn't clear to me what should be done if a glyph is both a ligature */ - /* and a mark (There are some greek accent ligatures, it is probably more*/ - /* important that they be indicated as marks). Here I chose mark rather */ - /* than ligature as the mark class is far more likely to be used */ - 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( 3 ); - - for ( pst=sc->possub; pst!=NULL; pst=pst->next ) { - if ( pst->type == pst_ligature ) -return( 2 ); /* Ligature */ - } - - /* I not quite sure what a componant glyph is. Probably something */ - /* that is not in the cmap table and is referenced in other glyphs */ - /* (I've never seen it used by others) */ - /* (Note: No glyph in a CID font can be components as all CIDs mean */ - /* something) (I think) */ - if ( sc->unicodeenc==-1 && sc->dependents!=NULL && - sc->parent->cidmaster!=NULL && !ReferencedByGSUB(sc)) -return( 4 ); - else -return( 1 ); -} - -void otf_dumpgdef(struct alltabs *at, SplineFont *sf) { - /* In spite of what the open type docs say, this table does appear to be */ - /* required (at least the glyph class def table) if we do mark to base */ - /* positioning */ - /* I was wondering at the apperant contradiction: something can be both a */ - /* base glyph and a ligature component, but it appears that the component*/ - /* class is unused and everything is a base unless it is a ligature or */ - /* mark */ - /* All my example fonts ignore the attachment list subtable and the mark */ - /* attach class def subtable, so I shall too */ - /* Ah. Some indic fonts need the mark attach class subtable for greater */ - /* control of lookup flags */ - /* All my example fonts contain a ligature caret list subtable, which is */ - /* empty. Odd, but perhaps important */ - int i,j,k, lcnt, needsclass; - int pos, offset; - int cnt, start, last, lastval; - SplineChar **glyphs, *sc; - - /* Don't look in the cidmaster if we are only dumping one subfont */ - if ( sf->cidmaster && sf->cidmaster->glyphs!=NULL ) sf = sf->cidmaster; - else if ( sf->mm!=NULL ) sf=sf->mm->normal; - - glyphs = NULL; - for ( k=0; k<2; ++k ) { - lcnt = 0; - needsclass = false; - for ( i=0; i<at->gi.gcnt; ++i ) if ( at->gi.bygid[i]!=-1 ) { - SplineChar *sc = sf->glyphs[at->gi.bygid[i]]; - if ( sc->glyph_class!=0 || gdefclass(sc)!=1 ) - needsclass = true; - if ( LigCaretCnt(sc)!=0 ) { - if ( glyphs!=NULL ) glyphs[lcnt] = sc; - ++lcnt; - } - } - if ( lcnt==0 ) - break; - if ( glyphs!=NULL ) - break; - glyphs = malloc((lcnt+1)*sizeof(SplineChar *)); - glyphs[lcnt] = NULL; - } - if ( !needsclass && lcnt==0 && sf->mark_class_cnt==0 && sf->mark_set_cnt==0 ) -return; /* No anchor positioning, no ligature carets */ - - at->gdef = tmpfile2(); - if ( sf->mark_set_cnt==0 ) { - putlong(at->gdef,0x00010000); /* Version */ - putshort(at->gdef, needsclass ? 12 : 0 ); /* glyph class defn table */ - } else { - putlong(at->gdef,0x00010002); /* Version with mark sets */ - putshort(at->gdef, needsclass ? 14 : 0 ); /* glyph class defn table */ - } - putshort(at->gdef, 0 ); /* attachment list table */ - putshort(at->gdef, 0 ); /* ligature caret table (come back and fix up later) */ - putshort(at->gdef, 0 ); /* mark attachment class table */ - if ( sf->mark_set_cnt>0 ) { - putshort(at->gdef, 0 ); /* mark attachment set table only meaningful if version is 0x10002*/ - } - - /* Glyph class subtable */ - if ( needsclass ) { - /* Mark shouldn't conflict with anything */ - /* Ligature is more important than Base */ - /* Component is not used */ - /* ttx can't seem to support class format type 1 so let's output type 2 */ - for ( j=0; j<2; ++j ) { - cnt = 0; - for ( i=0; i<at->gi.gcnt; ++i ) if ( at->gi.bygid[i]!=-1 ) { - sc = sf->glyphs[at->gi.bygid[i]]; - if ( sc!=NULL && sc->ttf_glyph!=-1 ) { - lastval = gdefclass(sc); - start = last = i; - for ( ; i<at->gi.gcnt; ++i ) if ( at->gi.bygid[i]!=-1 ) { - sc = sf->glyphs[at->gi.bygid[i]]; - if ( gdefclass(sc)!=lastval ) - break; - last = i; - } - --i; - if ( lastval!=0 ) { - if ( j==1 ) { - putshort(at->gdef,start); - putshort(at->gdef,last); - putshort(at->gdef,lastval); - } - ++cnt; - } - } - } - if ( j==0 ) { - putshort(at->gdef,2); /* class format 2, range list by class */ - putshort(at->gdef,cnt); - } - } - } - - /* Ligature caret subtable. Always include this if we have a GDEF */ - pos = ftell(at->gdef); - fseek(at->gdef,8,SEEK_SET); /* location of lig caret table offset */ - putshort(at->gdef,pos); - fseek(at->gdef,0,SEEK_END); - if ( lcnt==0 ) { - /* It always seems to be present, even if empty */ - putshort(at->gdef,4); /* Offset to (empty) coverage table */ - putshort(at->gdef,0); /* no ligatures */ - putshort(at->gdef,2); /* coverage table format 2 */ - putshort(at->gdef,0); /* no ranges in coverage table */ - } else { - pos = ftell(at->gdef); /* coverage location */ - putshort(at->gdef,0); /* Offset to coverage table (fix up later) */ - putshort(at->gdef,lcnt); - offset = 2*lcnt+4; - for ( i=0; i<lcnt; ++i ) { - putshort(at->gdef,offset); - offset+=2+6*LigCaretCnt(glyphs[i]); - } - for ( i=0; i<lcnt; ++i ) - DumpLigCarets(at->gdef,glyphs[i]); - offset = ftell(at->gdef); - fseek(at->gdef,pos,SEEK_SET); - putshort(at->gdef,offset-pos); - fseek(at->gdef,0,SEEK_END); - dumpcoveragetable(at->gdef,glyphs); - } - - /* Mark Attachment Class Subtable */ - if ( sf->mark_class_cnt>0 ) { - uint16 *mclasses = ClassesFromNames(sf,sf->mark_classes,sf->mark_class_cnt,at->maxp.numGlyphs,NULL,false); - pos = ftell(at->gdef); - fseek(at->gdef,10,SEEK_SET); /* location of mark attach table offset */ - putshort(at->gdef,pos); - fseek(at->gdef,0,SEEK_END); - DumpClass(at->gdef,mclasses,at->maxp.numGlyphs); - free(mclasses); - } - - /* Mark Attachment Class Subtable */ - if ( sf->mark_set_cnt>0 ) { - pos = ftell(at->gdef); - fseek(at->gdef,12,SEEK_SET); /* location of mark attach table offset */ - putshort(at->gdef,pos); - fseek(at->gdef,0,SEEK_END); - putshort(at->gdef,1); /* Version number */ - putshort(at->gdef,sf->mark_set_cnt); - for ( i=0; i<sf->mark_set_cnt; ++i ) - putlong(at->gdef,0); - for ( i=0; i<sf->mark_set_cnt; ++i ) { - int here = ftell(at->gdef); - fseek(at->gdef,pos+4+4*i,SEEK_SET); - putlong(at->gdef,here-pos); - fseek(at->gdef,0,SEEK_END); - glyphs = OrderedGlyphsFromNames(sf,sf->mark_sets[i]); - dumpcoveragetable(at->gdef,glyphs); - free(glyphs); - } - } - - at->gdeflen = ftell(at->gdef); - if ( at->gdeflen&1 ) putc('\0',at->gdef); - if ( (at->gdeflen+1)&2 ) putshort(at->gdef,0); -} - -/******************************************************************************/ -/* ******************************* MATH Table ******************************* */ -/* ********************** (Not strictly OpenType yet) *********************** */ -/******************************************************************************/ -enum math_bits { mb_constants=0x01, mb_italic=0x02, mb_topaccent=0x04, - mb_extended=0x08, mb_mathkern=0x10, mb_vertvariant=0x20, - mb_horizvariant=0x40, - mb_all = 0x7f, - mb_gi=(mb_italic|mb_topaccent|mb_extended|mb_mathkern), - mb_gv=(mb_vertvariant|mb_horizvariant) }; - -static int MathBits(struct alltabs *at, SplineFont *sf) { - int i, gid, ret; - SplineChar *sc; - - ret = sf->MATH ? mb_constants : 0; - - for ( i=0; i<at->gi.gcnt; ++i ) { - if ( (gid=at->gi.bygid[i])!=-1 && (sc=sf->glyphs[gid])!=NULL ) { - if ( sc->italic_correction!=TEX_UNDEF ) - ret |= mb_italic; - if ( sc->top_accent_horiz!=TEX_UNDEF ) - ret |= mb_topaccent; - if ( sc->is_extended_shape ) - ret |= mb_extended; - if ( sc->mathkern!=NULL ) - ret |= mb_mathkern; - if ( sc->vert_variants!=NULL ) - ret |= mb_vertvariant; - if ( sc->horiz_variants!=NULL ) - ret |= mb_horizvariant; - if ( ret==mb_all ) -return( mb_all ); - } - } -return( ret ); -} - -static void ttf_math_dump_italic_top(FILE *mathf,struct alltabs *at, SplineFont *sf, int is_italic) { - int i, gid, len; - SplineChar *sc, **glyphs; - uint32 coverage_pos, coverage_table; - uint32 devtab_offset; - DeviceTable *devtab; - - /* Figure out our glyph list (and count) */ - for ( i=len=0; i<at->gi.gcnt; ++i ) - if ( (gid=at->gi.bygid[i])!=-1 && (sc=sf->glyphs[gid])!=NULL ) - if ( (is_italic && sc->italic_correction!=TEX_UNDEF) || (!is_italic && sc->top_accent_horiz!=TEX_UNDEF)) - ++len; - glyphs = malloc((len+1)*sizeof(SplineChar *)); - for ( i=len=0; i<at->gi.gcnt; ++i ) - if ( (gid=at->gi.bygid[i])!=-1 && (sc=sf->glyphs[gid])!=NULL ) - if ( (is_italic && sc->italic_correction!=TEX_UNDEF) || (!is_italic && sc->top_accent_horiz!=TEX_UNDEF)) - glyphs[len++] = sc; - glyphs[len] = NULL; - - coverage_pos = ftell(mathf); - putshort(mathf,0); /* Coverage table, return to this */ - putshort(mathf,len); - devtab_offset = 4 + 4*len; - for ( i=0; i<len; ++i ) { - putshort(mathf,is_italic ? glyphs[i]->italic_correction : glyphs[i]->top_accent_horiz ); - devtab = is_italic ? glyphs[i]->italic_adjusts : glyphs[i]->top_accent_adjusts; - if ( devtab!=NULL ) { - putshort(mathf,devtab_offset); - devtab_offset += DevTabLen(devtab); - } else - putshort(mathf,0); - } - for ( i=0; i<len; ++i ) { - devtab = is_italic ? glyphs[i]->italic_adjusts : glyphs[i]->top_accent_adjusts; - if ( devtab!=NULL ) - dumpgposdevicetable(mathf,devtab); - } - if ( devtab_offset!=ftell(mathf)-coverage_pos ) - IError("Actual end did not match expected end in %s table, expected=%d, actual=%d", - is_italic ? "italic" : "top accent", devtab_offset, ftell(mathf)-coverage_pos ); - coverage_table = ftell(mathf); - fseek( mathf, coverage_pos, SEEK_SET); - putshort(mathf,coverage_table-coverage_pos); - fseek(mathf,coverage_table,SEEK_SET); - dumpcoveragetable(mathf,glyphs); - free(glyphs); -} - -static void ttf_math_dump_extended(FILE *mathf,struct alltabs *at, SplineFont *sf) { - int i, gid, len; - SplineChar *sc, **glyphs; - - for ( i=len=0; i<at->gi.gcnt; ++i ) - if ( (gid=at->gi.bygid[i])!=-1 && (sc=sf->glyphs[gid])!=NULL ) - if ( sc->is_extended_shape ) - ++len; - glyphs = malloc((len+1)*sizeof(SplineChar *)); - for ( i=len=0; i<at->gi.gcnt; ++i ) - if ( (gid=at->gi.bygid[i])!=-1 && (sc=sf->glyphs[gid])!=NULL ) - if ( sc->is_extended_shape ) - glyphs[len++] = sc; - glyphs[len] = NULL; - dumpcoveragetable(mathf,glyphs); - free(glyphs); -} - -static int mkv_len(struct mathkernvertex *mkv) { -return( 2+8*mkv->cnt-4 ); -} - -static int ttf_math_dump_mathkernvertex(FILE *mathf,struct mathkernvertex *mkv, - int devtab_pos) { - int i; - uint32 here = ftell(mathf); - - putshort(mathf,mkv->cnt-1); - - for ( i=0; i<mkv->cnt-1; ++i ) { - putshort(mathf,mkv->mkd[i].height); - if ( mkv->mkd[i].height_adjusts!=NULL ) { - putshort(mathf,devtab_pos-here); - devtab_pos += DevTabLen(mkv->mkd[i].height_adjusts); - } else - putshort(mathf,0); - } - for ( i=0; i<mkv->cnt; ++i ) { - putshort(mathf,mkv->mkd[i].kern); - if ( mkv->mkd[i].kern_adjusts!=NULL ) { - putshort(mathf,devtab_pos-here); - devtab_pos += DevTabLen(mkv->mkd[i].kern_adjusts); - } else - putshort(mathf,0); - } -return( devtab_pos ); -} - -static void ttf_math_dump_mathkerndevtab(FILE *mathf,struct mathkernvertex *mkv) { - int i; - - for ( i=0; i<mkv->cnt-1; ++i ) - if ( mkv->mkd[i].height_adjusts!=NULL ) - dumpgposdevicetable(mathf,mkv->mkd[i].height_adjusts); - for ( i=0; i<mkv->cnt; ++i ) - if ( mkv->mkd[i].kern_adjusts!=NULL ) - dumpgposdevicetable(mathf,mkv->mkd[i].kern_adjusts); -} - -static void ttf_math_dump_mathkern(FILE *mathf,struct alltabs *at, SplineFont *sf) { - int i, gid, len; - SplineChar *sc, **glyphs; - uint32 coverage_pos, coverage_table, kr_pos, midpos2; - - /* Figure out our glyph list (and count) */ - for ( i=len=0; i<at->gi.gcnt; ++i ) - if ( (gid=at->gi.bygid[i])!=-1 && (sc=sf->glyphs[gid])!=NULL ) - if ( sc->mathkern!=NULL ) - ++len; - glyphs = malloc((len+1)*sizeof(SplineChar *)); - for ( i=len=0; i<at->gi.gcnt; ++i ) - if ( (gid=at->gi.bygid[i])!=-1 && (sc=sf->glyphs[gid])!=NULL ) - if ( sc->mathkern!=NULL ) - glyphs[len++] = sc; - glyphs[len] = NULL; - - coverage_pos = ftell(mathf); - putshort(mathf,0); /* Coverage table, return to this */ - putshort(mathf,len); - kr_pos = coverage_pos + 4 + 8*len; - for ( i=0; i<len; ++i ) { - struct mathkern *mk = glyphs[i]->mathkern; - if ( mk->top_right.cnt==0 ) - putshort(mathf,0); - else { - putshort(mathf,kr_pos-coverage_pos); - kr_pos += mkv_len(&mk->top_right); - } - if ( mk->top_left.cnt==0 ) - putshort(mathf,0); - else { - putshort(mathf,kr_pos-coverage_pos); - kr_pos += mkv_len(&mk->top_left); - } - if ( mk->bottom_right.cnt==0 ) - putshort(mathf,0); - else { - putshort(mathf,kr_pos-coverage_pos); - kr_pos += mkv_len(&mk->bottom_right); - } - if ( mk->bottom_left.cnt==0 ) - putshort(mathf,0); - else { - putshort(mathf,kr_pos-coverage_pos); - kr_pos += mkv_len(&mk->bottom_left); - } - } - if ( ftell(mathf)!=coverage_pos + 4 + 8*len ) - IError("Actual midpoint1 did not match expected midpoint1 in mathkern table, expected=%d, actual=%d", - coverage_pos + 4 + 8*len, ftell(mathf) ); - - midpos2 = kr_pos; - for ( i=0; i<len; ++i ) { - struct mathkern *mk = glyphs[i]->mathkern; - if ( mk->top_right.cnt!=0 ) - kr_pos = ttf_math_dump_mathkernvertex(mathf,&mk->top_right,kr_pos); - if ( mk->top_left.cnt!=0 ) - kr_pos = ttf_math_dump_mathkernvertex(mathf,&mk->top_left,kr_pos); - if ( mk->bottom_right.cnt!=0 ) - kr_pos = ttf_math_dump_mathkernvertex(mathf,&mk->bottom_right,kr_pos); - if ( mk->bottom_left.cnt!=0 ) - kr_pos = ttf_math_dump_mathkernvertex(mathf,&mk->bottom_left,kr_pos); - } - if ( ftell(mathf)!=midpos2) - IError("Actual midpoint2 did not match expected midpoint2 in mathkern table, expected=%d, actual=%d", - midpos2, ftell(mathf) ); - - for ( i=0; i<len; ++i ) { - struct mathkern *mk = glyphs[i]->mathkern; - if ( mk->top_right.cnt!=0 ) - ttf_math_dump_mathkerndevtab(mathf,&mk->top_right); - if ( mk->top_left.cnt!=0 ) - ttf_math_dump_mathkerndevtab(mathf,&mk->top_left); - if ( mk->bottom_right.cnt!=0 ) - ttf_math_dump_mathkerndevtab(mathf,&mk->bottom_right); - if ( mk->bottom_left.cnt!=0 ) - ttf_math_dump_mathkerndevtab(mathf,&mk->bottom_left); - } - if ( kr_pos!=ftell(mathf) ) - IError("Actual end did not match expected end in mathkern table, expected=%d, actual=%d", - kr_pos, ftell(mathf) ); - - coverage_table = ftell(mathf); - fseek( mathf, coverage_pos, SEEK_SET); - putshort(mathf,coverage_table-coverage_pos); - fseek(mathf,coverage_table,SEEK_SET); - dumpcoveragetable(mathf,glyphs); - free(glyphs); -} - -static int gv_len(SplineFont *sf, struct glyphvariants *gv) { - char *pt, *start; - int ch, cnt; - SplineChar *sc; - - if ( gv==NULL || (gv->variants==NULL && gv->part_cnt==0)) -return( 0 ); - if ( gv->variants==NULL ) -return( 4 ); /* No variants, but we've got parts to assemble */ - cnt = 0; - for ( start=gv->variants ;; ) { - while ( *start==' ' ) ++start; - if ( *start=='\0' ) -return( 4+4*cnt ); /* MathGlyphConstructionTable */ - for ( pt = start ; *pt!=' ' && *pt!='\0'; ++pt ); - ch = *pt; *pt = '\0'; - sc = SFGetChar(sf,-1,start); - *pt = ch; - if ( sc!=NULL ) - ++cnt; - start = pt; - } -} - -static int gvc_len(struct glyphvariants *gv) { - if ( gv->part_cnt==0 ) -return( 0 ); - -return( 6+10*gv->part_cnt ); -} - -static uint32 ttf_math_dump_mathglyphconstructiontable(FILE *mathf, - struct glyphvariants *gv,SplineFont *sf, uint32 pos,int is_v) { - char *pt, *start; - int ch, cnt; - SplineChar *sc; - uint32 here = ftell(mathf); - DBounds b; - - putshort(mathf,gv->part_cnt==0? 0 : pos-here); - if ( gv->variants==NULL ) { - putshort(mathf,0); - } else { - cnt = 0; - for ( start=gv->variants ;; ) { - while ( *start==' ' ) ++start; - if ( *start=='\0' ) - break; - for ( pt = start ; *pt!=' ' && *pt!='\0'; ++pt ); - ch = *pt; *pt = '\0'; - sc = SFGetChar(sf,-1,start); - *pt = ch; - if ( sc!=NULL ) - ++cnt; - start = pt; - } - putshort(mathf,cnt); - for ( start=gv->variants ;; ) { - while ( *start==' ' ) ++start; - if ( *start=='\0' ) - break; - for ( pt = start ; *pt!=' ' && *pt!='\0'; ++pt ); - ch = *pt; *pt = '\0'; - sc = SFGetChar(sf,-1,start); - *pt = ch; - if ( sc!=NULL ) { - putshort(mathf,sc->ttf_glyph); - SplineCharFindBounds(sc,&b); - /* Don't ask me why I have a plus one here. In the MS font */ - /* CambriaMath all of these values are one more than I would */ - /* expect */ - if ( is_v ) - putshort(mathf,b.maxy-b.miny +1); - else - putshort(mathf,b.maxx-b.minx +1); - } - start=pt; - } - } -return( pos + gvc_len(gv)); -} - -static uint32 ttf_math_dump_mathglyphassemblytable(FILE *mathf, - struct glyphvariants *gv,SplineFont *sf, uint32 devtab_pos) { - SplineChar *sc; - uint32 here = ftell(mathf); - int i; - - if ( gv->part_cnt==0 ) -return( devtab_pos ); - putshort(mathf,gv->italic_correction); - if ( gv->italic_adjusts!=NULL ) { - putshort(mathf,devtab_pos-here); - devtab_pos += DevTabLen(gv->italic_adjusts); - } else - putshort(mathf,0); - putshort(mathf,gv->part_cnt); - for ( i=0; i<gv->part_cnt; ++i ) { - sc = SFGetChar(sf,-1,gv->parts[i].component); - if ( sc==NULL ) - putshort(mathf,0); /* .notdef */ - else - putshort(mathf,sc->ttf_glyph); - putshort(mathf,gv->parts[i].startConnectorLength); - putshort(mathf,gv->parts[i].endConnectorLength); - putshort(mathf,gv->parts[i].fullAdvance); - putshort(mathf,gv->parts[i].is_extender); - } -return(devtab_pos); -} - -static void ttf_math_dump_glyphvariant(FILE *mathf,struct alltabs *at, SplineFont *sf) { - int i, gid, vlen, hlen; - SplineChar *sc, **vglyphs, **hglyphs; - uint32 coverage_pos, coverage_table, offset, pos, assembly_pos; - - /* Figure out our glyph list (and count) */ - for ( i=vlen=hlen=0; i<at->gi.gcnt; ++i ) - if ( (gid=at->gi.bygid[i])!=-1 && (sc=sf->glyphs[gid])!=NULL ) { - if ( sc->vert_variants!=NULL ) - ++vlen; - if ( sc->horiz_variants!=NULL ) - ++hlen; - } - - vglyphs = malloc((vlen+1)*sizeof(SplineChar *)); - hglyphs = malloc((hlen+1)*sizeof(SplineChar *)); - for ( i=vlen=hlen=0; i<at->gi.gcnt; ++i ) - if ( (gid=at->gi.bygid[i])!=-1 && (sc=sf->glyphs[gid])!=NULL ) { - if ( sc->vert_variants!=NULL ) - vglyphs[vlen++] = sc; - if ( sc->horiz_variants!=NULL ) - hglyphs[hlen++] = sc; - } - vglyphs[vlen] = NULL; - hglyphs[hlen] = NULL; - - putshort(mathf,sf->MATH==NULL?(sf->ascent+sf->descent)/50 : sf->MATH->MinConnectorOverlap ); - coverage_pos = ftell(mathf); - putshort(mathf,0); /* Vertical Coverage table, return to this */ - putshort(mathf,0); /* Horizontal Coverage table, return to this */ - putshort(mathf,vlen); - putshort(mathf,hlen); - offset = 5*2+vlen*2+hlen*2; - for ( i=0; i<vlen; ++i ) { - putshort(mathf,offset); - offset += gv_len(sf,vglyphs[i]->vert_variants); - } - for ( i=0; i<hlen; ++i ) { - putshort(mathf,offset); - offset += gv_len(sf,hglyphs[i]->horiz_variants); - } - assembly_pos = pos = (coverage_pos-2)+offset; - for ( i=0; i<vlen; ++i ) { - /*uint32 start = ftell(mathf);*/ - pos = ttf_math_dump_mathglyphconstructiontable(mathf, - vglyphs[i]->vert_variants,sf,pos,true); - /*if ( ftell(mathf)-start != gv_len(sf,vglyphs[i]->vert_variants))*/ - /*IError("v gv_len incorrect");*/ - } - for ( i=0; i<hlen; ++i ) { - /*uint32 start = ftell(mathf);*/ - pos = ttf_math_dump_mathglyphconstructiontable(mathf, - hglyphs[i]->horiz_variants,sf,pos,false); - /*if ( ftell(mathf)-start != gv_len(sf,hglyphs[i]->horiz_variants))*/ - /*IError("h gv_len incorrect: %s", hglyphs[i]->name);*/ - } - if ( ftell(mathf)!=assembly_pos ) - IError("assembly tables at wrong place"); - - for ( i=0; i<vlen; ++i ) - pos = ttf_math_dump_mathglyphassemblytable(mathf, - vglyphs[i]->vert_variants,sf,pos); - for ( i=0; i<hlen; ++i ) - pos = ttf_math_dump_mathglyphassemblytable(mathf, - hglyphs[i]->horiz_variants,sf,pos); - for ( i=0; i<vlen; ++i ) - if ( vglyphs[i]->vert_variants->part_cnt!=0 && - vglyphs[i]->vert_variants->italic_adjusts!=NULL ) - dumpgposdevicetable(mathf,vglyphs[i]->vert_variants->italic_adjusts); - for ( i=0; i<hlen; ++i ) - if ( hglyphs[i]->horiz_variants->part_cnt!=0 && - hglyphs[i]->horiz_variants->italic_adjusts!=NULL ) - dumpgposdevicetable(mathf,hglyphs[i]->horiz_variants->italic_adjusts); - if ( vlen!=0 ) { - coverage_table = ftell(mathf); - fseek( mathf, coverage_pos, SEEK_SET); - putshort(mathf,coverage_table-(coverage_pos-2)); - fseek(mathf,coverage_table,SEEK_SET); - dumpcoveragetable(mathf,vglyphs); - } - free(vglyphs); - if ( hlen!=0 ) { - coverage_table = ftell(mathf); - fseek( mathf, coverage_pos+2, SEEK_SET); - putshort(mathf,coverage_table-(coverage_pos-2)); - fseek(mathf,coverage_table,SEEK_SET); - dumpcoveragetable(mathf,hglyphs); - } - free(hglyphs); -} - -void otf_dump_math(struct alltabs *at, SplineFont *sf) { - FILE *mathf; - int i; - uint32 devtab_offsets[60], const_start, gi_start, v_start; - int bits = MathBits(at,sf); - - if ( sf->MATH==NULL ) -return; - - at->math = mathf = tmpfile2(); - - putlong(mathf, 0x00010000 ); /* Version 1 */ - putshort(mathf, 10); /* Offset to constants */ - putshort(mathf, 0); /* GlyphInfo, fix later */ - putshort(mathf, 0); /* Variants, fix later */ - - /* Start on constants */ - memset(devtab_offsets,0,sizeof(devtab_offsets)); - const_start = ftell(mathf); - for ( i=0; math_constants_descriptor[i].script_name!=NULL; ++i ) { - int16 *pos = (int16 *) (((char *) (sf->MATH)) + math_constants_descriptor[i].offset ); - if ( pos == (int16 *) &sf->MATH->MinConnectorOverlap ) - continue; /* Actually lives in the Variant table, not here */ - putshort(mathf, *pos); - if ( math_constants_descriptor[i].devtab_offset != -1 ) { - devtab_offsets[i] = ftell(mathf); - putshort(mathf, 0); /* Fix up later if we support device tables */ - } - } - for ( i=0; math_constants_descriptor[i].script_name!=NULL; ++i ) { - int16 *pos = (int16 *) (((char *) (sf->MATH)) + math_constants_descriptor[i].offset ); - DeviceTable **devtab = (DeviceTable **) (((char *) (sf->MATH)) + math_constants_descriptor[i].devtab_offset ); - if ( pos == (int16 *) &sf->MATH->MinConnectorOverlap ) - continue; /* Actually lives in the Variant table, not here */ - if ( math_constants_descriptor[i].devtab_offset >= 0 && *devtab!=NULL ) { - uint32 here = ftell(mathf); - fseek(mathf,devtab_offsets[i],SEEK_SET); - putshort(mathf, here-const_start); - fseek(mathf,here,SEEK_SET); - dumpgposdevicetable(mathf,*devtab); - } - } - - /* The spec does not say this can be NULL */ - if ( 1 /* bits&mb_gi*/ ) { - gi_start = ftell(mathf); - fseek(mathf,6,SEEK_SET); - putshort(mathf,gi_start); - fseek(mathf,gi_start,SEEK_SET); - - putshort(mathf,0); /* Italics correction */ - putshort(mathf,0); /* top accent */ - putshort(mathf,0); /* is extended shape */ - putshort(mathf,0); /* math kern info */ - - if ( bits&mb_italic ) { - v_start = ftell(mathf); - fseek(mathf,gi_start,SEEK_SET); - putshort(mathf,v_start-gi_start); - fseek(mathf,v_start,SEEK_SET); - - ttf_math_dump_italic_top(mathf,at,sf,true); - } - - if ( bits&mb_topaccent ) { - v_start = ftell(mathf); - fseek(mathf,gi_start+2,SEEK_SET); - putshort(mathf,v_start-gi_start); - fseek(mathf,v_start,SEEK_SET); - - ttf_math_dump_italic_top(mathf,at,sf,false); - } - - if ( bits&mb_extended ) { - v_start = ftell(mathf); - fseek(mathf,gi_start+4,SEEK_SET); - putshort(mathf,v_start-gi_start); - fseek(mathf,v_start,SEEK_SET); - - ttf_math_dump_extended(mathf,at,sf); - } - - if ( bits&mb_mathkern ) { - v_start = ftell(mathf); - fseek(mathf,gi_start+6,SEEK_SET); - putshort(mathf,v_start-gi_start); - fseek(mathf,v_start,SEEK_SET); - - ttf_math_dump_mathkern(mathf,at,sf); - } - } - - /* The spec does not say this can be NULL */ - if ( 1 /* bits&mb_gv*/ ) { - v_start = ftell(mathf); - fseek(mathf,8,SEEK_SET); - putshort(mathf,v_start); - fseek(mathf,v_start,SEEK_SET); - - ttf_math_dump_glyphvariant(mathf,at,sf); - } - - at->mathlen = ftell(mathf); - if ( ftell(mathf)&1 ) - putc('\0',mathf); - if ( ftell(mathf)&2 ) - putshort(mathf,0); -} - -struct taglist { - uint32 tag; - struct taglist *next; -}; - -static int taglistcompar(const void *_cv1, const void *_cv2) { - const struct taglist *const *tl1 = _cv1, *const *tl2 = _cv2; - - if ( (*tl1)->tag==(*tl2)->tag ) -return( 0 ); - if ( (*tl1)->tag>(*tl2)->tag ) -return( 1 ); - -return( -1 ); -} - -static int langlistcompar(const void *_cv1, const void *_cv2) { - const struct taglist *const *tl1 = _cv1, *const *tl2 = _cv2; - - if ( (*tl1)->tag==(*tl2)->tag ) -return( 0 ); - if ( (*tl1)->tag == DEFAULT_LANG ) -return( -1 ); - if ( (*tl2)->tag == DEFAULT_LANG ) -return( 1 ); - if ( (*tl1)->tag>(*tl2)->tag ) -return( 1 ); - -return( -1 ); -} - -static struct taglist *sorttaglist(struct taglist *list,int (*compar)(const void *,const void*)) { - struct taglist *t, **array; - int i,cnt; - - if ( list==NULL || list->next==NULL ) -return( list ); - - for ( t=list, cnt=0; t!=NULL; t=t->next, ++cnt ); - array = malloc(cnt*sizeof(struct taglist *)); - for ( t=list, cnt=0; t!=NULL; t=t->next, ++cnt ) - array[cnt] = t; - qsort(array,cnt,sizeof(struct taglist *),compar); - for ( i=1; i<cnt; ++i ) - array[i-1]->next = array[i]; - array[cnt-1]->next = NULL; - list = array[0]; - free( array ); -return( list ); -} - -static void _base_sort(struct Base *base) { - /* Sort the base lines. Which can reorder the def_baseline index in the */ - /* script, and the baseline_pos lists */ - /* Sort the script list */ - /* Sort the language lists in each script */ - /* Sort the feature lists in each language */ - int i,j,pos, tag; - struct basescript *bs; - struct baselangextent *langs; - - if ( base==NULL ) -return; - - if ( base->baseline_cnt!=0 ) { - for ( i=0; i<base->baseline_cnt; ++i ) - for ( j=i+1; j<base->baseline_cnt; ++j ) { - if ( base->baseline_tags[i]>base->baseline_tags[j] ) { - tag = base->baseline_tags[i]; - base->baseline_tags[i] = base->baseline_tags[j]; - base->baseline_tags[j] = tag; - for ( bs=base->scripts ; bs!=NULL; bs=bs->next ) { - if ( bs->def_baseline==i ) - bs->def_baseline = j; - else if ( bs->def_baseline==j ) - bs->def_baseline = i; - pos = bs->baseline_pos[i]; - bs->baseline_pos[i] = bs->baseline_pos[j]; - bs->baseline_pos[j] = pos; - } - } - } - } - base->scripts = (struct basescript *) sorttaglist((struct taglist *) base->scripts,taglistcompar); - for ( bs=base->scripts ; bs!=NULL; bs=bs->next ) { - bs->langs = (struct baselangextent *) sorttaglist((struct taglist *) bs->langs,langlistcompar); - for ( langs = bs->langs; langs!=NULL; langs = langs->next ) - langs->features = (struct baselangextent *) sorttaglist((struct taglist *) langs->features,taglistcompar); - } -} - -void SFBaseSort(SplineFont *sf) { - _base_sort(sf->horiz_base); - _base_sort(sf->vert_base); -} - -static void dump_minmax(FILE *basef,struct baselangextent *bl) { - struct baselangextent *fl; - int fcnt; - - putshort(basef,bl->descent); - putshort(basef,bl->ascent); - for ( fl=bl->features, fcnt=0; fl!=NULL; fl=fl->next, ++fcnt ); - putshort(basef,fcnt); - for ( fl=bl->features; fl!=NULL; fl=fl->next ) { - putlong(basef,fl->lang); /* feature tag really */ - putshort(basef,fl->descent); - putshort(basef,fl->ascent); - } -} - -void otf_dumpbase(struct alltabs *at, SplineFont *sf) { - FILE *basef; - int i,j, cnt, lcnt; - uint32 here, bsl; - struct basescript *bs; - struct baselangextent *bl, *dflt; - int offset; - - if ( sf->horiz_base==NULL && sf->vert_base==NULL ) -return; - - SFBaseSort(sf); - - at->base = basef = tmpfile2(); - - putlong(basef, 0x00010000 ); /* Version 1 */ - putshort(basef, 0 ); /* offset to horizontal baselines, fill in later */ - putshort(basef, 0 ); /* offset to vertical baselines, fill in later */ - - for ( i=0; i<2; ++i ) { - struct Base *base = i==0 ? sf->horiz_base : sf->vert_base; - if ( base==NULL ) - continue; - here = ftell(basef); - fseek(basef,4+2*i,SEEK_SET); - putshort(basef,here-0); - fseek(basef,here,SEEK_SET); - - /* axis table */ - putshort(basef,base->baseline_cnt==0 ? 0 : 4 ); - putshort(basef,base->baseline_cnt==0 ? 4 : - 4+2+4*base->baseline_cnt ); - - if ( base->baseline_cnt!=0 ) { - /* BaseTagList table */ - putshort(basef,base->baseline_cnt); - for ( j=0; j<base->baseline_cnt; ++j ) - putlong(basef,base->baseline_tags[j]); - } - - /* BaseScriptList table */ - bsl = ftell(basef); - for ( bs=base->scripts, cnt=0; bs!=NULL; bs=bs->next, ++cnt ); - putshort(basef,cnt); - for ( bs=base->scripts; bs!=NULL; bs=bs->next ) { - putlong(basef,bs->script); - putshort(basef,0); - } - - /* BaseScript table */ - for ( bs=base->scripts, cnt=0; bs!=NULL; bs=bs->next, ++cnt ) { - uint32 bst = ftell(basef); - fseek(basef,bsl+2+6*cnt+4,SEEK_SET); - putshort(basef,bst-bsl); - fseek(basef,bst,SEEK_SET); - - for ( bl=bs->langs, dflt=NULL, lcnt=0; bl!=NULL; bl=bl->next ) { - if ( bl->lang==DEFAULT_LANG ) - dflt = bl; - else - ++lcnt; - } - offset = 6+6*lcnt; - putshort(basef,base->baseline_cnt==0?0:offset); - if ( base->baseline_cnt!=0 ) - offset += 4+2*base->baseline_cnt+4*base->baseline_cnt; - putshort(basef,dflt==NULL ? 0 : offset); - putshort(basef,lcnt); - for ( bl=bs->langs; bl!=NULL; bl=bl->next ) if ( bl->lang!=DEFAULT_LANG ) { - putlong(basef,bl->lang); - putshort(basef,0); - } - - /* Base Values table */ - if ( base->baseline_cnt!=0 ) { - offset = 4+2*base->baseline_cnt; - putshort(basef,bs->def_baseline); - putshort(basef,base->baseline_cnt); - for ( j=0; j<base->baseline_cnt; ++j ) { - putshort(basef,offset); - offset += 2*2; - } - for ( j=0; j<base->baseline_cnt; ++j ) { - putshort(basef,1); /* format 1 */ - putshort(basef,bs->baseline_pos[j]); - } - } - - if ( dflt!=NULL ) - dump_minmax(basef,dflt); - for ( bl=bs->langs, dflt=NULL, lcnt=0; bl!=NULL; bl=bl->next ) if ( bl->lang!=DEFAULT_LANG ) { - uint32 here = ftell(basef); - fseek(basef,bst+6+6*lcnt+4,SEEK_SET); - putshort(basef,here-bst); - fseek(basef,here,SEEK_SET); - dump_minmax(basef,bl); - } - } - } - - at->baselen = ftell(basef); - if ( ftell(basef)&1 ) - putc('\0',basef); - if ( ftell(basef)&2 ) - putshort(basef,0); -} - -static int jscriptsort(const void *_s1,const void *_s2) { - const Justify * const * __s1 = (const Justify * const *) _s1; - const Justify * const * __s2 = (const Justify * const *) _s2; - const Justify *s1 = *__s1; - const Justify *s2 = *__s2; - - if ( s1->script>s2->script ) -return( 1 ); - else if ( s1->script<s2->script ) -return( -1 ); - else -return( 0 ); -} - -static int jlangsort(const void *_s1,const void *_s2) { - const struct jstf_lang * const * __s1 = (const struct jstf_lang * const *) _s1; - const struct jstf_lang * const * __s2 = (const struct jstf_lang * const *) _s2; - const struct jstf_lang *s1 = *__s1; - const struct jstf_lang *s2 = *__s2; - - if ( s1->lang==s2->lang ) -return( 0 ); - - if ( s1->lang==DEFAULT_LANG ) -return( -1 ); - if ( s2->lang==DEFAULT_LANG ) -return( 1 ); - - if ( s1->lang>s2->lang ) -return( 1 ); - else -return( -1 ); -} - -static int lookup_order(const void *_s1,const void *_s2) { - const OTLookup * const * __s1 = (const OTLookup * const *) _s1; - const OTLookup * const * __s2 = (const OTLookup * const *) _s2; - const OTLookup *s1 = *__s1; - const OTLookup *s2 = *__s2; - - if ( s1->lookup_index>s2->lookup_index ) -return( 1 ); - else if ( s1->lookup_index<s2->lookup_index ) -return( -1 ); - else -return( 0 ); -} - -static void SFJstfSort(SplineFont *sf) { - /* scripts must be ordered */ - /* languages must be ordered within scripts */ - /* lookup lists must be ordered */ - Justify *jscript, **scripts; - int i,cnt,lmax; - struct jstf_lang **langs; - - for ( cnt=0, jscript= sf->justify; jscript!=NULL; ++cnt, jscript=jscript->next ); - if ( cnt>1 ) { - scripts = malloc(cnt*sizeof(Justify *)); - for ( i=0, jscript= sf->justify; jscript!=NULL; ++i, jscript=jscript->next ) - scripts[i] = jscript; - qsort(scripts,cnt,sizeof(Justify *),jscriptsort); - for ( i=1; i<cnt; ++i ) - scripts[i-1]->next = scripts[i]; - scripts[cnt-1]->next = NULL; - sf->justify = scripts[0]; - free(scripts); - } - - langs = NULL; lmax=0; - for ( jscript= sf->justify; jscript!=NULL; jscript=jscript->next ) { - struct jstf_lang *jlang; - for ( cnt=0, jlang=jscript->langs; jlang!=NULL; ++cnt, jlang=jlang->next ); - if ( cnt>1 ) { - if ( cnt>lmax ) - langs = realloc(langs,(lmax=cnt+10)*sizeof(struct jstf_lang *)); - for ( i=0, jlang=jscript->langs; jlang!=NULL; ++i, jlang=jlang->next ) - langs[i] = jlang; - qsort(langs,cnt,sizeof(Justify *),jlangsort); - for ( i=1; i<cnt; ++i ) - langs[i-1]->next = langs[i]; - langs[cnt-1]->next = NULL; - jscript->langs = langs[0]; - } - } - free(langs); - - /* don't bother to sort the lookup lists yet. We need to separate them into*/ - /* GPOS/GSUB first, might as well do it all at once later */ -} - -static void jstf_SplitTables(OTLookup **mixed,OTLookup ***_SUB,OTLookup ***_POS) { - /* (later is now, see comment above) */ - /* mixed contains both gsub and gpos lookups. put them into their own */ - /* lists, and then sort them */ - int cnt, s, p; - OTLookup **SUB, **POS; - - if ( mixed==NULL || mixed[0]==NULL ) { - *_SUB = NULL; - *_POS = NULL; -return; - } - - for ( cnt=0; mixed[cnt]!=NULL; ++cnt); - SUB = malloc((cnt+1)*sizeof(OTLookup *)); - POS = malloc((cnt+1)*sizeof(OTLookup *)); - for ( cnt=s=p=0; mixed[cnt]!=NULL; ++cnt) { - if ( mixed[cnt]->lookup_index==-1 ) /* Not actually used */ - continue; - if ( mixed[cnt]->lookup_type>=gpos_start ) - POS[p++] = mixed[cnt]; - else - SUB[s++] = mixed[cnt]; - } - POS[p] = SUB[s] = NULL; - - if ( p>1 ) - qsort(POS,p,sizeof(OTLookup *),lookup_order); - if ( s>1 ) - qsort(SUB,s,sizeof(OTLookup *),lookup_order); - if ( p==0 ) { - free(POS); - POS=NULL; - } - if ( s==0 ) { - free(SUB); - SUB=NULL; - } - *_SUB = SUB; - *_POS = POS; -} - -static uint32 jstf_dumplklist(FILE *jstf,OTLookup **PS,uint32 base) { - uint32 here; - int i; - - if ( PS==NULL ) -return( 0 ); - - here = ftell(jstf); - for ( i=0; PS[i]!=NULL; ++i ); - putshort(jstf,i); /* Lookup cnt */ - for ( i=0; PS[i]!=NULL; ++i ) - putshort( jstf, PS[i]->lookup_index ); - free(PS); -return( here - base ); -} - -static uint32 jstf_dumpmaxlookups(FILE *jstf,SplineFont *sf,struct alltabs *at, - OTLookup **maxes,uint32 base) { - uint32 here, lbase; - int cnt,i; - int scnt, j; - struct lookup_subtable *sub; - - if ( maxes==NULL ) -return( 0 ); - - for ( cnt=i=0; maxes[i]!=NULL; ++i ) - if ( !maxes[i]->unused ) - ++cnt; - if ( cnt==0 ) -return( 0 ); - - if ( (here=ftell(jstf))<0 ) -return( 0 ); - - putshort( jstf,cnt ); - for ( i=0; maxes[i]!=NULL; ++i ) if ( !maxes[i]->unused ) - putshort( jstf,0 ); - for ( cnt=i=0; maxes[i]!=NULL; ++i ) if ( !maxes[i]->unused ) { - if ( (lbase=ftell(jstf))<0 ) -return( 0 ); - fseek(jstf,here+2+2*cnt,SEEK_SET); - putshort(jstf,lbase-here); - fseek(jstf,lbase,SEEK_SET); - - putshort(jstf,maxes[i]->lookup_type - gpos_start ); - putshort(jstf,maxes[i]->lookup_flags); - - for ( scnt=0, sub=maxes[i]->subtables; sub!=NULL; sub=sub->next ) - if ( !sub->unused ) - ++scnt; - putshort( jstf,scnt ); - for ( j=0; j<scnt; ++j ) - putshort( jstf,0 ); - /* I don't think extension lookups get a MarkAttachmentType, I guess */ - /* that inherits from the parent? */ - - otf_dumpALookup(jstf, maxes[i], sf, at); - fseek(jstf,lbase+6,SEEK_SET); - for ( sub=maxes[i]->subtables; sub!=NULL; sub=sub->next ) - if ( !sub->unused ) - putshort(jstf,sub->subtable_offset-lbase); - ++cnt; - } - -return( here - base ); -} - -void otf_dumpjstf(struct alltabs *at, SplineFont *sf) { - FILE *jstf; - int i, cnt, lcnt, offset; - uint32 here, base; - Justify *jscript; - struct jstf_lang *jlang; - - if ( sf->justify==NULL ) -return; - - SFJstfSort(sf); - for ( jscript=sf->justify, cnt=0; jscript!=NULL; jscript=jscript->next, ++cnt ); - - at->jstf = jstf = tmpfile2(); - - putlong(jstf, 0x00010000 ); /* Version 1 */ - putshort(jstf, cnt ); /* script count */ - for ( jscript=sf->justify; jscript!=NULL; jscript=jscript->next ) { - putlong(jstf, jscript->script); - putshort(jstf, 0); /* Come back to this later */ - } - for ( jscript=sf->justify, cnt=0; jscript!=NULL; jscript=jscript->next, ++cnt ) { - base = ftell(jstf); - if ( base>0xffff ) - ff_post_error(_("Failure"),_("Offset in JSTF table is too big. The resultant font will not work.")); - fseek(jstf, 6+6*cnt+4,SEEK_SET); - putshort(jstf,base); - fseek(jstf, base, SEEK_SET); - - putshort(jstf,0); /* extender glyphs */ - putshort(jstf,0); /* default lang */ - for ( jlang=jscript->langs, lcnt=0; jlang!=NULL; jlang=jlang->next, ++lcnt ); - if ( lcnt>0 && jscript->langs->lang==DEFAULT_LANG ) - --lcnt; - putshort(jstf,lcnt); /* count of non-default languages */ - jlang = jscript->langs; - if ( jlang!=NULL && jlang->lang==DEFAULT_LANG ) - jlang=jlang->next; - for ( ; jlang!=NULL; jlang=jlang->next ) { - putlong(jstf, jlang->lang); - putshort(jstf, 0); /* Come back to this later */ - } - - if ( jscript->extenders!=NULL ) { - SplineChar **glyphs; - int gcnt,g; - - here = ftell(jstf); - fseek(jstf,base,SEEK_SET); - putshort(jstf,here-base); - fseek(jstf,here,SEEK_SET); - - glyphs = OrderedGlyphsFromNames(sf,jscript->extenders); - if ( glyphs==NULL ) - gcnt=0; - else - for ( gcnt=0; glyphs[gcnt]!=NULL; ++gcnt); - putshort(jstf,gcnt); - for ( g=0; g<gcnt; ++g ) - putshort(jstf,glyphs[g]->ttf_glyph); - free(glyphs); - } - - offset=0; - for ( jlang=jscript->langs, lcnt=0; jlang!=NULL; jlang=jlang->next, ++lcnt ) { - here = ftell(jstf); - if ( jlang->lang==DEFAULT_LANG ) { - fseek(jstf,base+2,SEEK_SET); - offset = -6; - } else - fseek(jstf,base+offset+10+lcnt*6,SEEK_SET); - putshort(jstf,here-base); - fseek(jstf,here,SEEK_SET); - - putshort(jstf,jlang->cnt); - for ( i=0; i<jlang->cnt; ++i ) - putshort(jstf,0); - for ( i=0; i<jlang->cnt; ++i ) { - OTLookup **enSUB, **enPOS, **disSUB, **disPOS; - uint32 enSUBoff, enPOSoff, disSUBoff, disPOSoff, maxOff; - uint32 pbase; - pbase = ftell(jstf); - fseek(jstf,here+2+i*2,SEEK_SET); - putshort(jstf,pbase-here); - fseek(jstf,pbase,SEEK_SET); - - putshort(jstf,0); - putshort(jstf,0); - putshort(jstf,0); - putshort(jstf,0); - putshort(jstf,0); - putshort(jstf,0); - putshort(jstf,0); - putshort(jstf,0); - putshort(jstf,0); - putshort(jstf,0); - - jstf_SplitTables(jlang->prios[i].enableShrink,&enSUB,&enPOS); - jstf_SplitTables(jlang->prios[i].disableShrink,&disSUB,&disPOS); - enSUBoff = jstf_dumplklist(jstf,enSUB, pbase); - disSUBoff = jstf_dumplklist(jstf,disSUB,pbase); - enPOSoff = jstf_dumplklist(jstf,enPOS, pbase); - disPOSoff = jstf_dumplklist(jstf,disPOS,pbase); - maxOff = jstf_dumpmaxlookups(jstf,sf,at,jlang->prios[i].maxShrink,pbase); - - fseek(jstf,pbase,SEEK_SET); - putshort(jstf,enSUBoff); - putshort(jstf,disSUBoff); - putshort(jstf,enPOSoff); - putshort(jstf,disPOSoff); - putshort(jstf,maxOff); - - fseek(jstf,0,SEEK_END); - jstf_SplitTables(jlang->prios[i].enableExtend,&enSUB,&enPOS); - jstf_SplitTables(jlang->prios[i].disableExtend,&disSUB,&disPOS); - enSUBoff = jstf_dumplklist(jstf,enSUB, pbase); - disSUBoff = jstf_dumplklist(jstf,disSUB,pbase); - enPOSoff = jstf_dumplklist(jstf,enPOS, pbase); - disPOSoff = jstf_dumplklist(jstf,disPOS,pbase); - maxOff = jstf_dumpmaxlookups(jstf,sf,at,jlang->prios[i].maxExtend,pbase); - - fseek(jstf,pbase+10,SEEK_SET); - putshort(jstf,enSUBoff); - putshort(jstf,disSUBoff); - putshort(jstf,enPOSoff); - putshort(jstf,disPOSoff); - putshort(jstf,maxOff); - fseek(jstf,0,SEEK_END); - } - } - } - - fseek(jstf,0,SEEK_END); - at->jstflen = ftell(jstf); - if ( ftell(jstf)&1 ) - putc('\0',jstf); - if ( ftell(jstf)&2 ) - putshort(jstf,0); -} - -void otf_dump_dummydsig(struct alltabs *at, SplineFont *sf) { - FILE *dsigf; - - /* I think the DSIG table is a big crock. At best the most it can do is */ - /* tell you that the font hasn't changed since it was signed. It gives */ - /* no guarantee that the data are reasonable. I think it's stupid. */ - /* I think it is even more stupid that MS choses this useless table as a*/ - /* mark of whether a ttf font is OpenType or not. */ - /* But users want their fonts to show up as OpenType under MS. And I'm */ - /* told an empty DSIG table works for that. So... a truely pointless */ - /* instance of a pointless table. I suppose that's a bit ironic. */ - - at->dsigf = dsigf = tmpfile2(); - putlong(dsigf,0x00000001); /* Standard version (and why isn't it 0x10000 like everything else?) */ - putshort(dsigf,0); /* No signatures in my signature table*/ - putshort(dsigf,0); /* No flags */ - - at->dsiglen = ftell(dsigf); - if ( ftell(dsigf)&1 ) - putc('\0',dsigf); - if ( ftell(dsigf)&2 ) - putshort(dsigf,0); -} |