Permalink
Browse files

Improved handling of class based kerning in metrics view

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...
1 parent e8d69ed commit 12304649b2c441657f589e522cfaf24b3a0f4d17 @monkeyiq monkeyiq committed Feb 11, 2013
Showing with 123 additions and 2 deletions.
  1. +21 −0 fontforge/lookups.c
  2. +26 −0 fontforge/lookups.h
  3. +76 −2 fontforge/metricsview.c
View
@@ -4406,6 +4406,27 @@ return( true );
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 infirst=0, insecond=0, scpos1, kwpos1, scpos2, kwpos2;
int i;
View
@@ -1,3 +1,29 @@
extern char *lookup_type_names[2][10];
extern void SortInsertLookup(SplineFont *sf, OTLookup *newotl);
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 );
View
@@ -1118,6 +1118,7 @@ return( gwwv_ask(_("Use Kerning Class?"),(const char **) yesno,0,1,
second_is_0 ? _("{Everything Else}") : lsc->name)==0 );
}
+
static int MV_ChangeKerning(MetricsView *mv, int which, int offset, int is_diff) {
SplineChar *sc = mv->glyphs[which].sc;
SplineChar *psc = mv->glyphs[which-1].sc;
@@ -1213,8 +1214,10 @@ return( false );
MMKern(sc->parent,psc,sc,is_diff?offset:offset-kp->off,sub,kp);
}
}
- mv->perchar[which-1].kernafter = iscale * (offset*mv->pixelsize)/
- (mv->sf->ascent+mv->sf->descent);
+ int16 newkernafter = iscale * (offset*mv->pixelsize)/
+ (mv->sf->ascent+mv->sf->descent);
+ mv->perchar[which-1].kernafter = newkernafter;
+
if ( mv->vertical ) {
for ( i=which; i<mv->glyphcnt; ++i ) {
mv->perchar[i].dy = mv->perchar[i-1].dy+mv->perchar[i-1].dheight +
@@ -1226,8 +1229,79 @@ return( false );
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;
GDrawRequestExpose(mv->v,NULL,false);
+
return( true );
}

0 comments on commit 1230464

Please sign in to comment.