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

« back to all changes in this revision

Viewing changes to fontembed/sfnt_subset.c

Tags: upstream-1.0.20
ImportĀ upstreamĀ versionĀ 1.0.20

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "sfnt.h"
 
2
#include "sfnt_int.h"
 
3
#include <stdio.h>
 
4
#include <stdlib.h>
 
5
#include <string.h>
 
6
#include <errno.h>
 
7
#include <assert.h>
 
8
#include "bitset.h"
 
9
 
 
10
int otf_ttc_extract(OTF_FILE *otf,OUTPUT_FN output,void *context) // {{{
 
11
{
 
12
  assert(otf);
 
13
  assert(output);
 
14
  assert(otf->numTTC);
 
15
  int iA;
 
16
 
 
17
  struct _OTF_WRITE *otw;
 
18
  otw=malloc(sizeof(struct _OTF_WRITE)*otf->numTables);
 
19
  if (!otw) {
 
20
    fprintf(stderr,"Bad alloc: %s\n", strerror(errno));
 
21
    return -1;
 
22
  }
 
23
 
 
24
  // just copy everything
 
25
  for (iA=0;iA<otf->numTables;iA++) {
 
26
    otw[iA].tag=otf->tables[iA].tag;
 
27
    otw[iA].action=otf_action_copy;
 
28
    otw[iA].param=otf;
 
29
    otw[iA].length=iA;
 
30
  }
 
31
  iA=otf_write_sfnt(otw,otf->version,otf->numTables,output,context);
 
32
  free(otw);
 
33
 
 
34
  return iA;
 
35
}
 
36
// }}}
 
37
 
 
38
// otw {0,}-terminated, will be modified; returns numTables for otf_write_sfnt
 
39
int otf_intersect_tables(OTF_FILE *otf,struct _OTF_WRITE *otw) // {{{
 
40
{
 
41
  int iA,iB,numTables=0;
 
42
  for (iA=0,iB=0;(iA<otf->numTables)&&(otw[iB].tag);) {
 
43
    if (otf->tables[iA].tag==otw[iB].tag) {
 
44
      if (otw[iB].action==otf_action_copy) {
 
45
        otw[iB].length=iA; // original table location found.
 
46
      }
 
47
      if (iB!=numTables) { // >, actually
 
48
        memmove(otw+numTables,otw+iB,sizeof(struct _OTF_WRITE));
 
49
      }
 
50
      iA++;
 
51
      iB++;
 
52
      numTables++;
 
53
    } else if (otf->tables[iA].tag<otw[iB].tag) {
 
54
      iA++;
 
55
    } else { // not in otf->tables
 
56
      if (otw[iB].action!=otf_action_copy) { // keep
 
57
        if (iB!=numTables) { // >, actually
 
58
          memmove(otw+numTables,otw+iB,sizeof(struct _OTF_WRITE));
 
59
        }
 
60
        numTables++;
 
61
      } // else delete
 
62
      iB++;
 
63
    }
 
64
  }
 
65
  return numTables;
 
66
}
 
67
// }}}
 
68
 
 
69
 
 
70
// include components (set bit in >glyphs) of currently loaded compound glyph (with >curgid)
 
71
// returns additional space requirements (when bits below >donegid are touched)
 
72
static int otf_subset_glyf(OTF_FILE *otf,int curgid,int donegid,BITSET glyphs) // {{{
 
73
{
 
74
  int ret=0;
 
75
  if (get_SHORT(otf->gly)>=0) { // not composite
 
76
    return ret; // done
 
77
  }
 
78
 
 
79
  char *cur=otf->gly+10;
 
80
 
 
81
  unsigned short flags;
 
82
  do {
 
83
    flags=get_USHORT(cur);
 
84
    const unsigned short sub_gid=get_USHORT(cur+2);
 
85
    assert(sub_gid<otf->numGlyphs);
 
86
    if (!bit_check(glyphs,sub_gid)) {
 
87
      // bad: temporarily load sub glyph
 
88
      const int len=otf_get_glyph(otf,sub_gid);
 
89
      assert(len>0);
 
90
      bit_set(glyphs,sub_gid);
 
91
      if (sub_gid<donegid) {
 
92
        ret+=len;
 
93
        ret+=otf_subset_glyf(otf,sub_gid,donegid,glyphs); // composite of composites?, e.g. in DejaVu
 
94
      }
 
95
      const int res=otf_get_glyph(otf,curgid); // reload current glyph
 
96
      assert(res);
 
97
    }
 
98
    
 
99
    // skip parameters
 
100
    cur+=6;
 
101
    if (flags&0x01) {
 
102
      cur+=2;
 
103
    }
 
104
    if (flags&0x08) {
 
105
      cur+=2;
 
106
    } else if (flags&0x40) {
 
107
      cur+=4;
 
108
    } else if (flags&0x80) {
 
109
      cur+=8;
 
110
    }
 
111
  } while (flags&0x20); // more components
 
112
 
 
113
  return ret;
 
114
}
 
115
// }}}
 
116
 
 
117
// TODO: cmap only required in non-CID context
 
118
int otf_subset(OTF_FILE *otf,BITSET glyphs,OUTPUT_FN output,void *context) // {{{ - returns number of bytes written
 
119
{
 
120
  assert(otf);
 
121
  assert(glyphs);
 
122
  assert(output);
 
123
 
 
124
  int iA,b,c;
 
125
 
 
126
  // first pass: include all required glyphs
 
127
  bit_set(glyphs,0); // .notdef always required
 
128
  int glyfSize=0;
 
129
  for (iA=0,b=0,c=1;iA<otf->numGlyphs;iA++,c<<=1) {
 
130
    if (!c) {
 
131
      b++;
 
132
      c=1;
 
133
    }
 
134
    if (glyphs[b]&c) {
 
135
      int len=otf_get_glyph(otf,iA);
 
136
      if (len<0) {
 
137
        assert(0);
 
138
        return -1;
 
139
      } else if (len>0) {
 
140
        glyfSize+=len;
 
141
        len=otf_subset_glyf(otf,iA,iA,glyphs);
 
142
        if (len<0) {
 
143
          assert(0);
 
144
          return -1;
 
145
        }
 
146
        glyfSize+=len;
 
147
      }
 
148
    }
 
149
  }
 
150
 
 
151
  // second pass: calculate new glyf and loca
 
152
  int locaSize=(otf->numGlyphs+1)*(otf->indexToLocFormat+1)*2;
 
153
 
 
154
  char *new_loca=malloc(locaSize);
 
155
  char *new_glyf=malloc(glyfSize);
 
156
  if ( (!new_loca)||(!new_glyf) ) {
 
157
    fprintf(stderr,"Bad alloc: %s\n", strerror(errno));
 
158
    assert(0);
 
159
    free(new_loca);
 
160
    free(new_glyf);
 
161
    return -1;
 
162
  }
 
163
 
 
164
  int offset=0;
 
165
  for (iA=0,b=0,c=1;iA<otf->numGlyphs;iA++,c<<=1) {
 
166
    if (!c) {
 
167
      b++;
 
168
      c=1;
 
169
    }
 
170
 
 
171
    assert(offset%2==0);
 
172
    // TODO? change format? if glyfSize<0x20000 
 
173
    if (otf->indexToLocFormat==0) {
 
174
      set_USHORT(new_loca+iA*2,offset/2);
 
175
    } else { // ==1
 
176
      set_ULONG(new_loca+iA*4,offset);
 
177
    }
 
178
 
 
179
    if (glyphs[b]&c) {
 
180
      const int len=otf_get_glyph(otf,iA);
 
181
      assert(len>=0);
 
182
      memcpy(new_glyf+offset,otf->gly,len);
 
183
      offset+=len;
 
184
    }
 
185
  }
 
186
  // last entry
 
187
  if (otf->indexToLocFormat==0) {
 
188
    set_USHORT(new_loca+otf->numGlyphs*2,offset/2);
 
189
  } else { // ==1
 
190
    set_ULONG(new_loca+otf->numGlyphs*4,offset);
 
191
  }
 
192
  assert(offset==glyfSize);
 
193
 
 
194
  // determine new tables.
 
195
  struct _OTF_WRITE otw[]={ // sorted
 
196
    // TODO: cmap only required in non-CID context   or always in CFF
 
197
      {OTF_TAG('c','m','a','p'),otf_action_copy,otf,},
 
198
      {OTF_TAG('c','v','t',' '),otf_action_copy,otf,},
 
199
      {OTF_TAG('f','p','g','m'),otf_action_copy,otf,},
 
200
      {OTF_TAG('g','l','y','f'),otf_action_replace,new_glyf,glyfSize},
 
201
      {OTF_TAG('h','e','a','d'),otf_action_copy,otf,}, // _copy_head
 
202
      {OTF_TAG('h','h','e','a'),otf_action_copy,otf,},
 
203
      {OTF_TAG('h','m','t','x'),otf_action_copy,otf,},
 
204
      {OTF_TAG('l','o','c','a'),otf_action_replace,new_loca,locaSize},
 
205
      {OTF_TAG('m','a','x','p'),otf_action_copy,otf,},
 
206
      {OTF_TAG('n','a','m','e'),otf_action_copy,otf,},
 
207
      {OTF_TAG('p','r','e','p'),otf_action_copy,otf,},
 
208
      // vhea vmtx (never used in PDF, but possible in PS>=3011)
 
209
      {0,0,0,0}};
 
210
 
 
211
  // and write them
 
212
  int numTables=otf_intersect_tables(otf,otw);
 
213
  int ret=otf_write_sfnt(otw,otf->version,numTables,output,context);
 
214
 
 
215
  free(new_loca);
 
216
  free(new_glyf);
 
217
  return ret;
 
218
 
 
219
  //TODO ? reduce cmap [to (1,0) ;-)]
 
220
  //TODO (cmap for non-cid)
 
221
}
 
222
// }}}
 
223
 
 
224
// TODO no subsetting actually done (for now)
 
225
int otf_subset_cff(OTF_FILE *otf,BITSET glyphs,OUTPUT_FN output,void *context) // {{{ - returns number of bytes written
 
226
{
 
227
  assert(otf);
 
228
  assert(output);
 
229
 
 
230
// TODO char *new_cff=cff_subset(...);
 
231
 
 
232
  // determine new tables.
 
233
  struct _OTF_WRITE otw[]={
 
234
      {OTF_TAG('C','F','F',' '),otf_action_copy,otf,},
 
235
//      {OTF_TAG('C','F','F',' '),otf_action_replace,new_glyf,glyfSize},
 
236
      {OTF_TAG('c','m','a','p'),otf_action_copy,otf,},
 
237
#if 0 // not actually needed!
 
238
      {OTF_TAG('c','v','t',' '),otf_action_copy,otf,},
 
239
      {OTF_TAG('f','p','g','m'),otf_action_copy,otf,},
 
240
      {OTF_TAG('h','e','a','d'),otf_action_copy,otf,}, // _copy_head
 
241
      {OTF_TAG('h','h','e','a'),otf_action_copy,otf,},
 
242
      {OTF_TAG('h','m','t','x'),otf_action_copy,otf,},
 
243
      {OTF_TAG('m','a','x','p'),otf_action_copy,otf,},
 
244
      {OTF_TAG('n','a','m','e'),otf_action_copy,otf,},
 
245
      {OTF_TAG('p','r','e','p'),otf_action_copy,otf,},
 
246
#endif
 
247
      {0,0,0,0}};
 
248
 
 
249
  // and write them
 
250
  int numTables=otf_intersect_tables(otf,otw);
 
251
  int ret=otf_write_sfnt(otw,otf->version,numTables,output,context);
 
252
 
 
253
//  free(new_cff);
 
254
  return ret;
 
255
}
 
256
// }}}
 
257
 
 
258
//int copy_block(FILE *f,long pos,int length,OUTPUT_FN output,void *context);  // copied bytes or -1 (also on premature EOF)
 
259
 
 
260
static int copy_block(FILE *f,long pos,int length,OUTPUT_FN output,void *context) // {{{
 
261
{
 
262
  assert(f);
 
263
  assert(output);
 
264
 
 
265
  char buf[4096];
 
266
  int iA,ret;
 
267
 
 
268
  ret=fseek(f,pos,SEEK_SET);
 
269
  if (ret==-1) {
 
270
    fprintf(stderr,"Seek failed: %s\n", strerror(errno));
 
271
    return -1;
 
272
  }
 
273
  ret=0;
 
274
  while (length>4096) {
 
275
    iA=fread(buf,1,4096,f);
 
276
    if (iA<4096) {
 
277
      return -1;
 
278
    }
 
279
    (*output)(buf,iA,context);
 
280
    ret+=iA;
 
281
    length-=iA;
 
282
  };
 
283
  iA=fread(buf,1,length,f);
 
284
  if (iA<length) {
 
285
    return -1;
 
286
  }
 
287
  (*output)(buf,iA,context);
 
288
  ret+=iA;
 
289
 
 
290
  return ret;
 
291
}
 
292
// }}}
 
293
 
 
294
int otf_cff_extract(OTF_FILE *otf,OUTPUT_FN output,void *context) // {{{ - returns number of bytes written
 
295
{
 
296
  assert(otf);
 
297
  assert(output);
 
298
 
 
299
  int idx=otf_find_table(otf,OTF_TAG('C','F','F',' '));
 
300
  if (idx==-1) {
 
301
    return -1;
 
302
  }
 
303
  const OTF_DIRENT *table=otf->tables+idx;
 
304
 
 
305
  return copy_block(otf->f,table->offset,table->length,output,context);
 
306
}
 
307
// }}}
 
308
 
 
309
// CFF *otf_get_cff(); // not load, but create by "substream"-in ctor
 
310
#if 0 // TODO elsewhere : char *cff_subset(...);
 
311
  // first pass: include all required glyphs
 
312
  bit_set(glyphs,0); // .notdef always required
 
313
  int glyfSize=0;
 
314
  for (iA=0,b=0,c=1;iA<otf->numGlyphs;iA++,c<<=1) {
 
315
    if (!c) {
 
316
      b++;
 
317
      c=1;
 
318
    }
 
319
    if (glyphs[b]&c) {
 
320
// TODO: cff_glyph
 
321
    }
 
322
  }
 
323
 
 
324
  // second pass: calculate new glyf and loca
 
325
  char *new_cff=malloc(cffSize);
 
326
  if (!new_cff) {
 
327
    fprintf(stderr,"Bad alloc: %s\n", strerror(errno));
 
328
    assert(0);
 
329
    return -1;
 
330
  }
 
331
 
 
332
  int offset=0;
 
333
  for (iA=0,b=0,c=1;iA<otf->numGlyphs;iA++,c<<=1) {
 
334
    if (!c) {
 
335
      b++;
 
336
      c=1;
 
337
    }
 
338
    if (glyphs[b]&c) {
 
339
//...
 
340
    }
 
341
  }
 
342
  return new_cff;
 
343
#endif