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