beta-0.89.2
[luatex.git] / source / texk / web2c / luatexdir / luafontloader / fontforge / fontforge / parsettfatt.c
blob85114e1213d33169dd913b73ff18531a81ff5878
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:
6 * Redistributions of source code must retain the above copyright notice, this
7 * list of conditions and the following disclaimer.
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.
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.
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.
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"
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 */
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;
50 for ( i=0; i<n && i+first<cnt; ++i )
51 class[first+i] = (getushort(ttf)-sub)/div;
52 return( class );
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;
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;
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 );
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;
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 );
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, " ");
115 len += strlen(info->chars[i]->name)+1;
118 if ( j==0 )
119 ret = galloc(len+1);
120 else
121 ret[len-1] = '\0';
123 free(glyphs);
124 return( ret );
127 static int ClassFindCnt(uint16 *class,int tot) {
128 int i, max=0;
130 for ( i=0; i<tot; ++i )
131 if ( class[i]>max ) max = class[i];
132 return( max+1 );
135 static int cmpuint16(const void *u1, const void *u2) {
136 return( ((int) *((const uint16 *) u1)) - ((int) *((const uint16 *) u2)) );
139 static char *GlyphsToNames(struct ttfinfo *info,uint16 *glyphs,int make_uniq) {
140 int i, j, len, off;
141 char *ret, *pt;
143 if ( glyphs==NULL )
144 return( copy(""));
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;
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++ = ' ';
173 if ( pt>ret ) pt[-1] = '\0';
174 return( ret );
177 struct scripts {
178 uint32 offset;
179 uint32 tag;
180 int langcnt; /* the default language is included as a */
181 struct language { /* normal entry with lang tag 'dflt' */
182 uint32 tag;
183 uint32 offset;
184 uint16 req; /* required feature index. 0xffff for null */
185 int fcnt;
186 uint16 *features;
187 } *languages;
190 struct feature {
191 uint32 offset;
192 uint32 tag;
193 int lcnt;
194 uint16 *lookups;
197 struct lookup {
198 uint16 type;
199 uint16 flags;
200 /* uint16 lookup; */ /* ???? can't imagine what this is*/
201 uint32 offset;
202 int subtabcnt;
203 int32 *subtab_offsets;
204 OTLookup *otlookup;
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;
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;
224 for ( i=0; i<cnt; ++i ) {
225 if ( cnt&0xffff0000 ) {
226 LogError( _("Bad count.\n"));
227 info->bad_ot = true;
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 );
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;
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;
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 );
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;
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));
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;
277 if ( ind+end-start+1>cnt )
278 cnt = ind+end-start+1;
280 } else {
281 LogError( _("Bad format for coverage table %d\n"), format );
282 info->bad_ot = true;
283 return( NULL );
285 glyphs[cnt] = 0xffff;
287 return( glyphs );
290 struct valuerecord {
291 int16 xplacement, yplacement;
292 int16 xadvance, yadvance;
293 uint16 offXplaceDev, offYplaceDev;
294 uint16 offXadvanceDev, offYadvanceDev;
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;
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;
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;
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;
339 class = getushort(ttf);
340 for ( j=start; j<=end; ++j ) if ( j<cnt )
341 glist[j] = class;
343 } else {
344 LogError( _("Unknown class table format: %d\n"), format );
345 info->bad_ot = true;
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;
357 glist[i] = 0;
361 return glist;
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);
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;
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;
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;
417 } else {
418 for ( i=0; i<c; ++i )
419 adjust->corrections[i] = (int8) getc(ttf);
422 fseek(ttf,here,SEEK_SET);
425 static ValDevTab *readValDevTab(FILE *ttf,struct valuerecord *vr,uint32 base,
426 struct ttfinfo *info) {
427 ValDevTab *ret;
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 );
443 #endif
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;
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;
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);
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;
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;
518 return( false );
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;
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;
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);
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;
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);
649 #endif
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);
669 free(class1); free(class2);
670 free(glyphs);
674 static AnchorPoint *readAnchorPoint(FILE *ttf,uint32 base,AnchorClass *class,
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);
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;
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);
704 #endif
705 ap->next = last;
706 return( ap );
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);
729 glyphs = getCoverageTable(ttf,stoffset+coverage,info);
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;
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);
750 if ( offsets[i].exit!=0 ) {
751 sc->anchor = readAnchorPoint(ttf,stoffset+offsets[i].exit,class,
752 at_cexit,sc->anchor,info);
755 free(offsets);
756 free(glyphs);
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;
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;
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 );
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;
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);
814 free(at_offsets);
815 return( classes );
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;
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);
847 free(offsets);
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;
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;
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;
889 free(aoffsets);
891 free(loffsets);
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;
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;
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;
932 info->anchor_class_cnt += classcnt;
933 ++ info->anchor_merge_cnt;
934 free(markglyphs); free(baseglyphs);
935 free(classes);
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);
966 glyphs = getCoverageTable(ttf,stoffset+coverage,info);
967 if ( glyphs==NULL ) {
968 free(vr);
969 return;
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
986 subtable->per_glyph_pst_or_kern = true;
987 free(vr);
988 free(glyphs);
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;
1003 sl->lookup = alllooks[i].otlookup;
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;
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;
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;
1070 rules[i].subrules[j].sl[k].lookup = (void *) (intpt) getushort(ttf);
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;
1087 fpst->rules = rule = gcalloc(cnt,sizeof(struct fpst_rule));
1088 fpst->rule_cnt = cnt;
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;
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);
1107 free(rules[i].subrules);
1109 free(rules);
1110 free(glyphs);
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
1218 rules[i].subrules[j].sl[k].lookup = (void *) (intpt) getushort(ttf);
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;
1235 fpst->rules = rule = gcalloc(cnt,sizeof(struct fpst_rule));
1236 fpst->rule_cnt = cnt;
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;
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);
1259 free(rules[i].subrules);
1261 free(rules);
1262 free(glyphs);
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;
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;
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;
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;
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;
1337 rules[i].subrules[j].sl[k].lookup = (void *) (intpt) getushort(ttf);
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;
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);
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;
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;
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);
1384 free(rules[i].subrules);
1386 free(rules);
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;
1393 uint16 coverage, offset;
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;
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;
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;
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;
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;
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;
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;
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;
1485 rules[i].subrules[j].sl[k].lookup = (void *) (intpt) getushort(ttf);
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;
1502 fpst->rules = rule = gcalloc(cnt,sizeof(struct fpst_rule));
1503 fpst->rule_cnt = cnt;
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);
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;
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);
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;
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);
1555 free(rules[i].subrules);
1557 free(rules);
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;
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;
1590 sl[k].lookup = (void *) (intpt) getushort(ttf);
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;
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);
1614 rule->lookup_cnt = scnt;
1615 rule->lookups = sl;
1616 for ( k=0; k<scnt; ++k )
1617 ProcessSubLookups(ttf,info,gpos,alllooks,&sl[k]);
1620 free(coverage);
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;
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;
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;
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;
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;
1676 sl[k].lookup = (void *) (intpt) getushort(ttf);
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;
1691 fpst->rules = rule = gcalloc(1,sizeof(struct fpst_rule));
1692 fpst->rule_cnt = 1;
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);
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);
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);
1718 rule->lookup_cnt = scnt;
1719 rule->lookups = sl;
1720 for ( k=0; k<scnt; ++k )
1721 ProcessSubLookups(ttf,info,gpos,alllooks,&sl[k]);
1724 free(bcoverage);
1725 free(coverage);
1726 free(fcoverage);
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;
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;
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 }
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;
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 */
1793 glyphs = getCoverageTable(ttf,stoffset+coverage,info);
1794 if ( glyphs==NULL ) {
1795 free(glyph2s);
1796 return;
1798 if ( justinuse==git_findnames ) {
1799 FeatureScriptLangList *fl;
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;
1823 str = galloc(strlen(basename)+strlen(pt)+2);
1824 sprintf(str,"%s.%s", basename, pt );
1825 info->chars[which]->name = str;
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;
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;
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);
1854 subtable->per_glyph_pst_or_kern = true;
1855 free(glyph2s);
1856 free(glyphs);
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;
1870 if ( justinuse==git_findnames )
1871 return;
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;
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;
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;
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;
1911 if ( cnt>max ) {
1912 max = cnt+30;
1913 glyph2s = grealloc(glyph2s,max*sizeof(uint16));
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;
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;
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;
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," ");
1955 if ( *pt!='\0' && pt[strlen(pt)-1]==' ' )
1956 pt[strlen(pt)-1] = '\0';
1959 subtable->per_glyph_pst_or_kern = true;
1960 free(glyphs);
1961 free(glyph2s);
1962 free(offsets);
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;
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;
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;
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;
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;
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;
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;
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;
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,"_");
2060 pt = str+strlen(str);
2061 pt[-1] = '.';
2062 strcpy(pt,tag);
2063 info->chars[lig]->name = str;
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++ = ' ';
2086 pt[-1] = '\0';
2088 free(lig_glyphs);
2090 free(lig_offsets);
2092 subtable->per_glyph_pst_or_kern = true;
2093 free(ls_offsets); free(glyphs);
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;
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;
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 */
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;
2166 sglyphs[i] = 0xffff;
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;
2180 fpst->rules = rule = gcalloc(1,sizeof(struct fpst_rule));
2181 fpst->rule_cnt = 1;
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);
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);
2203 rule->lookup_cnt = 0; /* substitution lookups needed for reverse chaining */
2205 free(sglyphs);
2206 free(fcoverage);
2207 free(bcoverage);
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;
2224 if ( info->last_size_pos==broken_pos || info->last_size_pos==correct_pos )
2225 return;
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;
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;
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;
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") );
2271 fseek(ttf,here,SEEK_SET);
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
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;
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 );
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 );
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);
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;
2318 for ( ; j<lcnt; ++j ) {
2319 scripts[i].languages[j].tag = getlong(ttf);
2320 scripts[i].languages[j].offset = scripts[i].offset+getushort(ttf);
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 );
2328 fseek(ttf,pos+scripts[i].languages[j].offset,SEEK_SET);
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 );
2337 scripts[i].languages[j].features = galloc(scripts[i].languages[j].fcnt*sizeof(uint16));
2338 for ( k=0; k<scripts[i].languages[j].fcnt; ++k )
2339 scripts[i].languages[j].features[k] = getushort(ttf);
2343 if ( feof(ttf)) {
2344 LogError(_("End of file in %s table"), isgpos ? "GPOS" : "GSUB" );
2345 info->bad_ot = true;
2346 return( NULL );
2349 return( scripts );
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;
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 );
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 );
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);
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 );
2387 fseek(ttf,pos+features[i].offset,SEEK_SET);
2388 parameters = getushort(ttf);
2389 if ( features[i].tag==CHR('s','i','z','e') && parameters!=0 && !feof(ttf))
2390 readttfsizeparameters(ttf,pos+parameters,
2391 pos+parameters+features[i].offset,info);
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 );
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);
2403 return( features );
2406 static struct lookup *readttflookups(FILE *ttf,int32 pos, struct ttfinfo *info, int isgpos) {
2407 int cnt,i,j;
2408 struct lookup *lookups;
2409 OTLookup *otlookup, *last=NULL;
2410 struct lookup_subtable *st;
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 );
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 );
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 );
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);
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 );
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;
2468 if ( isgpos )
2469 info->gpos_lookups = info->cur_lookups;
2470 else
2471 info->gsub_lookups = info->cur_lookups;
2472 return( lookups );
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;
2481 FeatureScriptLangList *fl;
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;
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;
2501 FListAppendScriptLang(fl,script_tag,lang_tag);
2506 static void tagLookupsWithScript(struct scripts *scripts,
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;
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 */
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);
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;
2543 FeatureScriptLangList *fl;
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;
2552 fl->scripts = prev;
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);
2567 l->otlookup->lookup_type = 0x100|lu_type;
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;
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;
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);
2615 l->otlookup->lookup_type = lu_type;
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;
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;
2653 static void gposLookupSwitch(FILE *ttf, int st,
2654 struct ttfinfo *info, struct lookup *l, struct lookup_subtable *subtable,
2655 struct lookup *alllooks) {
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;
2667 case gpos_mark2base: case gpos_mark2ligature: case gpos_mark2mark:
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;
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;
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) {
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;
2723 if ( ftell(ttf)>info->g_bounds ) {
2724 LogError( _("Subtable extends beyond end of GSUB table\n" ));
2725 info->bad_ot = true;
2729 static void ScriptsFree(struct scripts *scripts) {
2730 int i,j;
2732 if ( scripts==NULL )
2733 return;
2734 for ( i=0; scripts[i].offset!=0 ; ++i ) {
2735 for ( j=0; j<scripts[i].langcnt; ++j )
2736 free( scripts[i].languages[j].features);
2737 free(scripts[i].languages);
2739 free(scripts);
2742 static void FeaturesFree(struct feature *features) {
2743 int i;
2745 if ( features==NULL )
2746 return;
2747 for ( i=0; features[i].offset!=0 ; ++i )
2748 free(features[i].lookups);
2749 free(features);
2752 static void LookupsFree(struct lookup *lookups) {
2753 int i;
2755 for ( i=0; lookups[i].offset!=0 ; ++i ) {
2756 free( lookups[i].subtab_offsets );
2758 free(lookups);
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;
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;
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);
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 ) {
2789 ScriptsFree(scripts);
2790 FeaturesFree(features);
2791 return;
2793 tagLookupsWithScript(scripts,features,lookups,info);
2794 ScriptsFree(scripts); scripts = NULL;
2795 FeaturesFree(features); features = NULL;
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);
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);
2814 LookupsFree(lookups);
2815 if ( inusetype!=git_normal && !gpos ) {
2816 OTLookupListFree(info->gsub_lookups);
2817 info->gsub_lookups = info->cur_lookups = NULL;
2821 void readttfgsubUsed(FILE *ttf,struct ttfinfo *info) {
2822 ProcessGPOSGSUB(ttf,info,false,git_justinuse);
2823 info->g_bounds = 0;
2826 void GuessNamesFromGSUB(FILE *ttf,struct ttfinfo *info) {
2827 ProcessGPOSGSUB(ttf,info,false,git_findnames);
2828 info->g_bounds = 0;
2831 void readttfgpossub(FILE *ttf,struct ttfinfo *info,int gpos) {
2832 ProcessGPOSGSUB(ttf,info,gpos,git_normal);
2833 info->g_bounds = 0;
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;
2845 fseek(ttf,info->gdef_start,SEEK_SET);
2847 version = getlong(ttf) ;
2848 if (version != 0x00010000 && version != 0x00010002)
2849 return;
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 */
2857 if (version == 0x00010002)
2858 getushort(ttf); /* class defs */
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);
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 );
2879 free(mclasses);
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;
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;
2930 free(offsets);
2932 free(lc_offsets);
2933 free(glyphs);
2935 info->g_bounds = 0;
2938 static void OTLAppend(struct ttfinfo *info,OTLookup *otl,int gpos) {
2939 OTLookup *prev;
2940 int pos=0;
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;
2953 prev->next = otl;
2955 otl->lookup_index = pos;
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;
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;
2969 OTLookupFree(otl);
2972 static void InfoNameOTLookup(OTLookup *otl,struct ttfinfo *info) {
2973 SplineFont sf;
2975 memset(&sf,0,sizeof(sf));
2976 NameOTLookup(otl,&sf);
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;
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;
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);
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;
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;
3063 FListsAppendScriptLang(otl->features,SCScriptFromUnicode(chars[left]),
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;
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;
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
3104 kc->adjusts = gcalloc(kc->first_cnt*kc->second_cnt,sizeof(DeviceTable));
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;
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
3129 kc->adjusts = gcalloc(kc->first_cnt*kc->second_cnt,sizeof(DeviceTable));
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);
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 )
3145 FListsAppendScriptLang(otl->features,
3146 SCScriptFromUnicode(info->chars[i]),
3147 DEFAULT_LANG);
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);
3164 /******************************************************************************/
3165 /* ******************************* MATH Table ******************************* */
3166 /* ********************** (Not strictly OpenType yet) *********************** */
3167 /******************************************************************************/
3169 /* ******************************** Read MATH ******************************* */
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
3178 fseek(ttf,start,SEEK_SET);
3179 info->math = math = gcalloc(1,sizeof(struct MATH));
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);
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
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;
3208 fseek(ttf,start,SEEK_SET);
3209 coverage = getushort(ttf);
3210 cnt = getushort(ttf);
3211 glyphs = getCoverageTable(ttf,start+coverage,info);
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;
3232 #endif
3235 free(glyphs);
3238 static void ttf_math_read_extended(FILE *ttf,struct ttfinfo *info, uint32 start) {
3239 int i;
3240 uint16 *glyphs;
3242 glyphs = getCoverageTable(ttf,start,info);
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);
3250 static void ttf_math_read_mathkernv(FILE *ttf, uint32 start,struct mathkernvertex *mkv,
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));
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
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
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);
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);
3293 #endif
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;
3302 SplineCharQuickBounds(sc,&b);
3303 mkv->mkd[cnt-1].height = b.maxy;
3304 } else
3305 mkv->mkd[cnt-1].height = 0;
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;
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);
3324 glyphs = getCoverageTable(ttf,start+coverage,info);
3325 if ( glyphs==NULL ) {
3326 free(koff);
3327 return;
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);
3341 free(koff);
3342 free(glyphs);
3345 static void ttf_math_read_glyphinfo(FILE *ttf,struct ttfinfo *info, uint32 start) {
3346 int icoff,taoff,esoff,kioff;
3348 fseek(ttf,start,SEEK_SET);
3349 icoff = getushort(ttf);
3350 taoff = getushort(ttf);
3351 esoff = getushort(ttf);
3352 kioff = getushort(ttf);
3354 if ( icoff!=0 )
3355 ttf_math_read_icta(ttf,info,start+icoff,true);
3356 if ( taoff!=0 )
3357 ttf_math_read_icta(ttf,info,start+taoff,false);
3358 if ( esoff!=0 )
3359 ttf_math_read_extended(ttf,info,start+esoff);
3360 if ( kioff!=0 )
3361 ttf_math_read_mathkern(ttf,info,start+kioff);
3364 static struct glyphvariants *ttf_math_read_gvtable(FILE *ttf,struct ttfinfo *info, uint32 start,
3365 enum gsub_inusetype justinuse, SplineChar *basesc, int isv ) {
3366 struct glyphvariants *gv = chunkalloc(sizeof(struct glyphvariants));
3367 int ga_offset;
3368 int vcnt;
3369 uint16 *glyphs;
3370 int i, j, len;
3371 char *pt;
3372 int ic_offset, pcnt;
3373 SplineChar *sc;
3374 char ebuf[20], buffer[50], *ext;
3376 fseek(ttf,start,SEEK_SET);
3377 ga_offset = getushort(ttf);
3378 vcnt = getushort(ttf);
3379 if ( vcnt!=0 ) {
3380 if ( justinuse==git_justinuse ) {
3381 for ( i=0; i<vcnt; ++i ) {
3382 int gid = getushort(ttf);
3383 /* sizes[i] = */ getushort(ttf);
3384 if ( gid>=0 && gid<info->glyph_cnt )
3385 info->inuse[gid] = true;
3387 } else if ( justinuse==git_findnames ) {
3388 for ( i=0; i<vcnt; ++i ) {
3389 int gid = getushort(ttf);
3390 /* sizes[i] = */ getushort(ttf);
3391 if ( basesc!=NULL && basesc->name!=NULL &&
3392 gid>=0 && gid<info->glyph_cnt &&
3393 (sc = info->chars[gid])!=NULL && sc->name==NULL ) {
3394 snprintf(buffer,sizeof(buffer),"%.30s.%csize%d",
3395 basesc->name, isv?'v':'h', i);
3396 sc->name = copy(buffer);
3399 } else {
3400 glyphs = galloc(vcnt*sizeof(uint16));
3401 len = 0;
3402 for ( i=0; i<vcnt; ++i ) {
3403 glyphs[i] = getushort(ttf);
3404 /* sizes[i] = */ getushort(ttf);
3405 if ( glyphs[i]<info->glyph_cnt && (sc = info->chars[ glyphs[i]])!=NULL )
3406 len += strlen(sc->name)+1;
3408 if ( len!=0 ) {
3409 gv->variants = pt = galloc(len);
3410 for ( i=len=0; i<vcnt; ++i ) {
3411 if ( glyphs[i]<info->glyph_cnt && (sc = info->chars[ glyphs[i]])!=NULL ) {
3412 strcpy(pt+len,sc->name);
3413 len += strlen(sc->name);
3414 pt[len++] = ' ';
3417 pt[len-1] = '\0';
3419 free(glyphs);
3422 if ( ga_offset!=0 ) {
3423 start += ga_offset;
3424 fseek(ttf,start,SEEK_SET);
3425 gv->italic_correction = getushort(ttf);
3426 ic_offset = getushort(ttf);
3427 gv->part_cnt = pcnt = getushort(ttf);
3428 if ( justinuse==git_normal )
3429 gv->parts = gcalloc(pcnt,sizeof(struct gv_part));
3430 for ( i=j=0; i<pcnt; ++i ) {
3431 int gid, start, end, full, flags;
3432 gid = getushort(ttf);
3433 start = getushort(ttf);
3434 end = getushort(ttf);
3435 full = getushort(ttf);
3436 flags = getushort(ttf);
3437 if ( feof(ttf)) {
3438 LogError( _("Bad glyph variant subtable of MATH table.\n") );
3439 info->bad_ot = true;
3440 chunkfree(gv,sizeof(*gv));
3441 return( NULL );
3443 if ( justinuse==git_justinuse ) {
3444 if ( gid<info->glyph_cnt )
3445 info->inuse[gid] = true;
3446 } else if ( justinuse==git_findnames ) {
3447 if ( basesc!=NULL && basesc->name!=NULL &&
3448 gid>=0 && gid<info->glyph_cnt &&
3449 (sc = info->chars[gid])!=NULL && sc->name==NULL ) {
3450 if ( pcnt==1 )
3451 ext = "repeat";
3452 if ( i==0 )
3453 ext = isv ? "bot" : "left";
3454 else if ( i==pcnt-1 )
3455 ext = isv ? "top" : "right";
3456 else if ( i==1 && pcnt==3 )
3457 ext = "mid";
3458 else {
3459 sprintf( ebuf, "%cpart%d", isv?'v':'h', i );
3460 ext = ebuf;
3462 snprintf(buffer,sizeof(buffer),"%.30s.%s",
3463 basesc->name, ext );
3464 sc->name = copy(buffer);
3466 } else {
3467 if ( gid<info->glyph_cnt && (sc = info->chars[gid])!=NULL ) {
3468 gv->parts[j].component = copy( sc->name );
3469 gv->parts[j].startConnectorLength = start;
3470 gv->parts[j].endConnectorLength = end;
3471 gv->parts[j].fullAdvance = full;
3472 gv->parts[j++].is_extender = flags&1;
3476 gv->part_cnt = j;
3477 #ifdef FONTFORGE_CONFIG_DEVICETABLES
3478 if ( ic_offset!=0 && justinuse==git_normal ) {
3479 gv->italic_adjusts = chunkalloc(sizeof(DeviceTable));
3480 ReadDeviceTable(ttf,gv->italic_adjusts,start+ic_offset,info);
3482 #endif
3484 if ( justinuse==git_justinuse ) {
3485 chunkfree(gv,sizeof(*gv));
3486 return( NULL );
3488 return( gv );
3491 static void ttf_math_read_variants(FILE *ttf,struct ttfinfo *info, uint32 start,
3492 enum gsub_inusetype justinuse) {
3493 int vcoverage, hcoverage, vcnt, hcnt;
3494 int *hoffs, *voffs;
3495 uint16 *hglyphs, *vglyphs;
3496 int i;
3498 fseek(ttf,start,SEEK_SET);
3499 if ( info->math==NULL )
3500 info->math = gcalloc(1,sizeof(struct MATH));
3501 info->math->MinConnectorOverlap = getushort(ttf);
3502 vcoverage = getushort(ttf);
3503 hcoverage = getushort(ttf);
3504 vcnt = getushort(ttf);
3505 hcnt = getushort(ttf);
3506 hoffs = galloc(hcnt*sizeof(int));
3507 voffs = galloc(vcnt*sizeof(int));
3509 for ( i=0; i<vcnt; ++i )
3510 voffs[i] = getushort(ttf);
3511 for ( i=0; i<hcnt; ++i )
3512 hoffs[i] = getushort(ttf);
3513 vglyphs = hglyphs = NULL;
3514 if ( vcoverage!=0 )
3515 vglyphs = getCoverageTable(ttf,start+vcoverage,info);
3516 if ( hcoverage!=0 )
3517 hglyphs = getCoverageTable(ttf,start+hcoverage,info);
3519 if ( vglyphs!=NULL ) {
3520 for ( i=0; i<vcnt; ++i ) if ( vglyphs[i]<info->glyph_cnt && voffs[i]!=0) {
3521 if ( justinuse == git_normal || justinuse == git_findnames ) {
3522 SplineChar *sc = info->chars[ vglyphs[i]];
3523 if ( sc!=NULL )
3524 sc->vert_variants = ttf_math_read_gvtable(ttf,info,start+voffs[i],justinuse,sc,true);
3525 } else if ( info->inuse[ vglyphs[i]])
3526 ttf_math_read_gvtable(ttf,info,start+voffs[i],justinuse,NULL,true);
3529 if ( hglyphs!=NULL ) {
3530 for ( i=0; i<hcnt; ++i ) if ( hglyphs[i]<info->glyph_cnt && hoffs[i]!=0) {
3531 if ( justinuse == git_normal || justinuse == git_findnames ) {
3532 SplineChar *sc = info->chars[ hglyphs[i]];
3533 if ( sc!=NULL )
3534 sc->horiz_variants = ttf_math_read_gvtable(ttf,info,start+hoffs[i],justinuse,sc,false);
3535 } else if ( info->inuse[ hglyphs[i]])
3536 ttf_math_read_gvtable(ttf,info,start+hoffs[i],justinuse,NULL,false);
3540 free(vglyphs); free(voffs);
3541 free(hglyphs); free(hoffs);
3544 static void _otf_read_math(FILE *ttf,struct ttfinfo *info,
3545 enum gsub_inusetype justinuse) {
3546 int constants, glyphinfo, variants;
3547 if ( info->math_start==0 )
3548 return;
3549 fseek(ttf,info->math_start,SEEK_SET);
3551 info->g_bounds = info->math_start+info->math_length;
3553 if ( getlong(ttf)!=0x00010000 )
3554 return;
3555 constants = getushort(ttf);
3556 glyphinfo = getushort(ttf);
3557 variants = getushort(ttf);
3559 if ( justinuse == git_normal ) {
3560 if ( constants!=0 )
3561 ttf_math_read_constants(ttf,info,info->math_start+constants);
3562 if ( glyphinfo!=0 )
3563 ttf_math_read_glyphinfo(ttf,info,info->math_start+glyphinfo);
3565 if ( variants!=0 )
3566 ttf_math_read_variants(ttf,info,info->math_start+variants,justinuse);
3567 if ( ftell(ttf)>info->g_bounds ) {
3568 LogError("MATH table extends beyond table bounds");
3569 info->bad_ot = true;
3571 info->g_bounds = 0;
3574 void otf_read_math(FILE *ttf,struct ttfinfo *info) {
3575 _otf_read_math(ttf,info,git_normal);
3578 void otf_read_math_used(FILE *ttf,struct ttfinfo *info) {
3579 _otf_read_math(ttf,info,git_justinuse);
3582 void GuessNamesFromMATH(FILE *ttf,struct ttfinfo *info) {
3583 _otf_read_math(ttf,info,git_findnames);
3586 static struct baselangextent *readttfbaseminmax(FILE *ttf,uint32 offset,struct ttfinfo *info,
3587 uint32 script_tag,uint32 lang_tag) {
3588 int j,feat_cnt;
3589 struct baselangextent *lang, *cur, *last;
3590 (void)info; /* for -Wall */
3591 (void)script_tag; /* for -Wall */
3592 fseek(ttf,offset,SEEK_SET);
3593 lang = chunkalloc(sizeof(struct baselangextent));
3594 lang->lang = lang_tag;
3595 lang->descent = (short) getushort(ttf);
3596 lang->ascent = (short) getushort(ttf);
3598 feat_cnt = getushort(ttf);
3599 last = NULL;
3600 for ( j=0; j<feat_cnt; ++j ) {
3601 cur = chunkalloc(sizeof(struct baselangextent));
3602 if ( last==NULL )
3603 lang->features = cur;
3604 else
3605 last->next = cur;
3606 last = cur;
3607 cur->lang = getlong(ttf); /* Actually feature tag here */
3608 cur->descent = (short) getushort(ttf);
3609 cur->ascent = (short) getushort(ttf);
3611 return( lang );
3614 void readttfbase(FILE *ttf,struct ttfinfo *info) {
3615 int version;
3616 uint32 axes[2];
3617 uint32 basetags, basescripts;
3618 int basescriptcnt;
3619 struct tagoff { uint32 tag; uint32 offset; } *bs;
3620 int axis,i,j, tot;
3621 struct Base *curBase;
3622 struct basescript *curScript, *last;
3623 struct baselangextent *cur, *lastLang;
3625 if ( info->base_start==0 )
3626 return;
3627 fseek(ttf,info->base_start,SEEK_SET);
3629 version = getlong(ttf);
3630 if ( version!=0x00010000 )
3631 return;
3632 axes[0] = getushort(ttf); /* Horizontal */
3633 axes[1] = getushort(ttf); /* Vertical */
3635 for ( axis=0; axis<2; ++axis ) {
3636 if ( axes[axis]==0 )
3637 continue;
3638 fseek(ttf,info->base_start+axes[axis],SEEK_SET);
3639 curBase = chunkalloc(sizeof(struct Base));
3640 if ( axis==0 ) info->horiz_base = curBase; else info->vert_base = curBase;
3641 basetags = getushort(ttf);
3642 basescripts = getushort(ttf);
3643 if ( basetags==0 ) {
3644 curBase->baseline_cnt = 0;
3645 curBase->baseline_tags = NULL;
3646 } else {
3647 fseek(ttf,info->base_start+axes[axis]+basetags,SEEK_SET);
3648 curBase->baseline_cnt = getushort(ttf);
3649 curBase->baseline_tags = gcalloc(curBase->baseline_cnt,sizeof(uint32));
3650 for ( i=0; i<curBase->baseline_cnt; ++i )
3651 curBase->baseline_tags[i] = getlong(ttf);
3653 if ( basescripts!=0 ) {
3654 fseek(ttf,info->base_start+axes[axis]+basescripts,SEEK_SET);
3655 basescriptcnt = getushort(ttf);
3656 bs = gcalloc(basescriptcnt,sizeof(struct tagoff));
3657 for ( i=0; i<basescriptcnt; ++i ) {
3658 bs[i].tag = getlong(ttf);
3659 bs[i].offset = getushort(ttf);
3660 if ( bs[i].offset != 0 )
3661 bs[i].offset += info->base_start+axes[axis]+basescripts;
3663 last = NULL;
3664 for ( i=0; i<basescriptcnt; ++i ) if ( bs[i].offset!=0 ) {
3665 int basevalues, defminmax;
3666 int langsyscnt;
3667 struct tagoff *ls;
3668 fseek(ttf,bs[i].offset,SEEK_SET);
3669 basevalues = getushort(ttf);
3670 defminmax = getushort(ttf);
3671 langsyscnt = getushort(ttf);
3672 ls = gcalloc(langsyscnt,sizeof(struct tagoff));
3673 for ( j=0; j<langsyscnt; ++j ) {
3674 ls[j].tag = getlong(ttf);
3675 ls[j].offset = getushort(ttf);
3677 curScript = chunkalloc(sizeof(struct basescript));
3678 if ( last==NULL )
3679 curBase->scripts = curScript;
3680 else
3681 last->next = curScript;
3682 last = curScript;
3683 curScript->script = bs[i].tag;
3684 if ( basevalues!=0 ) {
3685 int coordcnt;
3686 int *coords;
3688 fseek( ttf,bs[i].offset+basevalues,SEEK_SET);
3689 curScript->def_baseline = getushort(ttf);
3690 tot = coordcnt = getushort(ttf);
3691 if ( coordcnt!=curBase->baseline_cnt ) {
3692 info->bad_ot = true;
3693 LogError( "!!!!! Coord count (%d) for '%c%c%c%c' script does not match base tag count (%d) in 'BASE' table\n",
3694 coordcnt,
3695 bs[i].tag>>24, bs[i].tag>>16, bs[i].tag>>8, bs[i].tag,
3696 curBase->baseline_cnt );
3697 if ( tot<curBase->baseline_cnt )
3698 tot = curBase->baseline_cnt;
3700 coords = gcalloc(coordcnt,sizeof(int));
3701 curScript->baseline_pos = gcalloc(tot,sizeof(int16));
3702 for ( j=0; j<coordcnt; ++j )
3703 coords[j] = getushort(ttf);
3704 for ( j=0; j<coordcnt; ++j ) if ( coords[j]!=0 ) {
3705 int format;
3706 fseek( ttf,bs[i].offset+basevalues+coords[j],SEEK_SET);
3707 format = getushort(ttf);
3708 curScript->baseline_pos[j] = (short) getushort(ttf);
3709 if ( format!=1 && format!=2 && format!=3 ) {
3710 info->bad_ot = true;
3711 LogError("!!!!! Bad Base Coord format (%d) for '%c%c%c%c' in '%c%c%c%c' script in 'BASE' table\n",
3712 format,
3713 curBase->baseline_tags[j]>>24, curBase->baseline_tags[j]>>16, curBase->baseline_tags[j]>>8, curBase->baseline_tags[j],
3714 bs[i].tag>>24, bs[i].tag>>16, bs[i].tag>>8, bs[i].tag );
3717 free(coords);
3719 lastLang = NULL;
3720 if ( defminmax!=0 )
3721 curScript->langs = lastLang = readttfbaseminmax(ttf,bs[i].offset+defminmax,info,bs[i].tag,DEFAULT_LANG);
3722 if ( langsyscnt!=0 ) {
3723 for ( j=0; j<langsyscnt; ++j ) if ( ls[j].offset!=0 ) {
3724 cur = readttfbaseminmax(ttf,bs[i].offset+ls[j].offset,info,bs[i].tag,ls[j].tag);
3725 if ( last==NULL )
3726 curScript->langs = cur;
3727 else
3728 lastLang->next = cur;
3729 lastLang = cur;
3732 free(ls);
3734 free(bs);