1 #include "embed.h"
2 #include "embed_pdf_int.h"
3 #include "embed_sfnt_int.h"
4 #include "sfnt.h"
5 #include "sfnt_int.h"
6 #include <assert.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10
emb_otf_get_rights(OTF_FILE * otf)11 EMB_RIGHT_TYPE emb_otf_get_rights(OTF_FILE *otf) // {{{
12 {
13 EMB_RIGHT_TYPE ret=EMB_RIGHT_FULL;
14
15 int len;
16 char *os2=otf_get_table(otf,OTF_TAG('O','S','/','2'),&len);
17 if (os2) {
18 const unsigned short os2_version=get_USHORT(os2);
19 // check len
20 assert( (os2_version!=0x0000)||(len==78) );
21 assert( (os2_version!=0x0001)||(len==86) );
22 assert( (os2_version<0x0002)||(os2_version>0x0004)||(len==96) );
23 if (os2_version<=0x0004) {
24 // get rights
25 unsigned short fsType=get_USHORT(os2+8);
26 // from Adobe's Fontpolicies_v9.pdf, pg 13:
27 if (fsType==0x0002) {
28 ret=EMB_RIGHT_NONE;
29 } else {
30 ret=fsType&0x0300; // EMB_RIGHT_BITMAPONLY, EMB_RIGHT_NO_SUBSET
31 if ((fsType&0x000c)==0x0004) {
32 ret|=EMB_RIGHT_READONLY;
33 }
34 }
35 }
36 free(os2);
37 }
38 return ret;
39 }
40 // }}}
41
42 // NOTE: statically allocated buffer
emb_otf_get_fontname(OTF_FILE * otf)43 const char *emb_otf_get_fontname(OTF_FILE *otf) // {{{
44 {
45 static char fontname[64];
46
47 int len;
48 const char *fname=otf_get_name(otf,3,1,0x409,6,&len); // microsoft
49 if (fname) {
50 int iA,iB=0;
51 for (iA=0;(iA<63)&&(iA*2<len);iA++) {
52 if ( (fname[2*iA]==0)&&
53 (fname[2*iA+1]>=33)&&(fname[2*iA+1]<=126)&&
54 (!strchr("[](){}<>/%",fname[iA*2+1])) ) {
55 fontname[iB++]=fname[iA*2+1];
56 }
57 }
58 fontname[iB]=0;
59 } else if ((fname=otf_get_name(otf,1,0,0,6,&len))) { // mac
60 int iA,iB=0;
61 for (iA=0;(iA<63)&&(iA<len);iA++) {
62 if ( (fname[iA]>=33)&&(fname[iA]<=126)&&
63 (!strchr("[](){}<>/%",fname[iA])) ) {
64 fontname[iB++]=fname[iA];
65 }
66 }
67 fontname[iB]=0;
68 } else {
69 fontname[0]=0;
70 }
71 if (!*fontname) {
72 // TODO construct a fontname, eg from */*/*/4
73 fprintf(stderr,"WARNING: no fontName\n");
74 }
75 return fontname;
76 }
77 // }}}
78
79 // TODO? monospaced by actual glyph width?
80 // TODO? use PCLT table? (esp. CFF, as table dircouraged for glyf fonts)
emb_otf_get_pdf_fontdescr(OTF_FILE * otf,EMB_PDF_FONTDESCR * ret)81 void emb_otf_get_pdf_fontdescr(OTF_FILE *otf,EMB_PDF_FONTDESCR *ret) // {{{
82 {
83 int len;
84
85 // TODO
86 // ... fill in struct
87 char *head=otf_get_table(otf,OTF_TAG('h','e','a','d'),&len);
88 assert(head); // version is 1.0 from otf_load
89 ret->bbxmin=get_SHORT(head+36)*1000/otf->unitsPerEm;
90 ret->bbymin=get_SHORT(head+38)*1000/otf->unitsPerEm;
91 ret->bbxmax=get_SHORT(head+40)*1000/otf->unitsPerEm;
92 ret->bbymax=get_SHORT(head+42)*1000/otf->unitsPerEm;
93 const int macStyle=get_USHORT(head+44);
94 free(head);
95
96 char *post=otf_get_table(otf,OTF_TAG('p','o','s','t'),&len);
97 assert(post);
98 const unsigned int post_version=get_ULONG(post);
99 // check length
100 assert( (post_version!=0x00010000)||(len==32) );
101 assert( (post_version!=0x00020000)||(len>=34+2*otf->numGlyphs) );
102 assert( (post_version!=0x00025000)||(len==35+otf->numGlyphs) );
103 assert( (post_version!=0x00030000)||(len==32) );
104 assert( (post_version!=0x00020000)||(get_USHORT(post+32)==otf->numGlyphs) ); // v4?
105 // assert( (post_version==0x00030000)==(!!(otf->flags&OTF_F_FMT_CFF)) ); // ghostscript embedding does this..
106 // TODO: v4 (apple) : uint16 reencoding[numGlyphs]
107 if ( (post_version==0x00010000)||
108 (post_version==0x00020000)||
109 (post_version==0x00025000)||
110 (post_version==0x00030000)||
111 (post_version==0x00040000) ) {
112 ret->italicAngle=get_LONG(post+4)>>16;
113 if (get_ULONG(post+12)>0) { // monospaced
114 ret->flags|=1;
115 }
116 } else {
117 fprintf(stderr,"WARNING: no italicAngle, no monospaced flag\n");
118 }
119 free(post);
120
121 char *os2=otf_get_table(otf,OTF_TAG('O','S','/','2'),&len);
122 if (os2) {
123 const unsigned short os2_version=get_USHORT(os2);
124 // check len
125 assert( (os2_version!=0x0000)||(len==78) );
126 assert( (os2_version!=0x0001)||(len==86) );
127 assert( (os2_version<0x0002)||(os2_version>0x0004)||(len==96) );
128 if (os2_version<=0x0004) {
129
130 // from PDF14Deltas.pdf, pg 113
131 const int weightClass=get_USHORT(os2+4);
132 ret->stemV=50+weightClass*weightClass/(65*65); // TODO, really bad
133 //printf("a %d\n",weightClass);
134
135 if (ret->supplement>=0) { // cid
136 ret->panose=ret->data;
137 memcpy(ret->panose,os2+30,12); // sFamilyClass + panose
138 }
139 const unsigned short fsSelection=get_USHORT(os2+62);
140 if (fsSelection&0x01) { // italic
141 ret->flags|=0x0040;
142 }
143 if ( (fsSelection&0x10)&&(weightClass>600) ) { // force bold
144 ret->flags|=0x0400;
145 }
146 const unsigned char family_class=get_USHORT(os2+30)>>8;
147 if (family_class==10) { // script
148 ret->flags|=0x0008;
149 }
150 if (family_class!=8) { // not sans-serif
151 ret->flags|=0x0002;
152 }
153
154 ret->avgWidth=get_SHORT(os2+2)*1000/otf->unitsPerEm;
155 ret->ascent=get_SHORT(os2+68)*1000/otf->unitsPerEm;
156 ret->descent=get_SHORT(os2+70)*1000/otf->unitsPerEm;
157 if (os2_version>=0x0002) {
158 ret->xHeight=get_SHORT(os2+86)*1000/otf->unitsPerEm;
159 ret->capHeight=get_SHORT(os2+88)*1000/otf->unitsPerEm;
160 } // else capHeight fixed later
161 } else {
162 free(os2);
163 os2=NULL;
164 }
165 } else {
166 fprintf(stderr,"WARNING: no OS/2 table\n");
167 // e.g. subsetted font from ghostscript // e.g. CFF
168 }
169 if (os2) {
170 free(os2);
171 } else { // TODO (if(CFF))
172 fprintf(stderr,"WARNING: no ascent/descent, capHeight, stemV, flags\n");
173 if (macStyle&0x01) { // force bold - just do it on bold
174 ret->flags|=0x0400;
175 }
176 if (macStyle&0x02) { // italic
177 ret->flags|=0x0004;
178 }
179 // ... flags TODO? (Serif, Script, Italic, AllCap,SmallCap, ForceBold)
180 }
181
182 // ? maybe get ascent,descent,capHeight,xHeight,stemV directly from cff
183 // Fallbacks
184 if ( (!ret->ascent)||(!ret->descent) ) {
185 char *hhea=otf_get_table(otf,OTF_TAG('h','h','e','a'),&len);
186 if (hhea) {
187 ret->ascent=get_SHORT(hhea+4)*1000/otf->unitsPerEm;
188 ret->descent=get_SHORT(hhea+6)*1000/otf->unitsPerEm;
189 }
190 free(hhea);
191 }
192 if (!ret->stemV) { // TODO? use name
193 const unsigned short d_gid=otf_from_unicode(otf,'.');
194 if (d_gid) { // stemV=bbox['.'].width;
195 len=otf_get_glyph(otf,d_gid);
196 assert(len>=10);
197 ret->stemV=(get_SHORT(otf->gly+6)-get_SHORT(otf->gly+2))*1000/otf->unitsPerEm;
198 } else {
199 if (macStyle&1) { // bold
200 ret->stemV=165;
201 } else {
202 ret->stemV=109; // TODO... unserious values...
203 }
204 }
205 }
206 if (!ret->capHeight) { // TODO? only reqd. for fonts with latin...
207 ret->capHeight=ret->ascent;
208 // TODO: OTF spec says: use metrics of 'H' (0 if not available)
209 }
210 if (0) { // TODO? uses only adobe latin standard? ?? e.g. Type1
211 ret->flags|=0x0020;
212 } else {
213 ret->flags|=0x0004;
214 }
215 // TODO SmallCap by font name(?)
216
217 // TODO ; ? cid ?
218 }
219 // }}}
220
221 // TODO: split generic part and otf part
222 // TODO: FIXME: gid vs. char ... NOTE: not called in multi_byte mode...
223 // Adobe does: char --MacRoman/WinAnsi--> name --AGL--> unicode --cmap(3,1) --> gid only avoidable by setting 'symbol'+custom(1,0)/(3,0)
224 // HINT: caller sets len == otf->numGlyphs (only when not using encoding...)
emb_otf_get_pdf_widths(OTF_FILE * otf,const unsigned short * encoding,int len,const BITSET glyphs)225 EMB_PDF_FONTWIDTHS *emb_otf_get_pdf_widths(OTF_FILE *otf,const unsigned short *encoding,int len,const BITSET glyphs) // {{{ glyphs==NULL -> all from 0 to len
226 {
227 assert(otf);
228
229 int first=len,last=0;
230 int iA;
231
232 if (glyphs) {
233 for (iA=0;iA<len;iA++) { // iA is a "gid" when in multi_byte mode...
234 const int gid=(encoding)?encoding[iA]:otf_from_unicode(otf,iA); // TODO
235 if (bit_check(glyphs,gid)) {
236 if (first>iA) { // first is a character index
237 first=iA;
238 }
239 if (last<iA) {
240 last=iA;
241 }
242 }
243 }
244 } else {
245 first=0;
246 last=len;
247 }
248 if (last<first) {
249 // empty
250 fprintf(stderr,"WARNING: empty embedding range\n");
251 return NULL;
252 }
253
254 // ensure hmtx is there
255 if (!otf->hmtx) {
256 if (otf_load_more(otf)!=0) {
257 fprintf(stderr,"Unsupported OTF font / cmap table \n");
258 return NULL;
259 }
260 }
261
262 // now create the array
263 EMB_PDF_FONTWIDTHS *ret=emb_pdf_fw_new(last-first+1);
264 if (!ret) {
265 return NULL;
266 }
267 ret->first=first;
268 ret->last=last;
269 ret->widths=ret->data;
270 for (iA=0;first<=last;iA++,first++) {
271 const int gid=(encoding)?encoding[first]:otf_from_unicode(otf,first); // TODO
272 if (gid>=otf->numGlyphs) {
273 fprintf(stderr,"Bad glyphid\n");
274 assert(0);
275 free(ret);
276 return NULL;
277 }
278 if ( (!glyphs)||(bit_check(glyphs,gid)) ) {
279 ret->widths[iA]=get_width_fast(otf,gid)*1000/otf->unitsPerEm;
280 } // else 0 from calloc
281 }
282
283 return ret;
284 }
285 // }}}
286
287 // otf->hmtx must be there
emb_otf_pdf_glyphwidth(void * context,int gid)288 static int emb_otf_pdf_glyphwidth(void *context,int gid) // {{{
289 {
290 OTF_FILE *otf=(OTF_FILE *)context;
291 return get_width_fast(otf,gid)*1000/otf->unitsPerEm;
292 }
293 // }}}
294
emb_otf_get_pdf_cidwidths(OTF_FILE * otf,const BITSET glyphs)295 EMB_PDF_FONTWIDTHS *emb_otf_get_pdf_cidwidths(OTF_FILE *otf,const BITSET glyphs) // {{{ // glyphs==NULL -> output all
296 {
297 assert(otf);
298
299 // ensure hmtx is there
300 if (!otf->hmtx) {
301 if (otf_load_more(otf)!=0) {
302 fprintf(stderr,"Unsupported OTF font / cmap table \n");
303 return NULL;
304 }
305 }
306 // int dw=emb_otf_pdf_glyphwidth(otf,0); // e.g.
307 int dw=-1; // let them estimate
308
309 return emb_pdf_fw_cidwidths(glyphs,otf->numGlyphs,dw,emb_otf_pdf_glyphwidth,otf);
310 }
311 // }}}
312
313 /*** PS stuff ***/
314
315 #include "dynstring.h"
316
317 const char *aglfn13(unsigned short uni); // aglfn13.c
318 #include "macroman.h"
319
320 // TODO? optimize pascal string skipping? (create index)
321 // NOTE: might return a statically allocated string
emb_otf_get_post_name(const char * post,unsigned short gid)322 static const char *emb_otf_get_post_name(const char *post,unsigned short gid) // {{{
323 {
324 if (!post) {
325 return NULL;
326 }
327 const unsigned int post_version=get_ULONG(post);
328 if (post_version==0x00010000) { // font has only 258 chars... font cannot be used on windows
329 if (gid<sizeof(macRoman)/sizeof(macRoman[0])) {
330 return macRoman[gid];
331 }
332 } else if (post_version==0x00020000) {
333 const unsigned short num_glyphs=get_USHORT(post+32);
334 // assert(num_glyphs==otf->numGlyphs);
335 if (gid<num_glyphs) {
336 unsigned short idx=get_USHORT(post+34+2*gid);
337 if (idx<258) {
338 if (idx<sizeof(macRoman)/sizeof(macRoman[0])) {
339 return macRoman[idx];
340 }
341 } else if (idx<32768) {
342 const unsigned char *pos=(unsigned char *)post+34+2*num_glyphs;
343 for (idx-=258;idx>0;idx--) { // this sucks...
344 pos+=*pos+1; // skip this string
345 }
346 // convert pascal string to asciiz
347 static char ret[256];
348 const unsigned char len=*pos;
349 memcpy(ret,(const char *)pos+1,len);
350 ret[len]=0;
351 return ret;
352 }
353 }
354 } else if (post_version==0x00025000) { // similiar to 0x00010000, deprecated
355 const unsigned short num_glyphs=get_USHORT(post+32);
356 if (gid<num_glyphs) {
357 const unsigned short idx=post[34+gid]+gid; // post is signed char *
358 if (idx<sizeof(macRoman)/sizeof(macRoman[0])) {
359 return macRoman[idx];
360 }
361 }
362 } else if (post_version==0x00030000) {
363 // no glyph names, sorry
364 // } else if (post_version==0x00040000) { // apple AAT ?!
365 }
366 return NULL;
367 }
368 // }}}
369
370 // TODO!? to_unicode should be able to represent more than one unicode character?
371 // NOTE: statically allocated string
get_glyphname(const char * post,unsigned short * to_unicode,int charcode,unsigned short gid)372 static const char *get_glyphname(const char *post,unsigned short *to_unicode,int charcode,unsigned short gid) // {{{ if charcode==0 -> force gid to be used
373 {
374 if (gid==0) {
375 return ".notdef";
376 }
377 const char *postName=emb_otf_get_post_name(post,gid);
378 if (postName) {
379 return postName;
380 }
381 static char ret[255];
382 if (charcode) {
383 if (to_unicode) { // i.e. encoding was there
384 charcode=to_unicode[charcode];
385 // TODO!? to_unicode should be able to represent more than one unicode character?
386 // TODO for additional credit: for ligatures, etc create /f_f /uni12341234 or the like
387 }
388 const char *aglname=aglfn13(charcode); // TODO? special case ZapfDingbats?
389 if (aglname) {
390 return aglname;
391 }
392 snprintf(ret,250,"uni%04X",charcode); // allows extraction
393 } else {
394 snprintf(ret,250,"c%d",gid); // last resort: only by gid
395 }
396 return ret;
397 }
398 // }}}
399
400 struct OUTFILTER_PS {
401 OUTPUT_FN out;
402 void *ctx;
403 int len;
404 };
405
406 // TODO: for maximum compatiblity (PS<2013 interpreter) split only on table or glyph boundary (needs lookup in loca table!)
407 // Note: table boundaries are at each call!
outfilter_ascii_ps(const char * buf,int len,void * context)408 static void outfilter_ascii_ps(const char *buf,int len,void *context) // {{{
409 {
410 struct OUTFILTER_PS *of=context;
411 OUTPUT_FN out=of->out;
412 int iA;
413
414 (*out)("<",1,of->ctx);
415 of->len++;
416
417 const char *last=buf;
418 char tmp[256];
419 while (len>0) {
420 for (iA=0;(iA<76)&&(len>0);iA+=2,len--) {
421 const unsigned char ch=buf[iA>>1];
422 tmp[iA]="0123456789abcdef"[ch>>4];
423 tmp[iA+1]="0123456789abcdef"[ch&0x0f];
424 }
425 buf+=iA>>1;
426 if (buf<last+64000) {
427 if (len>0) {
428 tmp[iA++]='\n';
429 }
430 (*out)(tmp,iA,of->ctx);
431 } else {
432 last=buf;
433 strcpy(tmp+iA,"00>\n<");
434 iA+=5;
435 (*out)(tmp,iA,of->ctx);
436 }
437 of->len+=iA;
438 }
439
440 (*out)("00>\n",4,of->ctx);
441 of->len+=4;
442 }
443 // }}}
444
outfilter_binary_ps(const char * buf,int len,void * context)445 static void outfilter_binary_ps(const char *buf,int len,void *context) // {{{
446 {
447 struct OUTFILTER_PS *of=context;
448 OUTPUT_FN out=of->out;
449
450 char tmp[100];
451 while (len>0) {
452 const int maxlen=(len>64000)?64000:len;
453 const int l=sprintf(tmp,"%d RD ",maxlen);
454 (*out)(tmp,l,of->ctx);
455 of->len+=l;
456
457 (*out)(buf,maxlen,of->ctx);
458 (*out)("\n",1,of->ctx);
459 of->len+=maxlen+1;
460 len-=maxlen;
461 buf+=maxlen;
462 }
463 }
464 // }}}
465
466 /*
467 encoding: character-code -> glyph id ["required", NULL: identity, i.e. from_unicode()] // TODO: respect subsetting
468 to_unicode: character-code -> unicode [NULL: no char names] // kind-of "reverse" of encoding (to_unicode does not make sense without >encoding)
469
470 Status:
471 - we need a 0..255 encoding to be used in the PS file
472 - we want to allow the use of encoding[]; this should map from your desired PS-stream output character (0..255) directly to the gid
473 - if encoding[] is not used, MacRoman/WinAnsi/latin1 is expected (easiest: latin1, as it is a subset of unicode)
474 i.e. your want to output latin1 to the PS-stream
475 - len is the length of >encoding, or the "last used latin1 character"
476 - oh. in multibyte-mode no >encoding probably should mean identity(gid->gid) not (latin1->gid)
477 - non-multibyte PDF -> only 255 chars ... not recommended (we can't just map to gids, but only to names, which acro will then cmap(3,1) to gids)
478
479 => problem with subsetting BITSET (keyed by gid); we want BITSET keyed by 0..255 (via encoding)
480
481 // TODO: a) multi font encoding
482 // TODO: b) cid/big font encoding (PS>=2015) [/CIDFontType 2] : CMap does Charcode->CID, /CIDMap does CID->GID [e.g. Identity/delta value]
483 // (also needed [or a)] for loca>64000 if split, etc) e.g. /CIDMap 0 [requires PS>=3011?]
484 // [Danger: do not split composites]
485 // TODO? incremental download [/GlyphDirectory array or dict] : /GlyphDirectory does GID-><glyf entry> mapping
486 // need 'fake' gdir table (size,offset=0) in sfnt; loca, glyf can be ommited; hmtx can be omitted for PS>=3011 [/MetricsCount 2]
487 // idea is to fill initial null entries in the array/dict [Beware of save/restore!]
488 // NOTE: even when subsetting the font has to come first in the PS file
489
490
491 ... special information: when multi-byte PDF encoding is used <gid> is output.
492 therefore /Encoding /Identity-H + /CIDSystemInfo Adobe-Identity-0 will yield 1-1 mapping for font.
493 problem is that text is not selectable. therefore there is the /ToUnicode CMap option
494 */
emb_otf_ps(OTF_FILE * otf,unsigned short * encoding,int len,unsigned short * to_unicode,OUTPUT_FN output,void * context)495 int emb_otf_ps(OTF_FILE *otf,unsigned short *encoding,int len,unsigned short *to_unicode,OUTPUT_FN output,void *context) // {{{
496 {
497 const int binary=0; // binary format? // TODO
498 if (len>256) {
499 fprintf(stderr,"Encoding too big(%d) for Type42\n",len);
500 return -1;
501 }
502 if (len<1) {
503 fprintf(stderr,"At least .notdef required in Type42\n");
504 return -1;
505 }
506 if (!encoding) {
507 to_unicode=NULL; // does not make sense
508 }
509 int iA,ret=0;
510
511 DYN_STRING ds;
512 if (dyn_init(&ds,1024)==-1) {
513 return -1;
514 }
515
516 int rlen=0;
517 char *head=otf_get_table(otf,OTF_TAG('h','e','a','d'),&rlen);
518 if (!head) {
519 free(ds.buf);
520 return -1;
521 }
522 dyn_printf(&ds,"%%!PS-TrueTypeFont-%d-%d\n",
523 otf->version,get_ULONG(head+4));
524 const int bbxmin=get_SHORT(head+36)*1000/otf->unitsPerEm,
525 bbymin=get_SHORT(head+38)*1000/otf->unitsPerEm,
526 bbxmax=get_SHORT(head+40)*1000/otf->unitsPerEm,
527 bbymax=get_SHORT(head+42)*1000/otf->unitsPerEm;
528 free(head);
529
530 char *post=otf_get_table(otf,OTF_TAG('p','o','s','t'),&rlen);
531 if ( (!post)&&(rlen!=-1) ) { // other error than "not found"
532 free(ds.buf);
533 return -1;
534 }
535 if (post) {
536 const unsigned int minMem=get_ULONG(post+16),maxMem=get_ULONG(post+20);
537 if (minMem) {
538 dyn_printf(&ds,"%%VMusage: %d %d\n",minMem,maxMem);
539 }
540 }
541
542 // don't forget the coordinate scaling...
543 dyn_printf(&ds,"11 dict begin\n"
544 "/FontName /%s def\n"
545 "/FontType 42 def\n"
546 "/FontMatrix [1 0 0 1 0 0] def\n"
547 "/FontBBox [%f %f %f %f] def\n"
548 "/PaintType 0 def\n",
549 // "/XUID [42 16#%X 16#%X 16#%X 16#%X] def\n" // TODO?!? (md5 of font data) (16# means base16)
550 emb_otf_get_fontname(otf),
551 bbxmin/1000.0,bbymin/1000.0,bbxmax/1000.0,bbymax/1000.0);
552 if (post) {
553 dyn_printf(&ds,"/FontInfo 4 dict dup begin\n"
554 // TODO? [even non-post]: /version|/Notice|/Copyright|/FullName|/FamilyName|/Weight () readonly def\n from name table: 5 7 0 4 1 2
555 // using: otf_get_name(otf,3,1,0x409,?,&len) / otf_get_name(otf,1,0,0,?,&len) + encoding
556 " /ItalicAngle %d def\n"
557 " /isFixedPitch %s def\n"
558 " /UnderlinePosition %f def\n"
559 " /UnderlineThickness %f def\n"
560 "end readonly def\n",
561 get_LONG(post+4)>>16,
562 (get_ULONG(post+12)?"true":"false"),
563 (get_SHORT(post+8)-get_SHORT(post+10)/2)/(float)otf->unitsPerEm,
564 get_SHORT(post+10)/(float)otf->unitsPerEm);
565 }
566 dyn_printf(&ds,"/Encoding 256 array\n"
567 "0 1 255 { 1 index exch /.notdef put } for\n");
568 for (iA=0;iA<len;iA++) { // encoding data: 0...255 -> /glyphname
569 const int gid=(encoding)?encoding[iA]:otf_from_unicode(otf,iA);
570 if (gid!=0) {
571 dyn_printf(&ds,"dup %d /%s put\n",
572 iA,get_glyphname(post,to_unicode,iA,gid));
573 }
574 }
575 dyn_printf(&ds,"readonly def\n");
576
577 if (binary) {
578 dyn_printf(&ds,"/RD { string currentfile exch readstring pop } executeonly def\n");
579 }
580 dyn_printf(&ds,"/sfnts[\n");
581
582 if (ds.len<0) {
583 free(post);
584 free(ds.buf);
585 return -1;
586 }
587 (*output)(ds.buf,ds.len,context);
588 ret+=ds.len;
589 ds.len=0;
590
591 // TODO: only tables as in otf_subset
592 // TODO: somehow communicate table boundaries:
593 // otf_action_copy does exactly one output call (per table)
594 // only otf_action_replace might do two (padding)
595 // {{{ copy tables verbatim (does not affect ds .len)
596 struct _OTF_WRITE *otfree=NULL;
597 #if 0
598 struct _OTF_WRITE *otw;
599 otwfree=otw=malloc(sizeof(struct _OTF_WRITE)*otf->numTables);
600 if (!otw) {
601 fprintf(stderr,"Bad alloc: %m\n");
602 free(post);
603 free(ds.buf);
604 return -1;
605 }
606 // just copy everything
607 for (iA=0;iA<otf->numTables;iA++) {
608 otw[iA].tag=otf->tables[iA].tag;
609 otw[iA].action=otf_action_copy;
610 otw[iA].param=otf;
611 otw[iA].length=iA;
612 }
613 int numTables=otf->numTables;
614 #else
615 struct _OTF_WRITE otw[]={ // sorted
616 {OTF_TAG('c','m','a','p'),otf_action_copy,otf,},
617 {OTF_TAG('c','v','t',' '),otf_action_copy,otf,},
618 {OTF_TAG('f','p','g','m'),otf_action_copy,otf,},
619 {OTF_TAG('g','l','y','f'),otf_action_copy,otf,},
620 {OTF_TAG('h','e','a','d'),otf_action_copy,otf,},
621 {OTF_TAG('h','h','e','a'),otf_action_copy,otf,},
622 {OTF_TAG('h','m','t','x'),otf_action_copy,otf,},
623 {OTF_TAG('l','o','c','a'),otf_action_copy,otf,},
624 {OTF_TAG('m','a','x','p'),otf_action_copy,otf,},
625 {OTF_TAG('n','a','m','e'),otf_action_copy,otf,},
626 {OTF_TAG('p','r','e','p'),otf_action_copy,otf,},
627 // vhea vmtx (never used in PDF, but possible in PS>=3011)
628 {0,0,0,0}};
629 int numTables=otf_intersect_tables(otf,otw);
630 #endif
631
632 struct OUTFILTER_PS of;
633 of.out=output;
634 of.ctx=context;
635 of.len=0;
636 if (binary) {
637 iA=otf_write_sfnt(otw,otf->version,numTables,outfilter_binary_ps,&of);
638 } else {
639 iA=otf_write_sfnt(otw,otf->version,numTables,outfilter_ascii_ps,&of);
640 }
641 free(otfree);
642 if (iA==-1) {
643 free(post);
644 free(ds.buf);
645 return -1;
646 }
647 ret+=of.len;
648 // }}} done copying
649
650 dyn_printf(&ds,"] def\n");
651
652 dyn_printf(&ds,"/CharStrings %d dict dup begin\n"
653 "/.notdef 0 def\n",len);
654 for (iA=0;iA<len;iA++) { // charstrings data: /glyphname -> gid
655 const int gid=(encoding)?encoding[iA]:otf_from_unicode(otf,iA);
656 if (gid) {
657 dyn_printf(&ds,"/%s %d def\n",get_glyphname(post,to_unicode,iA,gid),gid);
658 }
659 // (respecting subsetting...)
660 }
661 dyn_printf(&ds,"end readonly def\n");
662 dyn_printf(&ds,"FontName currentdict end definefont pop\n");
663 free(post);
664
665 if (ds.len<0) {
666 free(ds.buf);
667 return -1;
668 }
669 (*output)(ds.buf,ds.len,context);
670 ret+=ds.len;
671 ds.len=0;
672
673 free(ds.buf);
674 return ret;
675 }
676 // }}}
677
678