diff options
Diffstat (limited to 'Build/source/texk/web2c/luatexdir/luafontloader/fontforge/fontforge/parsettfvar.c')
-rw-r--r-- | Build/source/texk/web2c/luatexdir/luafontloader/fontforge/fontforge/parsettfvar.c | 771 |
1 files changed, 771 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/luatexdir/luafontloader/fontforge/fontforge/parsettfvar.c b/Build/source/texk/web2c/luatexdir/luafontloader/fontforge/fontforge/parsettfvar.c new file mode 100644 index 00000000000..1467fcbc06b --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/luafontloader/fontforge/fontforge/parsettfvar.c @@ -0,0 +1,771 @@ +/* Copyright (C) 2000-2008 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 "pfaedit.h" +#include <chardata.h> +#include <utype.h> +#include <ustring.h> +#include <math.h> +#include <locale.h> +#include <gwidget.h> +#include "ttf.h" + +/***************************************************************************/ +/* */ +/* Apple documents these tables at */ +/* http:// developer.apple.com/fonts/TTRefMan/RM06/Chap6[fgca]var.html */ +/* The documentation for fvar is inconsistant. At one point it says that */ +/* countSizePairs should be 3, at another point 2. It should be 2. */ +/* The documentation for gvar is not intelligable, cvar refers you to gvar */ +/* and is thus also incomprehensible */ +/* The documentation for avar appears correct, but as Apple has no fonts */ +/* with an 'avar' table, so it's hard to test. */ +/* */ +/***************************************************************************/ + +/* Parse Apple's variation tables (font, glyph, cvt and axis) */ +/* To be interesting a font must have an fvar and a gvar */ +/* If it's hinted it better have a cvar */ +/* It may have an avar if it wants to be complicated */ + +void VariationFree(struct ttfinfo *info) { + int i,j; + struct variations *variation = info->variations; + + if ( variation==NULL ) +return; + if ( variation->axes!=NULL ) { + for ( i=0; i<variation->axis_count; ++i ) { + free(variation->axes[i].mapfrom); + free(variation->axes[i].mapto); + } + free(variation->axes); + } + if ( variation->instances!=NULL ) { + for ( i=0; i<variation->instance_count; ++i ) { + free(variation->instances[i].coords); + } + free(variation->instances); + } + if ( variation->tuples!=NULL ) { + for ( i=0; i<variation->tuple_count; ++i ) { + free(variation->tuples[i].coords); + if ( variation->tuples[i].chars!=NULL ) + for ( j=0; j<info->glyph_cnt; ++j ) + SplineCharFree(variation->tuples[i].chars[j]); + free(variation->tuples[i].chars); + KernClassListFree(variation->tuples[i].khead); + KernClassListFree(variation->tuples[i].vkhead); + } + free(variation->tuples); + } + free(variation); + info->variations = NULL; +} + +static void parsefvar(struct ttfinfo *info, FILE *ttf) { + int data_off, axis_count, instance_count, cnt; + int i,j; + + fseek(ttf,info->fvar_start,SEEK_SET); + if ( getlong(ttf)!=0x00010000 ) /* I only understand version 1 */ +return; + data_off = getushort(ttf); + cnt = getushort(ttf); + if ( cnt>2 ) + LogError( _("Hmm, this 'fvar' table has more count/size pairs than I expect\n") ); + else if ( cnt<2 ) { + LogError( _("Hmm, this 'fvar' table has too few count/size pairs, I shan't parse it\n") ); +return; + } + axis_count = getushort(ttf); + if ( axis_count==0 || axis_count>4 ) { + if ( axis_count==0 ) + LogError( _("Hmm, this 'fvar' table has no axes, that doesn't make sense.\n") ); + else + LogError( _("Hmm, this 'fvar' table has more axes than FontForge can handle.\n") ); +return; + } + if ( getushort(ttf)!=20 ) { + LogError( _("Hmm, this 'fvar' table has an unexpected size for an axis, I shan't parse it\n") ); +return; + } + instance_count = getushort(ttf); + if ( getushort(ttf)!=4+4*axis_count ) { + LogError( _("Hmm, this 'fvar' table has an unexpected size for an instance, I shan't parse it\n") ); +return; + } + if ( data_off+axis_count*20+instance_count*(4+4*axis_count)> (int)info->fvar_len ) { + LogError( _("Hmm, this 'fvar' table is too short\n") ); +return; + } + + info->variations = gcalloc(1,sizeof(struct variations)); + info->variations->axis_count = axis_count; + info->variations->instance_count = instance_count; + info->variations->axes = gcalloc(axis_count,sizeof(struct taxis)); + info->variations->instances = gcalloc(instance_count,sizeof(struct tinstance)); + for ( i=0; i<instance_count; ++i ) + info->variations->instances[i].coords = galloc(axis_count*sizeof(real)); + + fseek(ttf,info->fvar_start+data_off,SEEK_SET); + for ( i=0; i<axis_count; ++i ) { + struct taxis *a = &info->variations->axes[i]; + a->tag = getlong(ttf); + a->min = getlong(ttf)/65536.0; + a->def = getlong(ttf)/65536.0; + a->max = getlong(ttf)/65536.0; + /* flags = */ getushort(ttf); + a->nameid = getushort(ttf); + } + for ( i=0; i<instance_count; ++i ) { + struct tinstance *ti = &info->variations->instances[i]; + ti->nameid = getushort(ttf); + /* flags = */ getushort(ttf); + for ( j=0 ; j<axis_count; ++j ) + ti->coords[j] = getlong(ttf)/65536.0; + } +} + +static void parseavar(struct ttfinfo *info, FILE *ttf) { + int axis_count, pair_count; + int i,j; + + if ( info->variations==NULL || info->avar_start==0 || info->avar_len==0 ) +return; + + fseek(ttf,info->avar_start,SEEK_SET); + if ( getlong(ttf)!=0x00010000 ) { /* I only understand version 1 */ + VariationFree(info); +return; + } + axis_count = getlong(ttf); + if ( axis_count!=info->variations->axis_count ) { + LogError( _("Hmm, the axis count in the 'avar' table is different from that in the 'fvar' table.\n") ); + VariationFree(info); +return; + } + for ( i=0; i<axis_count; ++i ) { + pair_count = getushort(ttf); + if ( pair_count!=0 ) { + info->variations->axes[i].mapfrom = galloc(pair_count*sizeof(real)); + info->variations->axes[i].mapto= galloc(pair_count*sizeof(real)); + for ( j=0; j<pair_count; ++j ) { + info->variations->axes[i].mapfrom[j] = getushort(ttf)/16384.0; + info->variations->axes[i].mapto[j] = getushort(ttf)/16384.0; + } + } + } + if ( ftell(ttf)-info->avar_start>info->avar_len) { + LogError( _("Hmm, the the 'avar' table is too long.\n") ); + VariationFree(info); +return; + } +} + +static SplineChar **InfoCopyGlyphs(struct ttfinfo *info) { + SplineChar **chars = galloc(info->glyph_cnt*sizeof(SplineChar *)); + int i; + RefChar *r; + + for ( i=0; i<info->glyph_cnt; ++i ) { + if ( info->chars[i]==NULL ) + chars[i] = NULL; + else { + chars[i] = SplineCharCopy(info->chars[i],NULL,NULL); + free(chars[i]->ttf_instrs); chars[i]->ttf_instrs = NULL; + chars[i]->ttf_instrs_len = 0; + PSTFree(chars[i]->possub); chars[i]->possub = NULL; + for ( r=chars[i]->layers[ly_fore].refs; r!=NULL; r=r->next ) + r->sc = NULL; + chars[i]->changed = false; + chars[i]->ticked = false; + } + } + + for ( i=0; i<info->glyph_cnt; ++i ) + ttfFixupRef(chars,i); +return( chars ); +} + +#define BAD_DELTA 0x10001 +static int *readpackeddeltas(FILE *ttf,int n) { + int *deltas; + int runcnt, i, j; + + deltas = galloc(n*sizeof(int)); + + i = 0; + while ( i<n ) { + runcnt = getc(ttf); + if ( runcnt&0x80 ) { + /* runcnt zeros get added */ + for ( j=0; j<=(runcnt&0x3f) && i<n ; ++j ) + deltas[i++] = 0; + } else if ( runcnt&0x40 ) { + /* runcnt shorts from the stack */ + for ( j=0 ; j<=(runcnt&0x3f) && i<n ; ++j ) + deltas[i++] = (int16) getushort(ttf); + } else { + /* runcnt signed bytes from the stack */ + for ( j=0; j<=(runcnt&0x3f) && i<n; ++j ) + deltas[i++] = (int8) getc(ttf); + } + if ( j<=(runcnt&0x3f) ) { + if ( n>0 ) + deltas[0] = BAD_DELTA; + } + } +return( deltas ); +} + +#define ALL_POINTS 0x10001 +#define END_OF_POINTS 0x10000 + +static int *readpackedpoints(FILE *ttf) { + int *points; + int n, runcnt, i, j, first; + + n = getc(ttf); + if ( n==EOF ) + n = 0; + if ( n&0x80 ) + n = getc(ttf)|((n&0x7f)<<8); + points = galloc((n+1)*sizeof(int)); + if ( n==0 ) + points[0] = ALL_POINTS; + else { + i = 0; + while ( i<n ) { + runcnt = getc(ttf); + if ( runcnt&0x80 ) { + runcnt = (runcnt&0x7f); + points[i++] = first = getushort(ttf); + /* first point not included in runcount */ + for ( j=0; j<runcnt && i<n; ++j ) + points[i++] = (first += getushort(ttf)); + } else { + points[i++] = first = getc(ttf); + for ( j=0; j<runcnt && i<n; ++j ) + points[i++] = (first += getc(ttf)); + } + } + points[n] = END_OF_POINTS; + } +return( points ); +} + +static int TuplesMatch(struct variations *v, int vtest, int dbase) { + /* variations for [0,1] make up part of design [1,1], but not the other */ + /* way round */ + int i; + + if ( dbase>=v->tuple_count ) +return( false ); + + if ( vtest==dbase ) +return( true ); + for ( i=0; i<v->axis_count; ++i ) { + if ( v->tuples[vtest].coords[i]==0 && v->tuples[dbase].coords[i]!=0 ) +return( false ); + if ( v->tuples[dbase].coords[i]!=0 && + v->tuples[dbase].coords[i]!=v->tuples[vtest].coords[i] ) +return( false ); + } +return( true ); +} + +static int PointCount(SplineChar *sc) { + int i; + RefChar *ref; + SplineSet *ss; + SplinePoint *sp; + + if ( sc->layers[ly_fore].refs!=NULL ) + for ( i=0, ref=sc->layers[ly_fore].refs; ref!=NULL; ++i, ref=ref->next ); + else { + for ( i=0, ss = sc->layers[ly_fore].splines; ss!=NULL; ss=ss->next ) { + for ( sp=ss->first; sp!=NULL ; ) { + if ( sp->ttfindex!=0xffff && sp->ttfindex!=0xfffe ) + ++i; + if ( sp->nextcpindex!=0xffff && sp->nextcpindex!=0xfffe ) + ++i; + if ( sp->next==NULL ) + break; + sp = sp->next->to; + if ( sp==ss->first ) + break; + } + } + } +return( i ); +} + +static void SCShiftAllBy(SplineChar *sc,int xd, int yd) { + /* If they change the left/right side-bearing, I think that means everything */ + /* should be shifted over */ + SplineSet *ss; + SplinePoint *sp; + RefChar *ref; + + if ( xd==0 && yd==0 ) +return; + + for ( ss = sc->layers[ly_fore].splines; ss!=NULL; ss=ss->next ) { + for ( sp=ss->first; sp!=NULL ; ) { + if ( sp->ttfindex!=0xffff && sp->ttfindex!=0xfffe ) { + sp->me.x += xd; + sp->me.y += yd; + } + if ( sp->nextcpindex!=0xffff && sp->nextcpindex!=0xfffe ) { + sp->nextcp.x += xd; + sp->nextcp.y += yd; + if ( sp->next!=NULL ) + sp->next->to->prevcp = sp->nextcp; + } + if ( sp->next==NULL ) + break; + sp = sp->next->to; + if ( sp == ss->first ) + break; + } + } + for ( ref=sc->layers[ly_fore].refs; ref!=NULL; ref=ref->next ) { + ref->transform[4] += xd; + ref->transform[5] += yd; + SCReinstanciateRefChar(sc,ref,ly_fore); + } +} + +static void VaryGlyph(SplineChar *sc,int *points, int *xdeltas, int *ydeltas, + int pcnt) { + /* A character contains either composites or contours */ + int i,j; + RefChar *ref; + SplineSet *ss; + SplinePoint *sp; + Spline *s, *first; + + if ( points[0]==ALL_POINTS ) { + if ( sc->layers[ly_fore].refs!=NULL ) { + for ( i=0, ref=sc->layers[ly_fore].refs; ref!=NULL; ++i, ref=ref->next ) { + if ( xdeltas[i]!=0 || ydeltas[i]!=0 ) { + ref->transform[4] += xdeltas[i]; + ref->transform[5] += ydeltas[i]; + SCReinstanciateRefChar(sc,ref,ly_fore); + } + } + } else { + for ( ss = sc->layers[ly_fore].splines; ss!=NULL; ss=ss->next ) { + for ( sp=ss->first; sp!=NULL ; ) { + if ( sp->ttfindex!=0xffff && sp->ttfindex!=0xfffe ) { + sp->me.x += xdeltas[sp->ttfindex]; + sp->me.y += ydeltas[sp->ttfindex]; + } + if ( sp->nextcpindex!=0xffff && sp->nextcpindex!=0xfffe ) { + sp->nextcp.x += xdeltas[sp->nextcpindex]; + sp->nextcp.y += ydeltas[sp->nextcpindex]; + if ( sp->next!=NULL ) + sp->next->to->prevcp = sp->nextcp; + } + if ( sp->next==NULL ) + break; + sp = sp->next->to; + if ( sp == ss->first ) + break; + } + } + } + SCShiftAllBy(sc,-xdeltas[pcnt-4],0); + SCShiftAllBy(sc,0,-ydeltas[pcnt-2]); + sc->width += xdeltas[pcnt-3]; + sc->vwidth += ydeltas[pcnt-1]; + } else { + j = 0; + if ( sc->layers[ly_fore].refs!=NULL ) { + for ( i=0, ref=sc->layers[ly_fore].refs; ref!=NULL; ++i, ref=ref->next ) { + if ( points[j]==i ) { + if ( xdeltas[j]!=0 || ydeltas[j]!=0 ) { + ref->transform[4] += xdeltas[j]; + ref->transform[5] += ydeltas[j]; + SCReinstanciateRefChar(sc,ref,ly_fore); + } + ++j; + } + } + } else { + for ( i=0, ss = sc->layers[ly_fore].splines; ss!=NULL; ss=ss->next ) { + if ( ss->first->prev!=NULL && ss->first->prev->from->nextcpindex==points[j] ) { + ss->first->prevcp.x += xdeltas[j]; + ss->first->prevcp.y += ydeltas[j]; + ss->first->prev->from->nextcp = ss->first->prevcp; + ++j; + } + for ( sp=ss->first; sp!=NULL ; ++i ) { + if ( sp->ttfindex!=0xffff && sp->ttfindex!=0xfffe ) + ++i; + if ( sp->ttfindex==points[j] ) { + sp->me.x += xdeltas[j]; + sp->me.y += ydeltas[j++]; + } + if ( sp->nextcpindex!=0xffff && sp->nextcpindex!=0xfffe ) + ++i; + if ( sp->nextcpindex==points[j] ) { + sp->nextcp.x += xdeltas[j]; + sp->nextcp.y += ydeltas[j++]; + if ( sp->next!=NULL ) + sp->next->to->prevcp = sp->nextcp; + } else if ( sp->nonextcp ) { + sp->nextcp = sp->me; + } + if ( sp->next==NULL ) + break; + sp = sp->next->to; + if ( sp == ss->first ) + break; + } + first = NULL; + } + } + if ( points[j]==i ) + SCShiftAllBy(sc,-xdeltas[j++],0); + if ( points[j]==i+1 ) + sc->width += xdeltas[j++]; + if ( points[j]==i+2 ) + SCShiftAllBy(sc,0,-ydeltas[j++]); + if ( points[j]==i+3 ) + sc->vwidth += ydeltas[j++]; + } + if ( sc->layers[ly_fore].refs==NULL ) { + for ( ss = sc->layers[ly_fore].splines; ss!=NULL; ss=ss->next ) { + for ( sp=ss->first; sp!=NULL ; ++i ) { + if ( sp->ttfindex==0xffff ) { + sp->me.x = ( sp->nextcp.x + sp->prevcp.x )/2; + sp->me.y = ( sp->nextcp.y + sp->prevcp.y )/2; + } + if ( sp->next==NULL ) + break; + sp = sp->next->to; + if ( sp == ss->first ) + break; + } + + first = NULL; + for ( s=ss->first->next; s!=NULL && s!=first; s=s->to->next ) { + SplineRefigure(s); + if ( first==NULL ) first = s; + } + } + } +} + +static void VaryGlyphs(struct ttfinfo *info,int tupleIndex,int gnum, + int *points, FILE *ttf ) { + /* one annoying thing about gvar, is that the variations do not describe */ + /* designs. well variations for [0,1] describes that design, but the */ + /* design for [1,1] includes the variations [0,1], [1,0], and [1,1] */ + int pcnt, tc; + int *xdeltas, *ydeltas; + struct variations *v = info->variations; + + if ( info->chars[gnum]==NULL ) /* Apple doesn't support ttc so this */ +return; /* can't happen */ + if ( points==NULL ) { + LogError( _("Mismatched local and shared tuple flags.\n") ); +return; + } + + if ( points[0]==ALL_POINTS ) + pcnt = PointCount(info->chars[gnum])+4; + else { + for ( pcnt=0; points[pcnt]!=END_OF_POINTS; ++pcnt ); + } + xdeltas = readpackeddeltas(ttf,pcnt); + ydeltas = readpackeddeltas(ttf,pcnt); + if ( xdeltas[0]!=BAD_DELTA && ydeltas[0]!=BAD_DELTA ) + for ( tc = 0; tc<v->tuple_count; ++tc ) { + if ( TuplesMatch(v,tc,tupleIndex)) + VaryGlyph(v->tuples[tc].chars[gnum],points,xdeltas,ydeltas,pcnt); + } else { + static int warned = false; + if ( !warned ) + LogError( _("Incorrect number of deltas in glyph %d (%s)\n"), gnum, + info->chars[gnum]->name!=NULL?info->chars[gnum]->name:"<Nameless>" ); + warned = true; + } + free(xdeltas); + free(ydeltas); +} + +static void parsegvar(struct ttfinfo *info, FILE *ttf) { + /* I'm only going to support a subset of the gvar. Only the global tuples */ + int axiscount, globaltc, gvarflags, gc, i,j,g; + uint32 tupoff, dataoff, *gvars; + struct variations *v = info->variations; + int warned=false; + + fseek(ttf,info->gvar_start,SEEK_SET); + if ( getlong(ttf)!=0x00010000 ) { /* I only understand version 1 */ + VariationFree(info); +return; + } + axiscount = getushort(ttf); + if ( axiscount!=info->variations->axis_count ) { + LogError( _("Hmm, the axis count in the 'gvar' table is different from that in the 'fvar' table.\n") ); + VariationFree(info); +return; + } + globaltc = getushort(ttf); + tupoff = getlong(ttf) + info->gvar_start; + gc = getushort(ttf); + gvarflags = getushort(ttf); + dataoff = getlong(ttf) + info->gvar_start; + if ( globaltc==0 || globaltc>AppleMmMax ) { + if ( globaltc==0 ) + LogError( _("Hmm, no global tuples specified in the 'gvar' table.\n") ); + else + LogError( _("Hmm, too many global tuples specified in the 'gvar' table.\n FontForge only supports %d\n"), AppleMmMax ); + VariationFree(info); +return; + } + if ( gc>info->glyph_cnt ) { + LogError( _("Hmm, more glyph variation data specified than there are glyphs in font.\n") ); + VariationFree(info); +return; + } + + gvars = galloc((gc+1)*sizeof(uint32)); + if ( gvarflags&1 ) { /* 32 bit data */ + for ( i=0; i<=gc; ++i ) + gvars[i] = getlong(ttf)+dataoff; + } else { + for ( i=0; i<=gc; ++i ) + gvars[i] = getushort(ttf)*2 +dataoff; /* Undocumented *2 */ + } + + v->tuple_count = globaltc; + v->tuples = gcalloc(globaltc,sizeof(struct tuples)); + fseek(ttf,tupoff,SEEK_SET); + for ( i=0; i<globaltc; ++i ) { + v->tuples[i].coords = galloc(axiscount*sizeof(float)); + for ( j=0; j<axiscount; ++j ) + v->tuples[i].coords[j] = ((short) getushort(ttf))/16384.0; + v->tuples[i].chars = InfoCopyGlyphs(info); + } + + for ( g=0; g<gc; ++g ) if ( gvars[g]!=gvars[g+1] ) { + int tc; + uint32 datoff; + int *sharedpoints=NULL; + fseek(ttf,gvars[g],SEEK_SET); + tc = getushort(ttf); + datoff = gvars[g]+getushort(ttf); + if ( tc&0x8000 ) { + uint32 here = ftell(ttf); + fseek(ttf,datoff,SEEK_SET); + sharedpoints = readpackedpoints(ttf); + datoff = ftell(ttf); + fseek(ttf,here,SEEK_SET); + } + for ( i=0; i<(tc&0xfff); ++i ) { + int tupleDataSize, tupleIndex; + tupleDataSize = getushort(ttf); + tupleIndex = getushort(ttf); + if ( tupleIndex&0xc000 ) { + if ( !warned ) + LogError( _("Warning: Glyph %d contains either private or intermediate tuple data.\n FontForge supports neither.\n"), + g); + warned = true; + if ( tupleIndex&0x8000 ) + fseek(ttf,2*axiscount,SEEK_CUR); + if ( tupleIndex&0x4000 ) + fseek(ttf,4*axiscount,SEEK_CUR); + } else { + int *localpoints=NULL; + uint32 here = ftell(ttf); + fseek(ttf,datoff,SEEK_SET); + if ( tupleIndex&0x2000 ) + localpoints = readpackedpoints(ttf); + VaryGlyphs(info,tupleIndex&0xfff,g, + (tupleIndex&0x2000)?localpoints:sharedpoints,ttf); + free(localpoints); + fseek(ttf,here,SEEK_SET); + } + datoff += tupleDataSize; + } + free(sharedpoints); + } + free(gvars); +} + +static void AlterEntry(struct ttf_table *cvt, int i, int delta ) { + int val = memushort(cvt->data,cvt->len,2*i); + memputshort(cvt->data,2*i,val+delta); +} + +static void VaryCvt(struct tuples *tuple,int *points, int *deltas, + int pcnt, struct ttf_table *orig_cvt) { + struct ttf_table *cvt; + int i; + + if ( (cvt = tuple->cvt)==NULL ) { + cvt = tuple->cvt = chunkalloc(sizeof(struct ttf_table)); + cvt->tag = orig_cvt->tag; + cvt->len = cvt->maxlen = orig_cvt->len; + cvt->data = galloc(cvt->len); + memcpy(cvt->data,orig_cvt->data,cvt->len); + } + if ( points[0]==ALL_POINTS ) { + for ( i=0; i<pcnt; ++i ) + AlterEntry(cvt,i,deltas[i]); + } else { + for ( i=0; i<pcnt; ++i ) + AlterEntry(cvt,points[i],deltas[i]); + } +} + +static void VaryCvts(struct ttfinfo *info,int tupleIndex, int *points, FILE *ttf, + struct ttf_table *origcvt ) { + /* one annoying thing about gvar, is that the variations do not describe */ + /* designs. well variations for [0,1] describes that design, but the */ + /* design for [1,1] includes the variations [0,1], [1,0], and [1,1] */ + /* And same is true of cvar */ + int pcnt, tc; + int *deltas; + struct variations *v = info->variations; + + if ( points[0]==ALL_POINTS ) + pcnt = origcvt->len/sizeof(uint16); + else { + for ( pcnt=0; points[pcnt]!=END_OF_POINTS; ++pcnt ); + } + deltas = readpackeddeltas(ttf,pcnt); + if ( deltas[0]!=BAD_DELTA ) + for ( tc = 0; tc<v->tuple_count; ++tc ) { + if ( TuplesMatch(v,tc,tupleIndex)) + VaryCvt(&v->tuples[tc],points,deltas,pcnt,origcvt); + } else { + static int warned = false; + if ( !warned ) + LogError( _("Incorrect number of deltas in cvt\n") ); + warned = true; + } + free(deltas); +} + +static void parsecvar(struct ttfinfo *info, FILE *ttf) { + struct ttf_table *cvt; + int tuplecount; + uint32 offset; + int *sharedpoints=NULL; + int i; + int warned = false; + + for ( cvt = info->tabs; cvt!=NULL && cvt->tag!=CHR('c','v','t',' '); cvt=cvt->next ); + if ( cvt==NULL ) +return; + + fseek(ttf,info->cvar_start,SEEK_SET); + if ( getlong(ttf)!=0x00010000 ) { /* I only understand version 1 */ + /* I think I can live without cvt variations... */ + /* So I shan't free the structure */ +return; + } + + tuplecount = getushort(ttf); + offset = info->cvar_start+getushort(ttf); + /* The documentation implies there are flags packed into the tuplecount */ + /* but John Jenkins tells me that shared points don't apply to cvar */ + /* Might as well parse it just in case */ + if ( tuplecount&0x8000 ) { + uint32 here = ftell(ttf); + fseek(ttf,offset,SEEK_SET); + sharedpoints = readpackedpoints(ttf); + offset = ftell(ttf); + fseek(ttf,here,SEEK_SET); + } + for ( i=0; i<(tuplecount&0xfff); ++i ) { + int tupleDataSize, tupleIndex; + tupleDataSize = getushort(ttf); + tupleIndex = getushort(ttf); + /* there is no provision here for a global tuple coordinate section */ + /* so John says there are no tuple indeces. Just embedded tuples */ + if ( tupleIndex&0x4000 ) { + if ( !warned ) + LogError( _("Warning: 'cvar' contains intermediate tuple data.\n FontForge doesn't support this.\n") ); + warned = true; + if ( tupleIndex&0x8000 ) + fseek(ttf,2*info->variations->axis_count,SEEK_CUR); + if ( tupleIndex&0x4000 ) + fseek(ttf,4*info->variations->axis_count,SEEK_CUR); + } else { + int *localpoints=NULL; + uint32 here; + int j,k,ti; + ti = tupleIndex&0xfff; + if ( tupleIndex&0x8000 ) { + real *coords = galloc(info->variations->axis_count*sizeof(real)); + for ( j=0; j<info->variations->axis_count; ++j ) + coords[j] = ((int16) getushort(ttf))/16384.0; + for ( k=0 ; k<info->variations->tuple_count; ++k ) { + for ( j=0; j<info->variations->axis_count; ++j ) + if ( coords[j]!=info->variations->tuples[k].coords[j] ) + break; + if ( j==info->variations->axis_count ) + break; + } + ti = -1; + if ( k!=info->variations->tuple_count ) + ti = k; + } + if ( ti!=-1 ) { + here = ftell(ttf); + fseek(ttf,offset,SEEK_SET); + if ( tupleIndex&0x2000 ) + localpoints = readpackedpoints(ttf); + VaryCvts(info,ti,(tupleIndex&0x2000)?localpoints:sharedpoints,ttf,cvt); + free(localpoints); + fseek(ttf,here,SEEK_SET); + } + } + offset += tupleDataSize; + } + free(sharedpoints); +} + +void readttfvariations(struct ttfinfo *info, FILE *ttf) { + if ( info->gvar_start==0 || info->gvar_len==0 || info->fvar_start==0 || info->fvar_len==0 ) +return; + + ff_progress_change_line2(_("Processing Variations")); + parsefvar(info,ttf); + if ( info->variations!=NULL && info->avar_start!=0 ) + parseavar(info,ttf); + if ( info->variations!=NULL ) + parsegvar(info,ttf); + if ( info->variations!=NULL && info->cvar_start!=0 && info->cvt_start!=0 ) + parsecvar(info,ttf); +} |