w32tex
About: TeX Live provides a comprehensive TeX system including all the major TeX-related programs, macro packages, and fonts that are free software. Windows sources.
  Fossies Dox: w32tex-src.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

parsettfatt.c
Go to the documentation of this file.
1 /* Copyright (C) 2000-2008 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 #include "pfaedit.h"
28 #include <chardata.h>
29 #include <utype.h>
30 #include <ustring.h>
31 #include <math.h>
32 #include <locale.h>
33 #include <stdlib.h>
34 #include "ttf.h"
35 
36 static uint16 *getAppleClassTable(FILE *ttf, int classdef_offset, int cnt, int sub, int div, struct ttfinfo *info) {
37  uint16 *class = gcalloc(cnt,sizeof(uint16));
38  int first, i, n;
39  /* Apple stores its class tables as containing offsets. I find it hard to */
40  /* think that way and convert them to indeces (by subtracting off a base */
41  /* offset and dividing by the item's size) before doing anything else */
42 
43  fseek(ttf,classdef_offset,SEEK_SET);
44  first = getushort(ttf);
45  n = getushort(ttf);
46  if ( first+n-1>=cnt ) {
47  LogError( _("Bad Apple Kern Class\n") );
48  info->bad_gx = true;
49  }
50  for ( i=0; i<n && i+first<cnt; ++i )
51  class[first+i] = (getushort(ttf)-sub)/div;
52 return( class );
53 }
54 
55 static char **ClassToNames(struct ttfinfo *info,int class_cnt,uint16 *class,int glyph_cnt) {
56  char **ret = galloc(class_cnt*sizeof(char *));
57  int *lens = gcalloc(class_cnt,sizeof(int));
58  int i;
59 
60  ret[0] = NULL;
61  for ( i=0 ; i<glyph_cnt; ++i ) if ( class[i]!=0 && info->chars[i]!=NULL && class[i]<class_cnt )
62  lens[class[i]] += strlen(info->chars[i]->name)+1;
63  for ( i=1; i<class_cnt ; ++i )
64  ret[i] = galloc(lens[i]+1);
65  memset(lens,0,class_cnt*sizeof(int));
66  for ( i=0 ; i<glyph_cnt; ++i ) if ( class[i]!=0 && info->chars[i]!=NULL ) {
67  if ( class[i]<class_cnt ) {
68  strcpy(ret[class[i]]+lens[class[i]], info->chars[i]->name );
69  lens[class[i]] += strlen(info->chars[i]->name)+1;
70  ret[class[i]][lens[class[i]]-1] = ' ';
71  } else {
72  LogError( _("Class index out of range %d (must be <%d)\n"),class[i], class_cnt );
73  info->bad_ot = true;
74  }
75  }
76  for ( i=1; i<class_cnt ; ++i )
77  if ( lens[i]==0 )
78  ret[i][0] = '\0';
79  else
80  ret[i][lens[i]-1] = '\0';
81  free(lens);
82 return( ret );
83 }
84 
85 static char *CoverageMinusClasses(uint16 *coverageglyphs,uint16 *classed,
86  struct ttfinfo *info ) {
87  int i, j, len;
88  uint8 *glyphs = gcalloc(info->glyph_cnt,1);
89  char *ret;
90 
91  for ( i=0; coverageglyphs[i]!=0xffff; ++i )
92  glyphs[coverageglyphs[i]] = 1;
93  for ( i=0; i<info->glyph_cnt; ++i )
94  if ( classed[i]!=0 )
95  glyphs[i] = 0;
96  for ( i=0; i<info->glyph_cnt; ++i )
97  if ( glyphs[i]!=0 )
98  break;
99  /* coverage table matches glyphs in classes. No need for special treatment*/
100  if ( i==info->glyph_cnt ) {
101  free(glyphs);
102 return( NULL );
103  }
104  /* Otherwise we need to generate a class string of glyph names in the coverage */
105  /* table but not in any class. These become the glyphs in class 0 */
106  ret = NULL;
107  for ( j=0; j<2; ++j ) {
108  len = 0;
109  for ( i=0; i<info->glyph_cnt; ++i ) {
110  if ( glyphs[i]!=0 ) {
111  if ( j ) {
112  strcpy( ret+len, info->chars[i]->name );
113  strcat( ret+len, " ");
114  }
115  len += strlen(info->chars[i]->name)+1;
116  }
117  }
118  if ( j==0 )
119  ret = galloc(len+1);
120  else
121  ret[len-1] = '\0';
122  }
123  free(glyphs);
124 return( ret );
125 }
126 
127 static int ClassFindCnt(uint16 *class,int tot) {
128  int i, max=0;
129 
130  for ( i=0; i<tot; ++i )
131  if ( class[i]>max ) max = class[i];
132 return( max+1 );
133 }
134 
135 static int cmpuint16(const void *u1, const void *u2) {
136 return( ((int) *((const uint16 *) u1)) - ((int) *((const uint16 *) u2)) );
137 }
138 
139 static char *GlyphsToNames(struct ttfinfo *info,uint16 *glyphs,int make_uniq) {
140  int i, j, len, off;
141  char *ret, *pt;
142 
143  if ( glyphs==NULL )
144 return( copy(""));
145 
146  /* Adobe produces coverage tables containing duplicate glyphs in */
147  /* GaramondPremrPro.otf. We want unique glyphs, so enforce that */
148  if ( make_uniq ) {
149  for ( i=0 ; glyphs[i]!=0xffff; ++i );
150  qsort(glyphs,i,sizeof(uint16),cmpuint16);
151  for ( i=0; glyphs[i]!=0xffff; ++i ) {
152  if ( glyphs[i+1]==glyphs[i] ) {
153  for ( j=i+1; glyphs[j]==glyphs[i]; ++j );
154  off = j-i -1;
155  for ( j=i+1; ; ++j ) {
156  glyphs[j] = glyphs[j+off];
157  if ( glyphs[j]==0xffff )
158  break;
159  }
160  }
161  }
162  }
163 
164  for ( i=len=0 ; glyphs[i]!=0xffff; ++i )
165  if ( info->chars[glyphs[i]]!=NULL )
166  len += strlen(info->chars[glyphs[i]]->name)+1;
167  ret = pt = galloc(len+1); *pt = '\0';
168  for ( i=0 ; glyphs[i]!=0xffff; ++i ) if ( info->chars[glyphs[i]]!=NULL ) {
169  strcpy(pt,info->chars[glyphs[i]]->name);
170  pt += strlen(pt);
171  *pt++ = ' ';
172  }
173  if ( pt>ret ) pt[-1] = '\0';
174 return( ret );
175 }
176 
177 struct scripts {
180  int langcnt; /* the default language is included as a */
181  struct language { /* normal entry with lang tag 'dflt' */
184  uint16 req; /* required feature index. 0xffff for null */
185  int fcnt;
188 };
189 
190 struct feature {
193  int lcnt;
195 };
196 
197 struct lookup {
200  /* uint16 lookup; */ /* ???? can't imagine what this is*/
205 };
206 
207 static uint16 *getCoverageTable(FILE *ttf, int coverage_offset, struct ttfinfo *info) {
208  int format, cnt, i,j, rcnt;
209  uint16 *glyphs=NULL;
210  int start, end, ind, max;
211 
212  fseek(ttf,coverage_offset,SEEK_SET);
213  format = getushort(ttf);
214  if ( format==1 ) {
215  cnt = getushort(ttf);
216  glyphs = galloc((cnt+1)*sizeof(uint16));
217  if ( ftell(ttf)+2*cnt > info->g_bounds ) {
218  LogError( _("coverage table extends beyond end of table\n") );
219  info->bad_ot = true;
220  if ( ftell(ttf)>info->g_bounds )
221 return( NULL );
222  cnt = (info->g_bounds-ftell(ttf))/2;
223  }
224  for ( i=0; i<cnt; ++i ) {
225  if ( cnt&0xffff0000 ) {
226  LogError( _("Bad count.\n"));
227  info->bad_ot = true;
228  }
229  glyphs[i] = getushort(ttf);
230  if ( feof(ttf) ) {
231  LogError( _("End of file found in coverage table.\n") );
232  info->bad_ot = true;
233  free(glyphs);
234 return( NULL );
235  }
236  if ( glyphs[i]>=info->glyph_cnt ) {
237  LogError( _("Bad coverage table. Glyph %d out of range [0,%d)\n"), glyphs[i], info->glyph_cnt );
238  info->bad_ot = true;
239  glyphs[i] = 0;
240  }
241  }
242  } else if ( format==2 ) {
243  glyphs = gcalloc((max=256),sizeof(uint16));
244  rcnt = getushort(ttf); cnt = 0;
245  if ( ftell(ttf)+6*rcnt > info->g_bounds ) {
246  LogError( _("coverage table extends beyond end of table\n") );
247  info->bad_ot = true;
248  rcnt = (info->g_bounds-ftell(ttf))/6;
249  }
250 
251  for ( i=0; i<rcnt; ++i ) {
252  start = getushort(ttf);
253  end = getushort(ttf);
254  ind = getushort(ttf);
255  if ( feof(ttf) ) {
256  LogError( _("End of file found in coverage table.\n") );
257  info->bad_ot = true;
258  free(glyphs);
259 return( NULL );
260  }
261  if ( start>end || end>=info->glyph_cnt ) {
262  LogError( _("Bad coverage table. Glyph range %d-%d out of range [0,%d)\n"), start, end, info->glyph_cnt );
263  info->bad_ot = true;
264  start = end = 0;
265  }
266  if ( ind+end-start+2 >= max ) {
267  int oldmax = max;
268  max = ind+end-start+2;
269  glyphs = grealloc(glyphs,max*sizeof(uint16));
270  memset(glyphs+oldmax,0,(max-oldmax)*sizeof(uint16));
271  }
272  for ( j=start; j<=end; ++j ) {
273  glyphs[j-start+ind] = j;
274  if ( j>=info->glyph_cnt )
275  glyphs[j-start+ind] = 0;
276  }
277  if ( ind+end-start+1>cnt )
278  cnt = ind+end-start+1;
279  }
280  } else {
281  LogError( _("Bad format for coverage table %d\n"), format );
282  info->bad_ot = true;
283 return( NULL );
284  }
285  glyphs[cnt] = 0xffff;
286 
287 return( glyphs );
288 }
289 
290 struct valuerecord {
295 };
296 
297 static uint16 *getClassDefTable(FILE *ttf, int classdef_offset, struct ttfinfo *info) {
298  int format, i, j;
299  uint16 start, glyphcnt, rangecnt, end, class;
300  uint16 *glist=NULL;
301  int warned = false;
302  int cnt = info->glyph_cnt;
303  uint32 g_bounds = info->g_bounds;
304 
305  fseek(ttf, classdef_offset, SEEK_SET);
306  glist = gcalloc(cnt,sizeof(uint16)); /* Class 0 is default */
307  format = getushort(ttf);
308  if ( format==1 ) {
309  start = getushort(ttf);
310  glyphcnt = getushort(ttf);
311  if ( start+(int) glyphcnt>cnt ) {
312  LogError( _("Bad class def table. start=%d cnt=%d, max glyph=%d\n"), start, glyphcnt, cnt );
313  info->bad_ot = true;
314  glyphcnt = cnt-start;
315  } else if ( ftell(ttf)+2*glyphcnt > g_bounds ) {
316  LogError( _("Class definition sub-table extends beyond end of table\n") );
317  info->bad_ot = true;
318  if (g_bounds<ftell(ttf))
319  glyphcnt = 0;
320  else
321  glyphcnt = (g_bounds-ftell(ttf))/2;
322  }
323  for ( i=0; i<glyphcnt; ++i )
324  glist[start+i] = getushort(ttf);
325  } else if ( format==2 ) {
326  rangecnt = getushort(ttf);
327  if ( ftell(ttf)+6*rangecnt > g_bounds ) {
328  LogError( _("Class definition sub-table extends beyond end of table\n") );
329  info->bad_ot = true;
330  rangecnt = (g_bounds-ftell(ttf))/6;
331  }
332  for ( i=0; i<rangecnt; ++i ) {
333  start = getushort(ttf);
334  end = getushort(ttf);
335  if ( start>end || end>=cnt ) {
336  LogError( _("Bad class def table. Glyph range %d-%d out of range [0,%d)\n"), start, end, cnt );
337  info->bad_ot = true;
338  }
339  class = getushort(ttf);
340  for ( j=start; j<=end; ++j ) if ( j<cnt )
341  glist[j] = class;
342  }
343  } else {
344  LogError( _("Unknown class table format: %d\n"), format );
345  info->bad_ot = true;
346  }
347 
348  /* Do another validity test */
349  for ( i=0; i<cnt; ++i ) {
350  if ( glist[i]>=cnt+1 ) {
351  if ( !warned ) {
352  LogError( _("Nonsensical class assigned to a glyph-- class=%d is too big. Glyph=%d\n"),
353  glist[i], i );
354  info->bad_ot = true;
355  warned = true;
356  }
357  glist[i] = 0;
358  }
359  }
360 
361 return glist;
362 }
363 
364 static void readvaluerecord(struct valuerecord *vr,int vf,FILE *ttf) {
365  memset(vr,'\0',sizeof(struct valuerecord));
366  if ( vf&1 )
367  vr->xplacement = getushort(ttf);
368  if ( vf&2 )
369  vr->yplacement = getushort(ttf);
370  if ( vf&4 )
371  vr->xadvance = getushort(ttf);
372  if ( vf&8 )
373  vr->yadvance = getushort(ttf);
374  if ( vf&0x10 )
375  vr->offXplaceDev = getushort(ttf);
376  if ( vf&0x20 )
377  vr->offYplaceDev = getushort(ttf);
378  if ( vf&0x40 )
379  vr->offXadvanceDev = getushort(ttf);
380  if ( vf&0x80 )
381  vr->offYadvanceDev = getushort(ttf);
382 }
383 
384 #ifdef FONTFORGE_CONFIG_DEVICETABLES
385 static void ReadDeviceTable(FILE *ttf,DeviceTable *adjust,uint32 devtab,
386  struct ttfinfo *info) {
387  long here;
388  int pack;
389  int w,b,i,c;
390 
391  if ( devtab==0 )
392 return;
393  here = ftell(ttf);
394  fseek(ttf,devtab,SEEK_SET);
395  adjust->first_pixel_size = getushort(ttf);
396  adjust->last_pixel_size = getushort(ttf);
397  pack = getushort(ttf);
398  if ( adjust->first_pixel_size>adjust->last_pixel_size || pack==0 || pack>3 ) {
399  LogError(_("Bad device table\n" ));
400  info->bad_ot = true;
401  adjust->first_pixel_size = adjust->last_pixel_size = 0;
402  } else {
403  c = adjust->last_pixel_size-adjust->first_pixel_size+1;
404  adjust->corrections = galloc(c);
405  if ( pack==1 ) {
406  for ( i=0; i<c; i+=8 ) {
407  w = getushort(ttf);
408  for ( b=0; b<8 && i+b<c; ++b )
409  adjust->corrections[i+b] = ((int16) ((w<<(b*2))&0xc000))>>14;
410  }
411  } else if ( pack==2 ) {
412  for ( i=0; i<c; i+=4 ) {
413  w = getushort(ttf);
414  for ( b=0; b<4 && i+b<c; ++b )
415  adjust->corrections[i+b] = ((int16) ((w<<(b*4))&0xf000))>>12;
416  }
417  } else {
418  for ( i=0; i<c; ++i )
419  adjust->corrections[i] = (int8) getc(ttf);
420  }
421  }
422  fseek(ttf,here,SEEK_SET);
423 }
424 
425 static ValDevTab *readValDevTab(FILE *ttf,struct valuerecord *vr,uint32 base,
426  struct ttfinfo *info) {
427  ValDevTab *ret;
428 
429  if ( vr->offXplaceDev==0 && vr->offYplaceDev==0 &&
430  vr->offXadvanceDev==0 && vr->offYadvanceDev==0 )
431 return( NULL );
432  ret = chunkalloc(sizeof(ValDevTab));
433  if ( vr->offXplaceDev!=0 )
434  ReadDeviceTable(ttf,&ret->xadjust,base + vr->offXplaceDev,info);
435  if ( vr->offYplaceDev!=0 )
436  ReadDeviceTable(ttf,&ret->yadjust,base + vr->offYplaceDev,info);
437  if ( vr->offXadvanceDev!=0 )
438  ReadDeviceTable(ttf,&ret->xadv,base + vr->offXadvanceDev,info);
439  if ( vr->offYadvanceDev!=0 )
440  ReadDeviceTable(ttf,&ret->yadv,base + vr->offYadvanceDev,info);
441 return( ret );
442 }
443 #endif
444 
445 static void addPairPos(struct ttfinfo *info, int glyph1, int glyph2,
446  struct lookup *l, struct lookup_subtable *subtable, struct valuerecord *vr1,struct valuerecord *vr2,
447  uint32 base,FILE *ttf) {
448  (void)ttf; /* for -Wall */
449  (void)l; /* for -Wall */
450  (void)base; /* for -Wall */
451  if ( glyph1<info->glyph_cnt && glyph2<info->glyph_cnt ) {
452  PST *pos = chunkalloc(sizeof(PST));
453  pos->type = pst_pair;
454  pos->subtable = subtable;
455  pos->next = info->chars[glyph1]->possub;
456  info->chars[glyph1]->possub = pos;
457  pos->u.pair.vr = chunkalloc(sizeof(struct vr [2]));
458  pos->u.pair.paired = copy(info->chars[glyph2]->name);
459  pos->u.pair.vr[0].xoff = vr1->xplacement;
460  pos->u.pair.vr[0].yoff = vr1->yplacement;
461  pos->u.pair.vr[0].h_adv_off = vr1->xadvance;
462  pos->u.pair.vr[0].v_adv_off = vr1->yadvance;
463  pos->u.pair.vr[1].xoff = vr2->xplacement;
464  pos->u.pair.vr[1].yoff = vr2->yplacement;
465  pos->u.pair.vr[1].h_adv_off = vr2->xadvance;
466  pos->u.pair.vr[1].v_adv_off = vr2->yadvance;
467 #ifdef FONTFORGE_CONFIG_DEVICETABLES
468  pos->u.pair.vr[0].adjust = readValDevTab(ttf,vr1,base,info);
469  pos->u.pair.vr[1].adjust = readValDevTab(ttf,vr2,base,info);
470 #endif
471  } else {
472  LogError( _("Bad pair position: glyphs %d & %d should have been < %d\n"),
473  glyph1, glyph2, info->glyph_cnt );
474  info->bad_ot = true;
475  }
476 }
477 
478 static int addKernPair(struct ttfinfo *info, int glyph1, int glyph2,
479  int16 offset, uint32 devtab, struct lookup *l, struct lookup_subtable *subtable,int isv,
480  FILE *ttf) {
481  KernPair *kp;
482  (void)ttf; /* for -Wall */
483  (void)l; /* for -Wall */
484  (void)devtab; /* for -Wall */
485  if ( glyph1<info->glyph_cnt && glyph2<info->glyph_cnt &&
486  info->chars[glyph1]!=NULL && info->chars[glyph2]!=NULL ) {
487  for ( kp=isv ? info->chars[glyph1]->vkerns : info->chars[glyph1]->kerns;
488  kp!=NULL; kp=kp->next ) {
489  if ( kp->sc == info->chars[glyph2] )
490  break;
491  }
492  if ( kp==NULL ) {
493  kp = chunkalloc(sizeof(KernPair));
494  kp->sc = info->chars[glyph2];
495  kp->off = offset;
496  kp->subtable = subtable;
497 #ifdef FONTFORGE_CONFIG_DEVICETABLES
498  if ( devtab!=0 ) {
499  kp->adjust = chunkalloc(sizeof(DeviceTable));
500  ReadDeviceTable(ttf,kp->adjust,devtab,info);
501  }
502 #endif
503  if ( isv ) {
504  kp->next = info->chars[glyph1]->vkerns;
505  info->chars[glyph1]->vkerns = kp;
506  } else {
507  kp->next = info->chars[glyph1]->kerns;
508  info->chars[glyph1]->kerns = kp;
509  }
510  } else if ( kp->subtable!=subtable )
511 return( true );
512  } else if ( glyph1>=info->glyph_cnt || glyph2>=info->glyph_cnt ) {
513  /* Might be NULL in a ttc file where we omit glyphs */
514  LogError( _("Bad kern pair: glyphs %d & %d should have been < %d\n"),
515  glyph1, glyph2, info->glyph_cnt );
516  info->bad_ot = true;
517  }
518 return( false );
519 }
520 
521 static void gposKernSubTable(FILE *ttf, int stoffset, struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable) {
522  int coverage, cnt, i, j, pair_cnt, vf1, vf2, glyph2;
523  int cd1, cd2, c1_cnt, c2_cnt;
524  uint16 format;
525  uint16 *ps_offsets;
526  uint16 *glyphs, *class1, *class2;
527  struct valuerecord vr1, vr2;
528  long foffset;
529  KernClass *kc;
530  int isv, r2l;
531 
532  format=getushort(ttf);
533  if ( format!=1 && format!=2 ) /* Unknown subtable format */
534 return;
535  coverage = getushort(ttf);
536  vf1 = getushort(ttf);
537  vf2 = getushort(ttf);
538  r2l = 0;
539 
540  /* Accept forms both with and without device tables */
541  if ( (vf1==0x0008 || vf1==0x0088) && vf2==0x0000 )
542  isv = 1; /* Top to bottom */
543  else if ( vf1==0x0000 && (vf2==0x0004 || vf2==0x0044) && (l->flags&pst_r2l)) {
544  isv = 0; /* Right to left */
545  r2l = 1;
546  } else if ( (vf1==0x0004 || vf1==0x0044) && vf2==0x0000 && !(l->flags&pst_r2l) )
547  isv = 0; /* Left to right */
548  else
549  isv = 2; /* Can't optimize, store all 8 settings */
550  if ( format==1 ) {
551  subtable->per_glyph_pst_or_kern = true;
552  cnt = getushort(ttf);
553  ps_offsets = galloc(cnt*sizeof(uint16));
554  for ( i=0; i<cnt; ++i )
555  ps_offsets[i]=getushort(ttf);
556  glyphs = getCoverageTable(ttf,stoffset+coverage,info);
557  if ( glyphs==NULL )
558 return;
559  for ( i=0; i<cnt; ++i ) if ( glyphs[i]<info->glyph_cnt ) {
560  fseek(ttf,stoffset+ps_offsets[i],SEEK_SET);
561  pair_cnt = getushort(ttf);
562  for ( j=0; j<pair_cnt; ++j ) {
563  glyph2 = getushort(ttf);
564  readvaluerecord(&vr1,vf1,ttf);
565  readvaluerecord(&vr2,vf2,ttf);
566  if ( isv==2 )
567  addPairPos(info, glyphs[i], glyph2,l,subtable,&vr1,&vr2, stoffset,ttf);
568  else if ( isv ) {
569  if ( addKernPair(info, glyphs[i], glyph2, vr1.yadvance,
570  vr1.offYadvanceDev==0?0:stoffset+vr1.offYadvanceDev,
571  l,subtable,isv,ttf))
572  addPairPos(info, glyphs[i], glyph2,l,subtable,&vr1,&vr2, stoffset,ttf);
573  /* If we've already got kern data for this pair of */
574  /* glyphs, then we can't make it be a true KernPair */
575  /* but we can save the info as a pst_pair */
576  } else if ( r2l ) { /* R2L */
577  if ( addKernPair(info, glyphs[i], glyph2, vr2.xadvance,
578  vr2.offXadvanceDev==0?0:stoffset+vr2.offXadvanceDev,
579  l,subtable,isv,ttf))
580  addPairPos(info, glyphs[i], glyph2,l,subtable,&vr1,&vr2,stoffset,ttf);
581  } else {
582  if ( addKernPair(info, glyphs[i], glyph2, vr1.xadvance,
583  vr1.offXadvanceDev==0?0:stoffset+vr1.offXadvanceDev,
584  l,subtable,isv,ttf))
585  addPairPos(info, glyphs[i], glyph2,l,subtable,&vr1,&vr2,stoffset,ttf);
586  }
587  }
588  }
589  free(ps_offsets); free(glyphs);
590  } else if ( format==2 ) { /* Class-based kerning */
591  cd1 = getushort(ttf);
592  cd2 = getushort(ttf);
593  foffset = ftell(ttf);
594  class1 = getClassDefTable(ttf, stoffset+cd1, info);
595  class2 = getClassDefTable(ttf, stoffset+cd2, info);
596  glyphs = getCoverageTable(ttf,stoffset+coverage,info);
597  fseek(ttf, foffset, SEEK_SET); /* come back */
598  c1_cnt = getushort(ttf);
599  c2_cnt = getushort(ttf);
600  if ( isv!=2 ) {
601  if ( isv ) {
602  if ( info->vkhead==NULL )
603  info->vkhead = kc = chunkalloc(sizeof(KernClass));
604  else
605  kc = info->vklast->next = chunkalloc(sizeof(KernClass));
606  info->vklast = kc;
607  } else {
608  if ( info->khead==NULL )
609  info->khead = kc = chunkalloc(sizeof(KernClass));
610  else
611  kc = info->klast->next = chunkalloc(sizeof(KernClass));
612  info->klast = kc;
613  }
614  subtable->vertical_kerning = isv;
615  subtable->kc = kc;
616  kc->first_cnt = c1_cnt; kc->second_cnt = c2_cnt;
617  kc->subtable = subtable;
618  kc->offsets = galloc(c1_cnt*c2_cnt*sizeof(int16));
619 #ifdef FONTFORGE_CONFIG_DEVICETABLES
620  kc->adjusts = gcalloc(c1_cnt*c2_cnt,sizeof(DeviceTable));
621 #endif
622  kc->firsts = ClassToNames(info,c1_cnt,class1,info->glyph_cnt);
623  kc->seconds = ClassToNames(info,c2_cnt,class2,info->glyph_cnt);
624  /* Now if the coverage table contains entries which are not in */
625  /* the list of first classes, then those glyphs are the real */
626  /* values for kc->firsts[0] */
627  kc->firsts[0] = CoverageMinusClasses(glyphs,class1,info);
628  for ( i=0; i<c1_cnt; ++i) {
629  for ( j=0; j<c2_cnt; ++j) {
630  readvaluerecord(&vr1,vf1,ttf);
631  readvaluerecord(&vr2,vf2,ttf);
632  if ( isv )
633  kc->offsets[i*c2_cnt+j] = vr1.yadvance;
634  else if ( r2l )
635  kc->offsets[i*c2_cnt+j] = vr2.xadvance;
636  else
637  kc->offsets[i*c2_cnt+j] = vr1.xadvance;
638 #ifdef FONTFORGE_CONFIG_DEVICETABLES
639  if ( isv ) {
640  if ( vr1.offYadvanceDev!=0 )
641  ReadDeviceTable(ttf,&kc->adjusts[i*c2_cnt+j],stoffset+vr1.offYadvanceDev,info);
642  } else if ( r2l ) {
643  if ( vr2.offXadvanceDev!=0 )
644  ReadDeviceTable(ttf,&kc->adjusts[i*c2_cnt+j],stoffset+vr2.offXadvanceDev,info);
645  } else {
646  if ( vr1.offXadvanceDev!=0 )
647  ReadDeviceTable(ttf,&kc->adjusts[i*c2_cnt+j],stoffset+vr1.offXadvanceDev,info);
648  }
649 #endif
650  }
651  }
652  } else { /* This happens when we have a feature which is neither 'kern' nor 'vkrn' we don't know what to do with it so we make it into kern pairs */
653  int k,m;
654  subtable->per_glyph_pst_or_kern = true;
655  for ( i=0; i<c1_cnt; ++i) {
656  for ( j=0; j<c2_cnt; ++j) {
657  readvaluerecord(&vr1,vf1,ttf);
658  readvaluerecord(&vr2,vf2,ttf);
659  if ( vr1.xadvance!=0 || vr1.xplacement!=0 || vr1.yadvance!=0 || vr1.yplacement!=0 ||
660  vr2.xadvance!=0 || vr2.xplacement!=0 || vr2.yadvance!=0 || vr2.yplacement!=0 )
661  for ( k=0; k<info->glyph_cnt; ++k )
662  if ( class1[k]==i )
663  for ( m=0; m<info->glyph_cnt; ++m )
664  if ( class2[m]==j )
665  addPairPos(info, k,m,l,subtable,&vr1,&vr2,stoffset,ttf);
666  }
667  }
668  }
669  free(class1); free(class2);
670  free(glyphs);
671  }
672 }
673 
675  enum anchor_type type,AnchorPoint *last, struct ttfinfo *info) {
676  AnchorPoint *ap;
677  int format;
678  (void)info; /* for -Wall */
679  fseek(ttf,base,SEEK_SET);
680 
681  ap = chunkalloc(sizeof(AnchorPoint));
682  ap->anchor = class;
683  /* All anchor types have the same initial 3 entries, format */
684  /* x,y pos. format 2 contains a truetype positioning point, and */
685  /* format==3 may also have device tables */
686  format = getushort(ttf);
687  ap->me.x = (int16) getushort(ttf);
688  ap->me.y = (int16) getushort(ttf);
689  ap->type = type;
690  if ( format==2 ) {
691  ap->ttf_pt_index = getushort(ttf);
692  ap->has_ttf_pt = true;
693  }
694 #ifdef FONTFORGE_CONFIG_DEVICETABLES
695  else if ( format==3 ) {
696  int devoff;
697  devoff = getushort(ttf);
698  if ( devoff!=0 )
699  ReadDeviceTable(ttf,&ap->xadjust,base+devoff,info);
700  devoff = getushort(ttf);
701  if ( devoff!=0 )
702  ReadDeviceTable(ttf,&ap->yadjust,base+devoff,info);
703  }
704 #endif
705  ap->next = last;
706 return( ap );
707 }
708 
709 static void gposCursiveSubTable(FILE *ttf, int stoffset, struct ttfinfo *info,struct lookup *l, struct lookup_subtable *subtable) {
710  int coverage, cnt, format, i;
711  struct ee_offsets { int entry, exit; } *offsets;
712  uint16 *glyphs;
713  AnchorClass *class;
714  SplineChar *sc;
715  char buf[50];
716  (void)l; /* for -Wall */
717  format=getushort(ttf);
718  if ( format!=1 ) /* Unknown subtable format */
719 return;
720  coverage = getushort(ttf);
721  cnt = getushort(ttf);
722  if ( cnt==0 )
723 return;
724  offsets = galloc(cnt*sizeof(struct ee_offsets));
725  for ( i=0; i<cnt; ++i ) {
726  offsets[i].entry = getushort(ttf);
727  offsets[i].exit = getushort(ttf);
728  }
729  glyphs = getCoverageTable(ttf,stoffset+coverage,info);
730 
731  class = chunkalloc(sizeof(AnchorClass));
732  snprintf(buf,sizeof(buf),_("Cursive-%d"),
733  info->anchor_class_cnt++ );
734  class->name = copy(buf);
735  subtable->anchor_classes = true;
736  class->subtable = subtable;
737  class->type = act_curs;
738  if ( info->ahead==NULL )
739  info->ahead = class;
740  else
741  info->alast->next = class;
742  info->alast = class;
743 
744  for ( i=0; i<cnt; ++i ) {
745  sc = info->chars[glyphs[i]];
746  if ( offsets[i].entry!=0 ) {
747  sc->anchor = readAnchorPoint(ttf,stoffset+offsets[i].entry,class,
748  at_centry,sc->anchor,info);
749  }
750  if ( offsets[i].exit!=0 ) {
751  sc->anchor = readAnchorPoint(ttf,stoffset+offsets[i].exit,class,
752  at_cexit,sc->anchor,info);
753  }
754  }
755  free(offsets);
756  free(glyphs);
757 }
758 
759 static AnchorClass **MarkGlyphsProcessMarks(FILE *ttf,int markoffset,
760  struct ttfinfo *info,struct lookup *l, struct lookup_subtable *subtable,uint16 *markglyphs,
761  int classcnt) {
762  AnchorClass **classes = gcalloc(classcnt,sizeof(AnchorClass *)), *ac;
763  char buf[50];
764  int i, cnt;
765  struct mr { uint16 class, offset; } *at_offsets;
766  SplineChar *sc;
767 
768  for ( i=0; i<classcnt; ++i ) {
769  snprintf(buf,sizeof(buf),_("Anchor-%d"),
770  info->anchor_class_cnt+i );
771  classes[i] = ac = chunkalloc(sizeof(AnchorClass));
772  ac->name = copy(buf);
773  subtable->anchor_classes = true;
774  ac->subtable = subtable;
775  /*ac->merge_with = info->anchor_merge_cnt+1;*/
776  ac->type = l->otlookup->lookup_type==gpos_mark2mark ? act_mkmk : act_mark;
777  /* I don't distinguish between mark to base and mark to lig */
778  if ( info->ahead==NULL )
779  info->ahead = ac;
780  else
781  info->alast->next = ac;
782  info->alast = ac;
783  }
784 
785  fseek(ttf,markoffset,SEEK_SET);
786  cnt = getushort(ttf);
787  if ( feof(ttf) ) {
788  LogError( _("Bad mark table.\n") );
789  info->bad_ot = true;
790 return( NULL );
791  }
792  at_offsets = galloc(cnt*sizeof(struct mr));
793  for ( i=0; i<cnt; ++i ) {
794  at_offsets[i].class = getushort(ttf);
795  at_offsets[i].offset = getushort(ttf);
796  if ( at_offsets[i].class>=classcnt ) {
797  at_offsets[i].class = 0;
798  if ( markglyphs[i]>=info->glyph_cnt )
799  LogError( _("Class out of bounds in GPOS mark sub-table\n") );
800  else
801  LogError( _("Class out of bounds in GPOS mark sub-table for mark %.30s\n"), info->chars[markglyphs[i]]->name);
802  info->bad_ot = true;
803  }
804  }
805  for ( i=0; i<cnt; ++i ) {
806  if ( markglyphs[i]>=info->glyph_cnt )
807  continue;
808  sc = info->chars[markglyphs[i]];
809  if ( sc==NULL || at_offsets[i].offset==0 )
810  continue;
811  sc->anchor = readAnchorPoint(ttf,markoffset+at_offsets[i].offset,
812  classes[at_offsets[i].class],at_mark,sc->anchor,info);
813  }
814  free(at_offsets);
815 return( classes );
816 }
817 
818 static void MarkGlyphsProcessBases(FILE *ttf,int baseoffset,
819  struct ttfinfo *info,struct lookup *l, struct lookup_subtable *subtable,uint16 *baseglyphs,int classcnt,
820  AnchorClass **classes,enum anchor_type at) {
821  int basecnt,i, j, ibase;
822  uint16 *offsets;
823  SplineChar *sc;
824  (void)subtable; /* for -Wall */
825  (void)l; /* for -Wall */
826  fseek(ttf,baseoffset,SEEK_SET);
827  basecnt = getushort(ttf);
828  if ( feof(ttf) ) {
829  LogError( _("Bad base table.\n") );
830  info->bad_ot = true;
831 return;
832  }
833  offsets = galloc(basecnt*classcnt*sizeof(uint16));
834  for ( i=0; i<basecnt*classcnt; ++i )
835  offsets[i] = getushort(ttf);
836  for ( i=ibase=0; i<basecnt; ++i, ibase+= classcnt ) {
837  if ( baseglyphs[i]>=info->glyph_cnt )
838  continue;
839  sc = info->chars[baseglyphs[i]];
840  if ( sc==NULL )
841  continue;
842  for ( j=0; j<classcnt; ++j ) if ( offsets[ibase+j]!=0 ) {
843  sc->anchor = readAnchorPoint(ttf,baseoffset+offsets[ibase+j],
844  classes[j], at,sc->anchor,info);
845  }
846  }
847  free(offsets);
848 }
849 
850 static void MarkGlyphsProcessLigs(FILE *ttf,int baseoffset,
851  struct ttfinfo *info,struct lookup *l, struct lookup_subtable *subtable,uint16 *baseglyphs,int classcnt,
852  AnchorClass **classes) {
853  int basecnt,compcnt, i, j, k, kbase;
854  uint16 *loffsets, *aoffsets;
855  SplineChar *sc;
856  (void)subtable; /* for -Wall */
857  (void)l; /* for -Wall */
858  fseek(ttf,baseoffset,SEEK_SET);
859  basecnt = getushort(ttf);
860  if ( feof(ttf) ) {
861  LogError( _("Bad ligature base table.\n") );
862  info->bad_ot = true;
863 return;
864  }
865  loffsets = galloc(basecnt*sizeof(uint16));
866  for ( i=0; i<basecnt; ++i )
867  loffsets[i] = getushort(ttf);
868  for ( i=0; i<basecnt; ++i ) {
869  sc = info->chars[baseglyphs[i]];
870  if ( baseglyphs[i]>=info->glyph_cnt || sc==NULL )
871  continue;
872  fseek(ttf,baseoffset+loffsets[i],SEEK_SET);
873  compcnt = getushort(ttf);
874  if ( feof(ttf)) {
875  LogError(_("Bad ligature anchor count.\n"));
876  info->bad_ot = true;
877  continue;
878  }
879  aoffsets = galloc(compcnt*classcnt*sizeof(uint16));
880  for ( k=0; k<compcnt*classcnt; ++k )
881  aoffsets[k] = getushort(ttf);
882  for ( k=kbase=0; k<compcnt; ++k, kbase+=classcnt ) {
883  for ( j=0; j<classcnt; ++j ) if ( aoffsets[kbase+j]!=0 ) {
884  sc->anchor = readAnchorPoint(ttf,baseoffset+loffsets[i]+aoffsets[kbase+j],
885  classes[j], at_baselig,sc->anchor,info);
886  sc->anchor->lig_index = k;
887  }
888  }
889  free(aoffsets);
890  }
891  free(loffsets);
892 }
893 
894 static void gposMarkSubTable(FILE *ttf, uint32 stoffset,
895  struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable) {
896  int markcoverage, basecoverage, classcnt, markoffset, baseoffset;
897  uint16 *markglyphs, *baseglyphs;
898  AnchorClass **classes;
899 
900  /* The header for the three different mark tables is the same */
901  /* Type = */ getushort(ttf);
902  markcoverage = getushort(ttf);
903  basecoverage = getushort(ttf);
904  classcnt = getushort(ttf);
905  markoffset = getushort(ttf);
906  baseoffset = getushort(ttf);
907  markglyphs = getCoverageTable(ttf,stoffset+markcoverage,info);
908  baseglyphs = getCoverageTable(ttf,stoffset+basecoverage,info);
909  if ( baseglyphs==NULL || markglyphs==NULL ) {
910  free(baseglyphs); free(markglyphs);
911 return;
912  }
913  /* as is the (first) mark table */
914  classes = MarkGlyphsProcessMarks(ttf,stoffset+markoffset,
915  info,l,subtable,markglyphs,classcnt);
916  if ( classes==NULL )
917 return;
918  switch ( l->otlookup->lookup_type ) {
919  case gpos_mark2base:
920  case gpos_mark2mark:
921  MarkGlyphsProcessBases(ttf,stoffset+baseoffset,
922  info,l,subtable,baseglyphs,classcnt,classes,
923  l->otlookup->lookup_type==gpos_mark2base?at_basechar:at_basemark);
924  break;
925  case gpos_mark2ligature:
926  MarkGlyphsProcessLigs(ttf,stoffset+baseoffset,
927  info,l,subtable,baseglyphs,classcnt,classes);
928  break;
929  default:
930  break;
931  }
932  info->anchor_class_cnt += classcnt;
933  ++ info->anchor_merge_cnt;
934  free(markglyphs); free(baseglyphs);
935  free(classes);
936 }
937 
938 static void gposSimplePos(FILE *ttf, int stoffset, struct ttfinfo *info,
939  struct lookup *l, struct lookup_subtable *subtable) {
940  int coverage, cnt, i, vf;
941  uint16 format;
942  uint16 *glyphs;
943  struct valuerecord *vr=NULL, _vr, *which;
944  (void)l; /* for -Wall */
945  format=getushort(ttf);
946  if ( format!=1 && format!=2 ) /* Unknown subtable format */
947 return;
948  coverage = getushort(ttf);
949  vf = getushort(ttf);
950 #ifdef FONTFORGE_CONFIG_DEVICETABLES
951  if ( vf==0 )
952 return;
953 #else
954  if ( (vf&0xf)==0 ) /* Not interested in things whose data just live in device tables */
955 return;
956 #endif
957  if ( format==1 ) {
958  memset(&_vr,0,sizeof(_vr));
959  readvaluerecord(&_vr,vf,ttf);
960  } else {
961  cnt = getushort(ttf);
962  vr = gcalloc(cnt,sizeof(struct valuerecord));
963  for ( i=0; i<cnt; ++i )
964  readvaluerecord(&vr[i],vf,ttf);
965  }
966  glyphs = getCoverageTable(ttf,stoffset+coverage,info);
967  if ( glyphs==NULL ) {
968  free(vr);
969 return;
970  }
971  for ( i=0; glyphs[i]!=0xffff; ++i ) if ( glyphs[i]<info->glyph_cnt ) {
972  PST *pos = chunkalloc(sizeof(PST));
973  pos->type = pst_position;
974  pos->subtable = subtable;
975  pos->next = info->chars[glyphs[i]]->possub;
976  info->chars[glyphs[i]]->possub = pos;
977  which = format==1 ? &_vr : &vr[i];
978  pos->u.pos.xoff = which->xplacement;
979  pos->u.pos.yoff = which->yplacement;
980  pos->u.pos.h_adv_off = which->xadvance;
981  pos->u.pos.v_adv_off = which->yadvance;
982 #ifdef FONTFORGE_CONFIG_DEVICETABLES
983  pos->u.pos.adjust = readValDevTab(ttf,which,stoffset,info);
984 #endif
985  }
986  subtable->per_glyph_pst_or_kern = true;
987  free(vr);
988  free(glyphs);
989 }
990 
991 static void ProcessSubLookups(FILE *ttf,struct ttfinfo *info,int gpos,
992  struct lookup *alllooks,struct seqlookup *sl) {
993  int i;
994  (void)ttf; /* for -Wall */
995  i = (intpt) sl->lookup;
996  if ( i<0 || i>=info->lookup_cnt ) {
997  LogError( _("Attempt to reference lookup %d (within a contextual lookup), but there are\n only %d lookups in %s\n"),
998  i, info->lookup_cnt, gpos ? "'GPOS'" : "'GSUB'" );
999  info->bad_ot = true;
1000  sl->lookup = NULL;
1001 return;
1002  }
1003  sl->lookup = alllooks[i].otlookup;
1004 }
1005 
1006 static void g___ContextSubTable1(FILE *ttf, int stoffset,
1007  struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable, int justinuse,
1008  struct lookup *alllooks, int gpos) {
1009  int i, j, k, rcnt, cnt;
1010  uint16 coverage;
1011  uint16 *glyphs;
1012  struct subrule {
1013  uint32 offset;
1014  int gcnt;
1015  int scnt;
1016  uint16 *glyphs;
1017  struct seqlookup *sl;
1018  };
1019  struct rule {
1020  uint32 offsets;
1021  int scnt;
1022  struct subrule *subrules;
1023  } *rules;
1024  FPST *fpst;
1025  struct fpst_rule *rule;
1026  int warned = false, warned2 = false;
1027  (void)l; /* for -Wall */
1028  coverage = getushort(ttf);
1029  rcnt = getushort(ttf); /* glyph count in coverage table */
1030  rules = galloc(rcnt*sizeof(struct rule));
1031  for ( i=0; i<rcnt; ++i )
1032  rules[i].offsets = getushort(ttf)+stoffset;
1033  glyphs = getCoverageTable(ttf,stoffset+coverage,info);
1034  cnt = 0;
1035  for ( i=0; i<rcnt; ++i ) {
1036  fseek(ttf,rules[i].offsets,SEEK_SET);
1037  rules[i].scnt = getushort(ttf);
1038  cnt += rules[i].scnt;
1039  rules[i].subrules = galloc(rules[i].scnt*sizeof(struct subrule));
1040  for ( j=0; j<rules[i].scnt; ++j )
1041  rules[i].subrules[j].offset = getushort(ttf)+rules[i].offsets;
1042  for ( j=0; j<rules[i].scnt; ++j ) {
1043  fseek(ttf,rules[i].subrules[j].offset,SEEK_SET);
1044  rules[i].subrules[j].gcnt = getushort(ttf);
1045  rules[i].subrules[j].scnt = getushort(ttf);
1046  rules[i].subrules[j].glyphs = galloc((rules[i].subrules[j].gcnt+1)*sizeof(uint16));
1047  rules[i].subrules[j].glyphs[0] = glyphs[i];
1048  for ( k=1; k<rules[i].subrules[j].gcnt; ++k ) {
1049  rules[i].subrules[j].glyphs[k] = getushort(ttf);
1050  if ( rules[i].subrules[j].glyphs[k]>=info->glyph_cnt ) {
1051  if ( !warned )
1052  LogError( _("Bad contextual or chaining sub table. Glyph %d out of range [0,%d)\n"),
1053  rules[i].subrules[j].glyphs[k], info->glyph_cnt );
1054  info->bad_ot = true;
1055  warned = true;
1056  rules[i].subrules[j].glyphs[k] = 0;
1057  }
1058  }
1059  rules[i].subrules[j].glyphs[k] = 0xffff;
1060  rules[i].subrules[j].sl = galloc(rules[i].subrules[j].scnt*sizeof(struct seqlookup));
1061  for ( k=0; k<rules[i].subrules[j].scnt; ++k ) {
1062  rules[i].subrules[j].sl[k].seq = getushort(ttf);
1063  if ( rules[i].subrules[j].sl[k].seq >= rules[i].subrules[j].gcnt+1 )
1064  if ( !warned2 ) {
1065  LogError( _("Attempt to apply a lookup to a location out of the range of this contextual\n lookup seq=%d max=%d\n"),
1066  rules[i].subrules[j].sl[k].seq, rules[i].subrules[j].gcnt );
1067  info->bad_ot = true;
1068  warned2 = true;
1069  }
1070  rules[i].subrules[j].sl[k].lookup = (void *) (intpt) getushort(ttf);
1071  }
1072  }
1073  }
1074 
1075  if ( justinuse==git_justinuse ) {
1076  /* Nothing to do. This lookup doesn't really reference any glyphs */
1077  /* any lookups it invokes will be processed on their own */
1078  } else {
1079  fpst = chunkalloc(sizeof(FPST));
1080  fpst->type = gpos ? pst_contextpos : pst_contextsub;
1081  fpst->format = pst_glyphs;
1082  fpst->subtable = subtable;
1083  fpst->next = info->possub;
1084  info->possub = fpst;
1085  subtable->fpst = fpst;
1086 
1087  fpst->rules = rule = gcalloc(cnt,sizeof(struct fpst_rule));
1088  fpst->rule_cnt = cnt;
1089 
1090  cnt = 0;
1091  for ( i=0; i<rcnt; ++i ) for ( j=0; j<rules[i].scnt; ++j ) {
1092  rule[cnt].u.glyph.names = GlyphsToNames(info,rules[i].subrules[j].glyphs,false);
1093  rule[cnt].lookup_cnt = rules[i].subrules[j].scnt;
1094  rule[cnt].lookups = rules[i].subrules[j].sl;
1095  rules[i].subrules[j].sl = NULL;
1096  for ( k=0; k<rule[cnt].lookup_cnt; ++k )
1097  ProcessSubLookups(ttf,info,gpos,alllooks,&rule[cnt].lookups[k]);
1098  ++cnt;
1099  }
1100  }
1101 
1102  for ( i=0; i<rcnt; ++i ) {
1103  for ( j=0; j<rules[i].scnt; ++j ) {
1104  free(rules[i].subrules[j].glyphs);
1105  free(rules[i].subrules[j].sl);
1106  }
1107  free(rules[i].subrules);
1108  }
1109  free(rules);
1110  free(glyphs);
1111 }
1112 
1113 static void g___ChainingSubTable1(FILE *ttf, int stoffset,
1114  struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable, int justinuse,
1115  struct lookup *alllooks, int gpos) {
1116  int i, j, k, rcnt, cnt, which;
1117  uint16 coverage;
1118  uint16 *glyphs;
1119  struct subrule {
1120  uint32 offset;
1121  int gcnt, bcnt, fcnt;
1122  int scnt;
1123  uint16 *glyphs, *bglyphs, *fglyphs;
1124  struct seqlookup *sl;
1125  };
1126  struct rule {
1127  uint32 offsets;
1128  int scnt;
1129  struct subrule *subrules;
1130  } *rules;
1131  FPST *fpst;
1132  struct fpst_rule *rule;
1133  int warned = false, warned2 = false;
1134  (void)l; /* for -Wall */
1135  coverage = getushort(ttf);
1136  rcnt = getushort(ttf); /* glyph count in coverage table */
1137  rules = galloc(rcnt*sizeof(struct rule));
1138  for ( i=0; i<rcnt; ++i )
1139  rules[i].offsets = getushort(ttf)+stoffset;
1140  glyphs = getCoverageTable(ttf,stoffset+coverage,info);
1141  if ( glyphs==NULL ) {
1142  free(rules);
1143 return;
1144  }
1145  cnt = 0;
1146  for ( i=0; i<rcnt; ++i ) {
1147  fseek(ttf,rules[i].offsets,SEEK_SET);
1148  rules[i].scnt = getushort(ttf);
1149  cnt += rules[i].scnt;
1150  rules[i].subrules = galloc(rules[i].scnt*sizeof(struct subrule));
1151  for ( j=0; j<rules[i].scnt; ++j )
1152  rules[i].subrules[j].offset = getushort(ttf)+rules[i].offsets;
1153  for ( j=0; j<rules[i].scnt; ++j ) {
1154  fseek(ttf,rules[i].subrules[j].offset,SEEK_SET);
1155  rules[i].subrules[j].bcnt = getushort(ttf);
1156  if ( feof(ttf)) {
1157  LogError( _("Unexpected end of file in contextual chaining subtable.\n") );
1158  info->bad_ot = true;
1159 return;
1160  }
1161  rules[i].subrules[j].bglyphs = galloc((rules[i].subrules[j].bcnt+1)*sizeof(uint16));
1162  for ( k=0; k<rules[i].subrules[j].bcnt; ++k )
1163  rules[i].subrules[j].bglyphs[k] = getushort(ttf);
1164  rules[i].subrules[j].bglyphs[k] = 0xffff;
1165 
1166  rules[i].subrules[j].gcnt = getushort(ttf);
1167  if ( feof(ttf)) {
1168  LogError( _("Unexpected end of file in contextual chaining subtable.\n") );
1169  info->bad_ot = true;
1170 return;
1171  }
1172  rules[i].subrules[j].glyphs = galloc((rules[i].subrules[j].gcnt+1)*sizeof(uint16));
1173  rules[i].subrules[j].glyphs[0] = glyphs[i];
1174  for ( k=1; k<rules[i].subrules[j].gcnt; ++k )
1175  rules[i].subrules[j].glyphs[k] = getushort(ttf);
1176  rules[i].subrules[j].glyphs[k] = 0xffff;
1177 
1178  rules[i].subrules[j].fcnt = getushort(ttf);
1179  if ( feof(ttf)) {
1180  LogError( _("Unexpected end of file in contextual chaining subtable.\n") );
1181  info->bad_ot = true;
1182 return;
1183  }
1184  rules[i].subrules[j].fglyphs = galloc((rules[i].subrules[j].fcnt+1)*sizeof(uint16));
1185  for ( k=0; k<rules[i].subrules[j].fcnt; ++k )
1186  rules[i].subrules[j].fglyphs[k] = getushort(ttf);
1187  rules[i].subrules[j].fglyphs[k] = 0xffff;
1188 
1189  for ( which = 0; which<3; ++which ) {
1190  for ( k=0; k<(&rules[i].subrules[j].gcnt)[which]; ++k ) {
1191  if ( (&rules[i].subrules[j].glyphs)[which][k]>=info->glyph_cnt ) {
1192  if ( !warned )
1193  LogError( _("Bad contextual or chaining sub table. Glyph %d out of range [0,%d)\n"),
1194  (&rules[i].subrules[j].glyphs)[which][k], info->glyph_cnt );
1195  info->bad_ot = true;
1196  warned = true;
1197  (&rules[i].subrules[j].glyphs)[which][k] = 0;
1198  }
1199  }
1200  }
1201 
1202  rules[i].subrules[j].scnt = getushort(ttf);
1203  if ( feof(ttf)) {
1204  LogError( _("Unexpected end of file in contextual chaining subtable.\n") );
1205  info->bad_ot = true;
1206 return;
1207  }
1208  rules[i].subrules[j].sl = galloc(rules[i].subrules[j].scnt*sizeof(struct seqlookup));
1209  for ( k=0; k<rules[i].subrules[j].scnt; ++k ) {
1210  rules[i].subrules[j].sl[k].seq = getushort(ttf);
1211  if ( rules[i].subrules[j].sl[k].seq >= rules[i].subrules[j].gcnt+1 )
1212  if ( !warned2 ) {
1213  LogError( _("Attempt to apply a lookup to a location out of the range of this contextual\n lookup seq=%d max=%d\n"),
1214  rules[i].subrules[j].sl[k].seq, rules[i].subrules[j].gcnt );
1215  info->bad_ot = true;
1216  warned2 = true;
1217  }
1218  rules[i].subrules[j].sl[k].lookup = (void *) (intpt) getushort(ttf);
1219  }
1220  }
1221  }
1222 
1223  if ( justinuse==git_justinuse ) {
1224  /* Nothing to do. This lookup doesn't really reference any glyphs */
1225  /* any lookups it invokes will be processed on their own */
1226  } else {
1227  fpst = chunkalloc(sizeof(FPST));
1228  fpst->type = gpos ? pst_chainpos : pst_chainsub;
1229  fpst->format = pst_glyphs;
1230  fpst->subtable = subtable;
1231  fpst->next = info->possub;
1232  info->possub = fpst;
1233  subtable->fpst = fpst;
1234 
1235  fpst->rules = rule = gcalloc(cnt,sizeof(struct fpst_rule));
1236  fpst->rule_cnt = cnt;
1237 
1238  cnt = 0;
1239  for ( i=0; i<rcnt; ++i ) for ( j=0; j<rules[i].scnt; ++j ) {
1240  rule[cnt].u.glyph.back = GlyphsToNames(info,rules[i].subrules[j].bglyphs,false);
1241  rule[cnt].u.glyph.names = GlyphsToNames(info,rules[i].subrules[j].glyphs,false);
1242  rule[cnt].u.glyph.fore = GlyphsToNames(info,rules[i].subrules[j].fglyphs,false);
1243  rule[cnt].lookup_cnt = rules[i].subrules[j].scnt;
1244  rule[cnt].lookups = rules[i].subrules[j].sl;
1245  rules[i].subrules[j].sl = NULL;
1246  for ( k=0; k<rule[cnt].lookup_cnt; ++k )
1247  ProcessSubLookups(ttf,info,gpos,alllooks,&rule[cnt].lookups[k]);
1248  ++cnt;
1249  }
1250  }
1251 
1252  for ( i=0; i<rcnt; ++i ) {
1253  for ( j=0; j<rules[i].scnt; ++j ) {
1254  free(rules[i].subrules[j].bglyphs);
1255  free(rules[i].subrules[j].glyphs);
1256  free(rules[i].subrules[j].fglyphs);
1257  free(rules[i].subrules[j].sl);
1258  }
1259  free(rules[i].subrules);
1260  }
1261  free(rules);
1262  free(glyphs);
1263 }
1264 
1265 static void g___ContextSubTable2(FILE *ttf, int stoffset,
1266  struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable, int justinuse,
1267  struct lookup *alllooks, int gpos) {
1268  int i, j, k, rcnt, cnt;
1269  uint16 coverage;
1270  uint16 classoff;
1271  struct subrule {
1272  uint32 offset;
1273  int ccnt;
1274  int scnt;
1275  uint16 *classindeces;
1276  struct seqlookup *sl;
1277  };
1278  struct rule {
1279  uint32 offsets;
1280  int scnt;
1281  struct subrule *subrules;
1282  } *rules;
1283  FPST *fpst;
1284  struct fpst_rule *rule;
1285  uint16 *glyphs, *class;
1286  int warned2 = false;
1287  (void)l; /* for -Wall */
1288  coverage = getushort(ttf);
1289  classoff = getushort(ttf);
1290  rcnt = getushort(ttf); /* class count in coverage table *//* == number of top level rules */
1291  rules = gcalloc(rcnt,sizeof(struct rule));
1292  for ( i=0; i<rcnt; ++i )
1293  rules[i].offsets = getushort(ttf)+stoffset;
1294  cnt = 0;
1295  for ( i=0; i<rcnt; ++i ) if ( rules[i].offsets!=(unsigned)stoffset ) { /* some classes might be unused */
1296  fseek(ttf,rules[i].offsets,SEEK_SET);
1297  rules[i].scnt = getushort(ttf);
1298  if ( rules[i].scnt<0 ) {
1299  LogError( _("Bad count in context chaining sub-table.\n") );
1300  info->bad_ot = true;
1301 return;
1302  }
1303  cnt += rules[i].scnt;
1304  rules[i].subrules = galloc(rules[i].scnt*sizeof(struct subrule));
1305  for ( j=0; j<rules[i].scnt; ++j )
1306  rules[i].subrules[j].offset = getushort(ttf)+rules[i].offsets;
1307  for ( j=0; j<rules[i].scnt; ++j ) {
1308  fseek(ttf,rules[i].subrules[j].offset,SEEK_SET);
1309  rules[i].subrules[j].ccnt = getushort(ttf);
1310  rules[i].subrules[j].scnt = getushort(ttf);
1311  if ( rules[i].subrules[j].ccnt<0 ) {
1312  LogError( _("Bad class count in contextual chaining sub-table.\n") );
1313  info->bad_ot = true;
1314  free(rules);
1315 return;
1316  }
1317  rules[i].subrules[j].classindeces = galloc(rules[i].subrules[j].ccnt*sizeof(uint16));
1318  rules[i].subrules[j].classindeces[0] = i;
1319  for ( k=1; k<rules[i].subrules[j].ccnt; ++k )
1320  rules[i].subrules[j].classindeces[k] = getushort(ttf);
1321  if ( rules[i].subrules[j].scnt<0 ) {
1322  LogError( _("Bad count in contextual chaining sub-table.\n") );
1323  info->bad_ot = true;
1324  free(rules);
1325 return;
1326  }
1327  rules[i].subrules[j].sl = galloc(rules[i].subrules[j].scnt*sizeof(struct seqlookup));
1328  for ( k=0; k<rules[i].subrules[j].scnt; ++k ) {
1329  rules[i].subrules[j].sl[k].seq = getushort(ttf);
1330  if ( rules[i].subrules[j].sl[k].seq >= rules[i].subrules[j].ccnt )
1331  if ( !warned2 ) {
1332  LogError( _("Attempt to apply a lookup to a location out of the range of this contextual\n lookup seq=%d max=%d\n"),
1333  rules[i].subrules[j].sl[k].seq, rules[i].subrules[j].ccnt-1);
1334  info->bad_ot = true;
1335  warned2 = true;
1336  }
1337  rules[i].subrules[j].sl[k].lookup = (void *) (intpt) getushort(ttf);
1338  }
1339  }
1340  }
1341 
1342  if ( justinuse==git_justinuse ) {
1343  /* Nothing to do. This lookup doesn't really reference any glyphs */
1344  /* any lookups it invokes will be processed on their own */
1345  } else {
1346  fpst = chunkalloc(sizeof(FPST));
1347  fpst->type = gpos ? pst_contextpos : pst_contextsub;
1348  fpst->format = pst_class;
1349  fpst->subtable = subtable;
1350  subtable->fpst = fpst;
1351  fpst->next = info->possub;
1352  info->possub = fpst;
1353 
1354  fpst->rules = rule = gcalloc(cnt,sizeof(struct fpst_rule));
1355  fpst->rule_cnt = cnt;
1356  class = getClassDefTable(ttf, stoffset+classoff, info);
1357  fpst->nccnt = ClassFindCnt(class,info->glyph_cnt);
1358  fpst->nclass = ClassToNames(info,fpst->nccnt,class,info->glyph_cnt);
1359 
1360  /* Just in case they used the coverage table to redefine class 0 */
1361  glyphs = getCoverageTable(ttf,stoffset+coverage,info);
1362  fpst->nclass[0] = CoverageMinusClasses(glyphs,class,info);
1363  free(glyphs); free(class); class = NULL;
1364 
1365  cnt = 0;
1366  for ( i=0; i<rcnt; ++i ) for ( j=0; j<rules[i].scnt; ++j ) {
1367  rule[cnt].u.class.nclasses = rules[i].subrules[j].classindeces;
1368  rule[cnt].u.class.ncnt = rules[i].subrules[j].ccnt;
1369  rules[i].subrules[j].classindeces = NULL;
1370  rule[cnt].lookup_cnt = rules[i].subrules[j].scnt;
1371  rule[cnt].lookups = rules[i].subrules[j].sl;
1372  rules[i].subrules[j].sl = NULL;
1373  for ( k=0; k<rule[cnt].lookup_cnt; ++k )
1374  ProcessSubLookups(ttf,info,gpos,alllooks,&rule[cnt].lookups[k]);
1375  ++cnt;
1376  }
1377  }
1378 
1379  for ( i=0; i<rcnt; ++i ) {
1380  for ( j=0; j<rules[i].scnt; ++j ) {
1381  free(rules[i].subrules[j].classindeces);
1382  free(rules[i].subrules[j].sl);
1383  }
1384  free(rules[i].subrules);
1385  }
1386  free(rules);
1387 }
1388 
1389 static void g___ChainingSubTable2(FILE *ttf, int stoffset,
1390  struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable, int justinuse,
1391  struct lookup *alllooks, int gpos) {
1392  int i, j, k, rcnt, cnt;
1394  uint16 bclassoff, classoff, fclassoff;
1395  struct subrule {
1396  uint32 offset;
1397  int ccnt, bccnt, fccnt;
1398  int scnt;
1399  uint16 *classindeces, *bci, *fci;
1400  struct seqlookup *sl;
1401  };
1402  struct rule {
1403  uint32 offsets;
1404  int scnt;
1405  struct subrule *subrules;
1406  } *rules;
1407  FPST *fpst;
1408  struct fpst_rule *rule;
1409  uint16 *glyphs, *class;
1410  int warned2 = false;
1411  (void)l; /* for -Wall */
1412  coverage = getushort(ttf);
1413  bclassoff = getushort(ttf);
1414  classoff = getushort(ttf);
1415  fclassoff = getushort(ttf);
1416  rcnt = getushort(ttf); /* class count *//* == max number of top level rules */
1417  rules = gcalloc(rcnt,sizeof(struct rule));
1418  for ( i=0; i<rcnt; ++i ) {
1419  offset = getushort(ttf);
1420  rules[i].offsets = offset==0 ? 0 : offset+stoffset;
1421  }
1422  cnt = 0;
1423  for ( i=0; i<rcnt; ++i ) if ( rules[i].offsets!=0 ) { /* some classes might be unused */
1424  fseek(ttf,rules[i].offsets,SEEK_SET);
1425  rules[i].scnt = getushort(ttf);
1426  if ( rules[i].scnt<0 ) {
1427  LogError( _("Bad count in context chaining sub-table.\n") );
1428  info->bad_ot = true;
1429 return;
1430  }
1431  cnt += rules[i].scnt;
1432  rules[i].subrules = galloc(rules[i].scnt*sizeof(struct subrule));
1433  for ( j=0; j<rules[i].scnt; ++j )
1434  rules[i].subrules[j].offset = getushort(ttf)+rules[i].offsets;
1435  for ( j=0; j<rules[i].scnt; ++j ) {
1436  fseek(ttf,rules[i].subrules[j].offset,SEEK_SET);
1437  rules[i].subrules[j].bccnt = getushort(ttf);
1438  if ( rules[i].subrules[j].bccnt<0 ) {
1439  LogError( _("Bad class count in contextual chaining sub-table.\n") );
1440  info->bad_ot = true;
1441  free(rules);
1442 return;
1443  }
1444  rules[i].subrules[j].bci = galloc(rules[i].subrules[j].bccnt*sizeof(uint16));
1445  for ( k=0; k<rules[i].subrules[j].bccnt; ++k )
1446  rules[i].subrules[j].bci[k] = getushort(ttf);
1447  rules[i].subrules[j].ccnt = getushort(ttf);
1448  if ( rules[i].subrules[j].ccnt<0 ) {
1449  LogError( _("Bad class count in contextual chaining sub-table.\n") );
1450  info->bad_ot = true;
1451  free(rules);
1452 return;
1453  }
1454  rules[i].subrules[j].classindeces = galloc(rules[i].subrules[j].ccnt*sizeof(uint16));
1455  rules[i].subrules[j].classindeces[0] = i;
1456  for ( k=1; k<rules[i].subrules[j].ccnt; ++k )
1457  rules[i].subrules[j].classindeces[k] = getushort(ttf);
1458  rules[i].subrules[j].fccnt = getushort(ttf);
1459  if ( rules[i].subrules[j].fccnt<0 ) {
1460  LogError( _("Bad class count in contextual chaining sub-table.\n") );
1461  info->bad_ot = true;
1462  free(rules);
1463 return;
1464  }
1465  rules[i].subrules[j].fci = galloc(rules[i].subrules[j].fccnt*sizeof(uint16));
1466  for ( k=0; k<rules[i].subrules[j].fccnt; ++k )
1467  rules[i].subrules[j].fci[k] = getushort(ttf);
1468  rules[i].subrules[j].scnt = getushort(ttf);
1469  if ( rules[i].subrules[j].scnt<0 ) {
1470  LogError( _("Bad count in contextual chaining sub-table.\n") );
1471  info->bad_ot = true;
1472  free(rules);
1473 return;
1474  }
1475  rules[i].subrules[j].sl = galloc(rules[i].subrules[j].scnt*sizeof(struct seqlookup));
1476  for ( k=0; k<rules[i].subrules[j].scnt; ++k ) {
1477  rules[i].subrules[j].sl[k].seq = getushort(ttf);
1478  if ( rules[i].subrules[j].sl[k].seq >= rules[i].subrules[j].ccnt )
1479  if ( !warned2 ) {
1480  LogError( _("Attempt to apply a lookup to a location out of the range of this contextual\n lookup seq=%d max=%d\n"),
1481  rules[i].subrules[j].sl[k].seq, rules[i].subrules[j].ccnt-1);
1482  info->bad_ot = true;
1483  warned2 = true;
1484  }
1485  rules[i].subrules[j].sl[k].lookup = (void *) (intpt) getushort(ttf);
1486  }
1487  }
1488  }
1489 
1490  if ( justinuse==git_justinuse ) {
1491  /* Nothing to do. This lookup doesn't really reference any glyphs */
1492  /* any lookups it invokes will be processed on their own */
1493  } else {
1494  fpst = chunkalloc(sizeof(FPST));
1495  fpst->type = gpos ? pst_chainpos : pst_chainsub;
1496  fpst->format = pst_class;
1497  fpst->subtable = subtable;
1498  subtable->fpst = fpst;
1499  fpst->next = info->possub;
1500  info->possub = fpst;
1501 
1502  fpst->rules = rule = gcalloc(cnt,sizeof(struct fpst_rule));
1503  fpst->rule_cnt = cnt;
1504 
1505  class = getClassDefTable(ttf, stoffset+classoff, info);
1506  fpst->nccnt = ClassFindCnt(class,info->glyph_cnt);
1507  fpst->nclass = ClassToNames(info,fpst->nccnt,class,info->glyph_cnt);
1508 
1509  /* Just in case they used the coverage table to redefine class 0 */
1510  glyphs = getCoverageTable(ttf,stoffset+coverage,info);
1511  fpst->nclass[0] = CoverageMinusClasses(glyphs,class,info);
1512  free(glyphs); free(class); class = NULL;
1513 
1514  /* The docs don't mention this, but in mangal.ttf fclassoff==0 NULL */
1515  if ( bclassoff!=0 )
1516  class = getClassDefTable(ttf, stoffset+bclassoff, info);
1517  else
1518  class = gcalloc(info->glyph_cnt,sizeof(uint16));
1519  fpst->bccnt = ClassFindCnt(class,info->glyph_cnt);
1520  fpst->bclass = ClassToNames(info,fpst->bccnt,class,info->glyph_cnt);
1521  free(class);
1522  if ( fclassoff!=0 )
1523  class = getClassDefTable(ttf, stoffset+fclassoff, info);
1524  else
1525  class = gcalloc(info->glyph_cnt,sizeof(uint16));
1526  fpst->fccnt = ClassFindCnt(class,info->glyph_cnt);
1527  fpst->fclass = ClassToNames(info,fpst->fccnt,class,info->glyph_cnt);
1528  free(class);
1529 
1530  cnt = 0;
1531  for ( i=0; i<rcnt; ++i ) for ( j=0; j<rules[i].scnt; ++j ) {
1532  rule[cnt].u.class.nclasses = rules[i].subrules[j].classindeces;
1533  rule[cnt].u.class.ncnt = rules[i].subrules[j].ccnt;
1534  rules[i].subrules[j].classindeces = NULL;
1535  rule[cnt].u.class.bclasses = rules[i].subrules[j].bci;
1536  rule[cnt].u.class.bcnt = rules[i].subrules[j].bccnt;
1537  rules[i].subrules[j].bci = NULL;
1538  rule[cnt].u.class.fclasses = rules[i].subrules[j].fci;
1539  rule[cnt].u.class.fcnt = rules[i].subrules[j].fccnt;
1540  rules[i].subrules[j].fci = NULL;
1541  rule[cnt].lookup_cnt = rules[i].subrules[j].scnt;
1542  rule[cnt].lookups = rules[i].subrules[j].sl;
1543  rules[i].subrules[j].sl = NULL;
1544  for ( k=0; k<rule[cnt].lookup_cnt; ++k )
1545  ProcessSubLookups(ttf,info,gpos,alllooks,&rule[cnt].lookups[k]);
1546  ++cnt;
1547  }
1548  }
1549 
1550  for ( i=0; i<rcnt; ++i ) {
1551  for ( j=0; j<rules[i].scnt; ++j ) {
1552  free(rules[i].subrules[j].classindeces);
1553  free(rules[i].subrules[j].sl);
1554  }
1555  free(rules[i].subrules);
1556  }
1557  free(rules);
1558 }
1559 
1560 static void g___ContextSubTable3(FILE *ttf, int stoffset,
1561  struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable, int justinuse,
1562  struct lookup *alllooks, int gpos) {
1563  int i, k, scnt, gcnt;
1564  uint16 *coverage;
1565  struct seqlookup *sl;
1566  uint16 *glyphs;
1567  FPST *fpst;
1568  struct fpst_rule *rule;
1569  int warned2 = false;
1570  (void)l; /* for -Wall */
1571  gcnt = getushort(ttf);
1572  scnt = getushort(ttf);
1573  if ( feof(ttf) ) {
1574  LogError( _("End of file in context chaining sub-table.\n") );
1575  info->bad_ot = true;
1576 return;
1577  }
1578  coverage = galloc(gcnt*sizeof(uint16));
1579  for ( i=0; i<gcnt; ++i )
1580  coverage[i] = getushort(ttf);
1581  sl = galloc(scnt*sizeof(struct seqlookup));
1582  for ( k=0; k<scnt; ++k ) {
1583  sl[k].seq = getushort(ttf);
1584  if ( sl[k].seq >= gcnt && !warned2 ) {
1585  LogError( _("Attempt to apply a lookup to a location out of the range of this contextual\n lookup seq=%d, max=%d\n"),
1586  sl[k].seq, gcnt-1 );
1587  info->bad_ot = true;
1588  warned2 = true;
1589  }
1590  sl[k].lookup = (void *) (intpt) getushort(ttf);
1591  }
1592 
1593  if ( justinuse==git_justinuse ) {
1594  /* Nothing to do. This lookup doesn't really reference any glyphs */
1595  /* any lookups it invokes will be processed on their own */
1596  } else {
1597  fpst = chunkalloc(sizeof(FPST));
1598  fpst->type = gpos ? pst_contextpos : pst_contextsub;
1599  fpst->format = pst_coverage;
1600  fpst->subtable = subtable;
1601  subtable->fpst = fpst;
1602  fpst->next = info->possub;
1603  info->possub = fpst;
1604 
1605  fpst->rules = rule = gcalloc(1,sizeof(struct fpst_rule));
1606  fpst->rule_cnt = 1;
1607  rule->u.coverage.ncnt = gcnt;
1608  rule->u.coverage.ncovers = galloc(gcnt*sizeof(char **));
1609  for ( i=0; i<gcnt; ++i ) {
1610  glyphs = getCoverageTable(ttf,stoffset+coverage[i],info);
1611  rule->u.coverage.ncovers[i] = GlyphsToNames(info,glyphs,true);
1612  free(glyphs);
1613  }
1614  rule->lookup_cnt = scnt;
1615  rule->lookups = sl;
1616  for ( k=0; k<scnt; ++k )
1617  ProcessSubLookups(ttf,info,gpos,alllooks,&sl[k]);
1618  }
1619 
1620  free(coverage);
1621 }
1622 
1623 static void g___ChainingSubTable3(FILE *ttf, int stoffset,
1624  struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable, int justinuse,
1625  struct lookup *alllooks, int gpos) {
1626  int i, k, scnt, gcnt, bcnt, fcnt;
1627  uint16 *coverage, *bcoverage, *fcoverage;
1628  struct seqlookup *sl;
1629  uint16 *glyphs;
1630  FPST *fpst;
1631  struct fpst_rule *rule;
1632  int warned2 = false;
1633  (void)l; /* for -Wall */
1634  bcnt = getushort(ttf);
1635  if ( feof(ttf)) {
1636  LogError( _("End of file in context chaining subtable.\n") );
1637  info->bad_ot = true;
1638 return;
1639  }
1640  bcoverage = galloc(bcnt*sizeof(uint16));
1641  for ( i=0; i<bcnt; ++i )
1642  bcoverage[i] = getushort(ttf);
1643  gcnt = getushort(ttf);
1644  if ( feof(ttf)) {
1645  LogError( _("End of file in context chaining subtable.\n") );
1646  info->bad_ot = true;
1647 return;
1648  }
1649  coverage = galloc(gcnt*sizeof(uint16));
1650  for ( i=0; i<gcnt; ++i )
1651  coverage[i] = getushort(ttf);
1652  fcnt = getushort(ttf);
1653  if ( feof(ttf)) {
1654  LogError( _("End of file in context chaining subtable.\n") );
1655  info->bad_ot = true;
1656 return;
1657  }
1658  fcoverage = galloc(fcnt*sizeof(uint16));
1659  for ( i=0; i<fcnt; ++i )
1660  fcoverage[i] = getushort(ttf);
1661  scnt = getushort(ttf);
1662  if ( feof(ttf)) {
1663  LogError( _("End of file in context chaining subtable.\n") );
1664  info->bad_ot = true;
1665 return;
1666  }
1667  sl = galloc(scnt*sizeof(struct seqlookup));
1668  for ( k=0; k<scnt; ++k ) {
1669  sl[k].seq = getushort(ttf);
1670  if ( sl[k].seq >= gcnt && !warned2 ) {
1671  LogError( _("Attempt to apply a lookup to a location out of the range of this contextual\n lookup seq=%d, max=%d\n"),
1672  sl[k].seq, gcnt-1 );
1673  info->bad_ot = true;
1674  warned2 = true;
1675  }
1676  sl[k].lookup = (void *) (intpt) getushort(ttf);
1677  }
1678 
1679  if ( justinuse==git_justinuse ) {
1680  /* Nothing to do. This lookup doesn't really reference any glyphs */
1681  /* any lookups it invokes will be processed on their own */
1682  } else {
1683  fpst = chunkalloc(sizeof(FPST));
1684  fpst->type = gpos ? pst_chainpos : pst_chainsub;
1685  fpst->format = pst_coverage;
1686  fpst->subtable = subtable;
1687  subtable->fpst = fpst;
1688  fpst->next = info->possub;
1689  info->possub = fpst;
1690 
1691  fpst->rules = rule = gcalloc(1,sizeof(struct fpst_rule));
1692  fpst->rule_cnt = 1;
1693 
1694  rule->u.coverage.bcnt = bcnt;
1695  rule->u.coverage.bcovers = galloc(bcnt*sizeof(char **));
1696  for ( i=0; i<bcnt; ++i ) {
1697  glyphs = getCoverageTable(ttf,stoffset+bcoverage[i],info);
1698  rule->u.coverage.bcovers[i] = GlyphsToNames(info,glyphs,true);
1699  free(glyphs);
1700  }
1701 
1702  rule->u.coverage.ncnt = gcnt;
1703  rule->u.coverage.ncovers = galloc(gcnt*sizeof(char **));
1704  for ( i=0; i<gcnt; ++i ) {
1705  glyphs = getCoverageTable(ttf,stoffset+coverage[i],info);
1706  rule->u.coverage.ncovers[i] = GlyphsToNames(info,glyphs,true);
1707  free(glyphs);
1708  }
1709 
1710  rule->u.coverage.fcnt = fcnt;
1711  rule->u.coverage.fcovers = galloc(fcnt*sizeof(char **));
1712  for ( i=0; i<fcnt; ++i ) {
1713  glyphs = getCoverageTable(ttf,stoffset+fcoverage[i],info);
1714  rule->u.coverage.fcovers[i] = GlyphsToNames(info,glyphs,true);
1715  free(glyphs);
1716  }
1717 
1718  rule->lookup_cnt = scnt;
1719  rule->lookups = sl;
1720  for ( k=0; k<scnt; ++k )
1721  ProcessSubLookups(ttf,info,gpos,alllooks,&sl[k]);
1722  }
1723 
1724  free(bcoverage);
1725  free(coverage);
1726  free(fcoverage);
1727 }
1728 
1729 static void gposContextSubTable(FILE *ttf, int stoffset,
1730  struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable,
1731  struct lookup *alllooks) {
1732  switch( getushort(ttf)) {
1733  case 1:
1734  g___ContextSubTable1(ttf,stoffset,info,l,subtable,git_normal,alllooks,true);
1735  break;
1736  case 2:
1737  g___ContextSubTable2(ttf,stoffset,info,l,subtable,git_normal,alllooks,true);
1738  break;
1739  case 3:
1740  g___ContextSubTable3(ttf,stoffset,info,l,subtable,git_normal,alllooks,true);
1741  break;
1742  }
1743 }
1744 
1745 static void gposChainingSubTable(FILE *ttf, int stoffset,
1746  struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable,
1747  struct lookup *alllooks) {
1748  switch( getushort(ttf)) {
1749  case 1:
1750  g___ChainingSubTable1(ttf,stoffset,info,l,subtable,git_normal,alllooks,true);
1751  break;
1752  case 2:
1753  g___ChainingSubTable2(ttf,stoffset,info,l,subtable,git_normal,alllooks,true);
1754  break;
1755  case 3:
1756  g___ChainingSubTable3(ttf,stoffset,info,l,subtable,git_normal,alllooks,true);
1757  break;
1758  }
1759 }
1760 
1761 static struct { uint32 tag; char *str; } tagstr[] = {
1762  { CHR('v','r','t','2'), "vert" },
1763  { CHR('s','m','c','p'), "sc" },
1764  { CHR('s','m','c','p'), "small" },
1765  { CHR('o','n','u','m'), "oldstyle" },
1766  { CHR('s','u','p','s'), "superior" },
1767  { CHR('s','u','b','s'), "inferior" },
1768  { CHR('s','w','s','h'), "swash" },
1769  { 0, NULL }
1770 };
1771 
1772 
1773 static void gsubSimpleSubTable(FILE *ttf, int stoffset, struct ttfinfo *info,
1774  struct lookup *l, struct lookup_subtable *subtable, int justinuse) {
1775  int coverage, cnt, i, j, which;
1776  uint16 format;
1777  uint16 *glyphs, *glyph2s=NULL;
1778  int delta=0;
1779 
1780  format=getushort(ttf);
1781  if ( format!=1 && format!=2 ) /* Unknown subtable format */
1782 return;
1783  coverage = getushort(ttf);
1784  if ( format==1 ) {
1785  delta = getushort(ttf);
1786  } else {
1787  cnt = getushort(ttf);
1788  glyph2s = galloc(cnt*sizeof(uint16));
1789  for ( i=0; i<cnt; ++i )
1790  glyph2s[i] = getushort(ttf);
1791  /* in range check comes later */
1792  }
1793  glyphs = getCoverageTable(ttf,stoffset+coverage,info);
1794  if ( glyphs==NULL ) {
1795  free(glyph2s);
1796 return;
1797  }
1798  if ( justinuse==git_findnames ) {
1800  fl = l->otlookup->features;
1801  /* Unnamed glyphs get a name built of the base name and the feature tag */
1802  /* assuming this lookup is tagged with a feature... */
1803  if ( fl!=NULL )
1804  for ( i=0; glyphs[i]!=0xffff; ++i ) if ( glyphs[i]<info->glyph_cnt ) {
1805  if ( info->chars[glyphs[i]]->name!=NULL ) {
1806  which = format==1 ? (uint16) (glyphs[i]+delta) : glyph2s[i];
1807  if ( which<info->glyph_cnt && which>=0 && info->chars[which]!=NULL &&
1808  info->chars[which]->name==NULL ) {
1809  char *basename = info->chars[glyphs[i]]->name;
1810  char *str;
1811  char tag[5], *pt=tag;
1812  for ( j=0; tagstr[j].tag!=0 && tagstr[j].tag!=fl->featuretag; ++j );
1813  if ( tagstr[j].tag!=0 )
1814  pt = tagstr[j].str;
1815  else {
1816  tag[0] = fl->featuretag>>24;
1817  if ( (tag[1] = (fl->featuretag>>16)&0xff)==' ' ) tag[1] = '\0';
1818  if ( (tag[2] = (fl->featuretag>>8)&0xff)==' ' ) tag[2] = '\0';
1819  if ( (tag[3] = (fl->featuretag)&0xff)==' ' ) tag[3] = '\0';
1820  tag[4] = '\0';
1821  pt = tag;
1822  }
1823  str = galloc(strlen(basename)+strlen(pt)+2);
1824  sprintf(str,"%s.%s", basename, pt );
1825  info->chars[which]->name = str;
1826  }
1827  }
1828  }
1829  } else if ( justinuse==git_justinuse ) {
1830  for ( i=0; glyphs[i]!=0xffff; ++i ) if ( glyphs[i]<info->glyph_cnt ) {
1831  info->inuse[glyphs[i]]= true;
1832  which = format==1 ? (uint16) (glyphs[i]+delta) : glyph2s[i];
1833  info->inuse[which]= true;
1834  }
1835  } else if ( justinuse==git_normal ) {
1836  for ( i=0; glyphs[i]!=0xffff; ++i ) if ( glyphs[i]<info->glyph_cnt && info->chars[glyphs[i]]!=NULL ) {
1837  which = format==1 ? (uint16) (glyphs[i]+delta) : glyph2s[i];
1838  if ( which>=info->glyph_cnt ) {
1839  LogError( _("Bad substitution glyph: GID %d not less than %d\n"),
1840  which, info->glyph_cnt);
1841  info->bad_ot = true;
1842  which = 0;
1843  }
1844  if ( info->chars[which]!=NULL ) { /* Might be in a ttc file */
1845  PST *pos = chunkalloc(sizeof(PST));
1846  pos->type = pst_substitution;
1847  pos->subtable = subtable;
1848  pos->next = info->chars[glyphs[i]]->possub;
1849  info->chars[glyphs[i]]->possub = pos;
1850  pos->u.subs.variant = copy(info->chars[which]->name);
1851  }
1852  }
1853  }
1854  subtable->per_glyph_pst_or_kern = true;
1855  free(glyph2s);
1856  free(glyphs);
1857 }
1858 
1859 /* Multiple and alternate substitution lookups have the same format */
1860 static void gsubMultipleSubTable(FILE *ttf, int stoffset, struct ttfinfo *info,
1861  struct lookup *l, struct lookup_subtable *subtable, int justinuse) {
1862  int coverage, cnt, i, j, len, max;
1863  uint16 format;
1864  uint16 *offsets;
1865  uint16 *glyphs, *glyph2s;
1866  char *pt;
1867  int bad;
1868  int badcnt = 0;
1869 
1870  if ( justinuse==git_findnames )
1871 return;
1872 
1873  format=getushort(ttf);
1874  if ( format!=1 ) /* Unknown subtable format */
1875 return;
1876  coverage = getushort(ttf);
1877  cnt = getushort(ttf);
1878  if ( feof(ttf)) {
1879  LogError( _("Unexpected end of file in GSUB sub-table.\n"));
1880  info->bad_ot = true;
1881 return;
1882  }
1883  offsets = galloc(cnt*sizeof(uint16));
1884  for ( i=0; i<cnt; ++i )
1885  offsets[i] = getushort(ttf);
1886  glyphs = getCoverageTable(ttf,stoffset+coverage,info);
1887  if ( glyphs==NULL ) {
1888  free(offsets);
1889 return;
1890  }
1891  for ( i=0; glyphs[i]!=0xffff; ++i );
1892  if ( i!=cnt ) {
1893  LogError( _("Coverage table specifies a different number of glyphs than the sub-table expects.\n" ));
1894  info->bad_ot = true;
1895  if ( cnt<i )
1896  glyphs[cnt] = 0xffff;
1897  else
1898  cnt = i;
1899  }
1900  max = 20;
1901  glyph2s = galloc(max*sizeof(uint16));
1902  for ( i=0; glyphs[i]!=0xffff; ++i ) {
1903  PST *alt;
1904  fseek(ttf,stoffset+offsets[i],SEEK_SET);
1905  cnt = getushort(ttf);
1906  if ( feof(ttf)) {
1907  LogError( _("Unexpected end of file in GSUB sub-table.\n"));
1908  info->bad_ot = true;
1909 return;
1910  }
1911  if ( cnt>max ) {
1912  max = cnt+30;
1913  glyph2s = grealloc(glyph2s,max*sizeof(uint16));
1914  }
1915  len = 0; bad = false;
1916  for ( j=0; j<cnt; ++j ) {
1917  glyph2s[j] = getushort(ttf);
1918  if ( feof(ttf)) {
1919  LogError( _("Unexpected end of file in GSUB sub-table.\n" ));
1920  info->bad_ot = true;
1921 return;
1922  }
1923  if ( glyph2s[j]>=info->glyph_cnt ) {
1924  if ( !justinuse )
1925  LogError( _("Bad Multiple/Alternate substitution glyph. GID %d not less than %d\n"),
1926  glyph2s[j], info->glyph_cnt );
1927  info->bad_ot = true;
1928  if ( ++badcnt>20 )
1929 return;
1930  glyph2s[j] = 0;
1931  }
1932  if ( justinuse==git_justinuse )
1933  /* Do Nothing */;
1934  else if ( info->chars[glyph2s[j]]==NULL )
1935  bad = true;
1936  else
1937  len += strlen( info->chars[glyph2s[j]]->name) +1;
1938  }
1939  if ( justinuse==git_justinuse ) {
1940  info->inuse[glyphs[i]] = 1;
1941  for ( j=0; j<cnt; ++j )
1942  info->inuse[glyph2s[j]] = 1;
1943  } else if ( info->chars[glyphs[i]]!=NULL && !bad ) {
1944  alt = chunkalloc(sizeof(PST));
1945  alt->type = l->otlookup->lookup_type==gsub_multiple?pst_multiple:pst_alternate;
1946  alt->subtable = subtable;
1947  alt->next = info->chars[glyphs[i]]->possub;
1948  info->chars[glyphs[i]]->possub = alt;
1949  pt = alt->u.subs.variant = galloc(len+1);
1950  *pt = '\0';
1951  for ( j=0; j<cnt; ++j ) {
1952  strcat(pt,info->chars[glyph2s[j]]->name);
1953  strcat(pt," ");
1954  }
1955  if ( *pt!='\0' && pt[strlen(pt)-1]==' ' )
1956  pt[strlen(pt)-1] = '\0';
1957  }
1958  }
1959  subtable->per_glyph_pst_or_kern = true;
1960  free(glyphs);
1961  free(glyph2s);
1962  free(offsets);
1963 }
1964 
1965 static void gsubLigatureSubTable(FILE *ttf, int stoffset,
1966  struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable, int justinuse) {
1967  int coverage, cnt, i, j, k, lig_cnt, cc, len;
1968  uint16 *ls_offsets, *lig_offsets;
1969  uint16 *glyphs, *lig_glyphs, lig;
1970  char *pt;
1971  PST *liga;
1972 
1973  /* Format = */ getushort(ttf);
1974  coverage = getushort(ttf);
1975  cnt = getushort(ttf);
1976  if ( feof(ttf)) {
1977  LogError( _("Unexpected end of file in GSUB ligature sub-table.\n" ));
1978  info->bad_ot = true;
1979 return;
1980  }
1981  ls_offsets = galloc(cnt*sizeof(uint16));
1982  for ( i=0; i<cnt; ++i )
1983  ls_offsets[i]=getushort(ttf);
1984  glyphs = getCoverageTable(ttf,stoffset+coverage,info);
1985  if ( glyphs==NULL )
1986 return;
1987  for ( i=0; i<cnt; ++i ) {
1988  fseek(ttf,stoffset+ls_offsets[i],SEEK_SET);
1989  lig_cnt = getushort(ttf);
1990  if ( feof(ttf)) {
1991  LogError( _("Unexpected end of file in GSUB ligature sub-table.\n" ));
1992  info->bad_ot = true;
1993 return;
1994  }
1995  lig_offsets = galloc(lig_cnt*sizeof(uint16));
1996  for ( j=0; j<lig_cnt; ++j )
1997  lig_offsets[j] = getushort(ttf);
1998  if ( feof(ttf)) {
1999  LogError( _("Unexpected end of file in GSUB ligature sub-table.\n" ));
2000  info->bad_ot = true;
2001 return;
2002  }
2003  for ( j=0; j<lig_cnt; ++j ) {
2004  fseek(ttf,stoffset+ls_offsets[i]+lig_offsets[j],SEEK_SET);
2005  lig = getushort(ttf);
2006  if ( lig>=info->glyph_cnt ) {
2007  LogError( _("Bad ligature glyph. GID %d not less than %d\n"),
2008  lig, info->glyph_cnt );
2009  info->bad_ot = true;
2010  lig = 0;
2011  }
2012  cc = getushort(ttf);
2013  if ( cc<0 || cc>100 ) {
2014  LogError( _("Unlikely count of ligature components (%d), I suspect this ligature sub-\n table is garbage, I'm giving up on it.\n"), cc );
2015  info->bad_ot = true;
2016  free(glyphs); free(lig_offsets);
2017 return;
2018  }
2019  lig_glyphs = galloc(cc*sizeof(uint16));
2020  lig_glyphs[0] = glyphs[i];
2021  for ( k=1; k<cc; ++k ) {
2022  lig_glyphs[k] = getushort(ttf);
2023  if ( lig_glyphs[k]>=info->glyph_cnt ) {
2024  if ( justinuse==git_normal )
2025  LogError( _("Bad ligature component glyph. GID %d not less than %d (in ligature %d)\n"),
2026  lig_glyphs[k], info->glyph_cnt, lig );
2027  info->bad_ot = true;
2028  lig_glyphs[k] = 0;
2029  }
2030  }
2031  if ( justinuse==git_justinuse ) {
2032  info->inuse[lig] = 1;
2033  for ( k=0; k<cc; ++k )
2034  info->inuse[lig_glyphs[k]] = 1;
2035  } else if ( justinuse==git_findnames ) {
2036  FeatureScriptLangList *fl = l->otlookup->features;
2037  /* If our ligature glyph has no name (and its components do) */
2038  /* give it a name by concatenating components with underscores */
2039  /* between them, and appending the tag */
2040  if ( fl!=NULL && info->chars[lig]!=NULL && info->chars[lig]->name==NULL ) {
2041  int len=0;
2042  for ( k=0; k<cc; ++k ) {
2043  if ( info->chars[lig_glyphs[k]]==NULL || info->chars[lig_glyphs[k]]->name==NULL )
2044  break;
2045  len += strlen(info->chars[lig_glyphs[k]]->name)+1;
2046  }
2047  if ( k==cc ) {
2048  char *str = galloc(len+6), *pt;
2049  char tag[5];
2050  tag[0] = fl->featuretag>>24;
2051  if ( (tag[1] = (fl->featuretag>>16)&0xff)==' ' ) tag[1] = '\0';
2052  if ( (tag[2] = (fl->featuretag>>8)&0xff)==' ' ) tag[2] = '\0';
2053  if ( (tag[3] = (fl->featuretag)&0xff)==' ' ) tag[3] = '\0';
2054  tag[4] = '\0';
2055  *str='\0';
2056  for ( k=0; k<cc; ++k ) {
2057  strcat(str,info->chars[lig_glyphs[k]]->name);
2058  strcat(str,"_");
2059  }
2060  pt = str+strlen(str);
2061  pt[-1] = '.';
2062  strcpy(pt,tag);
2063  info->chars[lig]->name = str;
2064  }
2065  }
2066  } else if ( info->chars[lig]!=NULL ) {
2067  for ( k=len=0; k<cc; ++k )
2068  if ( lig_glyphs[k]<info->glyph_cnt &&
2069  info->chars[lig_glyphs[k]]!=NULL )
2070  len += strlen(info->chars[lig_glyphs[k]]->name)+1;
2071  liga = chunkalloc(sizeof(PST));
2072  liga->type = pst_ligature;
2073  liga->subtable = subtable;
2074  liga->next = info->chars[lig]->possub;
2075  info->chars[lig]->possub = liga;
2076  liga->u.lig.lig = info->chars[lig];
2077  liga->u.lig.components = pt = galloc(len);
2078  for ( k=0; k<cc; ++k ) {
2079  if ( lig_glyphs[k]<info->glyph_cnt &&
2080  info->chars[lig_glyphs[k]]!=NULL ) {
2081  strcpy(pt,info->chars[lig_glyphs[k]]->name);
2082  pt += strlen(pt);
2083  *pt++ = ' ';
2084  }
2085  }
2086  pt[-1] = '\0';
2087  }
2088  free(lig_glyphs);
2089  }
2090  free(lig_offsets);
2091  }
2092  subtable->per_glyph_pst_or_kern = true;
2093  free(ls_offsets); free(glyphs);
2094 }
2095 
2096 static void gsubContextSubTable(FILE *ttf, int stoffset,
2097  struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable, int justinuse,
2098  struct lookup *alllooks) {
2099  if ( justinuse==git_findnames )
2100 return; /* Don't give names to these guys, they might not be unique */
2101  /* ie. because these are context based there is not a one to one */
2102  /* mapping between input glyphs and output glyphs. One input glyph */
2103  /* may go to several output glyphs (depending on context) and so */
2104  /* <input-glyph-name>"."<tag-name> would be used for several glyphs */
2105  switch( getushort(ttf)) {
2106  case 1:
2107  g___ContextSubTable1(ttf,stoffset,info,l,subtable,justinuse,alllooks,false);
2108  break;
2109  case 2:
2110  g___ContextSubTable2(ttf,stoffset,info,l,subtable,justinuse,alllooks,false);
2111  break;
2112  case 3:
2113  g___ContextSubTable3(ttf,stoffset,info,l,subtable,justinuse,alllooks,false);
2114  break;
2115  }
2116 }
2117 
2118 static void gsubChainingSubTable(FILE *ttf, int stoffset,
2119  struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable, int justinuse,
2120  struct lookup *alllooks) {
2121  if ( justinuse==git_findnames )
2122 return; /* Don't give names to these guys, the names might not be unique */
2123  switch( getushort(ttf)) {
2124  case 1:
2125  g___ChainingSubTable1(ttf,stoffset,info,l,subtable,justinuse,alllooks,false);
2126  break;
2127  case 2:
2128  g___ChainingSubTable2(ttf,stoffset,info,l,subtable,justinuse,alllooks,false);
2129  break;
2130  case 3:
2131  g___ChainingSubTable3(ttf,stoffset,info,l,subtable,justinuse,alllooks,false);
2132  break;
2133  }
2134 }
2135 
2136 static void gsubReverseChainSubTable(FILE *ttf, int stoffset,
2137  struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable, int justinuse) {
2138  int scnt, bcnt, fcnt, i;
2139  uint16 coverage, *bcoverage, *fcoverage, *sglyphs, *glyphs;
2140  FPST *fpst;
2141  struct fpst_rule *rule;
2142  (void)l; /* for -Wall */
2143  if ( justinuse==git_findnames )
2144 return; /* Don't give names to these guys, they might not be unique */
2145  if ( getushort(ttf)!=1 )
2146 return; /* Don't understand this format type */
2147 
2148  coverage = getushort(ttf);
2149  bcnt = getushort(ttf);
2150  bcoverage = galloc(bcnt*sizeof(uint16));
2151  for ( i = 0 ; i<bcnt; ++i )
2152  bcoverage[i] = getushort(ttf);
2153  fcnt = getushort(ttf);
2154  fcoverage = galloc(fcnt*sizeof(uint16));
2155  for ( i = 0 ; i<fcnt; ++i )
2156  fcoverage[i] = getushort(ttf);
2157  scnt = getushort(ttf);
2158  sglyphs = galloc((scnt+1)*sizeof(uint16));
2159  for ( i = 0 ; i<scnt; ++i )
2160  if (( sglyphs[i] = getushort(ttf))>=info->glyph_cnt ) {
2161  LogError( _("Bad reverse contextual chaining substitution glyph: %d is not less than %d\n"),
2162  sglyphs[i], info->glyph_cnt );
2163  info->bad_ot = true;
2164  sglyphs[i] = 0;
2165  }
2166  sglyphs[i] = 0xffff;
2167 
2168  if ( justinuse==git_justinuse ) {
2169  for ( i = 0 ; i<scnt; ++i )
2170  info->inuse[sglyphs[i]] = 1;
2171  } else {
2172  fpst = chunkalloc(sizeof(FPST));
2173  fpst->type = pst_reversesub;
2174  fpst->format = pst_reversecoverage;
2175  fpst->subtable = subtable;
2176  fpst->next = info->possub;
2177  info->possub = fpst;
2178  subtable->fpst = fpst;
2179 
2180  fpst->rules = rule = gcalloc(1,sizeof(struct fpst_rule));
2181  fpst->rule_cnt = 1;
2182 
2183  rule->u.rcoverage.always1 = 1;
2184  rule->u.rcoverage.bcnt = bcnt;
2185  rule->u.rcoverage.fcnt = fcnt;
2186  rule->u.rcoverage.ncovers = galloc(sizeof(char *));
2187  rule->u.rcoverage.bcovers = galloc(bcnt*sizeof(char *));
2188  rule->u.rcoverage.fcovers = galloc(fcnt*sizeof(char *));
2189  rule->u.rcoverage.replacements = GlyphsToNames(info,sglyphs,false);
2190  glyphs = getCoverageTable(ttf,stoffset+coverage,info);
2191  rule->u.rcoverage.ncovers[0] = GlyphsToNames(info,glyphs,false);
2192  free(glyphs);
2193  for ( i=0; i<bcnt; ++i ) {
2194  glyphs = getCoverageTable(ttf,stoffset+bcoverage[i],info);
2195  rule->u.rcoverage.bcovers[i] = GlyphsToNames(info,glyphs,true);
2196  free(glyphs);
2197  }
2198  for ( i=0; i<fcnt; ++i ) {
2199  glyphs = getCoverageTable(ttf,stoffset+fcoverage[i],info);
2200  rule->u.rcoverage.fcovers[i] = GlyphsToNames(info,glyphs,true);
2201  free(glyphs);
2202  }
2203  rule->lookup_cnt = 0; /* substitution lookups needed for reverse chaining */
2204  }
2205  free(sglyphs);
2206  free(fcoverage);
2207  free(bcoverage);
2208 }
2209 
2210 static void readttfsizeparameters(FILE *ttf,int32 broken_pos,int32 correct_pos,
2211  struct ttfinfo *info) {
2212  int32 here;
2213  /* Both of the two fonts I've seen that contain a 'size' feature */
2214  /* have multiple features all of which point to the same parameter */
2215  /* area. Odd. */
2216  /* When Adobe first released fonts containing the 'size' feature */
2217  /* they did not follow the spec, and the offset to the size parameters */
2218  /* was relative to the wrong location. They claim (Aug 2006) that */
2219  /* this has been fixed. Be prepared to read either style of 'size' */
2220  /* following the heuristics Adobe provides */
2221  int32 test[2];
2222  int i, nid;
2223 
2224  if ( info->last_size_pos==broken_pos || info->last_size_pos==correct_pos )
2225 return;
2226 
2227  if ( info->last_size_pos!=0 ) {
2228  LogError( _("This font, %s, has multiple GPOS 'size' features. I'm not sure how to interpret that. I shall pick one arbitrarily.\n"),
2229  info->fontname==NULL? _("<Untitled>") : info->fontname );
2230  info->bad_ot = true;
2231 return;
2232  }
2233 
2234  test[0] = correct_pos; test[1] = broken_pos;
2235  here = ftell(ttf);
2236  for ( i=0; i<2; ++i ) {
2237  fseek(ttf,test[i],SEEK_SET);
2238  info->last_size_pos = test[i];
2239  info->design_size = getushort(ttf);
2240  if ( info->design_size==0 )
2241  continue;
2242  info->fontstyle_id = getushort(ttf);
2243  nid = getushort(ttf);
2244  info->design_range_bottom = getushort(ttf);
2245  info->design_range_top = getushort(ttf);
2246  if ( info->fontstyle_id == 0 && nid==0 &&
2247  info->design_range_bottom==0 && info->design_range_top==0 ) {
2248  /* Reasonable spec, only design size provided */
2249  info->fontstyle_name = NULL;
2250  break;
2251  }
2252  if ( info->design_size < info->design_range_bottom ||
2253  info->design_size > info->design_range_top ||
2254  info->design_range_bottom > info->design_range_top ||
2255  nid<256 || nid>32767 )
2256  continue;
2257  info->fontstyle_name = FindAllLangEntries(ttf,info,nid);
2258  if ( info->fontstyle_name==NULL )
2259  continue;
2260  else
2261  break;
2262  }
2263  if ( i==2 ) {
2264  LogError(_("The 'size' feature does not seem to follow the standard,\nnor does it conform to Adobe's early misinterpretation of\nthe standard. I cannot parse it.\n") );
2265  info->bad_ot = true;
2266  info->design_size = info->design_range_bottom = info->design_range_top = info->fontstyle_id = 0;
2267  info->fontstyle_name = NULL;
2268  } else if ( i==1 ) {
2269  LogError(_("The 'size' feature of this font conforms to Adobe's early misinterpretation of the otf standard.\n") );
2270  }
2271  fseek(ttf,here,SEEK_SET);
2272 
2273 #if 0
2274  printf( "pos=%d size=%g, range=(%g,%g] id=%d name=%d\n", pos,
2275  info->design_size/10.0, info->design_range_bottom/10.0, info->design_range_top/10.0,
2276  info->fontstyle_id, info->fontstyle_name );
2277 #endif
2278 }
2279 
2280 static struct scripts *readttfscripts(FILE *ttf,int32 pos, struct ttfinfo *info, int isgpos) {
2281  int i,j,k,cnt;
2282  int deflang, lcnt;
2283  struct scripts *scripts;
2284 
2285  if ( pos>=(int32)info->g_bounds ) {
2286  LogError(_("Attempt to read script data beyond end of %s table"), isgpos ? "GPOS" : "GSUB" );
2287  info->bad_ot = true;
2288 return( NULL );
2289  }
2290  fseek(ttf,pos,SEEK_SET);
2291  cnt = getushort(ttf);
2292  if ( cnt<=0 )
2293 return( NULL );
2294  else if ( cnt>1000 ) {
2295  LogError( _("Too many scripts %d\n"), cnt );
2296  info->bad_ot = true;
2297 return( NULL );
2298  }
2299 
2300  scripts = gcalloc(cnt+1,sizeof(struct scripts));
2301  for ( i=0; i<cnt; ++i ) {
2302  scripts[i].tag = getlong(ttf);
2303  scripts[i].offset = getushort(ttf);
2304  }
2305  for ( i=0; i<cnt; ++i ) {
2306  fseek(ttf,pos+scripts[i].offset,SEEK_SET);
2307  deflang = getushort(ttf);
2308  lcnt = getushort(ttf);
2309  lcnt += (deflang!=0);
2310  scripts[i].langcnt = lcnt;
2311  scripts[i].languages = gcalloc(lcnt+1,sizeof(struct language));
2312  j = 0;
2313  if ( deflang!=0 ) {
2314  scripts[i].languages[0].tag = CHR('d','f','l','t');
2315  scripts[i].languages[0].offset = deflang+scripts[i].offset;
2316  ++j;
2317  }
2318  for ( ; j<lcnt; ++j ) {
2319  scripts[i].languages[j].tag = getlong(ttf);
2321  }
2322  for ( j=0; j<lcnt; ++j ) {
2323  if ( pos+scripts[i].languages[j].offset>=info->g_bounds ) {
2324  LogError(_("Attempt to read script data beyond end of %s table"), isgpos ? "GPOS" : "GSUB" );
2325  info->bad_ot = true;
2326 return( NULL );
2327  }
2329  (void) getushort(ttf); /* lookup ordering table undefined */
2330  scripts[i].languages[j].req = getushort(ttf);
2331  scripts[i].languages[j].fcnt = getushort(ttf);
2332  if ( feof(ttf)) {
2333  LogError(_("End of file when reading scripts in %s table"), isgpos ? "GPOS" : "GSUB" );
2334  info->bad_ot = true;
2335 return( NULL );
2336  }
2338  for ( k=0; k<scripts[i].languages[j].fcnt; ++k )
2339  scripts[i].languages[j].features[k] = getushort(ttf);
2340  }
2341  }
2342 
2343  if ( feof(ttf)) {
2344  LogError(_("End of file in %s table"), isgpos ? "GPOS" : "GSUB" );
2345  info->bad_ot = true;
2346 return( NULL );
2347  }
2348 
2349 return( scripts );
2350 }
2351 
2352 static struct feature *readttffeatures(FILE *ttf,int32 pos,int isgpos, struct ttfinfo *info) {
2353  /* read the features table returning an array containing all interesting */
2354  /* features */
2355  int cnt;
2356  int i,j;
2357  struct feature *features;
2358  int parameters;
2359 
2360  if ( pos>=(int32)info->g_bounds ) {
2361  LogError(_("Attempt to read feature data beyond end of %s table"), isgpos ? "GPOS" : "GSUB" );
2362  info->bad_ot = true;
2363 return( NULL );
2364  }
2365  fseek(ttf,pos,SEEK_SET);
2366  info->feature_cnt = cnt = getushort(ttf);
2367  if ( cnt<=0 )
2368 return( NULL );
2369  else if ( cnt>1000 ) {
2370  LogError( _("Too many features %d\n"), cnt );
2371  info->bad_ot = true;
2372 return( NULL );
2373  }
2374 
2375  features = gcalloc(cnt+1,sizeof(struct feature));
2376  for ( i=0; i<cnt; ++i ) {
2377  features[i].tag = getlong(ttf);
2378  features[i].offset = getushort(ttf);
2379  }
2380 
2381  for ( i=0; i<cnt; ++i ) {
2382  if ( pos+features[i].offset>=info->g_bounds ) {
2383  LogError(_("Attempt to read feature data beyond end of %s table"), isgpos ? "GPOS" : "GSUB" );
2384  info->bad_ot = true;
2385 return( NULL );
2386  }
2388  parameters = getushort(ttf);
2389  if ( features[i].tag==CHR('s','i','z','e') && parameters!=0 && !feof(ttf))
2392  features[i].lcnt = getushort(ttf);
2393  if ( feof(ttf) ) {
2394  LogError(_("End of file when reading features in %s table"), isgpos ? "GPOS" : "GSUB" );
2395  info->bad_ot = true;
2396 return( NULL );
2397  }
2398  features[i].lookups = galloc(features[i].lcnt*sizeof(uint16));
2399  for ( j=0; j<features[i].lcnt; ++j )
2400  features[i].lookups[j] = getushort(ttf);
2401  }
2402 
2403 return( features );
2404 }
2405 
2406 static struct lookup *readttflookups(FILE *ttf,int32 pos, struct ttfinfo *info, int isgpos) {
2407  int cnt,i,j;
2408  struct lookup *lookups;
2410  struct lookup_subtable *st;
2411 
2412  if ( pos>=(int32)info->g_bounds ) {
2413  LogError(_("Attempt to read lookup data beyond end of %s table"), isgpos ? "GPOS" : "GSUB" );
2414  info->bad_ot = true;
2415 return( NULL );
2416  }
2417 
2418  fseek(ttf,pos,SEEK_SET);
2419  info->lookup_cnt = cnt = getushort(ttf);
2420  info->cur_lookups = NULL;
2421  if ( cnt<=0 )
2422 return( NULL );
2423  else if ( cnt>1000 ) {
2424  LogError( _("Too many lookups %d\n"), cnt );
2425  info->bad_ot = true;
2426 return( NULL );
2427  }
2428 
2429  lookups = gcalloc(cnt+1,sizeof(struct lookup));
2430  for ( i=0; i<cnt; ++i )
2431  lookups[i].offset = getushort(ttf);
2432  for ( i=0; i<cnt; ++i ) {
2433  if ( pos+lookups[i].offset>=info->g_bounds ) {
2434  LogError(_("Attempt to read lookup data beyond end of %s table"), isgpos ? "GPOS" : "GSUB" );
2435  info->bad_ot = true;
2436 return( NULL );
2437  }
2438  fseek(ttf,pos+lookups[i].offset,SEEK_SET);
2439  lookups[i].type = getushort(ttf);
2440  lookups[i].flags = getushort(ttf);
2441  lookups[i].subtabcnt = getushort(ttf);
2442  lookups[i].subtab_offsets = galloc(lookups[i].subtabcnt*sizeof(int32));
2443  for ( j=0; j<lookups[i].subtabcnt; ++j )
2444  lookups[i].subtab_offsets[j] = pos+lookups[i].offset+getushort(ttf);
2445 
2446  lookups[i].otlookup = otlookup = chunkalloc(sizeof(OTLookup));
2447  otlookup->lookup_index = i;
2448  if ( last==NULL )
2449  info->cur_lookups = otlookup;
2450  else
2451  last->next = otlookup;
2452  last = otlookup;
2453  otlookup->lookup_type = (isgpos<<8) | lookups[i].type;
2454  otlookup->lookup_flags = lookups[i].flags;
2455  otlookup->lookup_index = i;
2456  if ( feof(ttf) ) {
2457  LogError(_("End of file when reading lookups in %s table"), isgpos ? "GPOS" : "GSUB" );
2458  info->bad_ot = true;
2459 return( NULL );
2460  }
2461  for ( j=0; j<lookups[i].subtabcnt; ++j ) {
2462  st = chunkalloc(sizeof(struct lookup_subtable));
2463  st->next = otlookup->subtables;
2464  st->lookup = otlookup;
2465  otlookup->subtables = st;
2466  }
2467  }
2468  if ( isgpos )
2469  info->gpos_lookups = info->cur_lookups;
2470  else
2471  info->gsub_lookups = info->cur_lookups;
2472 return( lookups );
2473 }
2474 
2475 static void tagLookupsWithFeature(uint32 script_tag,uint32 lang_tag,
2476  int required_feature, struct feature *feature, struct lookup *lookups,
2477  struct ttfinfo *info) {
2478  uint32 feature_tag = required_feature ? REQUIRED_FEATURE : feature->tag;
2479  int i;
2480  OTLookup *otlookup;
2482 
2483  /* The otf docs are ambiguous as to the capitalization of the default */
2484  /* script. The capitalized version is correct (uncapitalized is used for languages) */
2485  if ( script_tag == DEFAULT_LANG )
2486  script_tag = DEFAULT_SCRIPT;
2487 
2488  for ( i=0; i < feature->lcnt; ++i ) {
2489  if ( feature->lookups[i]>=info->lookup_cnt ) {
2490  LogError( _("Lookup out of bounds in feature table.\n") );
2491  info->bad_ot = true;
2492  } else {
2493  otlookup = lookups[feature->lookups[i]].otlookup;
2494  for ( fl = otlookup->features; fl!=NULL && fl->featuretag!=feature_tag; fl=fl->next );
2495  if ( fl==NULL ) {
2496  fl = chunkalloc(sizeof(FeatureScriptLangList));
2497  fl->featuretag = feature_tag;
2498  fl->next = otlookup->features;
2499  otlookup->features = fl;
2500  }
2501  FListAppendScriptLang(fl,script_tag,lang_tag);
2502  }
2503  }
2504 }
2505 
2507  struct feature *features, struct lookup *lookups,struct ttfinfo *info ) {
2508  int i,j;
2509  struct scripts *s;
2510  struct language *lang;
2511  struct lookup *l;
2512 
2513  if ( scripts==NULL || features==NULL )
2514 return; /* Legal, I'd guess, but not very interesting. Perhaps all lookups are controlled by the JSTF table or something */
2515 
2516  /* First tag every lookup with all script, lang, feature combinations that*/
2517  /* invoke it */
2518  for ( s=scripts; s->tag!=0; ++s ) {
2519  for ( lang=s->languages, i=0; i<s->langcnt; ++i, ++lang ) {
2520  if ( lang->req==0xffff )
2521  /* Do Nothing */;
2522  else if ( lang->req>= info->feature_cnt ) {
2523  LogError( _("Required feature out of bounds in script table.\n") );
2524  info->bad_ot = true;
2525  } else
2526  tagLookupsWithFeature(s->tag,lang->tag,true,&features[lang->req],
2527  lookups,info);
2528  for ( j=0; j<lang->fcnt; ++j ) {
2529  if ( lang->features[j]>=info->feature_cnt ) {
2530  LogError( _("Feature out of bounds in script table.\n") );
2531  info->bad_ot = true;
2532  } else
2533  tagLookupsWithFeature(s->tag,lang->tag,false,&features[lang->features[j]],
2534  lookups,info);
2535  }
2536  }
2537  }
2538 
2539  /* The scripts got added backwards so reverse to put them in */
2540  /* alphabetic order again */
2541  for ( l=lookups, i=0; l->offset!=0; ++l, ++i ) {
2542  OTLookup *otl = l->otlookup;
2544  struct scriptlanglist *sl, *next, *prev;
2545  for ( fl=otl->features; fl!=NULL; fl=fl->next ) {
2546  prev = NULL;
2547  for ( sl=fl->scripts; sl!=NULL; sl = next ) {
2548  next = sl->next;
2549  sl->next = prev;
2550  prev = sl;
2551  }
2552  fl->scripts = prev;
2553  }
2554  }
2555 }
2556 
2557 static void gposExtensionSubTable(FILE *ttf, int stoffset,
2558  struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable,
2559  struct lookup *alllooks) {
2560  uint32 base = ftell(ttf), st, offset;
2561  int lu_type;
2562  (void)stoffset; /* for -Wall */
2563  /* Format = */ getushort(ttf);
2564  lu_type = getushort(ttf);
2565  offset = getlong(ttf);
2566 
2567  l->otlookup->lookup_type = 0x100|lu_type;
2568 
2569  fseek(ttf,st = base+offset,SEEK_SET);
2570  switch ( lu_type ) {
2571  case 1:
2572  gposSimplePos(ttf,st,info,l,subtable);
2573  break;
2574  case 2:
2575  gposKernSubTable(ttf,st,info,l,subtable);
2576  break;
2577  case 3:
2578  gposCursiveSubTable(ttf,st,info,l,subtable);
2579  break;
2580  case 4: case 5: case 6:
2581  gposMarkSubTable(ttf,st,info,l,subtable);
2582  break;
2583  case 7:
2584  gposContextSubTable(ttf,st,info,l,subtable,alllooks);
2585  break;
2586  case 8:
2587  gposChainingSubTable(ttf,st,info,l,subtable,alllooks);
2588  break;
2589  case 9:
2590  LogError( _("This font is erroneous: it has a GPOS extension subtable that points to\nanother extension sub-table.\n") );
2591  info->bad_ot = true;
2592  break;
2593 /* Any cases added here also need to go in the gposLookupSwitch */
2594  default:
2595  LogError( _("Unknown GPOS sub-table type: %d\n"), lu_type );
2596  info->bad_ot = true;
2597  break;
2598  }
2599  if ( ftell(ttf)>info->gpos_start+info->gpos_length ) {
2600  LogError( _("Subtable extends beyond end of GPOS table\n") );
2601  info->bad_ot = true;
2602  }
2603 }
2604 
2605 static void gsubExtensionSubTable(FILE *ttf, int stoffset,
2606  struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable, int justinuse,
2607  struct lookup *alllooks) {
2608  uint32 base = ftell(ttf), st, offset;
2609  int lu_type;
2610  (void)stoffset; /* for -Wall */
2611  /* Format = */ getushort(ttf);
2612  lu_type = getushort(ttf);
2613  offset = getlong(ttf);
2614 
2615  l->otlookup->lookup_type = lu_type;
2616 
2617  fseek(ttf,st = base+offset,SEEK_SET);
2618  switch ( lu_type ) {
2619  case 1:
2620  gsubSimpleSubTable(ttf,st,info,l,subtable,justinuse);
2621  break;
2622  case 2: case 3: /* Multiple and alternate have same format, different semantics */
2623  gsubMultipleSubTable(ttf,st,info,l,subtable,justinuse);
2624  break;
2625  case 4:
2626  gsubLigatureSubTable(ttf,st,info,l,subtable,justinuse);
2627  break;
2628  case 5:
2629  gsubContextSubTable(ttf,st,info,l,subtable,justinuse,alllooks);
2630  break;
2631  case 6:
2632  gsubChainingSubTable(ttf,st,info,l,subtable,justinuse,alllooks);
2633  break;
2634  case 7:
2635  LogError( _("This font is erroneous: it has a GSUB extension subtable that points to\nanother extension sub-table.\n") );
2636  info->bad_ot = true;
2637  break;
2638  case 8:
2639  gsubReverseChainSubTable(ttf,st,info,l,subtable,justinuse);
2640  break;
2641 /* Any cases added here also need to go in the gsubLookupSwitch */
2642  default:
2643  LogError( _("Unknown GSUB sub-table type: %d\n"), lu_type );
2644  info->bad_ot = true;
2645  break;
2646  }
2647  if ( ftell(ttf)>info->gsub_start+info->gsub_length ) {
2648  LogError( _("Subtable extends beyond end of GSUB table\n") );
2649  info->bad_ot = true;
2650  }
2651 }
2652 
2653 static void gposLookupSwitch(FILE *ttf, int st,
2654  struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable,
2655  struct lookup *alllooks) {
2656 
2657  switch ( l->type | 0x100 ) {
2658  case gpos_single:
2659  gposSimplePos(ttf,st,info,l,subtable);
2660  break;
2661  case gpos_pair:
2662  gposKernSubTable(ttf,st,info,l,subtable);
2663  break;
2664  case gpos_cursive:
2665  gposCursiveSubTable(ttf,st,info,l,subtable);
2666  break;
2668  gposMarkSubTable(ttf,st,info,l,subtable);
2669  break;
2670  case gpos_context:
2671  gposContextSubTable(ttf,st,info,l,subtable,alllooks);
2672  break;
2673  case gpos_contextchain:
2674  gposChainingSubTable(ttf,st,info,l,subtable,alllooks);
2675  break;
2676  case 0x109:
2677  gposExtensionSubTable(ttf,st,info,l,subtable,alllooks);
2678  break;
2679 /* Any cases added here also need to go in the gposExtensionSubTable */
2680  default:
2681  LogError( _("Unknown GPOS sub-table type: %d\n"), l->otlookup->lookup_type );
2682  info->bad_ot = true;
2683  break;
2684  }
2685  if ( ftell(ttf)>info->gpos_start+info->gpos_length ) {
2686  LogError( _("Subtable extends beyond end of GPOS table\n") );
2687  info->bad_ot = true;
2688  }
2689 }
2690 
2691 static void gsubLookupSwitch(FILE *ttf, int st,
2692  struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable, int justinuse,
2693  struct lookup *alllooks) {
2694 
2695  switch ( l->type ) {
2696  case gsub_single:
2697  gsubSimpleSubTable(ttf,st,info,l,subtable,justinuse);
2698  break;
2699  case gsub_multiple: case gsub_alternate: /* Multiple and alternate have same format, different semantics */
2700  gsubMultipleSubTable(ttf,st,info,l,subtable,justinuse);
2701  break;
2702  case gsub_ligature:
2703  gsubLigatureSubTable(ttf,st,info,l,subtable,justinuse);
2704  break;
2705  case gsub_context:
2706  gsubContextSubTable(ttf,st,info,l,subtable,justinuse,alllooks);
2707  break;
2708  case gsub_contextchain:
2709  gsubChainingSubTable(ttf,st,info,l,subtable,justinuse,alllooks);
2710  break;
2711  case 7:
2712  gsubExtensionSubTable(ttf,st,info,l,subtable,justinuse,alllooks);
2713  break;
2714  case gsub_reversecchain:
2715  gsubReverseChainSubTable(ttf,st,info,l,subtable,justinuse);
2716  break;
2717 /* Any cases added here also need to go in the gsubExtensionSubTable */
2718  default:
2719  LogError( _("Unknown GSUB sub-table type: %d\n"), l->otlookup->lookup_type );
2720  info->bad_ot = true;
2721  break;
2722  }
2723  if ( ftell(ttf)>info->g_bounds ) {
2724  LogError( _("Subtable extends beyond end of GSUB table\n" ));
2725  info->bad_ot = true;
2726  }
2727 }
2728 
2729 static void ScriptsFree(struct scripts *scripts) {
2730  int i,j;
2731 
2732  if ( scripts==NULL )
2733 return;
2734  for ( i=0; scripts[i].offset!=0 ; ++i ) {
2735  for ( j=0; j<scripts[i].langcnt; ++j )
2737  free(scripts[i].languages);
2738  }
2739  free(scripts);
2740 }
2741 
2742 static void FeaturesFree(struct feature *features) {
2743  int i;
2744 
2745  if ( features==NULL )
2746 return;
2747  for ( i=0; features[i].offset!=0 ; ++i )
2748  free(features[i].lookups);
2749  free(features);
2750 }
2751 
2752 static void LookupsFree(struct lookup *lookups) {
2753  int i;
2754 
2755  for ( i=0; lookups[i].offset!=0 ; ++i ) {
2756  free( lookups[i].subtab_offsets );
2757  }
2758  free(lookups);
2759 }
2760 
2761 static void ProcessGPOSGSUB(FILE *ttf,struct ttfinfo *info,int gpos,int inusetype) {
2762  int k;
2763  int32 base, lookup_start, st;
2764  int32 script_off, feature_off;
2765  struct scripts *scripts;
2766  struct feature *features;
2767  struct lookup *lookups, *l;
2768  struct lookup_subtable *subtable;
2769 
2770  if ( gpos ) {
2771  base = info->gpos_start;
2772  info->g_bounds = base + info->gpos_length;
2773  } else {
2774  base = info->gsub_start;
2775  info->g_bounds = base + info->gsub_length;
2776  }
2777  fseek(ttf,base,SEEK_SET);
2778  /* version = */ getlong(ttf);
2779  script_off = getushort(ttf);
2780  feature_off = getushort(ttf);
2781  lookup_start = base+getushort(ttf);
2782 
2783  scripts = readttfscripts(ttf,base+script_off,info,gpos);
2784  features = readttffeatures(ttf,base+feature_off,gpos,info);
2785  /* It is legal to have lookups with no features or scripts */
2786  /* For example if all the lookups were controlled by the JSTF table */
2787  lookups = readttflookups(ttf,lookup_start,info,gpos);
2788  if ( lookups==NULL ) {
2791 return;
2792  }
2796 
2797  for ( l = lookups; l->offset!=0; ++l ) {
2798  for ( k=0, subtable=l->otlookup->subtables; k<l->subtabcnt; ++k, subtable=subtable->next ) {
2799  st = l->subtab_offsets[k];
2800  fseek(ttf,st,SEEK_SET);
2801  if ( gpos ) {
2802  gposLookupSwitch(ttf,st,info,l,subtable,lookups);
2803  } else {
2804  gsubLookupSwitch(ttf,st,info,l,subtable,inusetype,lookups);
2805  }
2806  }
2807  }
2808 
2809  /* Then generate some user-friendly names for the all the lookups */
2810  if ( inusetype==git_normal )
2811  for ( l=lookups; l->offset!=0; ++l )
2812  NameOTLookup(l->otlookup,NULL);
2813 
2814  LookupsFree(lookups);
2815  if ( inusetype!=git_normal && !gpos ) {
2816  OTLookupListFree(info->gsub_lookups);
2817  info->gsub_lookups = info->cur_lookups = NULL;
2818  }
2819 }
2820 
2821 void readttfgsubUsed(FILE *ttf,struct ttfinfo *info) {
2822  ProcessGPOSGSUB(ttf,info,false,git_justinuse);
2823  info->g_bounds = 0;
2824 }
2825 
2826 void GuessNamesFromGSUB(FILE *ttf,struct ttfinfo *info) {
2827  ProcessGPOSGSUB(ttf,info,false,git_findnames);
2828  info->g_bounds = 0;
2829 }
2830 
2831 void readttfgpossub(FILE *ttf,struct ttfinfo *info,int gpos) {
2832  ProcessGPOSGSUB(ttf,info,gpos,git_normal);
2833  info->g_bounds = 0;
2834 }
2835 
2836 void readttfgdef(FILE *ttf,struct ttfinfo *info) {
2837  int lclo, gclass, mac;
2838  int coverage, cnt, i,j, format;
2839  uint16 *glyphs, *lc_offsets, *offsets;
2840  uint32 caret_base;
2841  uint32 version;
2842  PST *pst;
2843  SplineChar *sc;
2844 
2845  fseek(ttf,info->gdef_start,SEEK_SET);
2846 
2847  version = getlong(ttf) ;
2848  if (version != 0x00010000 && version != 0x00010002)
2849  return;
2850 
2851  info->g_bounds = info->gdef_start + info->gdef_length;
2852  gclass = getushort(ttf);
2853  /* attach list = */ getushort(ttf);
2854  lclo = getushort(ttf); /* ligature caret list */
2855  mac = getushort(ttf); /* mark attach class */
2856 
2857  if (version == 0x00010002)
2858  getushort(ttf); /* class defs */
2859 
2860  if ( gclass!=0 ) {
2861  uint16 *gclasses = getClassDefTable(ttf,info->gdef_start+gclass, info);
2862  for ( i=0; i<info->glyph_cnt; ++i )
2863  if ( info->chars[i]!=NULL && gclasses[i]!=0 )
2864  info->chars[i]->glyph_class = gclasses[i]+1;
2865  free(gclasses);
2866  }
2867 
2868  if ( mac!=0 ) {
2869  uint16 *mclasses = getClassDefTable(ttf,info->gdef_start+mac, info);
2870  const char *format_spec = _("MarkClass-%d");
2871  info->mark_class_cnt = ClassFindCnt(mclasses,info->glyph_cnt);
2872  info->mark_classes = ClassToNames(info,info->mark_class_cnt,mclasses,info->glyph_cnt);
2873  info->mark_class_names = galloc(info->mark_class_cnt*sizeof(char *));
2874  info->mark_class_names[0] = NULL;
2875  for ( i=1; i<info->mark_class_cnt; ++i ) {
2876  info->mark_class_names[i] = galloc((strlen(format_spec)+10));
2877  sprintf( info->mark_class_names[i], format_spec, i );
2878  }
2879  free(mclasses);
2880  }
2881 
2882  if ( lclo!=0 ) {
2883  lclo += info->gdef_start;
2884  fseek(ttf,lclo,SEEK_SET);
2885  coverage = getushort(ttf);
2886  cnt = getushort(ttf);
2887  if ( cnt==0 )
2888 return;
2889  lc_offsets = galloc(cnt*sizeof(uint16));
2890  for ( i=0; i<cnt; ++i )
2891  lc_offsets[i]=getushort(ttf);
2892  glyphs = getCoverageTable(ttf,lclo+coverage,info);
2893  if ( glyphs==NULL )
2894 return;
2895  for ( i=0; i<cnt; ++i ) if ( glyphs[i]<info->glyph_cnt ) {
2896  fseek(ttf,lclo+lc_offsets[i],SEEK_SET);
2897  sc = info->chars[glyphs[i]];
2898  for ( pst=sc->possub; pst!=NULL && pst->type!=pst_lcaret; pst=pst->next );
2899  if ( pst==NULL ) {
2900  pst = chunkalloc(sizeof(PST));
2901  pst->next = sc->possub;
2902  sc->possub = pst;
2903  pst->type = pst_lcaret;
2904  pst->subtable = NULL;
2905  sc->lig_caret_cnt_fixed = true;
2906  }
2907  caret_base = ftell(ttf);
2908  pst->u.lcaret.cnt = getushort(ttf);
2909  if ( pst->u.lcaret.carets!=NULL ) free(pst->u.lcaret.carets);
2910  offsets = galloc(pst->u.lcaret.cnt*sizeof(uint16));
2911  for ( j=0; j<pst->u.lcaret.cnt; ++j )
2912  offsets[j] = getushort(ttf);
2913  pst->u.lcaret.carets = galloc(pst->u.lcaret.cnt*sizeof(int16));
2914  for ( j=0; j<pst->u.lcaret.cnt; ++j ) {
2915  fseek(ttf,caret_base+offsets[j],SEEK_SET);
2916  format=getushort(ttf);
2917  if ( format==1 ) {
2918  pst->u.lcaret.carets[j] = getushort(ttf);
2919  } else if ( format==2 ) {
2920  pst->u.lcaret.carets[j] = 0;
2921  /* point = */ getushort(ttf);
2922  } else if ( format==3 ) {
2923  pst->u.lcaret.carets[j] = getushort(ttf);
2924  /* in device table = */ getushort(ttf);
2925  } else {
2926  LogError( _("!!!! Unknown caret format %d !!!!\n"), format );
2927  info->bad_ot = true;
2928  }
2929  }
2930  free(offsets);
2931  }
2932  free(lc_offsets);
2933  free(glyphs);
2934  }
2935  info->g_bounds = 0;
2936 }
2937 
2938 static void OTLAppend(struct ttfinfo *info,OTLookup *otl,int gpos) {
2939  OTLookup *prev;
2940  int pos=0;
2941 
2942  if ( gpos && info->gpos_lookups == NULL )
2943  info->gpos_lookups = otl;
2944  else if ( !gpos && info->gsub_lookups == NULL )
2945  info->gsub_lookups = otl;
2946  else {
2947  prev = gpos ? info->gpos_lookups : info->gsub_lookups;
2948  pos = 1;
2949  while ( prev->next!=NULL ) {
2950  prev = prev->next;
2951  ++pos;
2952  }
2953  prev->next = otl;
2954  }
2955  otl->lookup_index = pos;
2956 }
2957 
2958 static void OTLRemove(struct ttfinfo *info,OTLookup *otl,int gpos) {
2959  /* Remove the most recent lookup. We got bad data and can't use it */
2960  OTLookup *prev, **base;
2961 
2962  base = gpos ? &info->gpos_lookups : &info->gsub_lookups;
2963  if ( *base==otl )
2964  *base = NULL;
2965  else if ( *base!=NULL ) {
2966  for ( prev = *base; prev->next!=NULL && prev->next!=otl; prev = prev->next );
2967  prev->next = NULL;
2968  }
2969  OTLookupFree(otl);
2970 }
2971 
2972 static void InfoNameOTLookup(OTLookup *otl,struct ttfinfo *info) {
2973  SplineFont sf;
2974 
2975  memset(&sf,0,sizeof(sf));
2976  NameOTLookup(otl,&sf);
2977 }
2978 
2979 /* Apple's docs imply that kerning info is always provided left to right, even*/
2980 /* for right to left scripts. My guess is that their docs are wrong, as they */
2981 /* often are, but if that be so then we need code in here to reverse */
2982 /* the order of the characters for right to left since pfaedit's convention */
2983 /* is to follow writing order rather than to go left to right */
2984 void readttfkerns(FILE *ttf,struct ttfinfo *info) {
2985  int tabcnt, len, coverage,i,j, npairs, version, format, flags_good, tab;
2986  int left, right, offset, array, rowWidth;
2987  int header_size;
2988  KernPair *kp;
2989  KernClass *kc;
2990  uint32 begin_table;
2991  uint16 *class1, *class2;
2992  int isv;
2993  OTLookup *otl;
2994 
2995  fseek(ttf,info->kern_start,SEEK_SET);
2996  version = getushort(ttf);
2997  tabcnt = getushort(ttf);
2998  if ( version!=0 ) {
2999  LogError(_("Invalid or unsupported version (0x%x) for 'kern' table"), version );
3000  info->bad_gx = true;
3001 return;
3002  }
3003  for ( tab=0; tab<tabcnt; ++tab ) {
3004  begin_table = ftell(ttf);
3005  /* version = */ getushort(ttf);
3006  len = getushort(ttf);
3007  coverage = getushort(ttf);
3008  format = coverage>>8;
3009  flags_good = ((coverage&7)<=1);
3010  isv = !(coverage&1);
3011  header_size = 6;
3012  otl = NULL;
3013  if ( flags_good ) {
3014  otl = chunkalloc(sizeof(OTLookup));
3015  otl->lookup_type = gpos_pair;
3016  otl->subtables = chunkalloc(sizeof(struct lookup_subtable));
3017  otl->subtables->lookup = otl;
3018  otl->subtables->per_glyph_pst_or_kern = true;
3019  otl->subtables->vertical_kerning = isv;
3020  otl->features = chunkalloc(sizeof(FeatureScriptLangList));
3021  if (isv)
3022  otl->features->featuretag = CHR('v','k','r','n');
3023  else
3024  otl->features->featuretag = CHR('k','e','r','n');
3025  OTLAppend(info,otl,true);
3026  }
3027  if ( flags_good && format==0 ) {
3028  /* format 0, horizontal kerning data (as pairs) not perpendicular */
3029  SplineChar **chars = info->chars;
3030  npairs = getushort(ttf);
3031  if ( len-14 != 6*npairs || npairs>10920 ) {
3032  LogError( _("In the 'kern' table, a subtable's length does not match the number of kerning pairs.") );
3033  info->bad_gx = true;
3034  }
3035  /* searchRange = */ getushort(ttf);
3036  /* entrySelector = */ getushort(ttf);
3037  /* rangeShift = */ getushort(ttf);
3038  otl->subtables[0].per_glyph_pst_or_kern = true;
3039  for ( j=0; j<npairs; ++j ) {
3040  left = getushort(ttf);
3041  right = getushort(ttf);
3042  offset = (short) getushort(ttf);
3043  if ( left<0 || right<0 ) {
3044  /* We've seen such buggy fonts... */
3045  LogError( _("Bad kern pair: glyphs %d & %d mustn't be negative\n"),
3046  left, right );
3047  info->bad_gx = true;
3048  } else if ( left>=info->glyph_cnt || right>=info->glyph_cnt ) {
3049  /* Holes happen when reading ttc files. They are probably ok */
3050  LogError( _("Bad kern pair: glyphs %d & %d must be less than %d\n"),
3051  left, right, info->glyph_cnt );
3052  info->bad_gx = true;
3053  } else if (chars[left]==NULL || chars[right]==NULL ) {
3054  /* Shouldn't happen. */
3055  LogError( _("Bad kern pair: glyphs at %d & %d are null\n"),
3056  left, right);
3057  info->bad_gx = true;
3058  } else {
3059  kp = chunkalloc(sizeof(KernPair));
3060  kp->sc = chars[right];
3061  kp->off = offset;
3062  kp->subtable = otl->subtables;
3064  DEFAULT_LANG);
3065  if ( isv ) {
3066  kp->next = chars[left]->vkerns;
3067  chars[left]->vkerns = kp;
3068  } else {
3069  kp->next = chars[left]->kerns;
3070  chars[left]->kerns = kp;
3071  }
3072  }
3073  }
3074  InfoNameOTLookup(otl,info);
3075  } else if ( flags_good && (format==2 || format==3 )) {
3076  /* two class based formats */
3077  KernClass **khead, **klast;
3078  if ( isv ) {
3079  khead = &info->vkhead;
3080  klast = &info->vklast;
3081  } else {
3082  khead = &info->khead;
3083  klast = &info->klast;
3084  }
3085  if ( *khead==NULL )
3086  *khead = kc = chunkalloc(sizeof(KernClass));
3087  else
3088  kc = (*klast)->next = chunkalloc(sizeof(KernClass));
3089  *klast = kc;
3090  if ( format==2 ) {
3091  rowWidth = getushort(ttf);
3092  left = getushort(ttf);
3093  right = getushort(ttf);
3094  array = getushort(ttf);
3095  kc->second_cnt = rowWidth/sizeof(uint16);
3096  class1 = getAppleClassTable(ttf, begin_table+left, info->glyph_cnt, array, rowWidth, info );
3097  class2 = getAppleClassTable(ttf, begin_table+right, info->glyph_cnt, 0, sizeof(uint16), info );
3098  for ( i=0; i<info->glyph_cnt; ++i )
3099  if ( class1[i]>kc->first_cnt )
3100  kc->first_cnt = class1[i];
3101  ++ kc->first_cnt;
3102  kc->offsets = galloc(kc->first_cnt*kc->second_cnt*sizeof(int16));
3103 #ifdef FONTFORGE_CONFIG_DEVICETABLES
3105 #endif
3106  fseek(ttf,begin_table+array,SEEK_SET);
3107  for ( i=0; i<kc->first_cnt*kc->second_cnt; ++i )
3108  kc->offsets[i] = getushort(ttf);
3109  } else {
3110  /* format 3, horizontal kerning data (as classes limited to 256 entries) */
3111  /* OpenType's spec doesn't document this */
3112  int gc, kv, flags;
3113  int16 *kvs;
3114  gc = getushort(ttf);
3115  kv = getc(ttf);
3116  kc->first_cnt = getc(ttf);
3117  kc->second_cnt = getc(ttf);
3118  flags = getc(ttf);
3119  if ( gc>info->glyph_cnt ) {
3120  LogError( _("Kerning subtable 3 says the glyph count is %d, but maxp says %d\n"),
3121  gc, info->glyph_cnt );
3122  info->bad_gx = true;
3123  }
3124  class1 = gcalloc(gc>info->glyph_cnt?gc:info->glyph_cnt,sizeof(uint16));
3125  class2 = gcalloc(gc>info->glyph_cnt?gc:info->glyph_cnt,sizeof(uint16));
3126  kvs = galloc(kv*sizeof(int16));
3127  kc->offsets = galloc(kc->first_cnt*kc->second_cnt*sizeof(int16));
3128 #ifdef FONTFORGE_CONFIG_DEVICETABLES
3130 #endif
3131  for ( i=0; i<kv; ++i )
3132  kvs[i] = (int16) getushort(ttf);
3133  for ( i=0; i<gc; ++i )
3134  class1[i] = getc(ttf);
3135  for ( i=0; i<gc; ++i )
3136  class2[i] = getc(ttf);
3137  for ( i=0; i<kc->first_cnt*kc->second_cnt; ++i )
3138  kc->offsets[i] = kvs[getc(ttf)];
3139  free(kvs);
3140  }
3141  kc->firsts = ClassToNames(info,kc->first_cnt,class1,info->glyph_cnt);
3142  kc->seconds = ClassToNames(info,kc->second_cnt,class2,info->glyph_cnt);
3143  for ( i=0; i<info->glyph_cnt; ++i ) {
3144  if ( class1[i]>=4 && info->chars[i]!=NULL )
3146  SCScriptFromUnicode(info->chars[i]),
3147  DEFAULT_LANG);
3148  }
3149  free(class1); free(class2);
3150  fseek(ttf,begin_table+len,SEEK_SET);
3151  otl->subtables[0].kc = kc;
3152  kc->subtable = otl->subtables;
3153  InfoNameOTLookup(otl,info);
3154  } else {
3155  LogError(_("Invalid or unsupported format (%d) for subtable of 'kern' table"), format );
3156  info->bad_gx = true;
3157  fseek(ttf,len-header_size,SEEK_CUR);
3158  if ( otl!=NULL )
3159  OTLRemove(info,otl,true);
3160  }
3161  }
3162 }
3163 
3164 /******************************************************************************/
3165 /* ******************************* MATH Table ******************************* */
3166 /* ********************** (Not strictly OpenType yet) *********************** */
3167 /******************************************************************************/
3168 
3169 /* ******************************** Read MATH ******************************* */
3170 
3171 static void ttf_math_read_constants(FILE *ttf,struct ttfinfo *info, uint32 start) {
3172  struct MATH *math;
3173  int i;
3174 #ifdef FONTFORGE_CONFIG_DEVICETABLES
3175  uint16 off;
3176 #endif
3177 
3178  fseek(ttf,start,SEEK_SET);
3179  info->math = math = gcalloc(1,sizeof(struct MATH));
3180 
3181  for ( i=0; math_constants_descriptor[i].script_name!=NULL; ++i ) {
3182  int16 *pos = (int16 *) (((char *) (math)) + math_constants_descriptor[i].offset );
3183  if ( pos == (int16 *) &math->MinConnectorOverlap )
3184  continue; /* Actually lives in the Variant table, not here */
3185  *pos = getushort(ttf);
3186 #ifdef FONTFORGE_CONFIG_DEVICETABLES
3187  if ( math_constants_descriptor[i].devtab_offset >= 0 ) {
3188  DeviceTable **devtab = (DeviceTable **) (((char *) (math)) + math_constants_descriptor[i].devtab_offset );
3189  off = getushort(ttf);
3190  if ( off!=0 ) {
3191  *devtab = chunkalloc(sizeof(DeviceTable));
3192  ReadDeviceTable(ttf,*devtab,start+off,info);
3193  }
3194  }
3195 #else
3196  /* No support for device tables, skip it */
3197  if ( math_constants_descriptor[i].devtab_offset != -1 )
3198  (void) getushort(ttf);
3199 #endif
3200  }
3201 }
3202 
3203 static void ttf_math_read_icta(FILE *ttf,struct ttfinfo *info, uint32 start, int is_ic) {
3204  /* The italic correction and top accent sub-tables have the same format */
3205  int coverage, cnt, i, val, offset;
3206  uint16 *glyphs;
3207 
3208  fseek(ttf,start,SEEK_SET);
3209  coverage = getushort(ttf);
3210  cnt = getushort(ttf);
3212  if ( glyphs==NULL )
3213 return;
3214  fseek(ttf,start+4,SEEK_SET);
3215  for ( i=0; i<cnt; ++i ) {
3216  val = (int16) getushort(ttf);
3217  offset = getushort(ttf);
3218  if ( glyphs[i]<info->glyph_cnt && info->chars[ glyphs[i]]!=NULL ) {
3219  if ( is_ic )
3220  info->chars[ glyphs[i] ]->italic_correction = val;
3221  else
3222  info->chars[ glyphs[i] ]->top_accent_horiz = val;
3223 #ifdef FONTFORGE_CONFIG_DEVICETABLES
3224  if ( offset!=0 ) {
3225  DeviceTable *dv = chunkalloc(sizeof(DeviceTable));
3226  ReadDeviceTable(ttf,dv,start+offset,info);
3227  if ( is_ic )
3228  info->chars[ glyphs[i] ]->italic_adjusts = dv;
3229  else
3230  info->chars[ glyphs[i] ]->top_accent_adjusts = dv;
3231  }
3232 #endif
3233  }
3234  }
3235  free(glyphs);
3236 }
3237 
3238 static void ttf_math_read_extended(FILE *ttf,struct ttfinfo *info, uint32 start) {
3239  int i;
3240  uint16 *glyphs;
3241 
3243  if ( glyphs==NULL )
3244 return;
3245  for ( i=0; glyphs[i]!=0xffff; ++i ) if ( glyphs[i]<info->glyph_cnt && info->chars[ glyphs[i]]!=NULL )
3246  info->chars[ glyphs[i] ]->is_extended_shape = true;
3247  free(glyphs);
3248 }
3249 
3251  SplineChar *sc, int istop, struct ttfinfo *info) {
3252  int cnt, i;
3253  (void)info; /* for -Wall */
3254  fseek(ttf,start,SEEK_SET);
3255  /* There is one more width than height. I store the width count */
3256  /* and guess a dummy height later */
3257  mkv->cnt = cnt = getushort(ttf)+1;
3258  mkv->mkd = gcalloc(cnt,sizeof(struct mathkerndata));
3259 
3260  for ( i=0; i<cnt-1; ++i ) {
3261  mkv->mkd[i].height = getushort(ttf);
3262 #ifdef FONTFORGE_CONFIG_DEVICETABLES
3263  mkv->mkd[i].height_adjusts = (void *) (intpt) getushort(ttf);
3264 #else
3265  (void) getushort(ttf);
3266 #endif
3267  }
3268 
3269  for ( i=0; i<cnt; ++i ) {
3270  mkv->mkd[i].kern = getushort(ttf);
3271 #ifdef FONTFORGE_CONFIG_DEVICETABLES
3272  mkv->mkd[i].kern_adjusts = (void *) (intpt) getushort(ttf);
3273 #else
3274  (void) getushort(ttf);
3275 #endif
3276  }
3277 
3278 #ifdef FONTFORGE_CONFIG_DEVICETABLES
3279  for ( i=0; i<cnt; ++i ) {
3280  DeviceTable *dv;
3281  uint32 offset;
3282  if ( mkv->mkd[i].height_adjusts!=NULL ) {
3283  offset = start + (intpt) mkv->mkd[i].height_adjusts;
3284  mkv->mkd[i].height_adjusts = dv = chunkalloc(sizeof(DeviceTable));
3285  ReadDeviceTable(ttf,dv,offset,info);
3286  }
3287  if ( mkv->mkd[i].kern_adjusts!=NULL ) {
3288  offset = start + (intpt) mkv->mkd[i].kern_adjusts;
3289  mkv->mkd[i].kern_adjusts = dv = chunkalloc(sizeof(DeviceTable));
3290  ReadDeviceTable(ttf,dv,offset,info);
3291  }
3292  }
3293 #endif
3294 
3295  if ( cnt>=3 )
3296  mkv->mkd[cnt-1].height = 2*mkv->mkd[cnt-2].height - mkv->mkd[cnt-3].height;
3297  else if ( cnt>=2 )
3298  mkv->mkd[cnt-1].height = mkv->mkd[cnt-2].height + 100;
3299  else if ( cnt==1 ) {
3300  if ( istop ) {
3301  DBounds b;
3303  mkv->mkd[cnt-1].height = b.maxy;
3304  } else
3305  mkv->mkd[cnt-1].height = 0;
3306  }
3307 }
3308 
3309 static void ttf_math_read_mathkern(FILE *ttf,struct ttfinfo *info, uint32 start) {
3310  int coverage, cnt, i;
3311  uint16 *glyphs;
3312  struct koff { uint16 tr, tl, br, bl; } *koff;
3313 
3314  fseek(ttf,start,SEEK_SET);
3315  coverage = getushort(ttf);
3316  cnt = getushort(ttf);
3317  koff = galloc(cnt*sizeof(struct koff));
3318  for ( i=0; i<cnt; ++i ) {
3319  koff[i].tr = getushort(ttf);
3320  koff[i].tl = getushort(ttf);
3321  koff[i].br = getushort(ttf);
3322  koff[i].bl = getushort(ttf);
3323  }
3325  if ( glyphs==NULL ) {
3326  free(koff);
3327 return;
3328  }
3329  for ( i=0; i<cnt; ++i ) if ( glyphs[i]<info->glyph_cnt && info->chars[ glyphs[i]]!=NULL ) {
3330  SplineChar *sc = info->chars[ glyphs[i]];
3331  sc->mathkern = chunkalloc(sizeof(struct mathkern));
3332  if ( koff[i].tr!=0 )
3333  ttf_math_read_mathkernv(ttf,start+koff[i].tr,&sc->mathkern->top_right,sc,true,info);
3334  if ( koff[i].tl!=0 )
3335  ttf_math_read_mathkernv(ttf,start+koff[i].tl,&sc->mathkern->top_left,sc,true,info);
3336  if ( koff[i].br!=0 )
3337  ttf_math_read_mathkernv(ttf,start+koff[i].br,&sc->mathkern->bottom_right,sc,false,info);
3338  if ( koff[i].bl!=0 )
3339  ttf_math_read_mathkernv(ttf,start+koff[i].bl,&sc->mathkern->bottom_left,sc,false,info);
3340  }
3341  free(koff);
3342  free(glyphs);