1 /* Copyright (C) 2000-2008 by George Williams */
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.
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
));
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
);
46 if ( first
+n
-1>=cnt
) {
47 LogError( _("Bad Apple Kern Class\n") );
50 for ( i
=0; i
<n
&& i
+first
<cnt
; ++i
)
51 class[first
+i
] = (getushort(ttf
)-sub
)/div
;
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));
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] = ' ';
72 LogError( _("Class index out of range %d (must be <%d)\n"),class[i
], class_cnt
);
76 for ( i
=1; i
<class_cnt
; ++i
)
80 ret
[i
][lens
[i
]-1] = '\0';
85 static char *CoverageMinusClasses(uint16
*coverageglyphs
,uint16
*classed
,
86 struct ttfinfo
*info
) {
88 uint8
*glyphs
= gcalloc(info
->glyph_cnt
,1);
91 for ( i
=0; coverageglyphs
[i
]!=0xffff; ++i
)
92 glyphs
[coverageglyphs
[i
]] = 1;
93 for ( i
=0; i
<info
->glyph_cnt
; ++i
)
96 for ( i
=0; i
<info
->glyph_cnt
; ++i
)
99 /* coverage table matches glyphs in classes. No need for special treatment*/
100 if ( i
==info
->glyph_cnt
) {
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 */
107 for ( j
=0; j
<2; ++j
) {
109 for ( i
=0; i
<info
->glyph_cnt
; ++i
) {
110 if ( glyphs
[i
]!=0 ) {
112 strcpy( ret
+len
, info
->chars
[i
]->name
);
113 strcat( ret
+len
, " ");
115 len
+= strlen(info
->chars
[i
]->name
)+1;
127 static int ClassFindCnt(uint16
*class,int tot
) {
130 for ( i
=0; i
<tot
; ++i
)
131 if ( class[i
]>max
) max
= class[i
];
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
) {
146 /* Adobe produces coverage tables containing duplicate glyphs in */
147 /* GaramondPremrPro.otf. We want unique glyphs, so enforce that */
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
);
155 for ( j
=i
+1; ; ++j
) {
156 glyphs
[j
] = glyphs
[j
+off
];
157 if ( glyphs
[j
]==0xffff )
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
);
173 if ( pt
>ret
) pt
[-1] = '\0';
180 int langcnt
; /* the default language is included as a */
181 struct language
{ /* normal entry with lang tag 'dflt' */
184 uint16 req
; /* required feature index. 0xffff for null */
200 /* uint16 lookup; */ /* ???? can't imagine what this is*/
203 int32
*subtab_offsets
;
207 static uint16
*getCoverageTable(FILE *ttf
, int coverage_offset
, struct ttfinfo
*info
) {
208 int format
, cnt
, i
,j
, rcnt
;
210 int start
, end
, ind
, max
;
212 fseek(ttf
,coverage_offset
,SEEK_SET
);
213 format
= getushort(ttf
);
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") );
220 if ( ftell(ttf
)>info
->g_bounds
)
222 cnt
= (info
->g_bounds
-ftell(ttf
))/2;
224 for ( i
=0; i
<cnt
; ++i
) {
225 if ( cnt
&0xffff0000 ) {
226 LogError( _("Bad count.\n"));
229 glyphs
[i
] = getushort(ttf
);
231 LogError( _("End of file found in coverage table.\n") );
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
);
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") );
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
);
256 LogError( _("End of file found in coverage table.\n") );
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
);
266 if ( ind
+end
-start
+2 >= 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;
281 LogError( _("Bad format for coverage table %d\n"), format
);
285 glyphs
[cnt
] = 0xffff;
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
) {
299 uint16 start
, glyphcnt
, rangecnt
, end
, class;
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
);
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
);
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") );
318 if (g_bounds
<ftell(ttf
))
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") );
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
);
339 class = getushort(ttf
);
340 for ( j
=start
; j
<=end
; ++j
) if ( j
<cnt
)
344 LogError( _("Unknown class table format: %d\n"), format
);
348 /* Do another validity test */
349 for ( i
=0; i
<cnt
; ++i
) {
350 if ( glist
[i
]>=cnt
+1 ) {
352 LogError( _("Nonsensical class assigned to a glyph-- class=%d is too big. Glyph=%d\n"),
364 static void readvaluerecord(struct valuerecord
*vr
,int vf
,FILE *ttf
) {
365 memset(vr
,'\0',sizeof(struct valuerecord
));
367 vr
->xplacement
= getushort(ttf
);
369 vr
->yplacement
= getushort(ttf
);
371 vr
->xadvance
= getushort(ttf
);
373 vr
->yadvance
= getushort(ttf
);
375 vr
->offXplaceDev
= getushort(ttf
);
377 vr
->offYplaceDev
= getushort(ttf
);
379 vr
->offXadvanceDev
= getushort(ttf
);
381 vr
->offYadvanceDev
= getushort(ttf
);
384 #ifdef FONTFORGE_CONFIG_DEVICETABLES
385 static void ReadDeviceTable(FILE *ttf
,DeviceTable
*adjust
,uint32 devtab
,
386 struct ttfinfo
*info
) {
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" ));
401 adjust
->first_pixel_size
= adjust
->last_pixel_size
= 0;
403 c
= adjust
->last_pixel_size
-adjust
->first_pixel_size
+1;
404 adjust
->corrections
= galloc(c
);
406 for ( i
=0; i
<c
; i
+=8 ) {
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 ) {
414 for ( b
=0; b
<4 && i
+b
<c
; ++b
)
415 adjust
->corrections
[i
+b
] = ((int16
) ((w
<<(b
*4))&0xf000))>>12;
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
) {
429 if ( vr
->offXplaceDev
==0 && vr
->offYplaceDev
==0 &&
430 vr
->offXadvanceDev
==0 && vr
->offYadvanceDev
==0 )
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
);
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
);
472 LogError( _("Bad pair position: glyphs %d & %d should have been < %d\n"),
473 glyph1
, glyph2
, info
->glyph_cnt
);
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
,
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
] )
493 kp
= chunkalloc(sizeof(KernPair
));
494 kp
->sc
= info
->chars
[glyph2
];
496 kp
->subtable
= subtable
;
497 #ifdef FONTFORGE_CONFIG_DEVICETABLES
499 kp
->adjust
= chunkalloc(sizeof(DeviceTable
));
500 ReadDeviceTable(ttf
,kp
->adjust
,devtab
,info
);
504 kp
->next
= info
->chars
[glyph1
]->vkerns
;
505 info
->chars
[glyph1
]->vkerns
= kp
;
507 kp
->next
= info
->chars
[glyph1
]->kerns
;
508 info
->chars
[glyph1
]->kerns
= kp
;
510 } else if ( kp
->subtable
!=subtable
)
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
);
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
;
526 uint16
*glyphs
, *class1
, *class2
;
527 struct valuerecord vr1
, vr2
;
532 format
=getushort(ttf
);
533 if ( format
!=1 && format
!=2 ) /* Unknown subtable format */
535 coverage
= getushort(ttf
);
536 vf1
= getushort(ttf
);
537 vf2
= getushort(ttf
);
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 */
546 } else if ( (vf1
==0x0004 || vf1
==0x0044) && vf2
==0x0000 && !(l
->flags
&pst_r2l
) )
547 isv
= 0; /* Left to right */
549 isv
= 2; /* Can't optimize, store all 8 settings */
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
);
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
);
567 addPairPos(info
, glyphs
[i
], glyph2
,l
,subtable
,&vr1
,&vr2
, stoffset
,ttf
);
569 if ( addKernPair(info
, glyphs
[i
], glyph2
, vr1
.yadvance
,
570 vr1
.offYadvanceDev
==0?0:stoffset
+vr1
.offYadvanceDev
,
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
,
580 addPairPos(info
, glyphs
[i
], glyph2
,l
,subtable
,&vr1
,&vr2
,stoffset
,ttf
);
582 if ( addKernPair(info
, glyphs
[i
], glyph2
, vr1
.xadvance
,
583 vr1
.offXadvanceDev
==0?0:stoffset
+vr1
.offXadvanceDev
,
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
);
602 if ( info
->vkhead
==NULL
)
603 info
->vkhead
= kc
= chunkalloc(sizeof(KernClass
));
605 kc
= info
->vklast
->next
= chunkalloc(sizeof(KernClass
));
608 if ( info
->khead
==NULL
)
609 info
->khead
= kc
= chunkalloc(sizeof(KernClass
));
611 kc
= info
->klast
->next
= chunkalloc(sizeof(KernClass
));
614 subtable
->vertical_kerning
= isv
;
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
));
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
);
633 kc
->offsets
[i
*c2_cnt
+j
] = vr1
.yadvance
;
635 kc
->offsets
[i
*c2_cnt
+j
] = vr2
.xadvance
;
637 kc
->offsets
[i
*c2_cnt
+j
] = vr1
.xadvance
;
638 #ifdef FONTFORGE_CONFIG_DEVICETABLES
640 if ( vr1
.offYadvanceDev
!=0 )
641 ReadDeviceTable(ttf
,&kc
->adjusts
[i
*c2_cnt
+j
],stoffset
+vr1
.offYadvanceDev
,info
);
643 if ( vr2
.offXadvanceDev
!=0 )
644 ReadDeviceTable(ttf
,&kc
->adjusts
[i
*c2_cnt
+j
],stoffset
+vr2
.offXadvanceDev
,info
);
646 if ( vr1
.offXadvanceDev
!=0 )
647 ReadDeviceTable(ttf
,&kc
->adjusts
[i
*c2_cnt
+j
],stoffset
+vr1
.offXadvanceDev
,info
);
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 */
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
)
663 for ( m
=0; m
<info
->glyph_cnt
; ++m
)
665 addPairPos(info
, k
,m
,l
,subtable
,&vr1
,&vr2
,stoffset
,ttf
);
669 free(class1
); free(class2
);
674 static AnchorPoint
*readAnchorPoint(FILE *ttf
,uint32 base
,AnchorClass
*class,
675 enum anchor_type type
,AnchorPoint
*last
, struct ttfinfo
*info
) {
678 (void)info
; /* for -Wall */
679 fseek(ttf
,base
,SEEK_SET
);
681 ap
= chunkalloc(sizeof(AnchorPoint
));
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
);
691 ap
->ttf_pt_index
= getushort(ttf
);
692 ap
->has_ttf_pt
= true;
694 #ifdef FONTFORGE_CONFIG_DEVICETABLES
695 else if ( format
==3 ) {
697 devoff
= getushort(ttf
);
699 ReadDeviceTable(ttf
,&ap
->xadjust
,base
+devoff
,info
);
700 devoff
= getushort(ttf
);
702 ReadDeviceTable(ttf
,&ap
->yadjust
,base
+devoff
,info
);
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
;
716 (void)l
; /* for -Wall */
717 format
=getushort(ttf
);
718 if ( format
!=1 ) /* Unknown subtable format */
720 coverage
= getushort(ttf
);
721 cnt
= getushort(ttf
);
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
)
741 info
->alast
->next
= 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
);
759 static AnchorClass
**MarkGlyphsProcessMarks(FILE *ttf
,int markoffset
,
760 struct ttfinfo
*info
,struct lookup
*l
, struct lookup_subtable
*subtable
,uint16
*markglyphs
,
762 AnchorClass
**classes
= gcalloc(classcnt
,sizeof(AnchorClass
*)), *ac
;
765 struct mr
{ uint16
class, offset
; } *at_offsets
;
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
)
781 info
->alast
->next
= ac
;
785 fseek(ttf
,markoffset
,SEEK_SET
);
786 cnt
= getushort(ttf
);
788 LogError( _("Bad mark table.\n") );
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") );
801 LogError( _("Class out of bounds in GPOS mark sub-table for mark %.30s\n"), info
->chars
[markglyphs
[i
]]->name
);
805 for ( i
=0; i
<cnt
; ++i
) {
806 if ( markglyphs
[i
]>=info
->glyph_cnt
)
808 sc
= info
->chars
[markglyphs
[i
]];
809 if ( sc
==NULL
|| at_offsets
[i
].offset
==0 )
811 sc
->anchor
= readAnchorPoint(ttf
,markoffset
+at_offsets
[i
].offset
,
812 classes
[at_offsets
[i
].class],at_mark
,sc
->anchor
,info
);
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
;
824 (void)subtable
; /* for -Wall */
825 (void)l
; /* for -Wall */
826 fseek(ttf
,baseoffset
,SEEK_SET
);
827 basecnt
= getushort(ttf
);
829 LogError( _("Bad base table.\n") );
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
)
839 sc
= info
->chars
[baseglyphs
[i
]];
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
);
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
;
856 (void)subtable
; /* for -Wall */
857 (void)l
; /* for -Wall */
858 fseek(ttf
,baseoffset
,SEEK_SET
);
859 basecnt
= getushort(ttf
);
861 LogError( _("Bad ligature base table.\n") );
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
)
872 fseek(ttf
,baseoffset
+loffsets
[i
],SEEK_SET
);
873 compcnt
= getushort(ttf
);
875 LogError(_("Bad ligature anchor count.\n"));
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
;
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
);
913 /* as is the (first) mark table */
914 classes
= MarkGlyphsProcessMarks(ttf
,stoffset
+markoffset
,
915 info
,l
,subtable
,markglyphs
,classcnt
);
918 switch ( l
->otlookup
->lookup_type
) {
921 MarkGlyphsProcessBases(ttf
,stoffset
+baseoffset
,
922 info
,l
,subtable
,baseglyphs
,classcnt
,classes
,
923 l
->otlookup
->lookup_type
==gpos_mark2base
?at_basechar
:at_basemark
);
925 case gpos_mark2ligature
:
926 MarkGlyphsProcessLigs(ttf
,stoffset
+baseoffset
,
927 info
,l
,subtable
,baseglyphs
,classcnt
,classes
);
932 info
->anchor_class_cnt
+= classcnt
;
933 ++ info
->anchor_merge_cnt
;
934 free(markglyphs
); free(baseglyphs
);
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
;
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 */
948 coverage
= getushort(ttf
);
950 #ifdef FONTFORGE_CONFIG_DEVICETABLES
954 if ( (vf
&0xf)==0 ) /* Not interested in things whose data just live in device tables */
958 memset(&_vr
,0,sizeof(_vr
));
959 readvaluerecord(&_vr
,vf
,ttf
);
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
) {
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
);
986 subtable
->per_glyph_pst_or_kern
= true;
991 static void ProcessSubLookups(FILE *ttf
,struct ttfinfo
*info
,int gpos
,
992 struct lookup
*alllooks
,struct seqlookup
*sl
) {
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'" );
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
;
1017 struct seqlookup
*sl
;
1022 struct subrule
*subrules
;
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
);
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
) {
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;
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 )
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;
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 */
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
;
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
]);
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
);
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
;
1121 int gcnt
, bcnt
, fcnt
;
1123 uint16
*glyphs
, *bglyphs
, *fglyphs
;
1124 struct seqlookup
*sl
;
1129 struct subrule
*subrules
;
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
) {
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
);
1157 LogError( _("Unexpected end of file in contextual chaining subtable.\n") );
1158 info
->bad_ot
= true;
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
);
1168 LogError( _("Unexpected end of file in contextual chaining subtable.\n") );
1169 info
->bad_ot
= true;
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
);
1180 LogError( _("Unexpected end of file in contextual chaining subtable.\n") );
1181 info
->bad_ot
= true;
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
) {
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;
1197 (&rules
[i
].subrules
[j
].glyphs
)[which
][k
] = 0;
1202 rules
[i
].subrules
[j
].scnt
= getushort(ttf
);
1204 LogError( _("Unexpected end of file in contextual chaining subtable.\n") );
1205 info
->bad_ot
= true;
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 )
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;
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 */
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
;
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
]);
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
);
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
;
1275 uint16
*classindeces
;
1276 struct seqlookup
*sl
;
1281 struct subrule
*subrules
;
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
;
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;
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;
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;
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
)
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;
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 */
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
;
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
]);
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
);
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
;
1397 int ccnt
, bccnt
, fccnt
;
1399 uint16
*classindeces
, *bci
, *fci
;
1400 struct seqlookup
*sl
;
1405 struct subrule
*subrules
;
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
;
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;
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;
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;
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;
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;
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
)
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;
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 */
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 */
1516 class = getClassDefTable(ttf
, stoffset
+bclassoff
, info
);
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
);
1523 class = getClassDefTable(ttf
, stoffset
+fclassoff
, info
);
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
);
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
]);
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
);
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
;
1565 struct seqlookup
*sl
;
1568 struct fpst_rule
*rule
;
1569 int warned2
= false;
1570 (void)l
; /* for -Wall */
1571 gcnt
= getushort(ttf
);
1572 scnt
= getushort(ttf
);
1574 LogError( _("End of file in context chaining sub-table.\n") );
1575 info
->bad_ot
= true;
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;
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 */
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
));
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);
1614 rule
->lookup_cnt
= scnt
;
1616 for ( k
=0; k
<scnt
; ++k
)
1617 ProcessSubLookups(ttf
,info
,gpos
,alllooks
,&sl
[k
]);
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
;
1631 struct fpst_rule
*rule
;
1632 int warned2
= false;
1633 (void)l
; /* for -Wall */
1634 bcnt
= getushort(ttf
);
1636 LogError( _("End of file in context chaining subtable.\n") );
1637 info
->bad_ot
= true;
1640 bcoverage
= galloc(bcnt
*sizeof(uint16
));
1641 for ( i
=0; i
<bcnt
; ++i
)
1642 bcoverage
[i
] = getushort(ttf
);
1643 gcnt
= getushort(ttf
);
1645 LogError( _("End of file in context chaining subtable.\n") );
1646 info
->bad_ot
= true;
1649 coverage
= galloc(gcnt
*sizeof(uint16
));
1650 for ( i
=0; i
<gcnt
; ++i
)
1651 coverage
[i
] = getushort(ttf
);
1652 fcnt
= getushort(ttf
);
1654 LogError( _("End of file in context chaining subtable.\n") );
1655 info
->bad_ot
= true;
1658 fcoverage
= galloc(fcnt
*sizeof(uint16
));
1659 for ( i
=0; i
<fcnt
; ++i
)
1660 fcoverage
[i
] = getushort(ttf
);
1661 scnt
= getushort(ttf
);
1663 LogError( _("End of file in context chaining subtable.\n") );
1664 info
->bad_ot
= true;
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;
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 */
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
));
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);
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);
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);
1718 rule
->lookup_cnt
= scnt
;
1720 for ( k
=0; k
<scnt
; ++k
)
1721 ProcessSubLookups(ttf
,info
,gpos
,alllooks
,&sl
[k
]);
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
)) {
1734 g___ContextSubTable1(ttf
,stoffset
,info
,l
,subtable
,git_normal
,alllooks
,true);
1737 g___ContextSubTable2(ttf
,stoffset
,info
,l
,subtable
,git_normal
,alllooks
,true);
1740 g___ContextSubTable3(ttf
,stoffset
,info
,l
,subtable
,git_normal
,alllooks
,true);
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
)) {
1750 g___ChainingSubTable1(ttf
,stoffset
,info
,l
,subtable
,git_normal
,alllooks
,true);
1753 g___ChainingSubTable2(ttf
,stoffset
,info
,l
,subtable
,git_normal
,alllooks
,true);
1756 g___ChainingSubTable3(ttf
,stoffset
,info
,l
,subtable
,git_normal
,alllooks
,true);
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" },
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
;
1777 uint16
*glyphs
, *glyph2s
=NULL
;
1780 format
=getushort(ttf
);
1781 if ( format
!=1 && format
!=2 ) /* Unknown subtable format */
1783 coverage
= getushort(ttf
);
1785 delta
= getushort(ttf
);
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
) {
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... */
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
;
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 )
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';
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;
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;
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
;
1865 uint16
*glyphs
, *glyph2s
;
1870 if ( justinuse
==git_findnames
)
1873 format
=getushort(ttf
);
1874 if ( format
!=1 ) /* Unknown subtable format */
1876 coverage
= getushort(ttf
);
1877 cnt
= getushort(ttf
);
1879 LogError( _("Unexpected end of file in GSUB sub-table.\n"));
1880 info
->bad_ot
= true;
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
) {
1891 for ( i
=0; glyphs
[i
]!=0xffff; ++i
);
1893 LogError( _("Coverage table specifies a different number of glyphs than the sub-table expects.\n" ));
1894 info
->bad_ot
= true;
1896 glyphs
[cnt
] = 0xffff;
1901 glyph2s
= galloc(max
*sizeof(uint16
));
1902 for ( i
=0; glyphs
[i
]!=0xffff; ++i
) {
1904 fseek(ttf
,stoffset
+offsets
[i
],SEEK_SET
);
1905 cnt
= getushort(ttf
);
1907 LogError( _("Unexpected end of file in GSUB sub-table.\n"));
1908 info
->bad_ot
= true;
1913 glyph2s
= grealloc(glyph2s
,max
*sizeof(uint16
));
1915 len
= 0; bad
= false;
1916 for ( j
=0; j
<cnt
; ++j
) {
1917 glyph2s
[j
] = getushort(ttf
);
1919 LogError( _("Unexpected end of file in GSUB sub-table.\n" ));
1920 info
->bad_ot
= true;
1923 if ( glyph2s
[j
]>=info
->glyph_cnt
) {
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;
1932 if ( justinuse
==git_justinuse
)
1934 else if ( info
->chars
[glyph2s
[j
]]==NULL
)
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);
1951 for ( j
=0; j
<cnt
; ++j
) {
1952 strcat(pt
,info
->chars
[glyph2s
[j
]]->name
);
1955 if ( *pt
!='\0' && pt
[strlen(pt
)-1]==' ' )
1956 pt
[strlen(pt
)-1] = '\0';
1959 subtable
->per_glyph_pst_or_kern
= true;
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
;
1973 /* Format = */ getushort(ttf
);
1974 coverage
= getushort(ttf
);
1975 cnt
= getushort(ttf
);
1977 LogError( _("Unexpected end of file in GSUB ligature sub-table.\n" ));
1978 info
->bad_ot
= true;
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
);
1987 for ( i
=0; i
<cnt
; ++i
) {
1988 fseek(ttf
,stoffset
+ls_offsets
[i
],SEEK_SET
);
1989 lig_cnt
= getushort(ttf
);
1991 LogError( _("Unexpected end of file in GSUB ligature sub-table.\n" ));
1992 info
->bad_ot
= true;
1995 lig_offsets
= galloc(lig_cnt
*sizeof(uint16
));
1996 for ( j
=0; j
<lig_cnt
; ++j
)
1997 lig_offsets
[j
] = getushort(ttf
);
1999 LogError( _("Unexpected end of file in GSUB ligature sub-table.\n" ));
2000 info
->bad_ot
= true;
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;
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
);
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;
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
) {
2042 for ( k
=0; k
<cc
; ++k
) {
2043 if ( info
->chars
[lig_glyphs
[k
]]==NULL
|| info
->chars
[lig_glyphs
[k
]]->name
==NULL
)
2045 len
+= strlen(info
->chars
[lig_glyphs
[k
]]->name
)+1;
2048 char *str
= galloc(len
+6), *pt
;
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';
2056 for ( k
=0; k
<cc
; ++k
) {
2057 strcat(str
,info
->chars
[lig_glyphs
[k
]]->name
);
2060 pt
= str
+strlen(str
);
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
);
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
)) {
2107 g___ContextSubTable1(ttf
,stoffset
,info
,l
,subtable
,justinuse
,alllooks
,false);
2110 g___ContextSubTable2(ttf
,stoffset
,info
,l
,subtable
,justinuse
,alllooks
,false);
2113 g___ContextSubTable3(ttf
,stoffset
,info
,l
,subtable
,justinuse
,alllooks
,false);
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
)) {
2125 g___ChainingSubTable1(ttf
,stoffset
,info
,l
,subtable
,justinuse
,alllooks
,false);
2128 g___ChainingSubTable2(ttf
,stoffset
,info
,l
,subtable
,justinuse
,alllooks
,false);
2131 g___ChainingSubTable3(ttf
,stoffset
,info
,l
,subtable
,justinuse
,alllooks
,false);
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
;
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;
2166 sglyphs
[i
] = 0xffff;
2168 if ( justinuse
==git_justinuse
) {
2169 for ( i
= 0 ; i
<scnt
; ++i
)
2170 info
->inuse
[sglyphs
[i
]] = 1;
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
));
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);
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);
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);
2203 rule
->lookup_cnt
= 0; /* substitution lookups needed for reverse chaining */
2210 static void readttfsizeparameters(FILE *ttf
,int32 broken_pos
,int32 correct_pos
,
2211 struct ttfinfo
*info
) {
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 */
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 */
2224 if ( info
->last_size_pos
==broken_pos
|| info
->last_size_pos
==correct_pos
)
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;
2234 test
[0] = correct_pos
; test
[1] = broken_pos
;
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 )
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
;
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 )
2257 info
->fontstyle_name
= FindAllLangEntries(ttf
,info
,nid
);
2258 if ( info
->fontstyle_name
==NULL
)
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
);
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
);
2280 static struct scripts
*readttfscripts(FILE *ttf
,int32 pos
, struct ttfinfo
*info
, int isgpos
) {
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;
2290 fseek(ttf
,pos
,SEEK_SET
);
2291 cnt
= getushort(ttf
);
2294 else if ( cnt
>1000 ) {
2295 LogError( _("Too many scripts %d\n"), cnt
);
2296 info
->bad_ot
= true;
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
));
2314 scripts
[i
].languages
[0].tag
= CHR('d','f','l','t');
2315 scripts
[i
].languages
[0].offset
= deflang
+scripts
[i
].offset
;
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;
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
);
2333 LogError(_("End of file when reading scripts in %s table"), isgpos
? "GPOS" : "GSUB" );
2334 info
->bad_ot
= true;
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
);
2344 LogError(_("End of file in %s table"), isgpos
? "GPOS" : "GSUB" );
2345 info
->bad_ot
= true;
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 */
2357 struct feature
*features
;
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;
2365 fseek(ttf
,pos
,SEEK_SET
);
2366 info
->feature_cnt
= cnt
= getushort(ttf
);
2369 else if ( cnt
>1000 ) {
2370 LogError( _("Too many features %d\n"), cnt
);
2371 info
->bad_ot
= true;
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;
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
);
2394 LogError(_("End of file when reading features in %s table"), isgpos
? "GPOS" : "GSUB" );
2395 info
->bad_ot
= true;
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
);
2406 static struct lookup
*readttflookups(FILE *ttf
,int32 pos
, struct ttfinfo
*info
, int isgpos
) {
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;
2418 fseek(ttf
,pos
,SEEK_SET
);
2419 info
->lookup_cnt
= cnt
= getushort(ttf
);
2420 info
->cur_lookups
= NULL
;
2423 else if ( cnt
>1000 ) {
2424 LogError( _("Too many lookups %d\n"), cnt
);
2425 info
->bad_ot
= true;
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;
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
;
2449 info
->cur_lookups
= otlookup
;
2451 last
->next
= otlookup
;
2453 otlookup
->lookup_type
= (isgpos
<<8) | lookups
[i
].type
;
2454 otlookup
->lookup_flags
= lookups
[i
].flags
;
2455 otlookup
->lookup_index
= i
;
2457 LogError(_("End of file when reading lookups in %s table"), isgpos
? "GPOS" : "GSUB" );
2458 info
->bad_ot
= true;
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
;
2469 info
->gpos_lookups
= info
->cur_lookups
;
2471 info
->gsub_lookups
= info
->cur_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
;
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;
2493 otlookup
= lookups
[feature
->lookups
[i
]].otlookup
;
2494 for ( fl
= otlookup
->features
; fl
!=NULL
&& fl
->featuretag
!=feature_tag
; fl
=fl
->next
);
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
) {
2510 struct language
*lang
;
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*/
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 )
2522 else if ( lang
->req
>= info
->feature_cnt
) {
2523 LogError( _("Required feature out of bounds in script table.\n") );
2524 info
->bad_ot
= true;
2526 tagLookupsWithFeature(s
->tag
,lang
->tag
,true,&features
[lang
->req
],
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;
2533 tagLookupsWithFeature(s
->tag
,lang
->tag
,false,&features
[lang
->features
[j
]],
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
) {
2547 for ( sl
=fl
->scripts
; sl
!=NULL
; sl
= next
) {
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
;
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
) {
2572 gposSimplePos(ttf
,st
,info
,l
,subtable
);
2575 gposKernSubTable(ttf
,st
,info
,l
,subtable
);
2578 gposCursiveSubTable(ttf
,st
,info
,l
,subtable
);
2580 case 4: case 5: case 6:
2581 gposMarkSubTable(ttf
,st
,info
,l
,subtable
);
2584 gposContextSubTable(ttf
,st
,info
,l
,subtable
,alllooks
);
2587 gposChainingSubTable(ttf
,st
,info
,l
,subtable
,alllooks
);
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;
2593 /* Any cases added here also need to go in the gposLookupSwitch */
2595 LogError( _("Unknown GPOS sub-table type: %d\n"), lu_type
);
2596 info
->bad_ot
= true;
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
;
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
) {
2620 gsubSimpleSubTable(ttf
,st
,info
,l
,subtable
,justinuse
);
2622 case 2: case 3: /* Multiple and alternate have same format, different semantics */
2623 gsubMultipleSubTable(ttf
,st
,info
,l
,subtable
,justinuse
);
2626 gsubLigatureSubTable(ttf
,st
,info
,l
,subtable
,justinuse
);
2629 gsubContextSubTable(ttf
,st
,info
,l
,subtable
,justinuse
,alllooks
);
2632 gsubChainingSubTable(ttf
,st
,info
,l
,subtable
,justinuse
,alllooks
);
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;
2639 gsubReverseChainSubTable(ttf
,st
,info
,l
,subtable
,justinuse
);
2641 /* Any cases added here also need to go in the gsubLookupSwitch */
2643 LogError( _("Unknown GSUB sub-table type: %d\n"), lu_type
);
2644 info
->bad_ot
= true;
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 ) {
2659 gposSimplePos(ttf
,st
,info
,l
,subtable
);
2662 gposKernSubTable(ttf
,st
,info
,l
,subtable
);
2665 gposCursiveSubTable(ttf
,st
,info
,l
,subtable
);
2667 case gpos_mark2base
: case gpos_mark2ligature
: case gpos_mark2mark
:
2668 gposMarkSubTable(ttf
,st
,info
,l
,subtable
);
2671 gposContextSubTable(ttf
,st
,info
,l
,subtable
,alllooks
);
2673 case gpos_contextchain
:
2674 gposChainingSubTable(ttf
,st
,info
,l
,subtable
,alllooks
);
2677 gposExtensionSubTable(ttf
,st
,info
,l
,subtable
,alllooks
);
2679 /* Any cases added here also need to go in the gposExtensionSubTable */
2681 LogError( _("Unknown GPOS sub-table type: %d\n"), l
->otlookup
->lookup_type
);
2682 info
->bad_ot
= true;
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
) {
2697 gsubSimpleSubTable(ttf
,st
,info
,l
,subtable
,justinuse
);
2699 case gsub_multiple
: case gsub_alternate
: /* Multiple and alternate have same format, different semantics */
2700 gsubMultipleSubTable(ttf
,st
,info
,l
,subtable
,justinuse
);
2703 gsubLigatureSubTable(ttf
,st
,info
,l
,subtable
,justinuse
);
2706 gsubContextSubTable(ttf
,st
,info
,l
,subtable
,justinuse
,alllooks
);
2708 case gsub_contextchain
:
2709 gsubChainingSubTable(ttf
,st
,info
,l
,subtable
,justinuse
,alllooks
);
2712 gsubExtensionSubTable(ttf
,st
,info
,l
,subtable
,justinuse
,alllooks
);
2714 case gsub_reversecchain
:
2715 gsubReverseChainSubTable(ttf
,st
,info
,l
,subtable
,justinuse
);
2717 /* Any cases added here also need to go in the gsubExtensionSubTable */
2719 LogError( _("Unknown GSUB sub-table type: %d\n"), l
->otlookup
->lookup_type
);
2720 info
->bad_ot
= true;
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
) {
2732 if ( scripts
==NULL
)
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
);
2742 static void FeaturesFree(struct feature
*features
) {
2745 if ( features
==NULL
)
2747 for ( i
=0; features
[i
].offset
!=0 ; ++i
)
2748 free(features
[i
].lookups
);
2752 static void LookupsFree(struct lookup
*lookups
) {
2755 for ( i
=0; lookups
[i
].offset
!=0 ; ++i
) {
2756 free( lookups
[i
].subtab_offsets
);
2761 static void ProcessGPOSGSUB(FILE *ttf
,struct ttfinfo
*info
,int gpos
,int inusetype
) {
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
;
2771 base
= info
->gpos_start
;
2772 info
->g_bounds
= base
+ info
->gpos_length
;
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
);
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
);
2802 gposLookupSwitch(ttf
,st
,info
,l
,subtable
,lookups
);
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
);
2826 void GuessNamesFromGSUB(FILE *ttf
,struct ttfinfo
*info
) {
2827 ProcessGPOSGSUB(ttf
,info
,false,git_findnames
);
2831 void readttfgpossub(FILE *ttf
,struct ttfinfo
*info
,int gpos
) {
2832 ProcessGPOSGSUB(ttf
,info
,gpos
,git_normal
);
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
;
2845 fseek(ttf
,info
->gdef_start
,SEEK_SET
);
2847 version
= getlong(ttf
) ;
2848 if (version
!= 0x00010000 && version
!= 0x00010002)
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 */
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;
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
);
2883 lclo
+= info
->gdef_start
;
2884 fseek(ttf
,lclo
,SEEK_SET
);
2885 coverage
= getushort(ttf
);
2886 cnt
= getushort(ttf
);
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
);
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
);
2900 pst
= chunkalloc(sizeof(PST
));
2901 pst
->next
= sc
->possub
;
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
);
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
);
2926 LogError( _("!!!! Unknown caret format %d !!!!\n"), format
);
2927 info
->bad_ot
= true;
2938 static void OTLAppend(struct ttfinfo
*info
,OTLookup
*otl
,int gpos
) {
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
;
2947 prev
= gpos
? info
->gpos_lookups
: info
->gsub_lookups
;
2949 while ( prev
->next
!=NULL
) {
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
;
2965 else if ( *base
!=NULL
) {
2966 for ( prev
= *base
; prev
->next
!=NULL
&& prev
->next
!=otl
; prev
= prev
->next
);
2972 static void InfoNameOTLookup(OTLookup
*otl
,struct ttfinfo
*info
) {
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
;
2991 uint16
*class1
, *class2
;
2995 fseek(ttf
,info
->kern_start
,SEEK_SET
);
2996 version
= getushort(ttf
);
2997 tabcnt
= getushort(ttf
);
2999 LogError(_("Invalid or unsupported version (0x%x) for 'kern' table"), version
);
3000 info
->bad_gx
= true;
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);
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
));
3022 otl
->features
->featuretag
= CHR('v','k','r','n');
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"),
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"),
3057 info
->bad_gx
= true;
3059 kp
= chunkalloc(sizeof(KernPair
));
3060 kp
->sc
= chars
[right
];
3062 kp
->subtable
= otl
->subtables
;
3063 FListsAppendScriptLang(otl
->features
,SCScriptFromUnicode(chars
[left
]),
3066 kp
->next
= chars
[left
]->vkerns
;
3067 chars
[left
]->vkerns
= kp
;
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
;
3079 khead
= &info
->vkhead
;
3080 klast
= &info
->vklast
;
3082 khead
= &info
->khead
;
3083 klast
= &info
->klast
;
3086 *khead
= kc
= chunkalloc(sizeof(KernClass
));
3088 kc
= (*klast
)->next
= chunkalloc(sizeof(KernClass
));
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
];
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
));
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
);
3110 /* format 3, horizontal kerning data (as classes limited to 256 entries) */
3111 /* OpenType's spec doesn't document this */
3114 gc
= getushort(ttf
);
3116 kc
->first_cnt
= getc(ttf
);
3117 kc
->second_cnt
= 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
));
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
)];
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
]),
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
);
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
);
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
) {
3174 #ifdef FONTFORGE_CONFIG_DEVICETABLES
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
);
3191 *devtab
= chunkalloc(sizeof(DeviceTable
));
3192 ReadDeviceTable(ttf
,*devtab
,start
+off
,info
);
3196 /* No support for device tables, skip it */
3197 if ( math_constants_descriptor
[i
].devtab_offset
!= -1 )
3198 (void) getushort(ttf
);
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
;
3208 fseek(ttf
,start
,SEEK_SET
);
3209 coverage
= getushort(ttf
);
3210 cnt
= getushort(ttf
);
3211 glyphs
= getCoverageTable(ttf
,start
+coverage
,info
);
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
) {
3220 info
->chars
[ glyphs
[i
] ]->italic_correction
= val
;
3222 info
->chars
[ glyphs
[i
] ]->top_accent_horiz
= val
;
3223 #ifdef FONTFORGE_CONFIG_DEVICETABLES
3225 DeviceTable
*dv
= chunkalloc(sizeof(DeviceTable
));
3226 ReadDeviceTable(ttf
,dv
,start
+offset
,info
);
3228 info
->chars
[ glyphs
[i
] ]->italic_adjusts
= dv
;
3230 info
->chars
[ glyphs
[i
] ]->top_accent_adjusts
= dv
;
3238 static void ttf_math_read_extended(FILE *ttf
,struct ttfinfo
*info
, uint32 start
) {
3242 glyphs
= getCoverageTable(ttf
,start
,info
);
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;
3250 static void ttf_math_read_mathkernv(FILE *ttf
, uint32 start
,struct mathkernvertex
*mkv
,
3251 SplineChar
*sc
, int istop
, struct ttfinfo
*info
) {
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
);
3265 (void) getushort(ttf
);
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
);
3274 (void) getushort(ttf
);
3278 #ifdef FONTFORGE_CONFIG_DEVICETABLES
3279 for ( i
=0; i
<cnt
; ++i
) {
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
);
3296 mkv
->mkd
[cnt
-1].height
= 2*mkv
->mkd
[cnt
-2].height
- mkv
->mkd
[cnt
-3].height
;
3298 mkv
->mkd
[cnt
-1].height
= mkv
->mkd
[cnt
-2].height
+ 100;
3299 else if ( cnt
==1 ) {
3302 SplineCharQuickBounds(sc
,&b
);
3303 mkv
->mkd
[cnt
-1].height
= b
.maxy
;
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
;
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
) {
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
);
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
);
3355 ttf_math_read_icta(ttf
,info
,start
+icoff
,true);
3357 ttf_math_read_icta(ttf
,info
,start
+taoff
,false);
3359 ttf_math_read_extended(ttf
,info
,start
+esoff
);
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
));
3372 int ic_offset
, pcnt
;
3374 char ebuf
[20], buffer
[50], *ext
;
3376 fseek(ttf
,start
,SEEK_SET
);
3377 ga_offset
= getushort(ttf
);
3378 vcnt
= getushort(ttf
);
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
);
3400 glyphs
= galloc(vcnt
*sizeof(uint16
));
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;
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
);
3422 if ( ga_offset
!=0 ) {
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
);
3438 LogError( _("Bad glyph variant subtable of MATH table.\n") );
3439 info
->bad_ot
= true;
3440 chunkfree(gv
,sizeof(*gv
));
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
) {
3453 ext
= isv
? "bot" : "left";
3454 else if ( i
==pcnt
-1 )
3455 ext
= isv
? "top" : "right";
3456 else if ( i
==1 && pcnt
==3 )
3459 sprintf( ebuf
, "%cpart%d", isv
?'v':'h', i
);
3462 snprintf(buffer
,sizeof(buffer
),"%.30s.%s",
3463 basesc
->name
, ext
);
3464 sc
->name
= copy(buffer
);
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;
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
);
3484 if ( justinuse
==git_justinuse
) {
3485 chunkfree(gv
,sizeof(*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
;
3495 uint16
*hglyphs
, *vglyphs
;
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
;
3515 vglyphs
= getCoverageTable(ttf
,start
+vcoverage
,info
);
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
]];
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
]];
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 )
3549 fseek(ttf
,info
->math_start
,SEEK_SET
);
3551 info
->g_bounds
= info
->math_start
+info
->math_length
;
3553 if ( getlong(ttf
)!=0x00010000 )
3555 constants
= getushort(ttf
);
3556 glyphinfo
= getushort(ttf
);
3557 variants
= getushort(ttf
);
3559 if ( justinuse
== git_normal
) {
3561 ttf_math_read_constants(ttf
,info
,info
->math_start
+constants
);
3563 ttf_math_read_glyphinfo(ttf
,info
,info
->math_start
+glyphinfo
);
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;
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
) {
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
);
3600 for ( j
=0; j
<feat_cnt
; ++j
) {
3601 cur
= chunkalloc(sizeof(struct baselangextent
));
3603 lang
->features
= cur
;
3607 cur
->lang
= getlong(ttf
); /* Actually feature tag here */
3608 cur
->descent
= (short) getushort(ttf
);
3609 cur
->ascent
= (short) getushort(ttf
);
3614 void readttfbase(FILE *ttf
,struct ttfinfo
*info
) {
3617 uint32 basetags
, basescripts
;
3619 struct tagoff
{ uint32 tag
; uint32 offset
; } *bs
;
3621 struct Base
*curBase
;
3622 struct basescript
*curScript
, *last
;
3623 struct baselangextent
*cur
, *lastLang
;
3625 if ( info
->base_start
==0 )
3627 fseek(ttf
,info
->base_start
,SEEK_SET
);
3629 version
= getlong(ttf
);
3630 if ( version
!=0x00010000 )
3632 axes
[0] = getushort(ttf
); /* Horizontal */
3633 axes
[1] = getushort(ttf
); /* Vertical */
3635 for ( axis
=0; axis
<2; ++axis
) {
3636 if ( axes
[axis
]==0 )
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
;
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
;
3664 for ( i
=0; i
<basescriptcnt
; ++i
) if ( bs
[i
].offset
!=0 ) {
3665 int basevalues
, defminmax
;
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
));
3679 curBase
->scripts
= curScript
;
3681 last
->next
= curScript
;
3683 curScript
->script
= bs
[i
].tag
;
3684 if ( basevalues
!=0 ) {
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",
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 ) {
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",
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
);
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
);
3726 curScript
->langs
= cur
;
3728 lastLang
->next
= cur
;