1 /* Copyright (C) 2000-2012 by George Williams */
2 /*
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are met:
5
6 * Redistributions of source code must retain the above copyright notice, this
7 * list of conditions and the following disclaimer.
8
9 * Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
12
13 * The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include <fontforge-config.h>
29
30 #include "tottfaat.h"
31
32 #include "asmfpst.h"
33 #include "fontforge.h"
34 #include "fvfonts.h"
35 #include "gfile.h"
36 #include "macenc.h"
37 #include "splinesaveafm.h"
38 #include "splineutil.h"
39 #include "tottf.h"
40 #include "tottfgpos.h"
41 #include "utype.h"
42
43 #include "ttf.h"
44
45 /* This file contains routines to create some of the Apple Advanced Typography Tables */
46 /* (or GX fonts) */
47
48 /* ************************************************************************** */
49 /* ************************* The 'acnt' table ************************* */
50 /* ************************************************************************** */
51
aat_dumpacnt(struct alltabs * at,SplineFont * sf)52 void aat_dumpacnt(struct alltabs *at, SplineFont *sf) {
53 }
54
55 /* ************************************************************************** */
56 /* ************************* The 'kern' table ************************* */
57 /* ************************************************************************** */
58
59
60 /* Apple's docs imply that kerning info is always provided left to right, even*/
61 /* for right to left scripts. If that be so then we need code in here to reverse */
62 /* the order of the characters for right to left since pfaedit's convention */
63 /* is to follow writing order rather than to go left to right */
64
65
DumpKernClass(FILE * file,uint16 * class,int cnt,int add,int mul)66 static void DumpKernClass(FILE *file, uint16 *class,int cnt,int add,int mul) {
67 int i, first=-1, last=-1;
68
69 for ( i=0; i<cnt; ++i ) {
70 if ( class[i] ) last = i;
71 if ( class[i] && first==-1 ) first = i;
72 }
73 putshort(file,first);
74 putshort(file,last-first+1);
75 for ( i=first; i<=last; ++i )
76 putshort(file,class[i]*mul+add);
77 }
78
79 static int morx_dumpASM(FILE *temp,ASM *sm, struct alltabs *at, SplineFont *sf );
80
81 struct kerncounts {
82 int cnt;
83 int vcnt;
84 int mh, mv;
85 int kccnt;
86 int vkccnt;
87 int ksm;
88 int hsubs;
89 int *hbreaks;
90 int vsubs;
91 int *vbreaks;
92 };
93
CountKerns(struct alltabs * at,SplineFont * sf,struct kerncounts * kcnt)94 static int CountKerns(struct alltabs *at, SplineFont *sf, struct kerncounts *kcnt) {
95 int i, cnt, vcnt, j, kccnt=0, vkccnt=0, ksm=0, mh, mv;
96 KernPair *kp;
97 KernClass *kc;
98 ASM *sm;
99
100 cnt = mh = vcnt = mv = 0;
101 for ( i=0; i<at->gi.gcnt; ++i ) if ( at->gi.bygid[i]!=-1 ) {
102 j = 0;
103 for ( kp = sf->glyphs[at->gi.bygid[i]]->kerns; kp!=NULL; kp=kp->next )
104 if ( kp->off!=0 && kp->sc->ttf_glyph!=-1 &&
105 LookupHasDefault(kp->subtable->lookup ))
106 ++cnt, ++j;
107 if ( j>mh ) mh=j;
108 j=0;
109 for ( kp = sf->glyphs[at->gi.bygid[i]]->vkerns; kp!=NULL; kp=kp->next )
110 if ( kp->off!=0 && kp->sc->ttf_glyph!=-1 &&
111 LookupHasDefault(kp->subtable->lookup ))
112 ++vcnt, ++j;
113 if ( j>mv ) mv=j;
114 }
115 kcnt->cnt = cnt;
116 kcnt->vcnt = vcnt;
117 kcnt->mh = mh;
118 kcnt->mv = mv;
119 kcnt->hbreaks = kcnt->vbreaks = NULL;
120 if ( cnt>=10000 ) {
121 /* the sub-table size is 6*cnt+14 or so and needs to be less 65535 */
122 /* so break it up into little bits */
123 /* We might not need this when applemode is set because the subtable */
124 /* length is a long. BUT... there's a damn binsearch header with */
125 /* shorts in it still */
126 int b=0;
127 kcnt->hbreaks = malloc((at->gi.gcnt+1)*sizeof(int));
128 cnt = 0;
129 for ( i=0; i<at->gi.gcnt; ++i ) if ( at->gi.bygid[i]!=-1 ) {
130 j = 0;
131 for ( kp = sf->glyphs[at->gi.bygid[i]]->kerns; kp!=NULL; kp=kp->next )
132 if ( kp->off!=0 && LookupHasDefault(kp->subtable->lookup ))
133 ++j;
134 if ( (cnt+j)*6>64000L && cnt!=0 ) {
135 kcnt->hbreaks[b++] = cnt;
136 cnt = 0;
137 }
138 cnt += j;
139 }
140 kcnt->hbreaks[b++] = cnt;
141 kcnt->hsubs = b;
142 } else if ( cnt!=0 )
143 kcnt->hsubs = 1;
144 else
145 kcnt->hsubs = 0;
146 if ( vcnt>=10000 ) {
147 int b=0;
148 kcnt->vbreaks = malloc((at->gi.gcnt+1)*sizeof(int));
149 vcnt = 0;
150 for ( i=0; i<at->gi.gcnt; ++i ) if ( at->gi.bygid[i]!=-1 ) {
151 j = 0;
152 for ( kp = sf->glyphs[at->gi.bygid[i]]->vkerns; kp!=NULL; kp=kp->next )
153 if ( kp->off!=0 && LookupHasDefault(kp->subtable->lookup))
154 ++j;
155 if ( (vcnt+j)*6>64000L && vcnt!=0 ) {
156 kcnt->vbreaks[b++] = vcnt;
157 vcnt = 0;
158 }
159 vcnt += j;
160 }
161 kcnt->vbreaks[b++] = vcnt;
162 kcnt->vsubs = b;
163 } else if ( vcnt!=0 )
164 kcnt->vsubs = 1;
165 else
166 kcnt->vsubs = 0;
167
168 if ( at->applemode ) { /* if we aren't outputting Apple's extensions to kerning (by classes, and by state machine) then don't check for those extensions */
169 for ( kc=sf->kerns; kc!=NULL; kc = kc->next ) if ( LookupHasDefault(kc->subtable->lookup) )
170 ++kccnt;
171 for ( kc=sf->vkerns; kc!=NULL; kc = kc->next ) if ( LookupHasDefault(kc->subtable->lookup) )
172 ++vkccnt;
173 for ( sm=sf->sm; sm!=NULL; sm=sm->next )
174 if ( sm->type == asm_kern )
175 ++ksm;
176 }
177 kcnt->kccnt = kccnt;
178 kcnt->vkccnt = vkccnt;
179 kcnt->ksm = ksm;
180 return( kcnt->hsubs + kcnt->vsubs + kccnt + vkccnt + ksm );
181 }
182
ttf_dumpsfkerns(struct alltabs * at,SplineFont * sf,int tupleIndex,int version)183 static void ttf_dumpsfkerns(struct alltabs *at, SplineFont *sf, int tupleIndex, int version) {
184 struct kerncounts kcnt;
185 int i, j, k, m, c, gid, tot, km;
186 KernPair *kp;
187 KernClass *kc;
188 ASM *sm;
189 uint16 *glnum, *offsets;
190 int isv;
191 int tupleMask = tupleIndex==-1 ? 0 : 0x2000;
192 int b, bmax;
193 int *breaks;
194 int winfail=0;
195 int subtableBeginPos,subtableEndPos;
196
197 if ( CountKerns(at,sf,&kcnt)==0 )
198 return;
199
200 if ( tupleIndex==-1 ) tupleIndex = 0;
201
202 for ( isv=0; isv<2; ++isv ) {
203 c = isv ? kcnt.vcnt : kcnt.cnt;
204 bmax = isv ? kcnt.vsubs : kcnt.hsubs;
205 breaks = isv ? kcnt.vbreaks : kcnt.hbreaks;
206 if ( c!=0 ) {
207 km = isv ? kcnt.mv : kcnt.mh;
208 glnum = malloc(km*sizeof(uint16));
209 offsets = malloc(km*sizeof(uint16));
210 gid = 0;
211 for ( b=0; b<bmax; ++b ) {
212 c = bmax==1 ? c : breaks[b];
213
214 // skip subtable header because we don't know the number of kern pairs yet
215 subtableBeginPos=ftell(at->kern);
216 if(version==0) fseek(at->kern,7*sizeof(uint16),SEEK_CUR);
217 else fseek(at->kern,8*sizeof(uint16),SEEK_CUR);
218
219 for ( tot = 0; gid<at->gi.gcnt && tot<c; ++gid ) if ( at->gi.bygid[gid]!=-1 ) {
220 SplineChar *sc = sf->glyphs[at->gi.bygid[gid]];
221 // if requested, omit kern pairs with unmapped glyphs
222 // (required for compatibility with non-OpenType-aware Windows applications)
223 if( (at->gi.flags&ttf_flag_oldkernmappedonly) && (unsigned)(sc->unicodeenc)>0xFFFF ) continue;
224 m = 0;
225 for ( kp = isv ? sc->vkerns : sc->kerns; kp!=NULL; kp=kp->next ) {
226 // if requested, omit kern pairs with unmapped glyphs
227 // (required for compatibility with non-OpenType-aware Windows applications)
228 if( (at->gi.flags&ttf_flag_oldkernmappedonly) && (unsigned)(kp->sc->unicodeenc)>0xFFFF ) continue;
229 if ( kp->off!=0 && kp->sc->ttf_glyph!=-1 &&
230 LookupHasDefault(kp->subtable->lookup)) {
231 /* order the pairs */
232 for ( j=0; j<m; ++j )
233 if ( kp->sc->ttf_glyph<glnum[j] )
234 break;
235 for ( k=m; k>j; --k ) {
236 glnum[k] = glnum[k-1];
237 offsets[k] = offsets[k-1];
238 }
239 glnum[j] = kp->sc->ttf_glyph;
240 offsets[j] = kp->off;
241 ++m;
242 /* check if a pair will cause problems on Windows */
243 /* If the glyph is outside BMP, so either unicode >0xffff */
244 /* or -1. Cast to unsigned catches both */
245 if( (unsigned)(sf->glyphs[at->gi.bygid[gid]]->unicodeenc)>0xFFFF ||
246 (unsigned)(sf->glyphs[at->gi.bygid[glnum[j]]]->unicodeenc)>0xFFFF )
247 winfail++;
248 }
249 }
250 for ( j=0; j<m; ++j ) {
251 putshort(at->kern,gid);
252 putshort(at->kern,glnum[j]);
253 putshort(at->kern,offsets[j]);
254 }
255 tot += m;
256 }
257
258 // now we can fill the subtable header
259 c=tot;
260 subtableEndPos=ftell(at->kern);
261 fseek(at->kern,subtableBeginPos,SEEK_SET);
262 if ( version==0 ) {
263 putshort(at->kern,0); /* subtable version */
264 if ( c>10920 )
265 ff_post_error(_("Too many kern pairs"),_("The 'kern' table supports at most 10920 kern pairs in a subtable"));
266 putshort(at->kern,(7+3*c)*sizeof(uint16)); /* subtable length */
267 putshort(at->kern,!isv); /* coverage, flags=hor/vert&format=0 */
268 } else {
269 putlong(at->kern,(8+3*c)*sizeof(uint16)); /* subtable length */
270 /* Apple's new format has a completely different coverage format */
271 putshort(at->kern,(isv?0x8000:0)| /* format 0, horizontal/vertical flags (coverage) */
272 tupleMask);
273 putshort(at->kern,tupleIndex);
274 }
275 putshort(at->kern,c);
276 for ( i=1,j=0; i<=c; i<<=1, ++j );
277 i>>=1; --j;
278 putshort(at->kern,i*6); /* binary search headers */
279 putshort(at->kern,j);
280 putshort(at->kern,6*(c-i));
281 fseek(at->kern,subtableEndPos,SEEK_SET);
282 }
283 free(offsets);
284 free(glnum);
285 }
286 }
287 free(kcnt.hbreaks); free(kcnt.vbreaks);
288
289 if( winfail > 0 )
290 ff_post_error(_("Kerning is likely to fail on Windows"),_(
291 "Note: On Windows many apps can have problems with this font's kerning, because %d of its glyph kern pairs cannot be mapped to unicode-BMP kern pairs (eg, they have a Unicode value of -1) To avoid this, go to Generate, Options, and check the \"Windows-compatible \'kern\'\" option."),
292 winfail);
293
294 if ( at->applemode ) for ( isv=0; isv<2; ++isv ) {
295 for ( kc=isv ? sf->vkerns : sf->kerns; kc!=NULL; kc=kc->next ) if ( LookupHasDefault(kc->subtable->lookup) ) {
296 /* If we are here, we must be using version 1 */
297 uint32 len_pos = ftell(at->kern), pos;
298 uint16 *class1, *class2;
299 int first_cnt = kc->first_cnt;
300
301 /* OpenType fonts can actually have a set of glyphs in class[0] of*/
302 /* the first class. This happens when there are glyphs in the */
303 /* coverage table which are not in any of the classes. Otherwise */
304 /* class 0 is sort of useless in opentype */
305 if ( kc->firsts[0]!=NULL )
306 ++first_cnt;
307
308 putlong(at->kern,0); /* subtable length */
309 putshort(at->kern,(isv?0x8002:2)| /* format 2, horizontal/vertical flags (coverage) */
310 tupleMask);
311 putshort(at->kern,tupleIndex);
312
313 putshort(at->kern,sizeof(uint16)*kc->second_cnt);
314 putshort(at->kern,0); /* left classes */
315 putshort(at->kern,0); /* right classes */
316 putshort(at->kern,16); /* Offset to array, next byte */
317
318 if ( kc->firsts[0]!=NULL ) {
319 /* Create a dummy class to correspond to the mac's class 0 */
320 /* all entries will be 0 */
321 for ( i=0 ; i<kc->second_cnt; ++i )
322 putshort(at->kern,0);
323 }
324 for ( i=0; i<kc->first_cnt*kc->second_cnt; ++i )
325 putshort(at->kern,kc->offsets[i]);
326
327 pos = ftell(at->kern);
328 fseek(at->kern,len_pos+10,SEEK_SET);
329 putshort(at->kern,pos-len_pos);
330 fseek(at->kern,pos,SEEK_SET);
331 class1 = ClassesFromNames(sf,kc->firsts,kc->first_cnt,at->maxp.numGlyphs,NULL,true);
332 DumpKernClass(at->kern,class1,at->maxp.numGlyphs,16,sizeof(uint16)*kc->second_cnt);
333 free(class1);
334
335 pos = ftell(at->kern);
336 fseek(at->kern,len_pos+12,SEEK_SET);
337 putshort(at->kern,pos-len_pos);
338 fseek(at->kern,pos,SEEK_SET);
339 class2 = ClassesFromNames(sf,kc->seconds,kc->second_cnt,at->maxp.numGlyphs,NULL,true);
340 DumpKernClass(at->kern,class2,at->maxp.numGlyphs,0,sizeof(uint16));
341 free(class2);
342
343 pos = ftell(at->kern);
344 fseek(at->kern,len_pos,SEEK_SET);
345 putlong(at->kern,pos-len_pos);
346 fseek(at->kern,pos,SEEK_SET);
347 }
348 }
349
350 if ( at->applemode ) if ( kcnt.ksm!=0 ) {
351 for ( sm=sf->sm; sm!=NULL; sm=sm->next ) if ( sm->type == asm_kern ) {
352 uint32 len_pos = ftell(at->kern), pos;
353
354 putlong(at->kern,0); /* subtable length */
355 putshort(at->kern,((sm->flags&0x8000)?0x8001:1)| /* format 1, horizontal/vertical flags (coverage) */
356 tupleMask);
357 putshort(at->kern,tupleIndex);
358 morx_dumpASM(at->kern,sm,at,sf);
359
360 pos = ftell(at->kern);
361 fseek(at->kern,len_pos,SEEK_SET);
362 putlong(at->kern,pos-len_pos);
363 fseek(at->kern,pos,SEEK_SET);
364 }
365 }
366 }
367
ttf_dumpkerns(struct alltabs * at,SplineFont * sf)368 void ttf_dumpkerns(struct alltabs *at, SplineFont *sf) {
369 int i, mmcnt=0, sum;
370 int version;
371 MMSet *mm = at->dovariations ? sf->mm : NULL;
372 struct kerncounts kcnt;
373 int must_use_old_style = 0;
374
375 if ( !at->applemode && (!at->opentypemode || (at->gi.flags&ttf_flag_oldkern)) ) {
376 must_use_old_style = true;
377 SFKernClassTempDecompose(sf,false);
378 mm = NULL;
379 } else {
380 if ( mm!=NULL ) {
381 for ( i=0; i<mm->instance_count; ++i ) {
382 mmcnt += CountKerns(at,mm->instances[i],&kcnt);
383 free(kcnt.hbreaks); free(kcnt.vbreaks);
384 }
385 sf = mm->normal;
386 }
387 }
388
389 sum = CountKerns(at,sf,&kcnt);
390 free(kcnt.hbreaks); free(kcnt.vbreaks);
391 if ( sum==0 && mmcnt==0 ) {
392 if ( must_use_old_style )
393 SFKernCleanup(sf,false);
394 return;
395 }
396
397 /* Old kerning format (version 0) uses 16 bit quantities */
398 /* Apple's new format (version 0x00010000) uses 32 bit quantities */
399 at->kern = GFileTmpfile();
400 if ( must_use_old_style ||
401 ( kcnt.kccnt==0 && kcnt.vkccnt==0 && kcnt.ksm==0 && mmcnt==0 )) {
402 /* MS does not support format 1,2,3 kern sub-tables so if we have them */
403 /* we might as well admit that this table is for apple only and use */
404 /* the new format apple recommends. Otherwise, use the old format */
405 /* If we might need to store tuple data, use the new format */
406 putshort(at->kern,0); /* version */
407 putshort(at->kern,sum); /* number of subtables */
408 version = 0;
409 } else {
410 putlong(at->kern,0x00010000); /* version */
411 putlong(at->kern,sum+mmcnt); /* number of subtables */
412 version = 1;
413 }
414
415 ttf_dumpsfkerns(at, sf, -1, version);
416 if ( mm!=NULL ) {
417 for ( i=0; i<mm->instance_count; ++i )
418 ttf_dumpsfkerns(at, mm->instances[i], i, version);
419 }
420 if ( must_use_old_style )
421 SFKernCleanup(sf,false);
422
423 at->kernlen = ftell(at->kern);
424 if ( at->kernlen&2 )
425 putshort(at->kern,0); /* pad it */
426 }
427
428 /* ************************************************************************** */
429 /* ************************* The 'lcar' table ************************* */
430 /* ************************************************************************** */
431
haslcaret(SplineChar * sc)432 static PST *haslcaret(SplineChar *sc) {
433 PST *pst; int j;
434
435 for ( pst=sc->possub; pst!=NULL && pst->type!=pst_lcaret; pst=pst->next );
436 if ( pst!=NULL ) {
437 if ( !sc->lig_caret_cnt_fixed ) {
438 for ( j=pst->u.lcaret.cnt-1; j>=0 && pst->u.lcaret.carets[j]==0; --j );
439 if ( j==-1 )
440 pst = NULL;
441 } else {
442 if ( pst->u.lcaret.cnt==0 )
443 pst = NULL;
444 }
445 }
446 return( pst );
447 }
448
aat_dumplcar(struct alltabs * at,SplineFont * sf)449 void aat_dumplcar(struct alltabs *at, SplineFont *sf) {
450 int i, j, k, l, seg_cnt, tot, last, offset;
451 PST *pst;
452 FILE *lcar=NULL;
453 SplineChar *sc;
454 /* We do four passes. The first just calculates how much space we will need */
455 /* the second provides the top-level lookup table structure */
456 /* the third provides the arrays of offsets needed for type 4 lookup tables */
457 /* the fourth provides the actual data on the ligature carets */
458
459 for ( k=0; k<4; ++k ) {
460 for ( i=seg_cnt=tot=0; i<at->gi.gcnt; ++i )
461 if ( at->gi.bygid[i]!=-1 &&
462 (pst = haslcaret(sc = sf->glyphs[at->gi.bygid[i]]))!=NULL ) {
463 if ( k==1 )
464 tot = 0;
465 else if ( k==2 ) {
466 putshort(lcar,offset);
467 offset += 2 + 2*LigCaretCnt(sc);
468 } else if ( k==3 ) {
469 putshort(lcar,LigCaretCnt(sc));
470 for ( l=0; l<pst->u.lcaret.cnt; ++l )
471 if ( pst->u.lcaret.carets[l]!=0 || sc->lig_caret_cnt_fixed )
472 putshort(lcar,pst->u.lcaret.carets[l]);
473 }
474 last = i;
475 for ( j=i+1, ++tot; j<at->gi.gcnt && at->gi.bygid[j]!=-1; ++j ) {
476 if ( (pst = haslcaret(sc = sf->glyphs[at->gi.bygid[j]]))== NULL )
477 break;
478 ++tot;
479 last = j;
480 if ( k==2 ) {
481 putshort(lcar,offset);
482 offset += 2 + 2*LigCaretCnt(sc);
483 } else if ( k==3 ) {
484 putshort(lcar,LigCaretCnt(sc));
485 for ( l=0; l<pst->u.lcaret.cnt; ++l )
486 if ( pst->u.lcaret.carets[l]!=0 || sc->lig_caret_cnt_fixed )
487 putshort(lcar,pst->u.lcaret.carets[l]);
488 }
489 }
490 if ( k==1 ) {
491 putshort(lcar,last);
492 putshort(lcar,i);
493 putshort(lcar,offset);
494 offset += 2*tot;
495 }
496 ++seg_cnt;
497 i = j-1;
498 }
499 if ( k==0 ) {
500 if ( seg_cnt==0 )
501 return;
502 lcar = GFileTmpfile();
503 putlong(lcar, 0x00010000); /* version */
504 putshort(lcar,0); /* data are distances (not points) */
505
506 putshort(lcar,4); /* Lookup table format 4 */
507 /* Binary search header */
508 putshort(lcar,6); /* Entry size */
509 putshort(lcar,seg_cnt); /* Number of segments */
510 for ( j=0,l=1; l<=seg_cnt; l<<=1, ++j );
511 --j; l>>=1;
512 putshort(lcar,6*l);
513 putshort(lcar,j);
514 putshort(lcar,6*(seg_cnt-l));
515 offset = /*4+2+*/6*2 + seg_cnt*6 + 6 /* fake segment at end */;
516 /* Offset relative to lookup table, not to lcar_start */
517 /* Or, that's true while we build the lookup table. Once we */
518 /* start working on the data offsets they are relative to */
519 /* lcar_start */
520 } else if ( k==1 ) { /* flag entry */
521 putshort(lcar,0xffff);
522 putshort(lcar,0xffff);
523 putshort(lcar,0);
524
525 offset += 6; /* Now offsets are relative to lcar_start */
526 }
527 }
528 at->lcar = lcar;
529 at->lcarlen = ftell(at->lcar);
530 if ( at->lcarlen&2 )
531 putshort(at->lcar,0);
532 }
533
534 /* ************************************************************************** */
535 /* ************************* The 'morx' table ************************* */
536 /* ************************* (and 'feat') ************************* */
537 /* ************************************************************************** */
538
539 /* Each lookup gets its own subtable, so there may be multiple subtables */
540 /* with the same feature/setting. The subtables will be ordered the same */
541 /* way the lookups are, which might lead to awkwardness if there are many */
542 /* chains and the same feature occurs in several of them */
543 /* (only the default language will be used) */
544 struct feature {
545 int16 featureType, featureSetting;
546 MacFeat *mf, *smf;
547 struct macsetting *ms, *sms;
548 unsigned int vertOnly: 1;
549 unsigned int r2l: 1; /* I think this is the "descending" flag */
550 unsigned int needsOff: 1;
551 unsigned int singleMutex: 1;
552 unsigned int dummyOff: 1;
553 uint8 subtable_type;
554 int chain;
555 int32 flag, offFlags;
556 uint32 feature_start;
557 uint32 feature_len; /* Does not include header yet */
558 struct feature *next; /* features in output order */
559 struct feature *nexttype; /* features in feature/setting order */
560 struct feature *nextsame; /* all features with the same feature/setting */
561 int setting_cnt, setting_index, real_index;
562 };
563
564 static struct feature *featureFromSubtable(SplineFont *sf, struct lookup_subtable *sub );
565 static int PSTHasTag(PST *pst, uint32 tag);
566
morxfeaturesfree(struct feature * features)567 static void morxfeaturesfree(struct feature *features) {
568 struct feature *n;
569
570 for ( ; features!=NULL; features=n ) {
571 n = features->next;
572 chunkfree( features,sizeof(*features) );
573 }
574 }
575
mort_classes(FILE * temp,SplineFont * sf,struct glyphinfo * gi)576 static void mort_classes(FILE *temp,SplineFont *sf,struct glyphinfo *gi) {
577 int first, last, i, cnt;
578 /* Mort tables just have a trimmed byte array for the classes */
579
580 for ( first=0; first<gi->gcnt; ++first )
581 if ( gi->bygid[first]!=-1 && sf->glyphs[gi->bygid[first]]->lsidebearing!=1 )
582 break;
583 for ( last=gi->gcnt-1; last>first; --last )
584 if ( gi->bygid[last]!=-1 && sf->glyphs[gi->bygid[last]]->lsidebearing!=1 )
585 break;
586 cnt = last-first+1;
587
588 putshort(temp,first);
589 putshort(temp,cnt);
590 for ( i=first; i<=last; ++i )
591 if ( gi->bygid[i]==-1 )
592 putc(1,temp);
593 else
594 putc(sf->glyphs[gi->bygid[i]]->lsidebearing,temp);
595 if ( cnt&1 )
596 putc(1,temp); /* Pad to a word boundary */
597 }
598
morx_lookupmap(FILE * temp,SplineChar ** glyphs,uint16 * maps,int gcnt)599 static void morx_lookupmap(FILE *temp,SplineChar **glyphs,uint16 *maps,int gcnt) {
600 int i, j, k, l, seg_cnt, tot, last, offset;
601 /* We do four passes. The first just calculates how much space we will need (if any) */
602 /* the second provides the top-level lookup table structure */
603 /* the third provides the arrays of offsets needed for type 4 lookup tables */
604
605 for ( k=0; k<3; ++k ) {
606 for ( i=seg_cnt=tot=0; i<gcnt; ++i ) {
607 if ( glyphs[i]==NULL )
608 continue;
609 if ( k==1 )
610 tot = 0;
611 else if ( k==2 ) {
612 putshort(temp,maps[i]);
613 }
614 last = i;
615 for ( j=i+1, ++tot; j<gcnt && glyphs[j]!=NULL && glyphs[j]->ttf_glyph==glyphs[i]->ttf_glyph+j-i; ++j ) {
616 ++tot;
617 last = j;
618 if ( k==2 ) {
619 putshort(temp,maps[j]);
620 }
621 }
622 if ( k==1 ) {
623 putshort(temp,glyphs[last]->ttf_glyph);
624 putshort(temp,glyphs[i]->ttf_glyph);
625 putshort(temp,offset);
626 offset += 2*tot;
627 }
628 ++seg_cnt;
629 i = j-1;
630 }
631 if ( k==0 ) {
632 putshort(temp,4); /* Lookup table format 4 */
633 /* Binary search header */
634 putshort(temp,6); /* Entry size */
635 putshort(temp,seg_cnt); /* Number of segments */
636 for ( j=0,l=1; l<=seg_cnt; l<<=1, ++j );
637 --j; l>>=1;
638 putshort(temp,6*l);
639 putshort(temp,j);
640 putshort(temp,6*(seg_cnt-l));
641 if ( seg_cnt==0 )
642 return;
643 offset = 6*2 + seg_cnt*6 + 6;
644 } else if ( k==1 ) { /* flag entry */
645 putshort(temp,0xffff);
646 putshort(temp,0xffff);
647 putshort(temp,0);
648 }
649 }
650 }
651
morx_dumpSubsFeature(FILE * temp,SplineChar ** glyphs,uint16 * maps,int gcnt)652 static void morx_dumpSubsFeature(FILE *temp,SplineChar **glyphs,uint16 *maps,int gcnt) {
653 morx_lookupmap(temp,glyphs,maps,gcnt);
654 }
655
aat_dumpmorx_substitutions(struct alltabs * at,SplineFont * sf,FILE * temp,struct feature * features,struct lookup_subtable * sub)656 static struct feature *aat_dumpmorx_substitutions(struct alltabs *at, SplineFont *sf,
657 FILE *temp, struct feature *features, struct lookup_subtable *sub) {
658 int i, k, gcnt;
659 SplineChar *sc, *msc, **glyphs;
660 uint16 *maps;
661 struct feature *cur;
662 PST *pst;
663
664 for ( k=0; k<2; ++k ) {
665 gcnt = 0;
666 for ( i=0; i<at->gi.gcnt; ++i ) if ( at->gi.bygid[i]!=-1 ) {
667 sc = sf->glyphs[at->gi.bygid[i]];
668 for ( pst=sc->possub; pst!=NULL && pst->subtable!=sub; pst=pst->next );
669 if ( pst!=NULL ) {
670 if ( k==1 ) {
671 msc = SFGetChar(sf,-1,pst->u.subs.variant);
672 glyphs[gcnt] = sc;
673 if ( msc!=NULL && msc->ttf_glyph!=-1 ) {
674 maps[gcnt++] = msc->ttf_glyph;
675 } else if ( msc==NULL &&
676 strcmp(pst->u.subs.variant,MAC_DELETED_GLYPH_NAME)==0 ) {
677 maps[gcnt++] = 0xffff;
678 }
679 } else
680 ++gcnt;
681 }
682 }
683 if ( k==0 ) {
684 if ( gcnt==0 )
685 return( features );
686 glyphs = malloc((gcnt+1)*sizeof(SplineChar *));
687 maps = malloc((gcnt+1)*sizeof(uint16));
688 } else {
689 glyphs[gcnt] = NULL; maps[gcnt] = 0;
690 }
691 }
692
693 cur = featureFromSubtable(sf,sub);
694 cur->next = features;
695 cur->r2l = sub->lookup->lookup_flags&pst_r2l ? true : false;
696 features = cur;
697 cur->subtable_type = 4;
698 cur->feature_start = ftell(temp);
699 morx_dumpSubsFeature(temp,glyphs,maps,gcnt);
700 if ( (ftell(temp)-cur->feature_start)&1 )
701 putc('\0',temp);
702 if ( (ftell(temp)-cur->feature_start)&2 )
703 putshort(temp,0);
704 cur->feature_len = ftell(temp)-cur->feature_start;
705 free(glyphs); free(maps);
706 return( features);
707 }
708
LigListMatchSubtable(SplineFont * sf,LigList * ligs,struct lookup_subtable * sub)709 static LigList *LigListMatchSubtable(SplineFont *sf,LigList *ligs,
710 struct lookup_subtable *sub) {
711 LigList *l;
712
713 for ( l=ligs; l!=NULL; l=l->next )
714 if ( l->lig->subtable==sub )
715 return( l );
716 return( NULL );
717 }
718
IsMarkChar(SplineChar * sc)719 static int IsMarkChar( SplineChar *sc ) {
720 AnchorPoint *ap;
721
722 ap=sc->anchor;
723 while ( ap!=NULL && (ap->type==at_centry || ap->type==at_cexit) )
724 ap = ap->next;
725 if ( ap!=NULL && (ap->type==at_mark || ap->type==at_basemark) )
726 return( true );
727
728 return( false );
729 }
730
731 struct transition { uint16 next_state, dontconsume, ismark, trans_ent; LigList *l; };
732 struct trans_entries { uint16 next_state, flags, act_index; LigList *l; };
morx_dumpLigaFeature(FILE * temp,SplineChar ** glyphs,int gcnt,struct lookup_subtable * sub,struct alltabs * at,SplineFont * sf,int ignoremarks)733 static void morx_dumpLigaFeature(FILE *temp,SplineChar **glyphs,int gcnt,
734 struct lookup_subtable *sub, struct alltabs *at, SplineFont *sf,
735 int ignoremarks) {
736 LigList *l;
737 struct splinecharlist *comp;
738 uint16 *used = calloc(at->maxp.numGlyphs,sizeof(uint16));
739 SplineChar **cglyphs;
740 uint16 *map;
741 int i,j,k,class, state_max, state_cnt, base, last;
742 uint32 start;
743 struct transition **states;
744 struct trans_entries *trans;
745 int trans_cnt;
746 int maxccnt=0;
747 int acnt, lcnt, charcnt;
748 uint32 *actions;
749 uint16 *components, *lig_glyphs;
750 uint32 here;
751 struct splinecharlist *scl;
752 int anymarks;
753
754 /* figure out the classes (one for each character used to make a lig) */
755 for ( i=0; i<gcnt; ++i ) {
756 used[glyphs[i]->ttf_glyph] = true;
757 for ( l=glyphs[i]->ligofme; l!=NULL; l=l->next ) if ( l->lig->subtable==sub ) {
758 for ( comp = l->components; comp!=NULL; comp=comp->next )
759 used[comp->sc->ttf_glyph] = true;
760 }
761 }
762 class = 4;
763 for ( i=0; i<at->maxp.numGlyphs; ++i ) if ( used[i] )
764 used[i] = class++;
765 anymarks = false;
766 charcnt = class;
767 if ( ignoremarks ) {
768 for ( i=0; i<at->gi.gcnt; ++i ) if ( at->gi.bygid[i]!=-1 ) {
769 if ( IsMarkChar(sf->glyphs[at->gi.bygid[i]])) {
770 anymarks = true;
771 ++charcnt;
772 used[i] = class;
773 }
774 }
775 if ( anymarks )
776 ++class;
777 }
778 cglyphs = malloc((charcnt+1)*sizeof(SplineChar *));
779 map = malloc((charcnt+1)*sizeof(uint16));
780 j=0;
781 for ( i=k=0; i<at->maxp.numGlyphs; ++i ) if ( used[i] ) {
782 j = at->gi.bygid[i];
783 if ( j!=-1 ) {
784 cglyphs[k] = sf->glyphs[j];
785 map[k++] = used[i];
786 }
787 }
788 cglyphs[k] = NULL;
789
790 start = ftell(temp);
791 putlong(temp,class);
792 putlong(temp,7*sizeof(uint32));
793 putlong(temp,0); /* Fill in later */
794 putlong(temp,0);
795 putlong(temp,0);
796 putlong(temp,0);
797 putlong(temp,0);
798 morx_lookupmap(temp,cglyphs,map,k); /* dump the class lookup table */
799 free( cglyphs ); free( map );
800 here = ftell(temp);
801 fseek(temp,start+2*sizeof(uint32),SEEK_SET);
802 putlong(temp,here-start); /* Point to start of state arrays */
803 fseek(temp,0,SEEK_END);
804
805 /* Now build the state machine */
806 /* Note: the ligofme list is so ordered that the longest ligatures come first */
807 /* we will depend on that in the case of "ffl", "ffi", "ff" */
808 state_max = 40; state_cnt = 2;
809 states = malloc(state_max*sizeof(struct transition *));
810 states[0] = calloc(class,sizeof(struct transition)); /* Initial state */
811 states[1] = calloc(class,sizeof(struct transition)); /* other Initial state */
812 for ( i=0; i<gcnt; ++i ) {
813 if ( state_cnt>=state_max )
814 states = realloc(states,(state_max += 40)*sizeof(struct transition *));
815 base = state_cnt;
816 states[0][used[glyphs[i]->ttf_glyph]].next_state = state_cnt;
817 states[1][used[glyphs[i]->ttf_glyph]].next_state = state_cnt;
818 states[state_cnt++] = calloc(class,sizeof(struct transition));
819 for ( l=glyphs[i]->ligofme; l!=NULL; l=l->next ) if ( l->lig->subtable==sub ) {
820 if ( l->ccnt > maxccnt ) maxccnt = l->ccnt;
821 last = base;
822 for ( comp = l->components; comp!=NULL; comp=comp->next ) {
823 if ( states[last][used[comp->sc->ttf_glyph]].next_state==0 ) {
824 if ( comp->next==NULL )
825 states[last][used[comp->sc->ttf_glyph]].l = l;
826 else {
827 states[last][used[comp->sc->ttf_glyph]].next_state = state_cnt;
828 if ( state_cnt>=state_max )
829 states = realloc(states,(state_max += 40)*sizeof(struct transition *));
830 last = state_cnt;
831 states[state_cnt++] = calloc(class,sizeof(struct transition));
832 }
833 } else {
834 last = states[last][used[comp->sc->ttf_glyph]].next_state;
835 if ( comp->next==NULL ) {
836 /* this is where we depend on the ordering */
837 for ( j=0; j<class; ++j )
838 if ( states[last][j].next_state==0 && states[last][j].l==NULL ) {
839 states[last][j].l = l;
840 states[last][j].dontconsume = true;
841 /* the next state should continue to be 0 (initial) */
842 }
843 }
844 }
845 }
846 }
847 }
848 if ( anymarks ) {
849 /* behavior for a mark is the same everywhere: stay in current state */
850 /* do no operations. consume the mark */
851 for ( i=0; i<state_cnt; ++i ) {
852 states[i][class-1].next_state = i;
853 states[i][class-1].ismark = true;
854 }
855 }
856 /* Ok, we've got the state machine now. Convert it into apple's wierd */
857 /* (space saving) format */
858 trans = malloc(class*state_cnt*sizeof(struct trans_entries));
859 trans_cnt = 0;
860 for ( i=0; i<state_cnt; ++i ) for ( j=0; j<class; ++j ) {
861 if ( states[i][j].ismark )
862 k = trans_cnt;
863 else for ( k=0; k<trans_cnt; ++k ) {
864 if ( trans[k].next_state==states[i][j].next_state &&
865 (trans[k].flags&0x4000?1:0) == states[i][j].dontconsume &&
866 trans[k].l ==states[i][j].l )
867 break;
868 }
869 states[i][j].trans_ent = k;
870 if ( k==trans_cnt ) {
871 trans[k].next_state = states[i][j].next_state;
872 trans[k].l = states[i][j].l;
873 trans[k].flags = 0;
874 if ( states[i][j].dontconsume )
875 trans[k].flags = 0x4000;
876 else if ( states[i][j].ismark )
877 /* Do nothing */;
878 else if ( trans[k].next_state!=0 || trans[k].l!=NULL )
879 trans[k].flags = 0x8000;
880 if ( trans[k].l!=NULL )
881 trans[k].flags |= 0x2000;
882 trans[k].act_index = 0;
883 ++trans_cnt;
884 }
885 }
886 /* Oops. Bug. */
887 /* Suppose we have two ligatures f+l=>fl & s+t->st. */
888 /* Suppose we get input "fst" */
889 /* Now the state machine we've built so far will go to the f branch, see */
890 /* the "s" and go back to state 0 */
891 /* Obviously that's wrong, we've lost the st. So either we go back to 0 */
892 /* but don't advance the glyph, or we take the transition from state 0 */
893 /* and copy it to here. The second is easier for me just now */
894 for ( i=2; i<state_cnt; ++i ) for ( j=4; j<class; ++j ) {
895 if ( states[i][j].trans_ent == 0 && states[0][j].trans_ent != 0 )
896 states[i][j].trans_ent = states[0][j].trans_ent;
897 }
898
899 /* Dump out the state machine */
900 for ( i=0; i<state_cnt; ++i ) for ( j=0; j<class; ++j )
901 putshort( temp, states[i][j].trans_ent );
902
903 /* Now figure out the ligature actions (and all the other tables) */
904 actions = malloc(trans_cnt*maxccnt*sizeof(uint32));
905 components = malloc(trans_cnt*maxccnt*sizeof(uint16));
906 lig_glyphs = malloc(trans_cnt*sizeof(uint16));
907 acnt = lcnt = 0;
908 for ( i=0; i<trans_cnt; ++i ) if ( trans[i].l!=NULL ) {
909 lig_glyphs[lcnt] = trans[i].l->lig->u.lig.lig->ttf_glyph;
910 /* component Glyphs get popped off the stack in the reverse order */
911 /* so we must built our tables backwards */
912 components[acnt+trans[i].l->ccnt-1] = lcnt;
913 actions[acnt+trans[i].l->ccnt-1] = 0x80000000 |
914 ((acnt+trans[i].l->ccnt-1 - trans[i].l->first->ttf_glyph)&0x3fffffff);
915 for ( scl=trans[i].l->components,j=trans[i].l->ccnt-2; scl!=NULL; scl=scl->next, --j ) {
916 components[acnt+j] = 0;
917 actions[acnt+j] = (acnt+j - scl->sc->ttf_glyph)&0x3fffffff;
918 }
919 trans[i].act_index = acnt;
920 ++lcnt;
921 acnt += trans[i].l->ccnt;
922 }
923
924 /* Now we know how big all the tables will be. Dump out their locations */
925 here = ftell(temp);
926 fseek(temp,start+3*sizeof(uint32),SEEK_SET);
927 putlong(temp,here-start); /* Point to start of entry array */
928 putlong(temp,here-start+6*trans_cnt); /* Point to start of actions */
929 putlong(temp,here-start+6*trans_cnt+4*acnt);/* Point to start of components */
930 putlong(temp,here-start+6*trans_cnt+6*acnt);/* Point to start of ligatures */
931 fseek(temp,0,SEEK_END);
932
933 /* Now dump the transitions */
934 for ( i=0; i<trans_cnt; ++i ) {
935 putshort(temp,trans[i].next_state);
936 putshort(temp,trans[i].flags);
937 putshort(temp,trans[i].act_index);
938 }
939 /* And the actions */
940 for ( i=0; i<acnt; ++i )
941 putlong(temp,actions[i]);
942 /* And the components */
943 for ( i=0; i<acnt; ++i )
944 putshort(temp,components[i]);
945 /* Do A simple check on the validity of what we've done */
946 if ( here+6*trans_cnt+6*acnt != ftell(temp) )
947 IError( "Offset wrong in morx ligature table\n" );
948 /* And finally the ligature glyph indeces */
949 for ( i=0; i<lcnt; ++i )
950 putshort(temp,lig_glyphs[i]);
951
952 /* clean up */
953 free(actions); free(components); free(lig_glyphs);
954 free(trans);
955 for ( i=0; i<state_cnt; ++i )
956 free(states[i]);
957 free(states);
958 free(used);
959 }
960
aat_dumpmorx_ligatures(struct alltabs * at,SplineFont * sf,FILE * temp,struct feature * features,struct lookup_subtable * sub)961 static struct feature *aat_dumpmorx_ligatures(struct alltabs *at, SplineFont *sf,
962 FILE *temp, struct feature *features, struct lookup_subtable *sub) {
963 int i, k, gcnt;
964 SplineChar *sc, *ssc, **glyphs;
965 struct feature *cur;
966 LigList *l;
967
968 glyphs = malloc((at->maxp.numGlyphs+1)*sizeof(SplineChar *));
969 for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
970 sf->glyphs[i]->ticked = false;
971
972 for ( i=0; i<at->gi.gcnt; ++i )
973 if ( at->gi.bygid[i]!=-1 && !(sc=sf->glyphs[at->gi.bygid[i]])->ticked &&
974 (l = LigListMatchSubtable(sf,sc->ligofme,sub))!=NULL ) {
975 int ignoremarks = sub->lookup->lookup_flags & pst_ignorecombiningmarks ? 1 : 0 ;
976 for ( k=i, gcnt=0; k<at->gi.gcnt; ++k )
977 if ( at->gi.bygid[k]!=-1 &&
978 (ssc=sf->glyphs[at->gi.bygid[k]])!=NULL && !ssc->ticked &&
979 LigListMatchSubtable(sf,ssc->ligofme,sub)) {
980 glyphs[gcnt++] = ssc;
981 ssc->ticked = true;
982 }
983 glyphs[gcnt] = NULL;
984 cur = featureFromSubtable(sf,sub);
985 cur->next = features;
986 features = cur;
987 cur->subtable_type = 2; /* ligature */
988 cur->feature_start = ftell(temp);
989 morx_dumpLigaFeature(temp,glyphs,gcnt,sub,at,sf,ignoremarks);
990 if ( (ftell(temp)-cur->feature_start)&1 )
991 putc('\0',temp);
992 if ( (ftell(temp)-cur->feature_start)&2 )
993 putshort(temp,0);
994 cur->feature_len = ftell(temp)-cur->feature_start;
995 cur->r2l = sub->lookup->lookup_flags&pst_r2l ? true : false;
996 }
997
998 free(glyphs);
999 return( features);
1000 }
1001
morx_dumpnestedsubs(FILE * temp,SplineFont * sf,OTLookup * otl,struct glyphinfo * gi)1002 static void morx_dumpnestedsubs(FILE *temp,SplineFont *sf,OTLookup *otl,struct glyphinfo *gi) {
1003 int i, j, gcnt;
1004 PST *pst;
1005 SplineChar **glyphs, *sc;
1006 uint16 *map;
1007 struct lookup_subtable *sub = otl->subtables; /* Mac can't have more than one subtable/lookup */
1008
1009 for ( j=0; j<2; ++j ) {
1010 gcnt = 0;
1011 for ( i = 0; i<gi->gcnt; ++i ) if ( gi->bygid[i]!=-1 ) {
1012 for ( pst=sf->glyphs[gi->bygid[i]]->possub;
1013 pst!=NULL && pst->subtable!=sub; pst=pst->next );
1014 if ( pst!=NULL && pst->type==pst_substitution &&
1015 (sc=SFGetChar(sf,-1,pst->u.subs.variant))!=NULL &&
1016 sc->ttf_glyph!=-1 ) {
1017 if ( j ) {
1018 glyphs[gcnt] = sf->glyphs[gi->bygid[i]];
1019 map[gcnt] = sc->ttf_glyph;
1020 }
1021 ++gcnt;
1022 }
1023 }
1024 if ( !j ) {
1025 glyphs = malloc((gcnt+1)*sizeof(SplineChar *));
1026 map = malloc(gcnt*sizeof(uint16));
1027 glyphs[gcnt] = NULL;
1028 }
1029 }
1030 morx_lookupmap(temp,glyphs,map,gcnt);
1031 free(glyphs);
1032 free(map);
1033 }
1034
NamesToGlyphs(SplineFont * sf,char * names,uint16 * cnt)1035 static uint16 *NamesToGlyphs(SplineFont *sf,char *names,uint16 *cnt) {
1036 char *pt, *start;
1037 int c, ch;
1038 uint16 *ret;
1039 SplineChar *sc;
1040
1041 for ( c=0, pt=names; *pt; ++pt )
1042 if ( *pt==' ' ) ++c;
1043 ret = malloc((c+1)*sizeof(uint16));
1044
1045 for ( c=0, pt=names; *pt; ) {
1046 while ( *pt==' ' ) ++pt;
1047 if ( *pt=='\0' )
1048 break;
1049 start = pt;
1050 while ( *pt!=' ' && *pt!='\0' ) ++pt;
1051 ch = *pt; *pt='\0';
1052 sc = SFGetChar(sf,-1,start);
1053 *pt = ch;
1054 if ( sc!=NULL && sc->ttf_glyph!=-1 )
1055 ret[c++] = sc->ttf_glyph;
1056 }
1057 *cnt = c;
1058 return( ret );
1059 }
1060
morx_dumpASM(FILE * temp,ASM * sm,struct alltabs * at,SplineFont * sf)1061 static int morx_dumpASM(FILE *temp,ASM *sm, struct alltabs *at, SplineFont *sf ) {
1062 int i, j, k, gcnt, ch;
1063 char *pt, *end;
1064 uint16 *map;
1065 SplineChar **glyphs, *sc;
1066 int stcnt, tcnt;
1067 struct ins { char *names; uint16 len,pos; uint16 *glyphs; } *subsins=NULL;
1068 OTLookup **subslookups=NULL;
1069 uint32 start, here, substable_pos, state_offset;
1070 struct transdata { uint16 transition, mark_index, cur_index; } *transdata;
1071 struct trans { uint16 ns, flags, mi, ci; } *trans;
1072 int ismort = sm->type == asm_kern;
1073 FILE *kernvalues;
1074
1075 for ( i=0; i<sf->glyphcnt; ++i ) if ( sf->glyphs[i]!=NULL )
1076 sf->glyphs[i]->lsidebearing = 1;
1077
1078 gcnt = 0;
1079 for ( i=4; i<sm->class_cnt; ++i ) {
1080 for ( pt = sm->classes[i]; ; pt=end ) {
1081 while ( *pt==' ' ) ++pt;
1082 if ( *pt=='\0' )
1083 break;
1084 for ( end=pt; *end!='\0' && *end!=' '; ++end );
1085 ch = *end; *end = '\0';
1086 sc = SFGetChar(sf,-1,pt);
1087 *end = ch;
1088 if ( sc!=NULL ) {
1089 sc->lsidebearing = i;
1090 ++gcnt;
1091 }
1092 }
1093 }
1094 glyphs = malloc((gcnt+1)*sizeof(SplineChar *));
1095 map = malloc((gcnt+1)*sizeof(uint16));
1096 gcnt = 0;
1097 for ( i=0; i<at->gi.gcnt; ++i ) if ( at->gi.bygid[i]!=-1 && sf->glyphs[at->gi.bygid[i]]->lsidebearing!=1 ) {
1098 glyphs[gcnt] = sf->glyphs[at->gi.bygid[i]];
1099 map[gcnt++] = sf->glyphs[at->gi.bygid[i]]->lsidebearing;
1100 }
1101 glyphs[gcnt] = NULL;
1102
1103 /* Give each subs tab an index into the mac's substitution lookups */
1104 transdata = calloc(sm->state_cnt*sm->class_cnt,sizeof(struct transdata));
1105 stcnt = 0;
1106 subslookups = NULL; subsins = NULL;
1107 if ( sm->type==asm_context ) {
1108 subslookups = malloc(2*sm->state_cnt*sm->class_cnt*sizeof(OTLookup*));
1109 for ( j=0; j<sm->state_cnt*sm->class_cnt; ++j ) {
1110 struct asm_state *this = &sm->state[j];
1111 transdata[j].mark_index = transdata[j].cur_index = 0xffff;
1112 if ( this->u.context.mark_lookup!=NULL ) {
1113 for ( i=0; i<stcnt; ++i )
1114 if ( subslookups[i]==this->u.context.mark_lookup )
1115 break;
1116 if ( i==stcnt )
1117 subslookups[stcnt++] = this->u.context.mark_lookup;
1118 transdata[j].mark_index = i;
1119 }
1120 if ( this->u.context.cur_lookup!=NULL ) {
1121 for ( i=0; i<stcnt; ++i )
1122 if ( subslookups[i]==this->u.context.cur_lookup )
1123 break;
1124 if ( i==stcnt )
1125 subslookups[stcnt++] = this->u.context.cur_lookup;
1126 transdata[j].cur_index = i;
1127 }
1128 }
1129 } else if ( sm->type==asm_insert ) {
1130 subsins = malloc(2*sm->state_cnt*sm->class_cnt*sizeof(struct ins));
1131 for ( j=0; j<sm->state_cnt*sm->class_cnt; ++j ) {
1132 struct asm_state *this = &sm->state[j];
1133 transdata[j].mark_index = transdata[j].cur_index = 0xffff;
1134 if ( this->u.insert.mark_ins!=0 ) {
1135 for ( i=0; i<stcnt; ++i )
1136 if ( strcmp(subsins[i].names,this->u.insert.mark_ins)==0 )
1137 break;
1138 if ( i==stcnt ) {
1139 subsins[stcnt].pos = stcnt==0 ? 0 : subsins[stcnt-1].pos +
1140 subsins[stcnt-1].len;
1141 subsins[stcnt].names = this->u.insert.mark_ins;
1142 subsins[stcnt].glyphs = NamesToGlyphs(sf,subsins[stcnt].names,&subsins[stcnt].len);
1143 ++stcnt;
1144 }
1145 transdata[j].mark_index = subsins[i].pos;
1146 }
1147 if ( this->u.insert.cur_ins!=0 ) {
1148 for ( i=0; i<stcnt; ++i )
1149 if ( strcmp(subsins[i].names,this->u.insert.cur_ins)==0 )
1150 break;
1151 if ( i==stcnt ) {
1152 subsins[stcnt].pos = stcnt==0 ? 0 : subsins[stcnt-1].pos +
1153 subsins[stcnt-1].len;
1154 subsins[stcnt].names = this->u.insert.cur_ins;
1155 subsins[stcnt].glyphs = NamesToGlyphs(sf,subsins[stcnt].names,&subsins[stcnt].len);
1156 ++stcnt;
1157 }
1158 transdata[j].cur_index = subsins[i].pos;
1159 }
1160 }
1161 } else if ( sm->type==asm_kern ) {
1162 int off=0;
1163 kernvalues = GFileTmpfile();
1164 for ( j=0; j<sm->state_cnt*sm->class_cnt; ++j ) {
1165 struct asm_state *this = &sm->state[j];
1166 transdata[j].mark_index = 0xffff;
1167 if ( this->u.kern.kcnt!=0 ) {
1168 for ( k=0; k<j; ++k )
1169 if ( sm->state[k].u.kern.kcnt==this->u.kern.kcnt &&
1170 memcmp(sm->state[k].u.kern.kerns,this->u.kern.kerns,
1171 this->u.kern.kcnt*sizeof(int16))==0 )
1172 break;
1173 if ( k!=j )
1174 transdata[j].mark_index = transdata[k].mark_index;
1175 else {
1176 transdata[j].mark_index = off;
1177 off += this->u.kern.kcnt*sizeof(int16);
1178 /* kerning values must be output backwards */
1179 for ( k=this->u.kern.kcnt-1; k>=1; --k )
1180 putshort(kernvalues,this->u.kern.kerns[k]&~1);
1181 /* And the last one must be odd */
1182 putshort(kernvalues,this->u.kern.kerns[0]|1);
1183 }
1184 }
1185 }
1186 }
1187
1188 trans = malloc(sm->state_cnt*sm->class_cnt*sizeof(struct trans));
1189 tcnt = 0;
1190 for ( j=0; j<sm->state_cnt*sm->class_cnt; ++j ) {
1191 struct asm_state *this = &sm->state[j];
1192 for ( i=0; i<tcnt; ++i )
1193 if ( trans[i].ns==this->next_state && trans[i].flags==this->flags &&
1194 trans[i].mi==transdata[j].mark_index &&
1195 trans[i].ci==transdata[j].cur_index )
1196 break;
1197 if ( i==tcnt ) {
1198 trans[tcnt].ns = this->next_state;
1199 trans[tcnt].flags = this->flags;
1200 trans[tcnt].mi = transdata[j].mark_index;
1201 trans[tcnt++].ci = transdata[j].cur_index;
1202 }
1203 transdata[j].transition = i;
1204 }
1205
1206
1207 /* Output the header */
1208 start = ftell(temp);
1209 if ( ismort /* old format still used for kerning */ ) {
1210 putshort(temp,sm->class_cnt);
1211 putshort(temp,5*sizeof(uint16)); /* class offset */
1212 putshort(temp,0); /* state offset */
1213 putshort(temp,0); /* transition entry offset */
1214 putshort(temp,0); /* kerning values offset */
1215 mort_classes(temp,sf,&at->gi); /* dump the class table */
1216 } else {
1217 putlong(temp,sm->class_cnt);
1218 if ( sm->type==asm_indic ) {
1219 putlong(temp,4*sizeof(uint32)); /* class offset */
1220 putlong(temp,0); /* state offset */
1221 putlong(temp,0); /* transition entry offset */
1222 } else {
1223 putlong(temp,5*sizeof(uint32)); /* class offset */
1224 putlong(temp,0); /* state offset */
1225 putlong(temp,0); /* transition entry offset */
1226 putlong(temp,0); /* substitution/insertion table offset */
1227 }
1228 morx_lookupmap(temp,glyphs,map,gcnt);/* dump the class lookup table */
1229 }
1230 free(glyphs); free(map);
1231
1232
1233 state_offset = ftell(temp)-start;
1234 if ( ismort ) {
1235 fseek(temp,start+2*sizeof(uint16),SEEK_SET);
1236 putshort(temp,state_offset); /* Point to start of state arrays */
1237 } else {
1238 fseek(temp,start+2*sizeof(uint32),SEEK_SET);
1239 putlong(temp,state_offset); /* Point to start of state arrays */
1240 }
1241 fseek(temp,0,SEEK_END);
1242
1243 if ( ismort ) {
1244 for ( j=0; j<sm->state_cnt*sm->class_cnt; ++j )
1245 putc(transdata[j].transition,temp);
1246 if ( ftell(temp)&1 )
1247 putc(0,temp); /* Pad to a word boundry */
1248 } else {
1249 for ( j=0; j<sm->state_cnt*sm->class_cnt; ++j )
1250 putshort(temp,transdata[j].transition);
1251 }
1252 free(transdata);
1253
1254 here = ftell(temp);
1255 if ( ismort ) {
1256 fseek(temp,start+3*sizeof(uint16),SEEK_SET);
1257 putshort(temp,here-start); /* Point to start of transition arrays */
1258 } else {
1259 fseek(temp,start+3*sizeof(uint32),SEEK_SET);
1260 putlong(temp,here-start); /* Point to start of transition arrays */
1261 }
1262 fseek(temp,0,SEEK_END);
1263
1264 /* Now the transitions */
1265 if ( sm->type==asm_kern ) {
1266 substable_pos = here+tcnt*2*sizeof(int16);
1267 for ( i=0; i<tcnt; ++i ) {
1268 /* mort tables use an offset rather than the state number */
1269 putshort(temp,trans[i].ns*sm->class_cnt+state_offset);
1270 if ( trans[i].mi!=0xffff )
1271 trans[i].flags |= substable_pos-start+trans[i].mi;
1272 putshort(temp,trans[i].flags);
1273 }
1274 } else {
1275 for ( i=0; i<tcnt; ++i ) {
1276 putshort(temp,trans[i].ns);
1277 putshort(temp,trans[i].flags);
1278 if ( sm->type!=asm_indic && sm->type!=asm_kern ) {
1279 putshort(temp,trans[i].mi );
1280 putshort(temp,trans[i].ci );
1281 }
1282 }
1283 }
1284 free(trans);
1285
1286 if ( sm->type==asm_context ) {
1287 substable_pos = ftell(temp);
1288 fseek(temp,start+4*sizeof(uint32),SEEK_SET);
1289 putlong(temp,substable_pos-start); /* Point to start of substitution lookup offsets */
1290 fseek(temp,0,SEEK_END);
1291
1292 /* And finally the substitutions */
1293 for ( i=0; i<stcnt; ++i )
1294 putlong(temp,0); /* offsets to the substitutions */
1295 for ( i=0; i<stcnt; ++i ) {
1296 here = ftell(temp);
1297 fseek(temp,substable_pos+i*sizeof(uint32),SEEK_SET);
1298 putlong(temp,here-substable_pos);
1299 fseek(temp,0,SEEK_END);
1300 morx_dumpnestedsubs(temp,sf,subslookups[i],&at->gi);
1301 }
1302 free(subslookups);
1303 } else if ( sm->type==asm_insert ) {
1304 substable_pos = ftell(temp);
1305 fseek(temp,start+4*sizeof(uint32),SEEK_SET);
1306 putlong(temp,substable_pos-start); /* Point to start of insertions */
1307 fseek(temp,0,SEEK_END);
1308
1309 for ( i=0; i<stcnt; ++i ) {
1310 for ( j=0; j<subsins[i].len; ++j )
1311 putshort(temp,subsins[i].glyphs[j]);
1312 free(subsins[i].glyphs);
1313 }
1314 free(subsins);
1315 } else if ( sm->type==asm_kern ) {
1316 if ( substable_pos!=ftell(temp) )
1317 IError( "Kern Values table in wrong place.\n" );
1318 fseek(temp,start+4*sizeof(uint16),SEEK_SET);
1319 putshort(temp,substable_pos-start); /* Point to start of insertions */
1320 fseek(temp,0,SEEK_END);
1321 if ( !ttfcopyfile(temp,kernvalues,substable_pos,"kern-subtable")) at->error = true;
1322 }
1323 return( true );
1324 }
1325
aat_dumpmorx_asm(struct alltabs * at,SplineFont * sf,FILE * temp,struct feature * features,ASM * sm)1326 static struct feature *aat_dumpmorx_asm(struct alltabs *at, SplineFont *sf,
1327 FILE *temp, struct feature *features, ASM *sm) {
1328 struct feature *cur;
1329
1330 cur = featureFromSubtable(sf,sm->subtable);
1331 cur->vertOnly = sm->flags&0x8000?1:0;
1332 cur->r2l = sm->flags&0x4000?1:0;
1333 cur->subtable_type = sm->type; /* contextual glyph subs */
1334 cur->feature_start = ftell(temp);
1335 if ( morx_dumpASM(temp,sm,at,sf)) {
1336 cur->next = features;
1337 features = cur;
1338 if ( (ftell(temp)-cur->feature_start)&1 )
1339 putc('\0',temp);
1340 if ( (ftell(temp)-cur->feature_start)&2 )
1341 putshort(temp,0);
1342 cur->feature_len = ftell(temp)-cur->feature_start;
1343 } else
1344 chunkfree(cur,sizeof(struct feature));
1345 return( features);
1346 }
1347
aat_dumpmorx_cvtopentype(struct alltabs * at,SplineFont * sf,FILE * temp,struct feature * features,struct lookup_subtable * sub)1348 static struct feature *aat_dumpmorx_cvtopentype(struct alltabs *at, SplineFont *sf,
1349 FILE *temp, struct feature *features, struct lookup_subtable *sub) {
1350 ASM *sm;
1351
1352 if ( FPSTisMacable(sf,sub->fpst)) {
1353 sm = ASMFromFPST(sf,sub->fpst,true);
1354 if ( sm!=NULL ) {
1355 features = aat_dumpmorx_asm(at,sf,temp,features,sm);
1356 ASMFree(sm);
1357 }
1358 }
1359 return( features );
1360 }
1361
IsOtfArabicFormFeature(OTLookup * otl)1362 static int IsOtfArabicFormFeature(OTLookup *otl) {
1363 FeatureScriptLangList *fl;
1364
1365 for ( fl=otl->features; fl!=NULL; fl=fl->next ) {
1366 if (( fl->featuretag == CHR('i','n','i','t') ||
1367 fl->featuretag==CHR('m','e','d','i') ||
1368 fl->featuretag==CHR('f','i','n','a') ||
1369 fl->featuretag==CHR('i','s','o','l') ) &&
1370 scriptsHaveDefault(fl->scripts))
1371 return( true );
1372 }
1373 return( false );
1374 }
1375
HasCursiveConnectionSM(SplineFont * sf)1376 static int HasCursiveConnectionSM(SplineFont *sf) {
1377 int featureType, featureSetting;
1378 uint32 tag;
1379 ASM *sm;
1380
1381 if ( OTTagToMacFeature(CHR('i','s','o','l'),&featureType,&featureSetting) ) {
1382 tag = (featureType<<16) | featureSetting;
1383 for ( sm = sf->sm; sm!=NULL; sm=sm->next ) {
1384 if ( sm->subtable->lookup->features->featuretag==tag )
1385 return( true );
1386 }
1387 }
1388 for ( sm = sf->sm; sm!=NULL; sm=sm->next ) {
1389 if ( sm->subtable->lookup->features->featuretag==CHR('i','s','o','l') )
1390 return( true );
1391 }
1392 return( false );
1393 }
1394
FormedScripts(SplineFont * sf)1395 static uint32 *FormedScripts(SplineFont *sf) {
1396 OTLookup *otl;
1397 uint32 *ret = NULL;
1398 int scnt=0, smax=0;
1399 FeatureScriptLangList *fl;
1400 struct scriptlanglist *sl;
1401 int i;
1402
1403 for ( otl= sf->gsub_lookups; otl!=NULL; otl=otl->next ) {
1404 if ( otl->lookup_type == gsub_single ) {
1405 for ( fl=otl->features; fl!=NULL; fl=fl->next ) {
1406 if ( fl->featuretag == CHR('i','n','i','t') ||
1407 fl->featuretag==CHR('m','e','d','i') ||
1408 fl->featuretag==CHR('f','i','n','a') ||
1409 fl->featuretag==CHR('i','s','o','l') ) {
1410 for ( sl=fl->scripts; sl!=NULL; sl=sl->next ) {
1411 for ( i=0; i<sl->lang_cnt; ++i ) {
1412 if ( (i<MAX_LANG ? sl->langs[i] : sl->morelangs[i-MAX_LANG])==DEFAULT_LANG ) {
1413 if ( scnt<=smax )
1414 ret = realloc(ret,(smax+=5)*sizeof(uint32));
1415 ret[scnt++] = sl->script;
1416 }
1417 }
1418 }
1419 }
1420 }
1421 }
1422 }
1423 if ( scnt==0 )
1424 return( NULL );
1425 if ( scnt<=smax )
1426 ret = realloc(ret,(smax+=1)*sizeof(uint32));
1427 ret[scnt] = 0;
1428 return( ret );
1429 }
1430
Macable(SplineFont * sf,OTLookup * otl)1431 int Macable(SplineFont *sf, OTLookup *otl) {
1432 int ft, fs;
1433 FeatureScriptLangList *features;
1434
1435 switch ( otl->lookup_type ) {
1436 /* These lookup types are mac only */
1437 case kern_statemachine: case morx_indic: case morx_context: case morx_insert:
1438 return( true );
1439 /* These lookup types or OpenType only */
1440 case gsub_multiple: case gsub_alternate:
1441 case gpos_single: case gpos_cursive: case gpos_mark2base:
1442 case gpos_mark2ligature: case gpos_mark2mark:
1443 return( false );
1444 /* These are OpenType only, but they might be convertable to a state */
1445 /* machine */
1446 case gsub_context:
1447 case gsub_contextchain: case gsub_reversecchain:
1448 case gpos_context: case gpos_contextchain:
1449 if ( sf==NULL || sf->sm!=NULL )
1450 return( false );
1451 /* Else fall through into the test on the feature tag */;
1452 /* These two can be expressed in both, and might be either */
1453 case gsub_single: case gsub_ligature: case gpos_pair:
1454 for ( features = otl->features; features!=NULL; features = features->next ) {
1455 if ( features->ismac || OTTagToMacFeature(features->featuretag,&ft,&fs))
1456 return( true );
1457 }
1458 }
1459 return( false );
1460 }
1461
aat_dumpmorx_cvtopentypeforms(struct alltabs * at,SplineFont * sf,FILE * temp,struct feature * features)1462 static struct feature *aat_dumpmorx_cvtopentypeforms(struct alltabs *at, SplineFont *sf,
1463 FILE *temp, struct feature *features) {
1464 ASM *sm;
1465 uint32 *scripts;
1466 int featureType, featureSetting;
1467 int i;
1468 OTLookup *otl;
1469
1470 if ( sf->cidmaster!=NULL )
1471 sf = sf->cidmaster;
1472 else if ( sf->mm!=NULL ) sf=sf->mm->normal;
1473
1474 for ( otl=sf->gsub_lookups; otl!=NULL; otl=otl->next )
1475 if ( Macable(sf,otl) && otl->lookup_type==gsub_single && IsOtfArabicFormFeature(otl))
1476 otl->ticked = true;
1477
1478 if ( OTTagToMacFeature(CHR('i','s','o','l'),&featureType,&featureSetting) ) {
1479 scripts = FormedScripts(sf);
1480 for ( i=0; scripts[i]!=0; ++i ) {
1481 sm = ASMFromOpenTypeForms(sf,scripts[i]);
1482 if ( sm!=NULL ) {
1483 features = aat_dumpmorx_asm(at,sf,temp,features,sm);
1484 ASMFree(sf->sm);
1485 }
1486 }
1487 free(scripts);
1488 }
1489 return( features );
1490 }
1491
featuresReverse(struct feature * features)1492 static struct feature *featuresReverse(struct feature *features) {
1493 struct feature *p, *n;
1494
1495 p = NULL;
1496 while ( features!=NULL ) {
1497 n = features->next;
1498 features->next = p;
1499 p = features;
1500 features = n;
1501 }
1502 return( p );
1503 }
1504
featuresOrderByType(struct feature * features)1505 static struct feature *featuresOrderByType(struct feature *features) {
1506 struct feature *f, **all;
1507 int i, j, cnt/*, saw_default*/;
1508
1509 for ( cnt=0, f=features; f!=NULL; f=f->next, ++cnt );
1510 if ( cnt==1 ) {
1511 return( features );
1512 }
1513 all = malloc(cnt*sizeof(struct feature *));
1514 for ( i=0, f=features; f!=NULL; f=f->next, ++i )
1515 all[i] = f;
1516 for ( i=0; i<cnt-1; ++i ) for ( j=i+1; j<cnt; ++j ) {
1517 if ( all[i]->featureType>all[j]->featureType ||
1518 (all[i]->featureType==all[j]->featureType && all[i]->featureSetting>all[j]->featureSetting )) {
1519 f = all[i];
1520 all[i] = all[j];
1521 all[j] = f;
1522 }
1523 }
1524 for ( i=0; i<cnt-1; ++i )
1525 all[i]->nexttype = all[i+1];
1526 all[cnt-1]->nexttype = NULL;
1527 features = all[0];
1528 free( all );
1529 return( features );
1530 }
1531
AddExclusiveNoops(SplineFont * sf,struct feature * features)1532 static struct feature *AddExclusiveNoops(SplineFont *sf, struct feature *features) {
1533 struct feature *f, *n, *def, *p, *t;
1534 /* mutually exclusive features need to have a setting which does nothing */
1535
1536 for ( f=features; f!=NULL; f=n ) {
1537 n= f->nexttype;
1538 if ( f->mf!=NULL && f->mf->ismutex ) {
1539 def = NULL;
1540 for ( n=f; n!=NULL && n->featureType==f->featureType; n=n->nexttype ) {
1541 if ( n->featureSetting==f->mf->default_setting )
1542 def = n;
1543 }
1544 if ( def==NULL ) {
1545 t = chunkalloc(sizeof(struct feature));
1546 *t = *f;
1547 t->feature_start = 0; t->feature_len=0; t->next = NULL;
1548 t->featureSetting = f->mf->default_setting;
1549 t->ms = FindMacSetting(sf,t->featureType,f->mf->default_setting,&t->sms);
1550 t->flag = 0;
1551 t->dummyOff = true;
1552 if ( f==features )
1553 p = NULL;
1554 else
1555 for ( p=features; p->nexttype!=f; p=p->nexttype );
1556 n = f;
1557 while ( n!=NULL && n->featureType==t->featureType && n->featureSetting<t->featureSetting ) {
1558 p = n;
1559 n = n->nexttype;
1560 }
1561 t->nexttype = n;
1562 if ( p==NULL )
1563 features = t;
1564 else
1565 p->nexttype = t;
1566 while ( n!=NULL && n->featureType==t->featureType )
1567 n=n->nexttype;
1568 }
1569 }
1570 }
1571 return( features );
1572 }
1573
SetExclusiveOffs(struct feature * features)1574 static void SetExclusiveOffs(struct feature *features) {
1575 struct feature *f, *n;
1576 int offFlags;
1577 /* mutually exclusive features need to have a setting which does nothing */
1578
1579 for ( f=features; f!=NULL; f=n ) {
1580 n= f->nexttype;
1581 if ( f->mf!=NULL && f->mf->ismutex ) {
1582 offFlags=0;
1583 for ( n=f; n!=NULL && n->featureType==f->featureType; n=n->nexttype ) {
1584 offFlags |= n->flag;
1585 }
1586 for ( n=f; n!=NULL && n->featureType==f->featureType; n=n->nexttype )
1587 n->offFlags = ~(offFlags&~n->flag);
1588 }
1589 }
1590 return;
1591 }
1592
aat_dumpfeat(struct alltabs * at,SplineFont * sf,struct feature * feature)1593 static void aat_dumpfeat(struct alltabs *at, SplineFont *sf, struct feature *feature) {
1594 int scnt, fcnt, cnt;
1595 struct feature *f, *n, *p;
1596 int k;
1597 uint32 offset;
1598 int strid = at->next_strid;
1599 int fn=0;
1600 MacFeat *mf, *smf;
1601 struct macsetting *ms, *sms;
1602 /* Dump the 'feat' table which is a connection between morx features and */
1603 /* the name table */
1604 /* We do three passes. The first just calculates how much space we will need */
1605 /* the second provides names for the feature types */
1606 /* and the third provides names for the feature settings */
1607 /* As we fill up the feat table we also create an array of strings */
1608 /* (strid, char *pointer) which will be used by the 'name' table to */
1609 /* give names to the features and their settings */
1610 /* The mac documentation says that the features should be sorted by feature type */
1611 /* This is a lie. Features should appear in the same order they appear */
1612 /* in the morx table, otherwise WorldText goes blooie */
1613 /* WorldText doesn't exist any more. Perhaps the morx table needs to be */
1614 /* sorted by feature id too? No, it can't be. Feature 0 must come last */
1615
1616 if ( feature==NULL )
1617 return;
1618
1619 fcnt = scnt = 0;
1620 for ( k=0; k<3; ++k ) {
1621 if ( k==1 ) {
1622 /* FeatureName entry for All Typographics */
1623 mf = FindMacFeature(sf,0,&smf);
1624 if ( (mf!=NULL && mf->featname!=NULL) || (smf!=NULL && smf->featname!=NULL)) {
1625 at->feat_name[fn].mn = mf!=NULL ? mf->featname : NULL;
1626 at->feat_name[fn].smn = smf!=NULL ? smf->featname : NULL;
1627 at->feat_name[fn++].strid = strid;
1628 }
1629 putshort(at->feat,0);
1630 putshort(at->feat,1);
1631 putlong(at->feat,offset);
1632 putshort(at->feat,0x0000); /* non exclusive */
1633 putshort(at->feat,strid++);
1634 offset += 1*4; /* (1 setting, 4 bytes) All Features */
1635 } else if ( k==2 ) {
1636 /* Setting Name Array for All Typographic Features */
1637 ms = FindMacSetting(sf,0,0,&sms);
1638 if ( (ms!=NULL && ms->setname!=NULL) || (sms!=NULL && sms->setname!=NULL)) {
1639 at->feat_name[fn].mn = ms!=NULL ? ms->setname: NULL;
1640 at->feat_name[fn].smn = sms!=NULL ? sms->setname: NULL;
1641 at->feat_name[fn++].strid = strid;
1642 }
1643 putshort(at->feat,0);
1644 putshort(at->feat,strid++);
1645 }
1646 for ( f=feature; f!=NULL; f=n ) {
1647 cnt=1;
1648 if ( k!=2 ) {
1649 p = f;
1650 for ( n=f->nexttype; n!=NULL && n->featureType==f->featureType; n = n->nexttype ) {
1651 if ( p->featureSetting!=n->featureSetting ) {
1652 ++cnt;
1653 p = n;
1654 }
1655 }
1656 } else {
1657 p = f;
1658 for ( n=f; n!=NULL && n->featureType==f->featureType; n = n->nexttype ) {
1659 if ( n==f || p->featureSetting!=n->featureSetting ) {
1660 if (( n->ms!=NULL && n->ms->setname!=NULL ) ||
1661 ( n->sms!=NULL && n->sms->setname!=NULL)) {
1662 at->feat_name[fn].mn = n->ms!=NULL ? n->ms->setname : NULL;
1663 at->feat_name[fn].smn = n->sms!=NULL ? n->sms->setname : NULL;
1664 at->feat_name[fn++].strid = strid;
1665 }
1666 putshort(at->feat,n->featureSetting);
1667 putshort(at->feat,strid++);
1668 p = n;
1669 }
1670 }
1671 }
1672 if ( k==0 ) {
1673 ++fcnt;
1674 scnt += cnt;
1675 } else if ( k==1 ) {
1676 if ( (f->mf!=NULL && f->mf->featname!=NULL) || (f->smf!=NULL && f->smf->featname!=NULL) ) {
1677 at->feat_name[fn].mn = f->mf!=NULL ? f->mf->featname : NULL;
1678 at->feat_name[fn].smn = f->smf!=NULL ? f->smf->featname : NULL;
1679 at->feat_name[fn++].strid = strid;
1680 }
1681 putshort(at->feat,f->featureType);
1682 putshort(at->feat,cnt);
1683 putlong(at->feat,offset);
1684 putshort(at->feat,f->mf!=NULL && f->mf->ismutex?(0xc000|f->mf->default_setting):
1685 0);
1686 putshort(at->feat,strid++);
1687 offset += 4*cnt;
1688 }
1689 }
1690 if ( k==0 ) {
1691 ++fcnt; /* Add one for "All Typographic Features" */
1692 ++scnt; /* Add one for All Features */
1693 at->feat = GFileTmpfile();
1694 at->feat_name = malloc((fcnt+scnt+1)*sizeof(struct feat_name));
1695 putlong(at->feat,0x00010000);
1696 putshort(at->feat,fcnt);
1697 putshort(at->feat,0);
1698 putlong(at->feat,0);
1699 offset = 12 /* header */ + fcnt*12;
1700 }
1701 }
1702 memset( &at->feat_name[fn],0,sizeof(struct feat_name));
1703 at->next_strid = strid;
1704
1705 at->featlen = ftell(at->feat);
1706 if ( at->featlen&2 )
1707 putshort(at->feat,0);
1708 }
1709
featuresAssignFlagsChains(struct feature * features,struct feature * feature_by_type)1710 static int featuresAssignFlagsChains(struct feature *features, struct feature *feature_by_type) {
1711 int bit, cnt, chain, fcnt, i, mybit;
1712 struct feature *f, *n, *p;
1713 uint16 chains_features[32];
1714 uint32 chains_bitindex[32]; /* Index for bit of first setting of this feature */
1715
1716 if ( features==NULL )
1717 return( 0 );
1718
1719 /* A feature may have several subtables which need not be contiguous in */
1720 /* the feature list */
1721 /* Indeed we could have a feature in several different chains */
1722 /* Sigh */
1723 /* we figure out how many possible settings there are for each feature */
1724 /* and reserve that many bits for the feature in all chains in which it */
1725 /* occurs */
1726 /* Note that here we count dummy settings (they need turn off bits) */
1727 /* so we use feature_by_type */
1728 for ( f=feature_by_type; f!=NULL; f=n ) {
1729 cnt=0;
1730 p = NULL;
1731 for ( n=f; n!=NULL && n->featureType==f->featureType; n=n->nexttype ) {
1732 if ( p==NULL || n->featureSetting != p->featureSetting ) {
1733 ++cnt;
1734 p = n;
1735 }
1736 n->setting_index = cnt-1;
1737 }
1738 for ( n=f; n!=NULL && n->featureType==f->featureType; n=n->nexttype )
1739 n->setting_cnt = cnt;
1740 }
1741 /* When we counted flags we need to count the dummy features for turning */
1742 /* things off. Those features live in features_by_type. When we put */
1743 /* things in chains we want only the meaningful features, and we want */
1744 /* them to be properly ordered. That we get from the "features" list */
1745 fcnt = 0; chain = 0; bit=0;
1746 for ( f=features; f!=NULL; f=f->next ) {
1747 for ( i=0; i<fcnt && chains_features[i]!=f->featureType; ++i );
1748 if ( i==fcnt ) {
1749 if ( bit+f->setting_cnt>=32 ) {
1750 ++chain;
1751 bit = 0;
1752 fcnt = 0;
1753 }
1754 chains_features[fcnt] = f->featureType;
1755 chains_bitindex[fcnt++] = bit;
1756 mybit = bit;
1757 bit += f->setting_cnt;
1758 } else
1759 mybit = chains_bitindex[i];
1760 f->real_index = mybit+f->setting_index;
1761 f->flag = 1<<f->real_index;
1762 if ( f->mf!=NULL && f->mf->ismutex ) {
1763 int off = (~((~0)<<f->setting_cnt))<<mybit;
1764 off &= !f->flag;
1765 f->offFlags = off;
1766 } else {
1767 if ( f->featureSetting&1 ) {
1768 for ( n=feature_by_type; n!=NULL &&
1769 (n->featureType!=f->featureType || n->featureSetting!=f->featureSetting+1);
1770 n=n->next );
1771 } else {
1772 for ( n=feature_by_type; n!=NULL &&
1773 (n->featureType!=f->featureType || n->featureSetting!=f->featureSetting+1);
1774 n=n->next );
1775 }
1776 if ( n!=NULL )
1777 f->offFlags = 1<<(mybit+n->setting_index);
1778 else
1779 f->offFlags = ~0;
1780 }
1781 f->chain = chain;
1782 }
1783 return( chain+1 );
1784 }
1785
morxDumpChain(struct alltabs * at,struct feature * features,struct feature * features_by_type,int chain,FILE * temp)1786 static void morxDumpChain(struct alltabs *at,struct feature *features,
1787 struct feature *features_by_type, int chain, FILE *temp) {
1788 uint32 def_flags=0;
1789 struct feature *f, *n;
1790 uint32 chain_start, end;
1791 char *buf;
1792 int len, tot, fs_cnt, sub_cnt;
1793 struct feature *all[32];
1794 int i,offFlags, last_ri=-1, last_f=-1, ri;
1795
1796 memset(all,0,sizeof(all));
1797 for ( f=features, fs_cnt=sub_cnt=0; f!=NULL; f=f->next ) {
1798 if ( f->chain==chain ) {
1799 if ( all[f->real_index]==NULL ) {
1800 int base = f->real_index-f->setting_index;
1801 /* Note we use features_by_type here. It will have the default*/
1802 /* settings for features, and will be ordered nicely */
1803 for ( n=features_by_type; n!=NULL; n=n->nexttype ) {
1804 if ( n->featureType==f->featureType && n->chain==chain ) {
1805 n->nextsame = all[base+n->setting_index];
1806 all[base+n->setting_index] = n;
1807 if ( n->ms!=NULL && n->ms->initially_enabled )
1808 def_flags |= n->flag;
1809 }
1810 }
1811 }
1812 ++sub_cnt;
1813 }
1814 }
1815
1816 /* Chain header */
1817 chain_start = ftell(at->morx);
1818 putlong(at->morx,def_flags);
1819 putlong(at->morx,0); /* Fix up length later */
1820 putlong(at->morx,0); /* fix up feature count */
1821 putlong(at->morx,sub_cnt); /* subtable cnt */
1822
1823 /* Features */
1824 fs_cnt = 0;
1825 for ( i=0; i<32; ++i ) if ( all[i]!=NULL ) {
1826 putshort(at->morx,all[i]->featureType);
1827 putshort(at->morx,all[i]->featureSetting);
1828 if ( all[i]->dummyOff ) {
1829 putlong(at->morx,0);
1830 if ( last_f==all[i]->featureType )
1831 ri = last_ri;
1832 else if ( i<31 && all[i+1]!=NULL && all[i+1]->featureType == all[i]->featureType )
1833 ri = i+1 - all[i+1]->real_index;
1834 else
1835 ri = 0; /* This can't happen */
1836 } else {
1837 putlong(at->morx,1<<i);
1838 ri = i-all[i]->real_index;
1839 last_ri = ri; last_f = all[i]->featureType;
1840 }
1841 offFlags = all[i]->offFlags;
1842 if ( ri>0 )
1843 offFlags<<=(ri);
1844 else if ( ri<0 )
1845 offFlags>>=(-ri);
1846 putlong(at->morx,offFlags);
1847 ++fs_cnt;
1848
1849 if ( all[i]->needsOff && (i==31 || all[i+1]==NULL ||
1850 all[i+1]->featureType!=all[i]->featureType ||
1851 all[i+1]->featureSetting!=all[i]->featureSetting+1 )) {
1852 putshort(at->morx,all[i]->featureType);
1853 putshort(at->morx,all[i]->featureSetting+1);
1854 putlong(at->morx,0);
1855 putlong(at->morx,all[i]->offFlags & ~all[i]->flag );
1856 ++fs_cnt;
1857 }
1858 /* I used to have code to output the default setting of a mutex */
1859 /* but I should already have put that in the feature list */
1860 }
1861 /* The feature list of every chain must end with these two features */
1862 putshort(at->morx,0); /* All Typo Features */
1863 putshort(at->morx,0); /* All Features */
1864 putlong(at->morx,0xffffffff); /* enable */
1865 putlong(at->morx,0xffffffff); /* disable */
1866 putshort(at->morx,0); /* All Typo Features */
1867 putshort(at->morx,1); /* No Features */
1868 putlong(at->morx,0); /* enable */
1869 putlong(at->morx,0); /* disable */
1870 fs_cnt += 2;
1871
1872 buf = malloc(16*1024);
1873 /* Subtables */
1874 for ( f=features; f!=NULL; f=f->next ) if ( f->chain==chain ) {
1875 putlong(at->morx,f->feature_len+12); /* Size of header needs to be added */
1876 putlong(at->morx,(f->vertOnly?0x80000000:f->r2l?0x40000000:0) | f->subtable_type);
1877 putlong(at->morx,f->flag);
1878 tot = f->feature_len;
1879 fseek(temp, f->feature_start, SEEK_SET);
1880 while ( tot!=0 ) {
1881 len = tot;
1882 if ( len>16*1024 ) len = 16*1024;
1883 len = fread(buf,1,len,temp);
1884 len = fwrite(buf,1,len,at->morx);
1885 if ( len<=0 ) {
1886 IError( "Disk error\n" );
1887 break;
1888 }
1889 tot -= len;
1890 }
1891 }
1892 free(buf);
1893
1894 /* Pad chain to a multiple of four */
1895 if ( (ftell(at->morx)-chain_start)&1 )
1896 putc('\0',at->morx);
1897 if ( (ftell(at->morx)-chain_start)&2 )
1898 putshort(at->morx,0);
1899 end = ftell(at->morx);
1900 fseek(at->morx,chain_start+4,SEEK_SET);
1901 putlong(at->morx,end-chain_start);
1902 putlong(at->morx,fs_cnt);
1903 fseek(at->morx,0,SEEK_END);
1904 }
1905
aat_dumpmorx(struct alltabs * at,SplineFont * sf)1906 void aat_dumpmorx(struct alltabs *at, SplineFont *sf) {
1907 FILE *temp = GFileTmpfile();
1908 struct feature *features = NULL, *features_by_type;
1909 int nchains, i;
1910 OTLookup *otl;
1911 struct lookup_subtable *sub;
1912
1913 /* Arabic Form features all need to be merged together and formed into */
1914 /* a cursive connection state machine. So the first time we see one of */
1915 /* we handle all of them. After that we ignore all of them. Note: if */
1916 /* OpenType has them happening in different orders, that information */
1917 /* will be lost. All will be processed at once. */
1918 for ( otl = sf->gsub_lookups; otl!=NULL; otl=otl->next )
1919 otl->ticked = false;
1920
1921 SFLigaturePrepare(sf);
1922
1923 /* Retain the same lookup ordering */
1924 for ( otl = sf->gsub_lookups; otl!=NULL; otl=otl->next ) {
1925 if ( !Macable(sf,otl))
1926 continue;
1927 if ( otl->lookup_type==gsub_single && IsOtfArabicFormFeature(otl) ) {
1928 if ( otl->ticked )
1929 /* Already processed */;
1930 else if ( HasCursiveConnectionSM(sf) )
1931 /* Skip the OpenType conversion and use the native state machine */;
1932 else
1933 features = aat_dumpmorx_cvtopentypeforms(at,sf,temp,features);
1934 } else {
1935 for ( sub=otl->subtables; sub!=NULL; sub=sub->next ) {
1936 switch ( otl->lookup_type ) {
1937 case gsub_single:
1938 features = aat_dumpmorx_substitutions(at,sf,temp,features,sub);
1939 break;
1940 case gsub_ligature:
1941 features = aat_dumpmorx_ligatures(at,sf,temp,features,sub);
1942 break;
1943 case morx_indic: case morx_context: case morx_insert:
1944 features = aat_dumpmorx_asm(at,sf,temp,features,sub->sm);
1945 break;
1946 default:
1947 if ( sf->sm==NULL )
1948 features = aat_dumpmorx_cvtopentype(at,sf,temp,features,sub);
1949 }
1950 }
1951 }
1952 }
1953
1954 SFLigatureCleanup(sf);
1955
1956 if ( features==NULL ) {
1957 fclose(temp);
1958 return;
1959 }
1960 /* The features are in reverse execution order */
1961 features = featuresReverse(features);
1962 /* But the feature table requires them in numeric order */
1963 features_by_type = featuresOrderByType(features);
1964 features_by_type = AddExclusiveNoops(sf,features_by_type);
1965 aat_dumpfeat(at, sf, features_by_type);
1966 nchains = featuresAssignFlagsChains(features,features_by_type);
1967 SetExclusiveOffs(features_by_type);
1968
1969 at->morx = GFileTmpfile();
1970 putlong(at->morx,0x00020000);
1971 putlong(at->morx,nchains);
1972 for ( i=0; i<nchains; ++i )
1973 morxDumpChain(at,features,features_by_type,i,temp);
1974 fclose(temp);
1975 morxfeaturesfree(features_by_type);
1976
1977 at->morxlen = ftell(at->morx);
1978 if ( at->morxlen&1 )
1979 putc('\0',at->morx);
1980 if ( (at->morxlen+1)&2 )
1981 putshort(at->morx,0);
1982 }
1983
1984 /* ************************************************************************** */
1985 /* ************************* The 'opbd' table ************************* */
1986 /* ************************************************************************** */
1987
haslrbounds(SplineChar * sc,PST ** left,PST ** right)1988 int haslrbounds(SplineChar *sc, PST **left, PST **right) {
1989 PST *pst;
1990
1991 *left = *right = NULL;
1992 for ( pst=sc->possub; pst!=NULL ; pst=pst->next ) {
1993 if ( pst->type == pst_position ) {
1994 if ( PSTHasTag(pst,CHR('l','f','b','d')) ) {
1995 *left = pst;
1996 if ( *right )
1997 return( true );
1998 } else if ( PSTHasTag(pst,CHR('r','t','b','d')) ) {
1999 *right = pst;
2000 if ( *left )
2001 return( true );
2002 }
2003 }
2004 }
2005 return( *left!=NULL || *right!=NULL );
2006 }
2007
aat_dumpopbd(struct alltabs * at,SplineFont * _sf)2008 void aat_dumpopbd(struct alltabs *at, SplineFont *_sf) {
2009 int i, j, k, l, seg_cnt, tot, last, offset;
2010 PST *left, *right;
2011 FILE *opbd=NULL;
2012 /* We do four passes. The first just calculates how much space we will need (if any) */
2013 /* the second provides the top-level lookup table structure */
2014 /* the third provides the arrays of offsets needed for type 4 lookup tables */
2015 /* the fourth provides the actual data on the optical bounds */
2016 SplineChar *sc;
2017
2018 for ( k=0; k<4; ++k ) {
2019 for ( i=seg_cnt=tot=0; i<at->gi.gcnt; ++i ) if ( at->gi.bygid[i]!=-1 ) {
2020 l = 0;
2021 sc = _sf->glyphs[at->gi.bygid[i]];
2022 if ( haslrbounds(sc,&left,&right) ) {
2023 if ( k==1 )
2024 tot = 0;
2025 else if ( k==2 ) {
2026 putshort(opbd,offset);
2027 offset += 8;
2028 } else if ( k==3 ) {
2029 putshort(opbd,left!=NULL?-left->u.pos.xoff:0);
2030 putshort(opbd,0); /* top */
2031 putshort(opbd,right!=NULL?-right->u.pos.h_adv_off:0);
2032 putshort(opbd,0); /* bottom */
2033 }
2034 last = i;
2035 for ( j=i+1, ++tot; j<at->gi.gcnt; ++j ) {
2036 if ( at->gi.bygid[i]==-1 || !haslrbounds(_sf->glyphs[at->gi.bygid[j]],&left,&right) )
2037 break;
2038 ++tot;
2039 last = j;
2040 if ( k==2 ) {
2041 putshort(opbd,offset);
2042 offset += 8;
2043 } else if ( k==3 ) {
2044 putshort(opbd,left!=NULL?-left->u.pos.xoff:0);
2045 putshort(opbd,0); /* top */
2046 putshort(opbd,right!=NULL?-right->u.pos.h_adv_off:0);
2047 putshort(opbd,0); /* bottom */
2048 }
2049 }
2050 if ( k==1 ) {
2051 putshort(opbd,last);
2052 putshort(opbd,i);
2053 putshort(opbd,offset);
2054 offset += 2*tot;
2055 }
2056 ++seg_cnt;
2057 i = j-1;
2058 }
2059 }
2060 if ( k==0 ) {
2061 if ( seg_cnt==0 )
2062 return;
2063 opbd = GFileTmpfile();
2064 putlong(opbd, 0x00010000); /* version */
2065 putshort(opbd,0); /* data are distances (not control points) */
2066
2067 putshort(opbd,4); /* Lookup table format 4 */
2068 /* Binary search header */
2069 putshort(opbd,6); /* Entry size */
2070 putshort(opbd,seg_cnt); /* Number of segments */
2071 for ( j=0,l=1; l<=seg_cnt; l<<=1, ++j );
2072 --j; l>>=1;
2073 putshort(opbd,6*l);
2074 putshort(opbd,j);
2075 putshort(opbd,6*(seg_cnt-l));
2076 /* offset from start of lookup, not table */
2077 offset = 6*2/* format, binsearch*/ + seg_cnt*6 +6 /*flag entry */;
2078 } else if ( k==1 ) { /* flag entry */
2079 putshort(opbd,0xffff);
2080 putshort(opbd,0xffff);
2081 putshort(opbd,0);
2082 }
2083 }
2084 at->opbd = opbd;
2085 at->opbdlen = ftell(at->opbd);
2086 if ( at->opbdlen&2 )
2087 putshort(at->opbd,0);
2088 }
2089
2090 /* ************************************************************************** */
2091 /* ************************* The 'prop' table ************************* */
2092 /* ************************************************************************** */
2093
props_array(SplineFont * sf,struct glyphinfo * gi)2094 uint16 *props_array(SplineFont *sf,struct glyphinfo *gi) {
2095 uint16 *props;
2096 int i;
2097 SplineChar *sc, *bsc;
2098 int dir, isfloat, isbracket, offset, doit=false;
2099 AnchorPoint *ap;
2100 PST *pst;
2101 int p;
2102
2103 props = calloc(gi->gcnt+1,sizeof(uint16));
2104 props[gi->gcnt] = -1;
2105
2106 for ( i=0; i<gi->gcnt; ++i ) if ( (p = gi->bygid==NULL ? i : gi->bygid[i])!=-1 ) {
2107 sc = sf->glyphs[p];
2108 if ( sc!=NULL && (gi->bygid==NULL || sc->ttf_glyph!=-1 )) {
2109 dir = 0;
2110 if ( sc->unicodeenc>=0x10300 && sc->unicodeenc<=0x103ff )
2111 dir = 0;
2112 else if ( sc->unicodeenc>=0x10800 && sc->unicodeenc<=0x10fff )
2113 dir = 1;
2114 else if ( sc->unicodeenc!=-1 && sc->unicodeenc<0x10fff ) {
2115 if ( iseuronumeric(sc->unicodeenc) )
2116 dir = 3;
2117 else if ( iseuronumsep(sc->unicodeenc))
2118 dir = 4;
2119 else if ( iseuronumterm(sc->unicodeenc))
2120 dir = 5;
2121 else if ( isarabnumeric(sc->unicodeenc))
2122 dir = 6;
2123 else if ( iscommonsep(sc->unicodeenc))
2124 dir = 7;
2125 else if ( isspace(sc->unicodeenc))
2126 dir = 10;
2127 else if ( islefttoright(sc->unicodeenc) )
2128 dir = 0;
2129 else if ( isrighttoleft(sc->unicodeenc) )
2130 dir = 1;
2131 else if ( SCScriptFromUnicode(sc)==CHR('a','r','a','b') )
2132 dir = 2;
2133 else if ( SCScriptFromUnicode(sc)==CHR('h','e','b','r') )
2134 dir = 1;
2135 else
2136 dir = 11; /* Other neutrals */
2137 /* Not dealing with unicode 3 classes */
2138 /* nor block seperator/ segment seperator */
2139 } else if ( SCScriptFromUnicode(sc)==CHR('a','r','a','b') )
2140 dir = 2;
2141 else if ( SCScriptFromUnicode(sc)==CHR('h','e','b','r') )
2142 dir = 1;
2143
2144 if ( dir==1 || dir==2 ) doit = true;
2145 isfloat = false;
2146 if ( sc->width==0 &&
2147 ((sc->anchor!=NULL && sc->anchor->type==at_mark) ||
2148 (sc->unicodeenc!=-1 && sc->unicodeenc<0x10000 && iscombining(sc->unicodeenc))))
2149 isfloat = doit = true;
2150 isbracket = offset = 0;
2151 if ( sc->unicodeenc!=-1 && sc->unicodeenc<0x10000 && tomirror(sc->unicodeenc)!=0 ) {
2152 bsc = SFGetChar(sf,tomirror(sc->unicodeenc),NULL);
2153 if ( bsc!=NULL && bsc->ttf_glyph-sc->ttf_glyph>-8 && bsc->ttf_glyph-sc->ttf_glyph<8 ) {
2154 isbracket = true;
2155 offset = bsc->ttf_glyph-sc->ttf_glyph;
2156 }
2157 }
2158 if ( !isbracket ) {
2159 for ( pst=sc->possub; pst!=NULL && PSTHasTag(pst,CHR('r','t','l','a')); pst=pst->next );
2160 if ( pst!=NULL && pst->type==pst_substitution &&
2161 (bsc=SFGetChar(sf,-1,pst->u.subs.variant))!=NULL &&
2162 bsc->ttf_glyph!=-1 && bsc->ttf_glyph-sc->ttf_glyph>-8 && bsc->ttf_glyph-sc->ttf_glyph<8 ) {
2163 isbracket = true;
2164 offset = bsc->ttf_glyph-sc->ttf_glyph;
2165 doit = true;
2166 }
2167 }
2168 if ( SCRightToLeft(sc) ) {
2169 /* Apple docs say attached right. So for r2l scripts we look for */
2170 /* a cursive entry, and for l2r a cursive exit */
2171 for ( ap=sc->anchor; ap!=NULL && ap->type!=at_centry; ap=ap->next );
2172 } else {
2173 for ( ap=sc->anchor; ap!=NULL && ap->type!=at_cexit; ap=ap->next );
2174 }
2175 props[sc->ttf_glyph] = dir |
2176 (isfloat ? 0x8000 : 0 ) |
2177 (isbracket ? 0x1000 : 0 ) |
2178 (ap!=NULL ? 0x80 : 0 ) |
2179 ((offset&0xf)<<8);
2180 /* not dealing with */
2181 /* hang left 0x4000 */
2182 /* hang right 0x2000 */
2183 }
2184 }
2185
2186 if ( !doit ) {
2187 free(props);
2188 return( NULL );
2189 }
2190
2191 return( props );
2192 }
2193
aat_dumpprop(struct alltabs * at,SplineFont * sf)2194 void aat_dumpprop(struct alltabs *at, SplineFont *sf) {
2195 uint16 *props = props_array(sf,&at->gi);
2196 uint32 bin_srch_header;
2197 int i, j, cnt;
2198
2199 if ( props==NULL )
2200 return;
2201
2202 at->prop = GFileTmpfile();
2203 putlong(at->prop,0x00020000);
2204 putshort(at->prop,1); /* Lookup data */
2205 putshort(at->prop,0); /* default property is simple l2r */
2206 putshort(at->prop,2); /* lookup format 2 => segment single value */
2207 /* Binsearch header */
2208 bin_srch_header = ftell(at->prop);
2209 putshort(at->prop,6); /* Entry size */
2210 putshort(at->prop,0); /* fill in later */
2211 putshort(at->prop,0);
2212 putshort(at->prop,0);
2213 putshort(at->prop,0);
2214
2215 cnt = 0;
2216 for ( i=0; i<at->gi.gcnt; ++i ) {
2217 while ( i<at->gi.gcnt && props[i]==0 ) ++i; /* skip default entries */
2218 if ( i>=at->gi.gcnt )
2219 break;
2220 for ( j=i+1; j<at->gi.gcnt && props[j]==props[i]; ++j );
2221 putshort(at->prop,j-1);
2222 putshort(at->prop,i);
2223 putshort(at->prop,props[i]);
2224 i = j-1;
2225 ++cnt;
2226 }
2227 putshort(at->prop,0xffff); /* Final eof marker */
2228 putshort(at->prop,0xffff);
2229 putshort(at->prop,0x0000);
2230
2231 fseek(at->prop,bin_srch_header,SEEK_SET);
2232 putshort(at->prop,6); /* Entry size */
2233 putshort(at->prop,cnt); /* Number of segments */
2234 for ( j=0,i=1; i<=cnt; i<<=1, ++j );
2235 --j; i>>=1;
2236 putshort(at->prop,6*i);
2237 putshort(at->prop,j);
2238 putshort(at->prop,6*(cnt-i));
2239
2240 fseek(at->prop,0,SEEK_END);
2241 at->proplen = ftell(at->prop);
2242 if ( at->proplen&2 )
2243 putshort(at->prop,0);
2244 free(props);
2245 }
2246
2247 /* ************************************************************************** */
2248 /* ************************* The 'bsln' table ************************* */
2249 /* ************************************************************************** */
2250
BslnFromTag(uint32 tag)2251 static int BslnFromTag(uint32 tag) {
2252 switch ( tag ) {
2253 case CHR('r','o','m','n'):
2254 return( 0 );
2255 /* Apple has a centered ideographic baseline, while OT has a top ideo bsln*/
2256 /* no way to get Apple's baseline #1 */
2257 case CHR('i','d','e','o'):
2258 return( 2 );
2259 case CHR('h','a','n','g'):
2260 return( 3 );
2261 case CHR('m','a','t','h'):
2262 return( 4 );
2263 default:
2264 return( 0xffff );
2265 }
2266 }
2267
PerGlyphDefBaseline(SplineFont * sf,int * def_baseline)2268 int16 *PerGlyphDefBaseline(SplineFont *sf,int *def_baseline) {
2269 int16 *baselines = malloc(sf->glyphcnt*sizeof(int16));
2270 int gid, bsln, i, any;
2271 SplineChar *sc;
2272 int counts[32]; /* Apple supports a max of 32 baselines, but only 5 are defined */
2273 struct Base *base = sf->horiz_base;
2274 struct basescript *bs;
2275 int bestbsln, bestcnt;
2276
2277 memset(counts,0,sizeof(counts));
2278
2279 for ( gid = 0; gid<sf->glyphcnt; ++gid ) if ( (sc = sf->glyphs[gid])!=NULL ) {
2280 uint32 script = SCScriptFromUnicode(sc);
2281 for ( bs= base->scripts; bs!=NULL; bs=bs->next )
2282 if ( bs->script==script )
2283 break;
2284 if ( bs==NULL )
2285 bsln = 0xffff;
2286 else
2287 bsln = BslnFromTag( base->baseline_tags[bs->def_baseline] );
2288 /* This if is duplicated (almost) in basedlg.c:Base_FinishEdit */
2289 if ( bsln==0xffff ) {
2290 if ( script==CHR('k','a','n','a') || script==CHR('h','a','n','g') ||
2291 script==CHR('h','a','n','i') || script==CHR('b','o','p','o') ||
2292 script==CHR('j','a','m','o') || script==CHR('y','i',' ',' '))
2293 bsln = 2;
2294 else if ( script==CHR('t','i','b','t' ) ||
2295 script == CHR('b','e','n','g' ) || script == CHR('b','n','g','2') ||
2296 script == CHR('d','e','v','a' ) || script == CHR('d','e','v','2') ||
2297 script == CHR('g','u','j','r' ) || script == CHR('g','j','r','2') ||
2298 script == CHR('g','u','r','u' ) || script == CHR('g','u','r','2') ||
2299 script == CHR('k','n','d','a' ) || script == CHR('k','n','d','2') ||
2300 script == CHR('m','l','y','m' ) || script == CHR('m','l','m','2') ||
2301 script == CHR('o','r','y','a' ) || script == CHR('o','r','y','2') ||
2302 script == CHR('t','a','m','l' ) || script == CHR('t','m','l','2') ||
2303 script == CHR('t','e','l','u' ) || script == CHR('t','e','l','2'))
2304 bsln = 3;
2305 else if ( script==CHR('m','a','t','h') )
2306 bsln = 4;
2307 else
2308 bsln = 0;
2309 }
2310 baselines[gid] = bsln;
2311 if ( bsln!=0xffff )
2312 ++counts[bsln];
2313 }
2314
2315 bestbsln = 0;
2316 bestcnt = 0;
2317 any = 0;
2318 for ( i=0; i<32 ; ++i ) {
2319 if ( counts[i]>bestcnt ) {
2320 bestbsln = i;
2321 bestcnt = counts[i];
2322 ++any;
2323 }
2324 }
2325 *def_baseline = bestbsln | (any<=1 ? 0x100 : 0 );
2326 return( baselines );
2327 }
2328
FigureBaseOffsets(SplineFont * sf,int def_bsln,int offsets[32])2329 void FigureBaseOffsets(SplineFont *sf,int def_bsln,int offsets[32]) {
2330 struct Base *base = sf->horiz_base;
2331 struct basescript *bs = base->scripts;
2332 int i;
2333
2334 memset( offsets,0xff,32*sizeof(int));
2335 for ( i=0; i<base->baseline_cnt; ++i ) {
2336 int bsln = BslnFromTag(base->baseline_tags[i]);
2337 if ( bsln!=0xffff )
2338 offsets[bsln] = bs->baseline_pos[i];
2339 }
2340 if ( offsets[def_bsln]!=-1 ) {
2341 for ( i=0; i<32; ++i ) {
2342 if ( offsets[i]!=-1 )
2343 offsets[i] -= offsets[def_bsln];
2344 }
2345 }
2346 /* I suspect baseline 1 is the standard baseline for CJK glyphs on the mac*/
2347 /* (because baseline 2 is often the same as baseline 1, which is wrong for 2) */
2348 /* OT doesn't have a centered ideographic baseline, so guestimate */
2349 /* And I don't want to base it on the actual ideo baseline (go up half an em?) */
2350 /* because in my small sample of 'bsln' tables baseline 2 has been wrong */
2351 /* most of the time, and it is wrong in the example in the docs. */
2352 /* (I know it is wrong because it has the same value as baseline 1, but */
2353 /* is supposed to be below baseline 1 ) */
2354 if ( offsets[1]==-1 ) {
2355 if ( offsets[2]!=-1 )
2356 offsets[1] = offsets[2]+(sf->ascent+sf->descent)/2;
2357 else
2358 offsets[1] = (sf->ascent+sf->descent)/2 - sf->descent;
2359 }
2360 for ( i=0; i<32; ++i )
2361 if ( offsets[i]==-1 )
2362 offsets[i] = 0;
2363 }
2364
aat_dumpbsln(struct alltabs * at,SplineFont * sf)2365 void aat_dumpbsln(struct alltabs *at, SplineFont *sf) {
2366 int def_baseline;
2367 int offsets[32];
2368 int16 *baselines;
2369 int i, gid, j, bsln, cnt;
2370
2371 if ( sf->horiz_base==NULL || sf->horiz_base->baseline_cnt==0 ||
2372 sf->horiz_base->scripts==NULL )
2373 return;
2374
2375 baselines = PerGlyphDefBaseline(sf,&def_baseline);
2376
2377 at->bsln = GFileTmpfile();
2378 putlong(at->bsln,0x00010000); /* Version */
2379 if ( def_baseline & 0x100 ) /* Only one baseline in the font */
2380 putshort(at->bsln,0); /* distanced based (no control point), no per-glyph info */
2381 else
2382 putshort(at->bsln,1); /* distanced based (no cp info) with per-glyph info */
2383 putshort(at->bsln,def_baseline&0x1f);/* Default baseline when no info specified for glyphs */
2384
2385 /* table of 32 int16 (the docs say uint16, but that must be wrong) giving */
2386 /* the offset of the nth baseline from the default baseline. */
2387 /* 0 => Roman, 1=> centered ideo, 2=>low ideo (same as OTF ideo) 3=>hang, 4=>Math */
2388 /* values 5-31 undefined, set to 0 */
2389 FigureBaseOffsets(sf,def_baseline&0x1f,offsets);
2390
2391 for ( i=0; i<32; ++i )
2392 putshort(at->bsln,offsets[i]);
2393
2394 if ( !(def_baseline&0x100) ) {
2395 def_baseline &= 0x1f;
2396
2397 putshort(at->bsln,2); /* Lookup format 2, segmented array w/ single value */
2398
2399 cnt = 0;
2400 for ( i=0; i<at->gi.gcnt; ++i ) if ( (gid=at->gi.bygid[i])!=-1 ) {
2401 if ( baselines[gid]!=-1 && baselines[gid]!=def_baseline ) {
2402 bsln = baselines[gid];
2403 for ( j=i; j<at->gi.gcnt && baselines[at->gi.bygid[i]]==bsln; ++j );
2404 i = j-1;
2405 ++cnt;
2406 }
2407 }
2408
2409 /* Dump out a binary search header */
2410 putshort(at->bsln,6); /* size of each item */
2411 putshort(at->bsln,cnt); /* number of items */
2412 for ( j=1, i=0; cnt<=j; j<<=1, ++i );
2413 putshort(at->bsln,6*j/2); /* j is a power of 2 too big */
2414 putshort(at->bsln,i-1);
2415 putshort(at->bsln,6*(cnt-(j>>1)) );
2416
2417 for ( i=0; i<at->gi.gcnt; ++i ) if ( (gid=at->gi.bygid[i])!=-1 ) {
2418 if ( baselines[gid]!=-1 && baselines[gid]!=def_baseline ) {
2419 bsln = baselines[gid];
2420 for ( j=i; j<at->gi.gcnt && baselines[at->gi.bygid[i]]==bsln; ++j );
2421 putshort(at->bsln,j-1);
2422 putshort(at->bsln,i);
2423 putshort(at->bsln,bsln);
2424 i = j-1;
2425 }
2426 }
2427
2428 putshort(at->bsln,0xffff); /* Final eof marker */
2429 putshort(at->bsln,0xffff);
2430 putshort(at->bsln,0x0000);
2431 }
2432
2433 at->bslnlen = ftell(at->bsln);
2434 /* Only contains 2 & 4 byte quantities, can't have an odd number of bytes */
2435 if ( at->bslnlen&2 )
2436 putshort(at->bsln,0);
2437 free(baselines);
2438 }
2439
2440 /* ************************************************************************** */
2441 /* ************************* utility routines ************************* */
2442 /* ************************************************************************** */
2443
MacFeatureToOTTag(int featureType,int featureSetting)2444 uint32 MacFeatureToOTTag(int featureType,int featureSetting) {
2445 int i;
2446 struct macsettingname *msn = user_macfeat_otftag ? user_macfeat_otftag : macfeat_otftag;
2447
2448 for ( i=0; msn[i].otf_tag!=0; ++i )
2449 if ( msn[i].mac_feature_type == featureType &&
2450 msn[i].mac_feature_setting == featureSetting )
2451 return( msn[i].otf_tag );
2452
2453 return( 0 );
2454 }
2455
OTTagToMacFeature(uint32 tag,int * featureType,int * featureSetting)2456 int OTTagToMacFeature(uint32 tag, int *featureType,int *featureSetting) {
2457 int i;
2458 struct macsettingname *msn = user_macfeat_otftag ? user_macfeat_otftag : macfeat_otftag;
2459
2460 for ( i=0; msn[i].otf_tag!=0; ++i )
2461 if ( msn[i].otf_tag == tag ) {
2462 *featureType = msn[i].mac_feature_type;
2463 *featureSetting = msn[i].mac_feature_setting;
2464 return( true );
2465 }
2466 *featureType = (tag >> 16);
2467 *featureSetting = (tag & 0xFFFF);
2468 /* Ranges taken from Apple Font Registry. An OT tag without a
2469 corresponding mac feature should fail this test.*/
2470 if (*featureType >= 0 && *featureType < 105 && *featureSetting < 16)
2471 return ( true );
2472
2473 *featureType = 0;
2474 *featureSetting = 0;
2475 return( false );
2476 }
2477
featureFromTag(SplineFont * sf,uint32 tag)2478 static struct feature *featureFromTag(SplineFont *sf, uint32 tag ) {
2479 int ft, fs;
2480 struct feature *feat;
2481
2482 feat = chunkalloc(sizeof(struct feature));
2483 if (OTTagToMacFeature(tag, &ft, &fs)) {
2484 feat->featureType = ft;
2485 feat->featureSetting = fs;
2486 feat->mf = FindMacFeature(sf,feat->featureType,&feat->smf);
2487 feat->ms = FindMacSetting(sf,feat->featureType,feat->featureSetting,&feat->sms);
2488 feat->needsOff = feat->mf!=NULL && !feat->mf->ismutex;
2489 feat->vertOnly = tag==CHR('v','r','t','2') || tag==CHR('v','k','n','a');
2490 }
2491
2492 return( feat );
2493 }
2494
featureFromSubtable(SplineFont * sf,struct lookup_subtable * sub)2495 static struct feature *featureFromSubtable(SplineFont *sf, struct lookup_subtable *sub ) {
2496 FeatureScriptLangList *fl;
2497 int ft, fs;
2498
2499 for ( fl=sub->lookup->features; fl!=NULL; fl=fl->next ) {
2500 if ( fl->ismac )
2501 break;
2502 }
2503 if ( fl==NULL ) {
2504 for ( fl=sub->lookup->features; fl!=NULL; fl=fl->next ) {
2505 if ( OTTagToMacFeature(fl->featuretag,&ft,&fs) )
2506 break;
2507 }
2508 if ( fl==NULL ) {
2509 IError("Could not find a mac feature");
2510 return NULL;
2511 }
2512 }
2513 return( featureFromTag(sf,fl->featuretag));
2514 }
2515
PSTHasTag(PST * pst,uint32 tag)2516 static int PSTHasTag(PST *pst, uint32 tag) {
2517 FeatureScriptLangList *fl;
2518
2519 if ( pst->subtable==NULL )
2520 return( false );
2521 for ( fl=pst->subtable->lookup->features; fl!=NULL; fl=fl->next )
2522 if ( fl->featuretag == tag )
2523 return( true );
2524
2525 return( false );
2526 }
2527
scriptsHaveDefault(struct scriptlanglist * sl)2528 int scriptsHaveDefault(struct scriptlanglist *sl) {
2529 int i;
2530
2531 for ( ; sl!=NULL; sl=sl->next ) {
2532 for ( i=0; i<sl->lang_cnt; ++i ) {
2533 if ( (i<MAX_LANG && sl->langs[i]==DEFAULT_LANG) ||
2534 (i>=MAX_LANG && sl->morelangs[i-MAX_LANG]==DEFAULT_LANG)) {
2535 return( true );
2536 }
2537 }
2538 }
2539 return( false );
2540 }
2541
LookupHasDefault(OTLookup * otl)2542 int LookupHasDefault(OTLookup *otl) {
2543 FeatureScriptLangList *feats;
2544
2545 if ( otl->def_lang_checked )
2546 return( otl->def_lang_found );
2547
2548 otl->def_lang_checked = true;
2549 for ( feats=otl->features; feats!=NULL; feats = feats->next ) {
2550 if ( scriptsHaveDefault(feats->scripts) ) {
2551 otl->def_lang_found = true;
2552 return( true );
2553 }
2554 }
2555 otl->def_lang_found = false;
2556 return( false );
2557 }
2558