• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
otf_ttc_extract(OTF_FILE * otf,OUTPUT_FN output,void * context)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
otf_intersect_tables(OTF_FILE * otf,struct _OTF_WRITE * otw)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)
otf_subset_glyf(OTF_FILE * otf,int curgid,int donegid,BITSET glyphs)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
otf_subset(OTF_FILE * otf,BITSET glyphs,OUTPUT_FN output,void * 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)
otf_subset_cff(OTF_FILE * otf,BITSET glyphs,OUTPUT_FN output,void * context)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 
copy_block(FILE * f,long pos,int length,OUTPUT_FN output,void * context)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 
otf_cff_extract(OTF_FILE * otf,OUTPUT_FN output,void * context)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
344