Skip to content

Commit

Permalink
Improved handling of class based kerning in metrics view
Browse files Browse the repository at this point in the history
When the user changes a value for the kerning of two glyphs, try to
find all other digraphs in the current metrics view which are in the
same kerning class and update them at the same time.

For example, consider a class with TcToTe in it and a metrics view
with:
xTcToTefiAV
being displayed.

If the kerning between the "To" glyphs is altered, fontforge will now
also alter the Tc and Te automatically and show the kerning updates in
the main portion of the metrics window.
  • Loading branch information
monkeyiq committed Feb 11, 2013
1 parent e8d69ed commit 1230464
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 2 deletions.
21 changes: 21 additions & 0 deletions fontforge/lookups.c
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -4406,6 +4406,27 @@ return( true );
return( false ); return( false );
} }



int KernClassFindIndexContaining( char **firsts_or_seconds,
int firsts_or_seconds_size,
const char *name )
{
int ret = -1;
int i = 0 ;

for ( i=1; i < firsts_or_seconds_size; ++i )
{
if ( PSTContains(firsts_or_seconds[i],name) )
{
ret = i;
break;
}
}

return ret;
}


int KernClassContains(KernClass *kc, char *name1, char *name2, int ordered ) { int KernClassContains(KernClass *kc, char *name1, char *name2, int ordered ) {
int infirst=0, insecond=0, scpos1, kwpos1, scpos2, kwpos2; int infirst=0, insecond=0, scpos1, kwpos1, scpos2, kwpos2;
int i; int i;
Expand Down
26 changes: 26 additions & 0 deletions fontforge/lookups.h
Original file line number Original file line Diff line number Diff line change
@@ -1,3 +1,29 @@
extern char *lookup_type_names[2][10]; extern char *lookup_type_names[2][10];
extern void SortInsertLookup(SplineFont *sf, OTLookup *newotl); extern void SortInsertLookup(SplineFont *sf, OTLookup *newotl);
extern char *SuffixFromTags(FeatureScriptLangList *fl); extern char *SuffixFromTags(FeatureScriptLangList *fl);

/**
* Get the index into the char* array "firsts_or_seconds" that contains "name".
* Or -1 if no such entry was found.
*
* This is handy when using KernClass* kc objects,
* you can pass in kc->firsts and kc->first_cnt and the name of a glyph
* to see if that char is contained in the first part of a pairing.
*
* This can be useful if you want to check if a digraph of chars
* "ab" and "xy" are in the same cell of a KernClass or not (handled in the same class).
* first do
* int idxx = KernClassFindIndexContaining( kc->firsts, kc->first_cnt, "x" );
* int idxy = KernClassFindIndexContaining( kc->seconds, kc->second_cnt, "y" );
*
* then to test any diagrap, say "ab" h for being in the same cell:
* int idxa = KernClassFindIndexContaining( kc->firsts, kc->first_cnt, "a" );
* int idxb = KernClassFindIndexContaining( kc->seconds, kc->second_cnt, "b" );
*
* and they are in the same cell of the kernclass
* if (idxx==idxa && idxy==idxb) {}
*
*/
extern int KernClassFindIndexContaining( char **firsts_or_seconds,
int firsts_or_seconds_size,
const char *name );
78 changes: 76 additions & 2 deletions fontforge/metricsview.c
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -1118,6 +1118,7 @@ return( gwwv_ask(_("Use Kerning Class?"),(const char **) yesno,0,1,
second_is_0 ? _("{Everything Else}") : lsc->name)==0 ); second_is_0 ? _("{Everything Else}") : lsc->name)==0 );
} }



static int MV_ChangeKerning(MetricsView *mv, int which, int offset, int is_diff) { static int MV_ChangeKerning(MetricsView *mv, int which, int offset, int is_diff) {
SplineChar *sc = mv->glyphs[which].sc; SplineChar *sc = mv->glyphs[which].sc;
SplineChar *psc = mv->glyphs[which-1].sc; SplineChar *psc = mv->glyphs[which-1].sc;
Expand Down Expand Up @@ -1213,8 +1214,10 @@ return( false );
MMKern(sc->parent,psc,sc,is_diff?offset:offset-kp->off,sub,kp); MMKern(sc->parent,psc,sc,is_diff?offset:offset-kp->off,sub,kp);
} }
} }
mv->perchar[which-1].kernafter = iscale * (offset*mv->pixelsize)/ int16 newkernafter = iscale * (offset*mv->pixelsize)/
(mv->sf->ascent+mv->sf->descent); (mv->sf->ascent+mv->sf->descent);
mv->perchar[which-1].kernafter = newkernafter;

if ( mv->vertical ) { if ( mv->vertical ) {
for ( i=which; i<mv->glyphcnt; ++i ) { for ( i=which; i<mv->glyphcnt; ++i ) {
mv->perchar[i].dy = mv->perchar[i-1].dy+mv->perchar[i-1].dheight + mv->perchar[i].dy = mv->perchar[i-1].dy+mv->perchar[i-1].dheight +
Expand All @@ -1226,8 +1229,79 @@ return( false );
mv->perchar[i-1].kernafter; mv->perchar[i-1].kernafter;
} }
} }

/**
* Class based kerning. If we have altered one pair "Tc" then we
* want to find any other pairs in the same class that are shown
* and alter them in a similar way. Note that the update to the
* value shown is already done as that is taken from the
* KernClass. We can get away with just calling MVRefreshValues()
* on the right indexes to update the kern value entry boxes. On
* the other hand, we have to make sure the guide and glyph
* display is adjusted accordingly too otherwise the user will not
* see the currect kerning for all other digraphs in the same
* class even thuogh the kerning entry box is updated.
*/
if( kc && psc && sc )
{
// cache the cell in the kernclass that we are editing for quick comparison
// in the loop
int pscidx = KernClassFindIndexContaining( kc->firsts, kc->first_cnt, psc->name );
int scidx = KernClassFindIndexContaining( kc->seconds, kc->second_cnt, sc->name );

if( pscidx > 0 && scidx > 0 )
{
for ( i=1; i<mv->glyphcnt; ++i )
{
// don't check yourself.
if( i-1 == which )
continue;

/* printf("mv->glyphs[i-1].sc.name:%s\n", mv->glyphs[i-1].sc->name ); */
/* printf("mv->glyphs[i ].sc.name:%s\n", mv->glyphs[i ].sc->name ); */

int pidx = KernClassFindIndexContaining( kc->firsts,
kc->first_cnt,
mv->glyphs[i-1].sc->name );
/*
* Same value for firsts in the kernclass matrix
*/
if( pidx == pscidx )
{
int idx = KernClassFindIndexContaining( kc->seconds,
kc->second_cnt,
mv->glyphs[ i ].sc->name );

/*
* First and Second match, we have the same cell
* in the kernclass and thus the same kern value
* should be applied.
*/
if( scidx == idx )
{
// update the kern text entry box in the lower part of
// the window.
MVRefreshValues( mv, i-1 );

//
// Shift the guide and kerning for this digraph, and move
// all the glyphs on the right over or back a bit so that things
// still all fit as expected.
//
mv->perchar[i-1].kernafter = newkernafter;
for ( int j=i; j<mv->glyphcnt; ++j ) {
mv->perchar[j].dx = mv->perchar[j-1].dx + mv->perchar[j-1].dwidth +
mv->perchar[j-1].kernafter;
}
}
}
}
}
}

mv->sf->changed = true; mv->sf->changed = true;
GDrawRequestExpose(mv->v,NULL,false); GDrawRequestExpose(mv->v,NULL,false);

return( true ); return( true );
} }


Expand Down

0 comments on commit 1230464

Please sign in to comment.