~ubuntu-branches/ubuntu/raring/cups-filters/raring-proposed

« back to all changes in this revision

Viewing changes to fontembed/embed_sfnt.c

  • Committer: Package Import Robot
  • Author(s): Till Kamppeter
  • Date: 2012-07-22 18:57:32 UTC
  • mfrom: (1.1.17)
  • Revision ID: package-import@ubuntu.com-20120722185732-26kkte5p1lth3rt5
Tags: 1.0.20-0bzr1
* New upstream release
   - pdftops: Added another workaround for Kyocera printers: Some
     models get very slow on images which request interpolation,
     so now we remove the image interpolation requests by additional
     PostScript code only inserted for Kyocera printers (LP: #1026974).
   - Made the Poppler-based filters pdftopdf and pdftoopvp build with
     both Poppler 0.18.x and 0.20.x (Upstream bug #1055).
   - Fixes according to Coverity scan results (Upstream bug #1054).
   - Switched build system to autotools. This especially fixes several
     build problems in Gentoo. Also build-tested with CUPS 1.6.0b1.
   - Fixes for compatibility with clang/gcc-4.7.
   - textonly: Filter did not work as a pipe with copies=1 (Upstream bug
     #1032).
   - texttopdf: Avoid trimming the results of FcFontSort(), as this may
     miss some reasonable candidates under certain circumstances. BTW,
     fix passing a non-pointer as a pointer to "result" (Closes: #670055).
   - Corrected documentation. The option for the maximum image rendering
     resolution in pdftops is "pdftops-max-image-resolution", not
     "pdftops-max-image-resolution-default".
* debian/patches/fcfontsort-no-trim.patch: Removed, fixed upstream.
* debian/rules: Updated options for ./configure and make for the new autotools
  build system.
* debian/watch: Switched to bz2 upstream packages.
* debian/rules, debian/copyright, debian/cups-filters.docs: Updated for
  renamed documentation files.
* debian/control, debian/libfontembed1.install,
  debian/libfontembed-dev.install: Added new binary packages for libfontembed.
* debian/copyright: Updated for recent file additions, and rearrangement of
  directories.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
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
 
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)
 
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...)
 
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
      assert(0);
 
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
 
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
 
 
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
      assert(0);
 
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
 
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 (gid<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
 
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!
 
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
 
 
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
*/
 
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