1 /* Copyright (C) 2009-2012 by George Williams */
2 /*
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions are met:
5 
6  * Redistributions of source code must retain the above copyright notice, this
7  * list of conditions and the following disclaimer.
8 
9  * Redistributions in binary form must reproduce the above copyright notice,
10  * this list of conditions and the following disclaimer in the documentation
11  * and/or other materials provided with the distribution.
12 
13  * The name of the author may not be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15 
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <fontforge-config.h>
29 
30 #include "autowidth2.h"
31 
32 #include "cvundoes.h"
33 #include "edgelist2.h"
34 #include "fontforgevw.h"
35 #include "fvfonts.h"
36 #include "splineoverlap.h"
37 #include "splineutil.h"
38 #include "tottfgpos.h"
39 #include "ustring.h"
40 #include "utype.h"
41 
42 #include <math.h>
43 
44 #define DENOM_FACTOR_OF_EMSIZE	50.0
45 
aw2_bbox_separation(AW_Glyph * g1,AW_Glyph * g2,AW_Data * all)46 static int aw2_bbox_separation(AW_Glyph *g1, AW_Glyph *g2, AW_Data *all) {
47     int j;
48     int imin_y, imax_y;
49     real tot, cnt;
50     real denom;
51     /* the goal is to give a weighted average that expresses the visual */
52     /*  separation between two glyphs when they are placed so their bounding */
53     /*  boxes are adjacent. The separation between two rectangles would be 0 */
54     /*  While the separation between "T" and "o" would be fairly large */
55     /* The trick is to guess a good weighting function. My guess is that */
56     /*  things that look close are more important than those which look far */
57     /*  So "T" and "O" should be dominated by the crossbar of the "T"... */
58 #if !defined(_NO_PYTHON)
59 
60     if ( PyFF_GlyphSeparationHook!=NULL )
61 return( PyFF_GlyphSeparation(g1,g2,all) );
62 #endif
63 
64     imin_y = g2->imin_y > g1->imin_y ? g2->imin_y : g1->imin_y;
65     imax_y = g2->imax_y < g1->imax_y ? g2->imax_y : g1->imax_y;
66     if ( imax_y < imin_y )		/* no overlap. ie grave and "a" */
67 return( 0 );
68     denom = all->denom;
69     tot = cnt = 0;
70     for ( j=imin_y ; j<imax_y; ++j ) {
71 	if ( g2->left[j-g2->imin_y] < 32767 && g1->right[j-g1->imin_y] > -32767 ) {
72 	    /* beware of gaps such as those in "i" or "aaccute" */
73 	    real sep = g2->left[j-g2->imin_y] - g1->right[j-g1->imin_y];
74 	    real weight = 1.0/(sep + denom);
75 	    weight *= weight;
76 
77 	    tot += weight*sep;
78 	    cnt += weight;
79 	}
80     }
81     if ( cnt!=0 )
82 	tot /= cnt;
83 return( rint( tot ) );
84 }
85 
aw2_figure_lsb(int right_index,AW_Data * all)86 static void aw2_figure_lsb(int right_index, AW_Data *all) {
87     int i;
88     AW_Glyph *me, *other;
89     int lsb, tot;
90     int *vpt = all->visual_separation + right_index;
91 
92     lsb=0;
93     me = &all->glyphs[right_index];
94     for ( i=0; i<all->gcnt; ++i ) {
95 	other = &all->glyphs[i];
96 	tot = all->desired_separation - vpt[i*all->gcnt] - other->rsb;
97 	if ( tot < all->min_sidebearing )
98 	    tot = all->min_sidebearing;
99 	else if ( tot > all->max_sidebearing )
100 	    tot = all->max_sidebearing;
101 	lsb += tot;
102     }
103     if ( i!=0 )
104 	lsb = (lsb + i/2)/i;
105     lsb = rint((3 * lsb + me->lsb)/4.0);
106     me->nlsb = lsb;
107 }
108 
aw2_figure_rsb(int left_index,AW_Data * all)109 static void aw2_figure_rsb(int left_index, AW_Data *all) {
110     int i;
111     AW_Glyph *me, *other;
112     int rsb, tot;
113     int *vpt = all->visual_separation + left_index*all->gcnt;
114 
115     rsb=0;
116     me = &all->glyphs[left_index];
117     for ( i=0; i<all->gcnt; ++i ) {
118 	other = &all->glyphs[i];
119 	tot = all->desired_separation - vpt[i] - other->lsb;
120 	if ( tot < all->min_sidebearing )
121 	    tot = all->min_sidebearing;
122 	else if ( tot > all->max_sidebearing )
123 	    tot = all->max_sidebearing;
124 	rsb += tot;
125     }
126     if ( i!=0 )
127 	rsb = (rsb + i/2)/i;
128     rsb = rint((3 * rsb + me->rsb)/4.0);
129     me->nrsb = rsb;
130 }
131 
aw2_figure_all_sidebearing(AW_Data * all)132 static void aw2_figure_all_sidebearing(AW_Data *all) {
133     int i,j;
134     AW_Glyph *me, *other;
135     real transform[6], half;
136     int width, changed;
137     uint8 *rsel = calloc(all->fv->map->enccount,sizeof(uint8));
138     real denom = (all->sf->ascent + all->sf->descent)/DENOM_FACTOR_OF_EMSIZE;
139     int ldiff, rdiff;
140 
141     all->denom = denom;
142     all->visual_separation = malloc(all->gcnt*all->gcnt*sizeof(int));
143     for ( i=0; i<all->gcnt; ++i ) {
144 	int *vpt = all->visual_separation + i*all->gcnt;
145 	me = &all->glyphs[i];
146 	for ( j=0; j<all->gcnt; ++j ) {
147 	    other = &all->glyphs[j];
148 	    vpt[j] = aw2_bbox_separation(me,other,all);
149 	}
150     }
151 
152     half = all->desired_separation/2;
153     for ( i=0; i<all->gcnt; ++i ) {
154 	me = &all->glyphs[i];
155 	me->lsb = me->rsb = half;
156     }
157 
158     for ( j=0; j<all->loop_cnt; ++j ) {
159 	for ( i=0; i<all->gcnt; ++i )
160 	    aw2_figure_lsb(i,all);
161 	for ( i=0; i<all->gcnt; ++i )
162 	    aw2_figure_rsb(i,all);
163 	for ( i=0; i<all->gcnt; ++i ) {
164 	    AW_Glyph *me = &all->glyphs[i];
165 	    me->rsb = me->nrsb;
166 	    me->lsb = me->nlsb;
167 	}
168     }
169     free(all->visual_separation); all->visual_separation = NULL;
170 
171     if ( all->normalize ) {
172 	/* This is the dummy flat edge we added. We want the separation between */
173 	/*  two adjacent flat edges to be desired_separation */
174 	me = &all->glyphs[all->gcnt-1];
175 	if ( me->lsb+me->rsb != all->desired_separation && me->sc==NULL ) {
176 	    if ( me->lsb+me->rsb!=0 ) {
177 		ldiff = (all->desired_separation-(me->lsb+me->rsb)) * me->lsb/(me->lsb+me->rsb);
178 	    } else {
179 		ldiff = all->desired_separation/2;
180 	    }
181 	    rdiff = (all->desired_separation-(me->lsb+me->rsb)) - ldiff;
182 	    for ( i=0; (me = &all->glyphs[i])->sc!=NULL; ++i ) {
183 		me->lsb += ldiff;
184 		me->rsb += rdiff;
185 	    }
186 	}
187     }
188 
189     transform[0] = transform[3] = 1.0;
190     transform[1] = transform[2] = transform[5] = 0;
191     for ( i=0; (me = &all->glyphs[i])->sc!=NULL; ++i ) {
192 	changed = 0;
193 	if ( me->lsb != me->bb.minx ) {
194 	    transform[4] = me->lsb-me->bb.minx;
195 	    FVTrans(all->fv,me->sc,transform,rsel,false);
196 	    changed = true;
197 	}
198 	width = me->lsb + me->rsb + rint(me->bb.maxx - me->bb.minx);
199 	if ( me->sc->width != width ) {
200 	    SCPreserveWidth(me->sc);
201 	    SCSynchronizeWidth(me->sc,width,me->sc->width,all->fv);
202 	    changed = true;
203 	}
204 	if ( changed )
205 	    SCCharChangedUpdate(me->sc,ly_none);
206     }
207     free(rsel);
208 }
209 
ak2_figure_kern(AW_Glyph * g1,AW_Glyph * g2,AW_Data * all)210 static int ak2_figure_kern(AW_Glyph *g1, AW_Glyph *g2, AW_Data *all) {
211     int sep = aw2_bbox_separation(g1,g2,all);
212     sep += g2->bb.minx + g1->sc->width - g1->bb.maxx;
213 return( all->desired_separation - sep );
214 }
215 
ak2_figure_touch(AW_Glyph * g1,AW_Glyph * g2,AW_Data * all)216 static int ak2_figure_touch(AW_Glyph *g1, AW_Glyph *g2, AW_Data *all) {
217     int j;
218     int imin_y, imax_y;
219     real smallest, tot;
220 
221     imin_y = g2->imin_y > g1->imin_y ? g2->imin_y : g1->imin_y;
222     imax_y = g2->imax_y < g1->imax_y ? g2->imax_y : g1->imax_y;
223     if ( imax_y < imin_y )		/* no overlap. ie grave and "a" */
224 return( - (g2->bb.minx + g1->sc->width - g1->bb.maxx) );
225     smallest = 0x7fff;
226     for ( j=imin_y ; j<imax_y; ++j ) {
227 	tot = g2->left[j-g2->imin_y] - g1->right[j-g1->imin_y];
228 	if ( tot<smallest )
229 	    smallest = tot;
230     }
231     if ( smallest == 0x7fff )	/* Overlaps only in gaps, "i" and something between the base and the dot */
232 return( - (g2->bb.minx + g1->sc->width - g1->bb.maxx) );
233 
234     smallest += g2->bb.minx + g1->sc->width - g1->bb.maxx;
235 return( all->desired_separation - smallest );
236 }
237 
ak2_figure_kernclass(int * class1,int * class2,AW_Data * all)238 static int ak2_figure_kernclass(int *class1, int *class2, AW_Data *all) {
239     int h,i;
240     real subtot, tot, cnt2;
241 
242     tot = cnt2 = 0;
243     for ( h=0; class1[h]!=-1; ++h ) {
244 	AW_Glyph *g1 = &all->glyphs[class1[h]];
245 	for ( i = 0; class2[i]!=-1; ++i ) {
246 	    AW_Glyph *g2 = &all->glyphs[class2[i]];
247 	    subtot = aw2_bbox_separation(g1,g2,all);
248 	    tot += g2->bb.minx + g1->sc->width - g1->bb.maxx + subtot;
249 	    ++cnt2;
250 	}
251     }
252     if ( cnt2==0 )
253 return( 0 );
254 
255     if ( cnt2!=0 )
256 	tot /= cnt2;
257 return( all->desired_separation - tot );
258 }
259 
ak2_figure_touchclass(int * class1,int * class2,AW_Data * all)260 static int ak2_figure_touchclass(int *class1, int *class2, AW_Data *all) {
261     int h,i,j;
262     int imin_y, imax_y;
263     real smallest, smaller, tot;
264 
265     smallest = 0x7fff;
266     for ( h=0; class1[h]!=-1; ++h ) {
267 	AW_Glyph *g1 = &all->glyphs[class1[h]];
268 	for ( i = 0; class2[i]!=-1; ++i ) {
269 	    AW_Glyph *g2 = &all->glyphs[class2[i]];
270 	    imin_y = g2->imin_y > g1->imin_y ? g2->imin_y : g1->imin_y;
271 	    imax_y = g2->imax_y < g1->imax_y ? g2->imax_y : g1->imax_y;
272 	    if ( imax_y < imin_y ) {		/* no overlap. ie grave and "a" */
273 		if ( smallest < - (g2->bb.minx + g1->sc->width - g1->bb.maxx) )
274 		    smallest = - (g2->bb.minx + g1->sc->width - g1->bb.maxx);
275 	continue;
276 	    }
277 	    smaller = 0x7fff;
278 	    for ( j=imin_y ; j<imax_y; ++j ) {
279 		tot = g2->left[j-g2->imin_y] - g1->right[j-g1->imin_y];
280 		if ( tot<smaller )
281 		    smaller = tot;
282 	    }
283 	    if ( smaller == 0x7fff ) {
284 		if ( smallest < - (g2->bb.minx + g1->sc->width - g1->bb.maxx) )
285 		    smallest = - (g2->bb.minx + g1->sc->width - g1->bb.maxx);
286 	continue;	/* Overlaps only in gaps */
287 	    }
288 	    smaller += g2->bb.minx + g1->sc->width - g1->bb.maxx;
289 	    if ( smaller<smallest )
290 		smallest = smaller;
291 	}
292     }
293     if ( smallest==0x7fff )
294 return( 0 );
295 
296 return( all->desired_separation - smallest );
297 }
298 
MonotonicFindY(Monotonic * m,double test,double old_t)299 static double MonotonicFindY(Monotonic *m,double test,double old_t) {
300     double tstart, tend, t;
301 
302     tstart = m->tstart; tend = m->tend;
303     if ( old_t!=-1 ) {
304 	if ( m->yup )
305 	    tstart = old_t;
306 	else
307 	    tend = old_t;
308     }
309     t = IterateSplineSolve(&m->s->splines[1],tstart,tend,test);
310 return( t );
311 }
312 
aw2_findedges(AW_Glyph * me,AW_Data * all)313 static void aw2_findedges(AW_Glyph *me, AW_Data *all) {
314     Monotonic *ms, *m;
315     real ytop, ybottom;
316     real x, xmin, xmax;
317     int i;
318     double t;
319     Spline1D *msp;
320     SplineSet *base;
321 
322     me->imin_y = floor(me->bb.miny/all->sub_height);
323     me->imax_y = ceil (me->bb.maxy/all->sub_height);
324     me->left = malloc((me->imax_y-me->imin_y+1)*sizeof(short));
325     me->right = malloc((me->imax_y-me->imin_y+1)*sizeof(short));
326 
327     base = LayerAllSplines(&me->sc->layers[all->layer]);
328     ms = SSsToMContours(base,over_remove);	/* over_remove is an arcane way of saying: Look at all contours, not just selected ones */
329     LayerUnAllSplines(&me->sc->layers[all->layer]);
330 
331     ytop = me->imin_y*all->sub_height;
332     for ( m=ms; m!=NULL; m=m->linked ) {
333 	m->t = -1;
334 	if ( m->b.miny<=ytop )		/* can't be less than, but... */
335 	    m->t = MonotonicFindY(m,ytop,-1);
336     }
337     for ( i=me->imin_y; i<=me->imax_y; ++i ) {
338 	ybottom = ytop; ytop += all->sub_height;
339 	xmin = 1e10; xmax = -1e10;
340 	for ( m=ms; m!=NULL; m=m->linked ) {
341 	    if ( m->b.maxy<ybottom || m->b.miny>ytop || m->b.maxy==m->b.miny )
342 	continue;
343 	    if ( (t = m->t)==-1 )
344 		t = MonotonicFindY(m,m->b.miny,-1);
345 	    msp = &m->s->splines[0];
346 	    if ( t!=-1 ) {
347 		x = ((msp->a*t + msp->b)*t+msp->c)*t+msp->d;
348 		if ( x>xmax ) xmax = x;
349 		if ( x<xmin ) xmin = x;
350 	    }
351 	    if ( ytop<m->b.maxy )
352 		t = m->t = MonotonicFindY(m,ytop,t);
353 	    else {
354 		m->t = -1;
355 		t = MonotonicFindY(m,m->b.maxy,t);
356 	    }
357 	    if ( t!=-1 ) {
358 		x = ((msp->a*t + msp->b)*t+msp->c)*t+msp->d;
359 		if ( x>xmax ) xmax = x;
360 		if ( x<xmin ) xmin = x;
361 	    }
362 	}
363 	if ( xmin>1e9 ) {
364 	    /* Glyph might have a gap (as "i" or ":" do) */
365 	    me->left[i-me->imin_y] = 32767 /* floor((me->bb.maxx - me->bb.minx)/2)*/;
366 	    me->right[i-me->imin_y] = -32767 /* floor(-(me->bb.maxx - me->bb.minx)/2)*/;
367 	} else {
368 	    me->left[i-me->imin_y] = floor(xmin - me->bb.minx);
369 	    me->right[i-me->imin_y] = floor(xmax - me->bb.maxx);	/* This is always non-positive, so floor will give the bigger absolute value */
370 	}
371     }
372     FreeMonotonics(ms);
373 }
374 
aw2_dummyedges(AW_Glyph * flat,AW_Data * all)375 static void aw2_dummyedges(AW_Glyph *flat,AW_Data *all) {
376     int i;
377     int imin_y = 32000, imax_y = -32000;
378 
379     if ( all!=NULL ) {
380 	for ( i=0; i<all->gcnt; ++i ) {
381 	    AW_Glyph *test = &all->glyphs[i];
382 	    if ( test->imin_y < imin_y ) imin_y = test->imin_y;
383 	    if ( test->imax_y > imax_y ) imax_y = test->imax_y;
384 	}
385 	if ( imin_y == 32000 ) {
386 	    imin_y = floor(-all->sf->descent/all->sub_height);
387 	    imax_y = ceil ( all->sf->ascent /all->sub_height);
388 	}
389 	flat->imin_y = imin_y; flat->imax_y = imax_y;
390     }
391     flat->left = calloc((flat->imax_y-flat->imin_y+1),sizeof(short));
392     flat->right = calloc((flat->imax_y-flat->imin_y+1),sizeof(short));
393 }
394 
AWGlyphFree(AW_Glyph * me)395 static void AWGlyphFree( AW_Glyph *me) {
396     free(me->left);
397     free(me->right);
398 #if !defined(_NO_PYTHON)
399     FFPy_AWGlyphFree(me);
400 #endif
401 }
402 
aw2_handlescript(AW_Data * all)403 static void aw2_handlescript(AW_Data *all) {
404     int i;
405     AW_Glyph *me;
406 
407     for ( i=0; (me = &all->glyphs[i])->sc!=NULL; ++i )
408 	aw2_findedges(me,all);
409     aw2_dummyedges(me,all); ++all->gcnt;
410     aw2_figure_all_sidebearing(all);
411     for ( i=0; i<all->gcnt; ++i )
412 	AWGlyphFree( &all->glyphs[i] );
413 }
414 
GlyphClassesFromNames(SplineFont * sf,char ** classnames,int class_cnt)415 SplineChar ***GlyphClassesFromNames(SplineFont *sf,char **classnames,
416 	int class_cnt ) {
417     SplineChar ***classes = calloc(class_cnt,sizeof(SplineChar **));
418     int i, pass, clen;
419     char *end, ch, *pt, *cn;
420     SplineChar *sc;
421 
422     for ( i=0; i<class_cnt; ++i ) {
423 	cn = copy(classnames[i]==NULL ? "" : classnames[i]);
424 	for ( pass=0; pass<2; ++pass ) {
425 	    clen = 0;
426 	    for ( pt = cn; *pt; pt = end+1 ) {
427 		while ( *pt==' ' ) ++pt;
428 		if ( *pt=='\0' )
429 	    break;
430 		end = strchr(pt,' ');
431 		if ( end==NULL )
432 		    end = pt+strlen(pt);
433 		ch = *end;
434 		if ( pass ) {
435 		    *end = '\0';
436 		    sc = SFGetChar(sf,-1,pt);
437 		    if ( sc!=NULL ) {
438 			classes[i][clen++] = sc;
439 		    }
440 		    *end = ch;
441 		} else
442 		    ++clen;
443 		if ( ch=='\0' )
444 	    break;
445 	    }
446 	    if ( pass )
447 		classes[i][clen] = NULL;
448 	    else
449 		classes[i] = malloc((clen+1)*sizeof(SplineChar *));
450 	}
451 	if ( cn != NULL ) { free( cn ) ; cn = NULL ; }
452     }
453 return( classes );
454 }
455 
AutoWidth2(FontViewBase * fv,int separation,int min_side,int max_side,int chunk_height,int loop_cnt)456 void AutoWidth2(FontViewBase *fv,int separation,int min_side,int max_side,
457 	int chunk_height, int loop_cnt) {
458     struct scriptlist {
459 	uint32 script;
460 	AW_Glyph *glyphs;
461 	int gcnt;
462     } *scripts;
463     int scnt, smax;
464     int enc, gid, s, i;
465     SplineFont *sf = fv->sf;
466     SplineChar *sc;
467     AW_Data all;
468 
469     if ( chunk_height <= 0 )
470 	chunk_height = (sf->ascent + sf->descent)/100;
471     if ( loop_cnt <= 0 )
472 	loop_cnt = 4;
473 
474     scnt = 0; smax = 10;
475     scripts = malloc(smax*sizeof(struct scriptlist));
476 
477     for ( gid=0; gid<sf->glyphcnt; ++gid ) {
478 	if ( (sc = sf->glyphs[gid])!=NULL )
479 	    sc->ticked = false;
480     }
481     for ( enc=0; enc<fv->map->enccount; ++enc ) {
482 	if ( fv->selected[enc] && (gid=fv->map->map[enc])!=-1 &&
483 		(sc = sf->glyphs[gid])!=NULL && ! sc->ticked &&
484 		HasUseMyMetrics(sc,fv->active_layer)==NULL ) {
485 		/* If Use My Metrics is set, then we can't change the width (which we grab from a refchar) */
486 	    uint32 script;
487 	    script = SCScriptFromUnicode(sc);
488 	    for ( s=0; s<scnt; ++s ) {
489 		if ( scripts[s].script == script )
490 	    break;
491 	    }
492 	    if ( s==scnt ) {
493 		if ( scnt>=smax )
494 		    scripts = realloc(scripts,(smax+=10)*sizeof(struct scriptlist));
495 		memset(&scripts[scnt],0,sizeof(struct scriptlist));
496 		scripts[scnt].script = script;
497 		scripts[scnt].glyphs = calloc(sf->glyphcnt+1,sizeof(AW_Glyph));
498 		++scnt;
499 	    }
500 	    i = scripts[s].gcnt;
501 	    scripts[s].glyphs[i].sc = sc;
502 	    SplineCharLayerFindBounds(sc,fv->active_layer,&scripts[s].glyphs[i].bb);
503 	    if ( scripts[s].glyphs[i].bb.minx<-16000 || scripts[s].glyphs[i].bb.maxx>16000 ||
504 		    scripts[s].glyphs[i].bb.miny<-16000 || scripts[s].glyphs[i].bb.maxy>16000 )
505 		ff_post_notice(_("Glyph too big"),_("%s has a bounding box which is too big for this algorithm to work. Ignored."),sc->name);
506 	    else
507 		++scripts[s].gcnt;
508 	}
509     }
510 
511     memset(&all,0,sizeof(all));
512     all.sf = sf;
513     all.fv = fv;
514     all.layer = fv->active_layer;
515     all.normalize = true;
516 
517     all.sub_height = chunk_height;
518     all.loop_cnt = loop_cnt;
519     all.desired_separation = separation;
520     all.min_sidebearing = min_side;
521     all.max_sidebearing = max_side;
522 
523     for ( s=0; s<scnt; ++s ) {
524 	memset(&scripts[s].glyphs[scripts[s].gcnt], 0, sizeof(AW_Glyph));
525 	all.glyphs = scripts[s].glyphs;
526 	all.gcnt   = scripts[s].gcnt;
527 	aw2_handlescript(&all);
528 	free(all.glyphs);
529     }
530     free(scripts);
531 #if !defined(_NO_PYTHON)
532     FFPy_AWDataFree(&all);
533 #endif		/* PYTHON */
534 }
535 
GuessOpticalOffset(SplineChar * sc,int layer,real * _loff,real * _roff,int chunk_height)536 void GuessOpticalOffset(SplineChar *sc,int layer,real *_loff, real *_roff,
537 	int chunk_height ) {
538     /* Given a glyph make a guess as to where the eye thinks the left/right */
539     /*  edges of the glyph are to be found */
540     /* On an "I" with no serifs, the edges are the right and left side bearings*/
541     /* But on an "O" the edge appears to be a bit closer to the center than the side bearing */
542     /* The left edge will always appear to be a non-negative (x) distance from the lsb */
543     /* the right edge will always appear to be a non-positve distance from the rsb */
544     SplineFont *sf = sc->parent;
545     AW_Data all;
546     AW_Glyph glyph, edge;
547     real loff, roff;
548     RefChar *r = HasUseMyMetrics(sc,layer);
549 
550     if ( r!=NULL )
551 	    sc = r->sc;
552 
553     if ( chunk_height <= 0 )
554 	chunk_height = (sf->ascent + sf->descent)/200;
555 
556     memset(&all,0,sizeof(all));
557     memset(&glyph,0,sizeof(glyph));
558     memset(&edge,0,sizeof(edge));
559     all.layer = layer;
560     all.sub_height = chunk_height;
561     all.sf = sf;
562     all.denom = (sf->ascent + sf->descent)/DENOM_FACTOR_OF_EMSIZE;
563 
564     glyph.sc = sc;
565     SplineCharLayerFindBounds(sc,layer,&glyph.bb);
566     if ( glyph.bb.minx<-16000 || glyph.bb.maxx>16000 ||
567 	    glyph.bb.miny<-16000 || glyph.bb.maxy>16000 ) {
568 	ff_post_notice(_("Glyph too big"),_("%s has a bounding box which is too big for this algorithm to work. Ignored."),sc->name);
569 	*_loff = glyph.bb.minx;
570 	*_roff = sc->width - glyph.bb.maxx;
571     } else {
572 	aw2_findedges(&glyph, &all);
573 	edge.imin_y = glyph.imin_y; edge.imax_y = glyph.imax_y;
574 	aw2_dummyedges(&edge,NULL);
575 	loff = aw2_bbox_separation(&edge,&glyph,&all);
576 	roff = aw2_bbox_separation(&glyph,&edge,&all);
577 	*_loff = glyph.bb.minx + loff;
578 	*_roff = sc->width - (glyph.bb.maxx - roff);
579 	AWGlyphFree( &glyph );
580 	AWGlyphFree( &edge );
581     }
582 #if !defined(_NO_PYTHON)
583     FFPy_AWDataFree(&all);
584 #endif		/* PYTHON */
585 }
586 
AutoKern2(SplineFont * sf,int layer,SplineChar ** left,SplineChar ** right,struct lookup_subtable * into,int separation,int min_kern,int from_closest_approach,int only_closer,int chunk_height,void (* addkp)(void * data,SplineChar * left,SplineChar * r,int off),void * data)587 void AutoKern2(SplineFont *sf, int layer,SplineChar **left,SplineChar **right,
588 	struct lookup_subtable *into,
589 	int separation, int min_kern, int from_closest_approach, int only_closer,
590 	int chunk_height,
591 	void (*addkp)(void *data,SplineChar *left,SplineChar *r,int off),
592 	void *data) {
593     AW_Data all;
594     AW_Glyph *glyphs;
595     int i,cnt,k, kern;
596     SplineChar *sc;
597     KernPair *last, *kp, *next;
598     int is_l2r = !(into->lookup->lookup_flags & pst_r2l);
599     /* Normally, kerning is based on some sort of average distance between */
600     /*  two glyphs, but sometimes it is useful to kern so much that the glyphs*/
601     /*  just touch. If that is desired then set from_closest_approach. */
602 
603     if ( chunk_height <= 0 )
604 	chunk_height = (sf->ascent + sf->descent)/200;
605     if ( separation==0 && !from_closest_approach ) {
606 	if ( into->separation==0 && !into->kerning_by_touch ) {
607 	    into->separation = sf->width_separation;
608 	    if ( sf->width_separation==0 )
609 		into->separation = 15*(sf->ascent+sf->descent)/100;
610 	    separation = into->separation;
611 	} else {
612 	    separation = into->separation;
613 	    from_closest_approach = into->kerning_by_touch;
614 	    min_kern = into->minkern;
615 	    only_closer = into->onlyCloser;
616 	}
617     }
618 
619     memset(&all,0,sizeof(all));
620     all.layer = layer;
621     all.sub_height = chunk_height;
622     all.desired_separation = separation;
623     all.sf = sf;
624     all.denom = (sf->ascent + sf->descent)/DENOM_FACTOR_OF_EMSIZE;
625 
626     /* ticked means a left glyph, ticked2 a right (a glyph can be both) */
627     for ( i=0; i<sf->glyphcnt; ++i ) if ( (sc = sf->glyphs[i])!=NULL )
628 	sc->ticked = sc->ticked2 = false;
629     for ( i=0; (sc = left[i])!=NULL; ++i )
630 	sc->ticked = true;
631     for ( i=0; (sc = right[i])!=NULL; ++i )
632 	sc->ticked2 = true;
633     for ( cnt=i=0; i<sf->glyphcnt; ++i ) if ( (sc = sf->glyphs[i])!=NULL )
634 	if ( sc->ticked || sc->ticked2 )
635 	    ++cnt;
636 
637     glyphs = calloc(cnt+1,sizeof(AW_Glyph));
638     for ( cnt=i=0; i<sf->glyphcnt; ++i ) if ( (sc = sf->glyphs[i])!=NULL ) {
639 	if ( sc->ticked || sc->ticked2 ) {
640 	    SplineCharLayerFindBounds(sc,layer,&glyphs[cnt].bb);
641 	    if ( glyphs[cnt].bb.minx<-16000 || glyphs[cnt].bb.maxx>16000 ||
642 		    glyphs[cnt].bb.miny<-16000 || glyphs[cnt].bb.maxy>16000 )
643 		ff_post_notice(_("Glyph too big"),_("%s has a bounding box which is too big for this algorithm to work. Ignored."),sc->name);
644 	    else {
645 		glyphs[cnt].sc = sc;
646 		aw2_findedges(&glyphs[cnt++], &all);
647 	    }
648 	}
649     }
650 
651     /* remove all current kern pairs in this subtable which include the specified glyphs */
652     if ( addkp==NULL ) {
653 	for ( i=0; (sc = left[i])!=NULL; ++i ) {
654 	    for ( last=NULL, kp=sc->kerns; kp!=NULL; kp = next ) {
655 		next = kp->next;
656 		if ( kp->subtable==into && kp->sc->ticked2 ) {
657 		    if ( last==NULL )
658 			sc->kerns = next;
659 		    else
660 			last->next = next;
661 		    kp->next = NULL;
662 		    KernPairsFree(kp);
663 		} else
664 		    last = kp;
665 	    }
666 	}
667     }
668 
669     all.glyphs = glyphs;
670     all.gcnt = cnt;
671     for ( i=0; i<cnt; ++i ) {
672 	AW_Glyph *g1 = &glyphs[i];
673 	if ( !g1->sc->ticked )
674     continue;
675 	for ( k=0; k<cnt; ++k ) {
676 	    AW_Glyph *g2 = &glyphs[k];
677 	    if ( !g2->sc->ticked2 )
678 	continue;
679 	    if ( from_closest_approach )
680 		kern = rint( ak2_figure_touch(g1,g2,&all));
681 	    else {
682 		kern = rint( ak2_figure_kern(g1,g2,&all));
683 		if ( kern<min_kern && kern>-min_kern )
684 		    kern = 0;
685 	    }
686 	    if ( only_closer && kern>0 )
687 		kern=0;
688 	    if ( kern!=0 ) {
689 		if ( addkp==NULL ) {
690 		    kp = chunkalloc(sizeof(KernPair));
691 		    kp->subtable = into;
692 		    kp->off = kern;
693 		    if ( is_l2r ) {
694 			kp->sc = g2->sc;
695 			kp->next = g1->sc->kerns;
696 			g1->sc->kerns = kp;
697 		    } else {
698 			kp->sc = g1->sc;
699 			kp->next = g2->sc->kerns;
700 			g2->sc->kerns = kp;
701 		    }
702 		} else
703 		    (*addkp)(data,g1->sc,g2->sc,kern);
704 	    }
705 	}
706     }
707     for ( i=0; i<cnt; ++i )
708 	AWGlyphFree( &glyphs[i] );
709     free(glyphs);
710 #if !defined(_NO_PYTHON)
711     FFPy_AWDataFree(&all);
712 #endif		/* PYTHON */
713 }
714 
AutoKern2NewClass(SplineFont * sf,int layer,char ** leftnames,char ** rightnames,int lcnt,int rcnt,void (* kcAddOffset)(void * data,int left_index,int right_index,int offset),void * data,int separation,int min_kern,int from_closest_approach,int only_closer,int chunk_height)715 void AutoKern2NewClass(SplineFont *sf,int layer,char **leftnames, char **rightnames,
716 	int lcnt, int rcnt,
717 	void (*kcAddOffset)(void *data,int left_index, int right_index,int offset), void *data,
718 	int separation, int min_kern, int from_closest_approach, int only_closer,
719 	int chunk_height) {
720     AW_Data all;
721     AW_Glyph *glyphs;
722     int i,cnt,k, kern;
723     SplineChar ***left = GlyphClassesFromNames(sf,leftnames,lcnt);
724     SplineChar ***right = GlyphClassesFromNames(sf,rightnames,rcnt);
725     int **ileft = malloc(lcnt*sizeof(int*));
726     int **iright = malloc(rcnt*sizeof(int*));
727     SplineChar **class, *sc;
728 
729     if ( chunk_height <= 0 )
730 	chunk_height = (sf->ascent + sf->descent)/200;
731 
732     memset(&all,0,sizeof(all));
733     all.layer = layer;
734     all.sub_height = chunk_height;
735     all.desired_separation = separation;
736     all.sf = sf;
737     all.denom = (sf->ascent + sf->descent)/DENOM_FACTOR_OF_EMSIZE;
738 
739     /* ticked means a left glyph, ticked2 a right (a glyph can be both) */
740     for ( i=0; i<sf->glyphcnt; ++i ) if ( (sc = sf->glyphs[i])!=NULL ) {
741 	sc->ticked = sc->ticked2 = false;
742 	sc->ttf_glyph = -1;
743     }
744     for ( i=0; i<lcnt; ++i )
745 	for ( class = left[i], k=0; (sc = class[k])!=NULL; ++k )
746 	    sc->ticked = true;
747     for ( i=0; i<rcnt; ++i )
748 	for ( class = right[i], k=0; (sc = class[k])!=NULL; ++k )
749 	    sc->ticked2 = true;
750     for ( cnt=i=0; i<sf->glyphcnt; ++i ) if ( (sc = sf->glyphs[i])!=NULL )
751 	if ( sc->ticked || sc->ticked2 )
752 	    ++cnt;
753 
754     glyphs = calloc(cnt+1,sizeof(AW_Glyph));
755     for ( cnt=i=0; i<sf->glyphcnt; ++i ) if ( (sc = sf->glyphs[i])!=NULL ) {
756 	if ( sc->ticked || sc->ticked2 ) {
757 	    SplineCharLayerFindBounds(sc,layer,&glyphs[cnt].bb);
758 	    if ( glyphs[cnt].bb.minx<-16000 || glyphs[cnt].bb.maxx>16000 ||
759 		    glyphs[cnt].bb.miny<-16000 || glyphs[cnt].bb.maxy>16000 ) {
760 		ff_post_notice(_("Glyph too big"),_("%s has a bounding box which is too big for this algorithm to work. Ignored."),sc->name);
761 		sc->ticked = sc->ticked2 = false;
762 	    } else {
763 		glyphs[cnt].sc = sc;
764 		sc->ttf_glyph = cnt;
765 		aw2_findedges(&glyphs[cnt++], &all);
766 	    }
767 	}
768     }
769 
770     for ( i=0; i<lcnt; ++i ) {
771 	for ( class = left[i], k=0; (sc = class[k])!=NULL; ++k );
772 	ileft[i] = malloc((k+1)*sizeof(int));
773 	for ( class = left[i], k=0; (sc = class[k])!=NULL; ++k )
774 	    ileft[i][k] = sc->ttf_glyph;
775 	ileft[i][k] = -1;
776     }
777     for ( i=0; i<rcnt; ++i ) {
778 	for ( class = right[i], k=0; (sc = class[k])!=NULL; ++k );
779 	iright[i] = malloc((k+1)*sizeof(int));
780 	for ( class = right[i], k=0; (sc = class[k])!=NULL; ++k )
781 	    iright[i][k] = sc->ttf_glyph;
782 	iright[i][k] = -1;
783     }
784 
785     all.glyphs = glyphs;
786     all.gcnt = cnt;
787     for ( i=0; i<lcnt; ++i ) {
788 	for ( k=0; k<rcnt; ++k ) {
789 	    if ( from_closest_approach )
790 		kern = rint( ak2_figure_touchclass(ileft[i],iright[k],&all));
791 	    else {
792 		kern = rint( ak2_figure_kernclass(ileft[i],iright[k],&all));
793 		if ( kern<min_kern && kern>-min_kern )
794 		    kern = 0;
795 	    }
796 	    if ( kern>0 && only_closer )
797 		kern = 0;
798 	    (*kcAddOffset)(data,i, k, kern);
799 	}
800     }
801 
802     for ( i=0; i<lcnt; ++i ) {
803 	free(ileft[i]);
804 	free(left[i]);
805     }
806     free(ileft); free(left);
807     for ( i=0; i<rcnt; ++i ) {
808 	free(iright[i]);
809 	free(right[i]);
810     }
811     free(iright); free(right);
812     free(glyphs);
813 }
814 
kc2AddOffset(void * data,int left_index,int right_index,int offset)815 static void kc2AddOffset(void *data,int left_index, int right_index,int offset) {
816     KernClass *kc = data;
817 
818     if ( kc->subtable->lookup->lookup_flags & pst_r2l ) {
819 	kc->offsets[right_index*kc->first_cnt+left_index] = offset;
820     } else
821 	kc->offsets[left_index*kc->second_cnt+right_index] = offset;
822 }
823 
AutoKern2BuildClasses(SplineFont * sf,int layer,SplineChar ** leftglyphs,SplineChar ** rightglyphs,struct lookup_subtable * sub,int separation,int min_kern,int touching,int only_closer,int autokern,real good_enough)824 void AutoKern2BuildClasses(SplineFont *sf,int layer,
825 	SplineChar **leftglyphs,SplineChar **rightglyphs,
826 	struct lookup_subtable *sub,
827 	int separation, int min_kern, int touching, int only_closer,
828 	int autokern,
829 	real good_enough) {
830     AW_Data all;
831     AW_Glyph *glyphs, *me, *other;
832     int chunk_height;
833     int i,j,k,cnt,lcnt,rcnt, lclasscnt,rclasscnt;
834     int len;
835     int *lused, *rused;
836     char **lclassnames, **rclassnames, *str;
837     int *visual_separation;
838     KernClass *kc = sub->kc;
839     SplineChar *sc;
840 
841     if ( kc==NULL )
842 return;
843     // free(kc->firsts); free(kc->seconds); // I think that this forgets to free the contained strings.
844     if (kc->firsts != NULL) {
845       int tmppos;
846       for (tmppos = 0; tmppos < kc->first_cnt; tmppos++)
847         if (kc->firsts[tmppos] != NULL) { free(kc->firsts[tmppos]); kc->firsts[tmppos] = NULL; }
848       free(kc->firsts); kc->firsts = NULL;
849     }
850     if (kc->seconds != NULL) {
851       int tmppos;
852       for (tmppos = 0; tmppos < kc->second_cnt; tmppos++)
853         if (kc->seconds[tmppos] != NULL) { free(kc->seconds[tmppos]); kc->seconds[tmppos] = NULL; }
854       free(kc->seconds); kc->seconds = NULL;
855     }
856     free(kc->offsets);
857     free(kc->adjusts);
858 
859     // Group kerning.
860     // Specifically, we drop the group kerning stuff if the classes are getting redefined.
861     if (kc->firsts_names != NULL) {
862       int tmppos;
863       for (tmppos = 0; tmppos < kc->first_cnt; tmppos++)
864         if (kc->firsts_names[tmppos] != NULL) { free(kc->firsts_names[tmppos]); kc->firsts_names[tmppos] = NULL; }
865       free(kc->firsts_names); kc->firsts_names = NULL;
866     }
867     if (kc->seconds_names != NULL) {
868       int tmppos;
869       for (tmppos = 0; tmppos < kc->second_cnt; tmppos++)
870         if (kc->seconds_names[tmppos] != NULL) { free(kc->seconds_names[tmppos]); kc->seconds_names[tmppos] = NULL; }
871       free(kc->seconds_names); kc->seconds_names = NULL;
872     }
873     if (kc->firsts_flags != NULL) { free(kc->firsts_flags); kc->firsts_flags = NULL; }
874     if (kc->seconds_flags != NULL) { free(kc->seconds_flags); kc->seconds_flags = NULL; }
875     if (kc->offsets_flags != NULL) { free(kc->offsets_flags); kc->offsets_flags = NULL; }
876 
877     if ( good_enough==-1 )
878 	good_enough = (sf->ascent+sf->descent)/100.0;
879 
880     if ( separation==0 && !touching ) {
881 	/* Use default values. Generate them if they don't exist */
882 	if ( sub->separation==0 && !sub->kerning_by_touch ) {
883 	    sub->separation = sf->width_separation;
884 	    if ( sf->width_separation==0 )
885 		sub->separation = 15*(sf->ascent+sf->descent)/100;
886 	    separation = sub->separation;
887 	    autokern = true;
888 	} else {
889 	    separation = sub->separation;
890 	    touching = sub->kerning_by_touch;
891 	    min_kern = sub->minkern;
892 	    only_closer = sub->onlyCloser;
893 	    autokern = !sub->dontautokern;
894 	}
895     }
896     sub->separation = separation;
897     sub->minkern = min_kern;
898     sub->kerning_by_touch = touching;
899     sub->onlyCloser = only_closer;
900     sub->dontautokern = !autokern;
901     chunk_height = (sf->ascent + sf->descent)/200;
902 
903     memset(&all,0,sizeof(all));
904     all.layer = layer;
905     all.sub_height = chunk_height;
906     all.desired_separation = separation;
907     all.sf = sf;
908     all.denom = (sf->ascent + sf->descent)/DENOM_FACTOR_OF_EMSIZE;
909 
910     /* ticked means a left glyph, ticked2 a right (a glyph can be both) */
911     for ( i=0; i<sf->glyphcnt; ++i ) if ( (sc = sf->glyphs[i])!=NULL ) {
912 	sc->ticked = sc->ticked2 = false;
913 	sc->ttf_glyph = -1;
914     }
915     for ( lcnt=0; (sc=leftglyphs[lcnt])!=NULL; ++lcnt )
916 	sc->ticked = true;
917     for ( rcnt=0; (sc=rightglyphs[rcnt])!=NULL; ++rcnt )
918 	sc->ticked2 = true;
919     for ( cnt=i=0; i<sf->glyphcnt; ++i ) if ( (sc = sf->glyphs[i])!=NULL )
920 	if ( sc->ticked || sc->ticked2 )
921 	    ++cnt;
922 
923     glyphs = calloc(cnt+1,sizeof(AW_Glyph));
924     for ( cnt=i=0; i<sf->glyphcnt; ++i ) if ( (sc = sf->glyphs[i])!=NULL ) {
925 	if ( sc->ticked || sc->ticked2 ) {
926 	    SplineCharLayerFindBounds(sc,layer,&glyphs[cnt].bb);
927 	    if ( glyphs[cnt].bb.minx<-16000 || glyphs[cnt].bb.maxx>16000 ||
928 		    glyphs[cnt].bb.miny<-16000 || glyphs[cnt].bb.maxy>16000 ) {
929 		ff_post_notice(_("Glyph too big"),_("%s has a bounding box which is too big for this algorithm to work. Ignored."),sc->name);
930 		sc->ticked = sc->ticked2 = false;
931 	    } else {
932 		glyphs[cnt].sc = sc;
933 		sc->ttf_glyph = cnt;
934 		aw2_findedges(&glyphs[cnt++], &all);
935 	    }
936 	}
937     }
938 
939     all.glyphs = glyphs;
940     all.gcnt = cnt;
941     visual_separation = malloc(lcnt*rcnt*sizeof(int));
942     for ( i=0; i<lcnt; ++i ) {
943 	int *vpt = visual_separation + i*rcnt;
944 	SplineChar *lsc = leftglyphs[i];
945 	if ( lsc->ticked ) {
946 	    me = &all.glyphs[lsc->ttf_glyph];
947 	    for ( j=0; j<rcnt; ++j ) {
948 		SplineChar *rsc = rightglyphs[j];
949 		if ( rsc->ticked2 ) {
950 		    other = &all.glyphs[rsc->ttf_glyph];
951 		    vpt[j] = aw2_bbox_separation(me,other,&all);
952 		} else
953 		    vpt[j] = 0;
954 	    }
955 	} else {
956 	    for ( j=0; j<rcnt; ++j )
957 		vpt[j] = 0;
958 	}
959     }
960     for ( i=0; i<cnt; ++i )
961 	AWGlyphFree( &glyphs[i] );
962 #if !defined(_NO_PYTHON)
963     FFPy_AWDataFree(&all);
964     free(glyphs); glyphs = all.glyphs = NULL;
965 #endif		/* PYTHON */
966     glyphs = all.glyphs = NULL;
967 
968     good_enough *= good_enough;
969 
970     lclassnames = malloc((lcnt+2) * sizeof(char *));
971     lclasscnt = 1;
972     lclassnames[0] = NULL;
973     lused = calloc(lcnt,sizeof(int));
974     for ( i=0; i<lcnt; ++i ) if ( leftglyphs[i]->ticked && !lused[i]) {
975 	lused[i] = lclasscnt;
976 	len = strlen(leftglyphs[i]->name)+1;
977 	for ( j=i+1; j<lcnt; ++j ) if ( leftglyphs[j]->ticked && !lused[j] ) {
978 	    long totdiff = 0, diff;
979 	    int *vpt1 = visual_separation + i*rcnt;
980 	    int *vpt2 = visual_separation + j*rcnt;
981 	    for ( k=0; k<rcnt; ++k ) {
982 		diff = vpt1[k] - vpt2[k];
983 		totdiff += diff*diff;
984 	    }
985 	    if ( totdiff/((double) rcnt) < good_enough ) {
986 		lused[j] = lclasscnt;
987 		len += strlen(leftglyphs[j]->name)+1;
988 	    }
989 	}
990 	lclassnames[lclasscnt] = str = malloc(len+1);
991 	for ( j=i; j<lcnt; ++j ) if ( lused[j]==lclasscnt ) {
992 	    strcpy(str,leftglyphs[j]->name);
993 	    str += strlen(str);
994 	    *str++ = ' ';
995 	}
996 	str[-1] = '\0';
997 	++lclasscnt;
998     }
999     lclassnames[lclasscnt] = NULL;
1000     kc = sub->kc;
1001     kc->firsts = realloc(lclassnames,(lclasscnt+1)*sizeof(char *));
1002     kc->first_cnt = lclasscnt;
1003     free(lused); lused = NULL;
1004 
1005     rclassnames = malloc((rcnt+2) * sizeof(char *));
1006     rclasscnt = 1;
1007     rclassnames[0] = NULL;
1008     rused = calloc(rcnt,sizeof(int));
1009     for ( i=0; i<rcnt; ++i ) if ( rightglyphs[i]->ticked2 && !rused[i]) {
1010 	rused[i] = rclasscnt;
1011 	len = strlen(rightglyphs[i]->name)+1;
1012 	for ( j=i+1; j<rcnt; ++j ) if ( rightglyphs[j]->ticked2 && !rused[j] ) {
1013 	    long totdiff = 0, diff;
1014 	    int *vpt1 = visual_separation + i;
1015 	    int *vpt2 = visual_separation + j;
1016 	    for ( k=0; k<lcnt; ++k ) {
1017 		diff = vpt1[k*rcnt] - vpt2[k*rcnt];
1018 		totdiff += diff*diff;
1019 	    }
1020 	    if ( totdiff/((double) lcnt) < good_enough ) {
1021 		rused[j] = rclasscnt;
1022 		len += strlen(rightglyphs[j]->name)+1;
1023 	    }
1024 	}
1025 	rclassnames[rclasscnt] = str = malloc(len+1);
1026 	for ( j=i; j<rcnt; ++j ) if ( rused[j]==rclasscnt ) {
1027 	    strcpy(str,rightglyphs[j]->name);
1028 	    str += strlen(str);
1029 	    *str++ = ' ';
1030 	}
1031 	str[-1] = '\0';
1032 	++rclasscnt;
1033     }
1034     rclassnames[rclasscnt] = NULL;
1035     kc->seconds = realloc(rclassnames,(rclasscnt+1)*sizeof(char *));
1036     kc->second_cnt = rclasscnt;
1037     free(rused);
1038     free(visual_separation);
1039 
1040     kc->offsets = calloc(lclasscnt*rclasscnt,sizeof(int16));;
1041     kc->adjusts = calloc(lclasscnt*rclasscnt,sizeof(DeviceTable));
1042 
1043     if ( autokern )
1044 	AutoKern2NewClass(sf,layer,kc->firsts, kc->seconds,
1045 		kc->first_cnt, kc->second_cnt,
1046 		kc2AddOffset, kc,
1047 		separation,min_kern,touching,only_closer,chunk_height);
1048 
1049     if ( sub->lookup->lookup_flags & pst_r2l ) {
1050 	char **temp = kc->seconds;
1051 	int tempsize = kc->second_cnt;
1052 	kc->seconds = kc->firsts;
1053 	kc->second_cnt = kc->first_cnt;
1054 	kc->firsts = temp;
1055 	kc->first_cnt = tempsize;
1056     }
1057 }
1058