~ubuntu-branches/debian/experimental/cups-filters/experimental

« back to all changes in this revision

Viewing changes to filter/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