1 /* Copyright (C) 2000-2012 by George Williams */
2 /*
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are met:
5
6 * Redistributions of source code must retain the above copyright notice, this
7 * list of conditions and the following disclaimer.
8
9 * Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
12
13 * The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include <fontforge-config.h>
29
30 #include "dumppfa.h"
31
32 #include "autohint.h"
33 #include "bvedit.h"
34 #include "fontforge.h"
35 #include "fvfonts.h"
36 #include "gfile.h"
37 #include "gutils.h"
38 #include "parsepfa.h"
39 #include "print.h" /* For makePatName */
40 #include "psfont.h"
41 #include "psread.h"
42 #include "splinefont.h"
43 #include "splineorder2.h"
44 #include "splinesave.h"
45 #include "splinesaveafm.h"
46 #include "splineutil.h"
47 #include "splineutil2.h"
48 #include "tottf.h"
49 #include "ustring.h"
50 #include "utype.h"
51 #include "zapfnomen.h"
52
53 #include <locale.h>
54 #include <math.h>
55 #include <stdarg.h>
56 #include <time.h>
57 #include <unistd.h>
58
59 #if !defined(__MINGW32__)
60 # include <pwd.h>
61 #endif
62
63 #ifdef __CygWin
64 #include <sys/stat.h>
65 #include <sys/types.h>
66 #include <unistd.h>
67 #endif
68
69 extern int autohint_before_generate;
70 char *xuid=NULL;
71
72 typedef void (*DumpChar)(int ch,void *data);
73 struct fileencryptdata {
74 DumpChar olddump;
75 void *olddata;
76 unsigned short r;
77 int hexline;
78 };
79 #define c1 52845
80 #define c2 22719
81
encodehex(int plain,void * d)82 static void encodehex(int plain, void *d) {
83 struct fileencryptdata *fed = d;
84 unsigned char cypher = ( plain ^ (fed->r>>8));
85
86 fed->r = (cypher + fed->r) * c1 + c2;
87 {
88 int ch1, ch2;
89
90 ch1 = cypher>>4;
91 if ( ch1<=9 )
92 (fed->olddump)('0'+ch1,fed->olddata);
93 else
94 (fed->olddump)('A'-10+ch1,fed->olddata);
95 ch2 = cypher&0xf;
96 if ( ch2<=9 )
97 (fed->olddump)('0'+ch2,fed->olddata);
98 else
99 (fed->olddump)('A'-10+ch2,fed->olddata);
100 fed->hexline += 2;
101 if ( fed->hexline>70 ) {
102 (fed->olddump)('\n',fed->olddata);
103 fed->hexline = 0;
104 }
105 }
106 }
107
encodebin(int plain,void * d)108 static void encodebin(int plain, void *d) {
109 struct fileencryptdata *fed = d;
110 unsigned char cypher = ( plain ^ (fed->r>>8));
111
112 fed->r = (cypher + fed->r) * c1 + c2;
113 (fed->olddump)(cypher,fed->olddata);
114 }
115
startfileencoding(DumpChar dumpchar,void * data,struct fileencryptdata * fed,int dobinary)116 static DumpChar startfileencoding(DumpChar dumpchar,void *data,
117 struct fileencryptdata *fed,int dobinary) {
118 static unsigned char randombytes[4] = { 0xaa, 0x55, 0x3e, 0x4d };
119 DumpChar func;
120
121 randombytes[0] += 3;
122 randombytes[1] += 5;
123 randombytes[2] += 7;
124 randombytes[3] += 11;
125
126 fed->olddump = dumpchar;
127 fed->olddata = data;
128 fed->r = 55665;
129 fed->hexline = 0;
130
131 if ( dobinary ) { unsigned short r; unsigned char cypher;
132 while ( 1 ) {
133 /* find some random bytes where at least one of them encrypts to */
134 /* a non hex character */
135 r = 55665;
136 cypher = ( randombytes[0] ^ (r>>8));
137 if ( isspace(cypher) )
138 goto try_again;
139 if ( cypher<'0' || (cypher>'9' && cypher<'A') || (cypher>'F' && cypher<'a') || cypher>'f' )
140 break;
141 r = (cypher + r) * c1 + c2;
142 cypher = ( randombytes[1] ^ (r>>8));
143 if ( cypher<'0' || (cypher>'9' && cypher<'A') || (cypher>'F' && cypher<'a') || cypher>'f' )
144 break;
145 r = (cypher + r) * c1 + c2;
146 cypher = ( randombytes[2] ^ (r>>8));
147 if ( cypher<'0' || (cypher>'9' && cypher<'A') || (cypher>'F' && cypher<'a') || cypher>'f' )
148 break;
149 r = (cypher + r) * c1 + c2;
150 cypher = ( randombytes[3] ^ (r>>8));
151 if ( cypher<'0' || (cypher>'9' && cypher<'A') || (cypher>'F' && cypher<'a') || cypher>'f' )
152 break;
153
154 try_again:
155 randombytes[0] += 3;
156 randombytes[1] += 5;
157 randombytes[2] += 7;
158 randombytes[3] += 11;
159 }
160 }
161
162 func = dobinary ? encodebin : encodehex;
163 func(randombytes[0],fed);
164 func(randombytes[1],fed);
165 func(randombytes[2],fed);
166 func(randombytes[3],fed);
167 return( func );
168 }
169
170 /* Encode a string in adobe's format. choose a different set of initial random*/
171 /* bytes every time. (the expected value of leniv is 4. we have some support */
172 /* for values bigger than 5 but not as much as for values <=4) */
encodestrout(void (* dumpchar)(int ch,void * data),void * data,unsigned char * value,int len,int leniv)173 static void encodestrout(void (*dumpchar)(int ch,void *data), void *data,
174 unsigned char *value, int len, int leniv) {
175 unsigned short r = 4330;
176 unsigned char plain, cypher;
177 static unsigned char randombytes[10] = { 0xaa, 0x55, 0x3e, 0x4d, 0x89, 0x98, 'a', '4', 0, 0xff };
178
179 randombytes[0] += 3;
180 randombytes[1] += 5;
181 randombytes[2] += 7;
182 randombytes[3] += 11;
183 randombytes[4] += 13;
184
185 while ( leniv>0 ) {
186 plain = randombytes[leniv--%10];
187 cypher = ( plain ^ (r>>8));
188 r = (cypher + r) * c1 + c2;
189 dumpchar(cypher,data);
190 }
191 while ( len-->0 ) {
192 plain = *value++;
193 cypher = ( plain ^ (r>>8));
194 r = (cypher + r) * c1 + c2;
195 dumpchar(cypher,data);
196 }
197 }
198
dumpstr(void (* dumpchar)(int ch,void * data),void * data,const char * buf)199 static void dumpstr(void (*dumpchar)(int ch,void *data), void *data, const char *buf) {
200 while ( *buf )
201 dumpchar(*buf++,data);
202 }
203
dumpcarefully(void (* dumpchar)(int ch,void * data),void * data,const char * buf)204 static void dumpcarefully(void (*dumpchar)(int ch,void *data), void *data, const char *buf) {
205 int ch;
206
207 while ( (ch = *(unsigned char *) buf++)!='\0' ) {
208 if ( ch<' ' || ch>=0x7f || ch=='\\' || ch=='(' || ch==')' ) {
209 dumpchar('\\',data);
210 dumpchar('0'+(ch>>6),data);
211 dumpchar('0'+((ch>>3)&0x7),data);
212 dumpchar('0'+(ch&0x7),data);
213 } else
214 dumpchar(ch,data);
215 }
216 }
217
dumpascomments(void (* dumpchar)(int ch,void * data),void * data,const char * buf)218 static void dumpascomments(void (*dumpchar)(int ch,void *data), void *data, const char *buf) {
219 int ch;
220
221 dumpchar('%',data);
222 dumpchar(' ',data);
223 while ( (ch = *buf++)!='\0' ) {
224 if ( ch=='\n' || ch=='\r' ) {
225 dumpchar('\n',data);
226 if ( ch=='\r' && *buf=='\n' ) ++buf;
227 if ( *buf=='\0' )
228 return;
229 dumpchar('%',data);
230 dumpchar(' ',data);
231 } else
232 dumpchar(ch,data);
233 }
234 dumpchar('\n',data);
235 }
236
dumpstrn(void (* dumpchar)(int ch,void * data),void * data,const char * buf,int n)237 static void dumpstrn(void (*dumpchar)(int ch,void *data), void *data, const char *buf, int n) {
238 while ( n-->0 )
239 dumpchar(*buf++,data);
240 }
241
dumpf(void (* dumpchar)(int ch,void * data),void * data,const char * format,...)242 static void dumpf(void (*dumpchar)(int ch,void *data), void *data, const char *format, ...) {
243 va_list args;
244 char buffer[300];
245
246 va_start(args,format);
247 vsprintf( buffer, format, args);
248 va_end(args);
249 dumpstr(dumpchar,data,buffer);
250 }
251
isStdEncoding(const char * encoding[256])252 static int isStdEncoding(const char *encoding[256]) {
253 int i;
254
255 for ( i=0; i<256; ++i )
256 if ( strcmp(encoding[i],".notdef")==0 )
257 /* that's ok */;
258 else if ( strcmp(encoding[i],AdobeStandardEncoding[i])!=0 )
259 return( 0 );
260
261 return( 1 );
262 }
263
dumpblues(void (* dumpchar)(int ch,void * data),void * data,const char * name,real * arr,int len,const char * ND)264 static void dumpblues(void (*dumpchar)(int ch,void *data), void *data,
265 const char *name, real *arr, int len, const char *ND) {
266 int i;
267 for ( --len; len>=0 && arr[len]==0.0; --len );
268 ++len;
269 if ( len&1 ) ++len;
270 dumpf( dumpchar,data,"/%s [",name);
271 for ( i=0; i<len; ++i )
272 dumpf( dumpchar,data,"%g ", (double) arr[i]);
273 dumpf( dumpchar,data,"]%s\n",ND );
274 }
275
dumpdblmaxarray(void (* dumpchar)(int ch,void * data),void * data,const char * name,real * arr,int len,const char * modifiers,const char * ND)276 static void dumpdblmaxarray(void (*dumpchar)(int ch,void *data), void *data,
277 const char *name, real *arr, int len, const char *modifiers, const char *ND) {
278 int i;
279 for ( --len; len>=0 && arr[len]==0.0; --len );
280 ++len;
281 dumpf( dumpchar,data,"/%s [",name);
282 for ( i=0; i<len; ++i )
283 dumpf( dumpchar,data,"%g ", (double) arr[i]);
284 dumpf( dumpchar,data,"]%s%s\n", modifiers, ND );
285 }
286
dumpdblarray(void (* dumpchar)(int ch,void * data),void * data,const char * name,double * arr,int len,const char * modifiers,int exec)287 static void dumpdblarray(void (*dumpchar)(int ch,void *data), void *data,
288 const char *name, double *arr, int len, const char *modifiers, int exec) {
289 int i;
290 dumpf( dumpchar,data,"/%s %c",name, exec? '{' : '[' );
291 for ( i=0; i<len; ++i )
292 dumpf( dumpchar,data,"%g ", arr[i]);
293 dumpf( dumpchar,data,"%c%sdef\n", exec ? '}' : ']', modifiers );
294 }
295
PSDictCopy(struct psdict * dict)296 struct psdict *PSDictCopy(struct psdict *dict) {
297 struct psdict *ret;
298 int i;
299
300 if ( dict==NULL )
301 return( NULL );
302
303 ret = calloc(1,sizeof(struct psdict));
304 ret->cnt = dict->cnt; ret->next = dict->next;
305 ret->keys = calloc(ret->cnt,sizeof(char *));
306 ret->values = calloc(ret->cnt,sizeof(char *));
307 for ( i=0; i<dict->next; ++i ) {
308 ret->keys[i] = copy(dict->keys[i]);
309 ret->values[i] = copy(dict->values[i]);
310 }
311
312 return( ret );
313 }
314
PSDictFindEntry(struct psdict * dict,const char * key)315 int PSDictFindEntry(struct psdict *dict, const char *key) {
316 int i;
317
318 if ( dict==NULL )
319 return( -1 );
320
321 for ( i=0; i<dict->next; ++i )
322 if ( strcmp(dict->keys[i],key)==0 )
323 return( i );
324
325 return( -1 );
326 }
327
PSDictHasEntry(struct psdict * dict,const char * key)328 char *PSDictHasEntry(struct psdict *dict, const char *key) {
329 int i;
330
331 if ( dict==NULL )
332 return( NULL );
333
334 for ( i=0; i<dict->next; ++i )
335 if ( strcmp(dict->keys[i],key)==0 )
336 return( dict->values[i] );
337
338 return( NULL );
339 }
340
PSDictSame(struct psdict * dict1,struct psdict * dict2)341 int PSDictSame(struct psdict *dict1, struct psdict *dict2) {
342 int i;
343
344 if ( (dict1==NULL || dict1->cnt==0) && (dict2==NULL || dict2->cnt==0))
345 return( true );
346 if ( dict1==NULL || dict2==NULL || dict1->cnt!=dict2->cnt )
347 return( false );
348
349 for ( i=0; i<dict1->cnt; ++i ) {
350 char *val = PSDictHasEntry(dict2,dict1->keys[i]);
351 if ( val==NULL || strcmp(val,dict1->values[i])!=0 )
352 return( false );
353 }
354 return( true );
355 }
356
PSDictRemoveEntry(struct psdict * dict,const char * key)357 int PSDictRemoveEntry(struct psdict *dict, const char *key) {
358 int i;
359
360 if ( dict==NULL )
361 return( false );
362
363 for ( i=0; i<dict->next; ++i )
364 if ( strcmp(dict->keys[i],key)==0 )
365 break;
366 if ( i==dict->next )
367 return( false );
368 free( dict->keys[i]);
369 free( dict->values[i] );
370 --dict->next;
371 while ( i<dict->next ) {
372 dict->keys[i] = dict->keys[i+1];
373 dict->values[i] = dict->values[i+1];
374 ++i;
375 }
376
377 return( true );
378 }
379
PSDictChangeEntry(struct psdict * dict,const char * key,const char * newval)380 int PSDictChangeEntry(struct psdict *dict, const char *key, const char *newval) {
381 int i;
382
383 if ( dict==NULL )
384 return( -1 );
385
386 for ( i=0; i<dict->next; ++i )
387 if ( strcmp(dict->keys[i],key)==0 )
388 break;
389 if ( i==dict->next ) {
390 if ( dict->next>=dict->cnt ) {
391 dict->cnt += 10;
392 dict->keys = realloc(dict->keys,dict->cnt*sizeof(char *));
393 dict->values = realloc(dict->values,dict->cnt*sizeof(char *));
394 }
395 dict->keys[dict->next] = copy(key);
396 dict->values[dict->next] = NULL;
397 ++dict->next;
398 }
399 free(dict->values[i]);
400 dict->values[i] = copy(newval);
401 return( i );
402 }
403
dumpsubrs(void (* dumpchar)(int ch,void * data),void * data,SplineFont * sf,struct pschars * subrs)404 static void dumpsubrs(void (*dumpchar)(int ch,void *data), void *data,
405 SplineFont *sf, struct pschars *subrs ) {
406 int leniv = 4;
407 int i;
408 char *pt;
409
410 if ( subrs==NULL )
411 return;
412 if ( (pt=PSDictHasEntry(sf->private,"lenIV"))!=NULL )
413 leniv = strtol(pt,NULL,10);
414 dumpf(dumpchar,data,"/Subrs %d array\n",subrs->next);
415 for ( i=0; i<subrs->next; ++i ) {
416 dumpf(dumpchar,data,"dup %d %d RD ", i, subrs->lens[i]+leniv );
417 encodestrout(dumpchar,data,subrs->values[i],subrs->lens[i],leniv);
418 dumpstr(dumpchar,data," NP\n");
419 }
420 dumpstr(dumpchar,data,"ND\n");
421 }
422
423 /* Dumped within the private dict to get access to ND and RD */
dumpcharstrings(void (* dumpchar)(int ch,void * data),void * data,SplineFont * sf,struct pschars * chars)424 static int dumpcharstrings(void (*dumpchar)(int ch,void *data), void *data,
425 SplineFont *sf, struct pschars *chars ) {
426 int leniv = 4;
427 int i;
428 char *pt;
429
430 if ( (pt=PSDictHasEntry(sf->private,"lenIV"))!=NULL )
431 leniv = strtol(pt,NULL,10);
432 dumpf(dumpchar,data,"2 index /CharStrings %d dict dup begin\n",chars->cnt);
433 for ( i=0; i<chars->next; ++i ) {
434 if ( chars->keys[i]==NULL )
435 break;
436 dumpf(dumpchar,data,"/%s %d RD ", chars->keys[i], chars->lens[i]+leniv );
437 encodestrout(dumpchar,data,chars->values[i],chars->lens[i],leniv);
438 dumpstr(dumpchar,data," ND\n");
439 if ( !ff_progress_next())
440 return( false );
441 }
442 dumpstr(dumpchar,data,"end end\nreadonly put\n");
443 return( true );
444 }
445
dumpsplineset(void (* dumpchar)(int ch,void * data),void * data,SplineSet * spl,int pdfopers,int forceclose,int makeballs,int do_clips)446 static void dumpsplineset(void (*dumpchar)(int ch,void *data), void *data,
447 SplineSet *spl, int pdfopers, int forceclose, int makeballs,
448 int do_clips ) {
449 SplinePoint *first, *sp;
450
451 for ( ; spl!=NULL; spl=spl->next ) {
452 if ( do_clips ^ spl->is_clip_path )
453 continue;
454 first = NULL;
455 for ( sp = spl->first; ; sp=sp->next->to ) {
456 if ( first==NULL )
457 dumpf( dumpchar, data, "\t%g %g %s\n", (double) sp->me.x, (double) sp->me.y,
458 pdfopers ? "m" : "moveto" );
459 else if ( sp->prev->knownlinear )
460 dumpf( dumpchar, data, "\t %g %g %s\n", (double) sp->me.x, (double) sp->me.y,
461 pdfopers ? "l" : "lineto" );
462 else
463 dumpf( dumpchar, data, "\t %g %g %g %g %g %g %s\n",
464 (double) sp->prev->from->nextcp.x, (double) sp->prev->from->nextcp.y,
465 (double) sp->prevcp.x, (double) sp->prevcp.y,
466 (double) sp->me.x, (double) sp->me.y,
467 pdfopers ? "c" : "curveto" );
468 if ( sp==first )
469 break;
470 if ( first==NULL ) first = sp;
471 if ( sp->next==NULL )
472 break;
473 }
474 if ( makeballs && (spl->first->next==NULL || (spl->first->next->to==spl->first)) )
475 dumpstr( dumpchar, data, pdfopers ? "\th\n" : "\tclosepath\n" );
476 if ( forceclose || spl->first->prev!=NULL )
477 dumpstr( dumpchar, data, pdfopers ? "\th\n" : "\tclosepath\n" );
478 }
479 }
480
InvertTransform(real inverse[6],real transform[6])481 static int InvertTransform(real inverse[6], real transform[6]) {
482 real temp[6], val;
483 int i;
484
485 for ( i=0; i<6; ++i ) temp[i] = transform[i];
486
487 inverse[0] = inverse[3] = 1;
488 inverse[1] = inverse[2] = inverse[4] = inverse[5] = 0;
489
490 if ( temp[0]==0 && temp[2]==0 )
491 return( false ); /* Not invertable */
492 if ( temp[0]==0 ) {
493 val = temp[0]; temp[0] = temp[2]; temp[2] = val;
494 val = temp[1]; temp[1] = temp[3]; temp[3] = val;
495 inverse[0] = inverse[3] = 0;
496 inverse[1] = inverse[2] = 1;
497 }
498 val = 1/temp[0];
499 temp[1] *= val; inverse[0] *= val; inverse[1]*=val;
500 val = temp[2];
501 temp[3] -= val*temp[1]; inverse[2] -= val*inverse[0]; inverse[3] -= val*inverse[1];
502 val = temp[4];
503 temp[5] -= val*temp[1]; inverse[4] -= val*inverse[0]; inverse[5] -= val*inverse[1];
504 if ( temp[3]==0 )
505 return( false );
506 val = 1/temp[3];
507 inverse[2] *= val; inverse[3]*=val;
508 val = temp[1];
509 inverse[0] -= val*inverse[2]; inverse[1] -= val*inverse[3];
510 val = temp[5];
511 inverse[4] -= val*inverse[2]; inverse[5] -= val*inverse[3];
512 return( true );
513 }
514
dumpGradient(void (* dumpchar)(int ch,void * data),void * data,struct gradient * grad,RefChar * ref,SplineChar * sc,int layer,int pdfopers,int isstroke)515 static void dumpGradient(void (*dumpchar)(int ch,void *data), void *data,
516 struct gradient *grad, RefChar *ref, SplineChar *sc, int layer, int pdfopers, int isstroke ) {
517
518 if ( pdfopers ) {
519 char buffer[200];
520 dumpf(dumpchar,data,"/Pattern %s\n", isstroke ? "CS" : "cs" );
521 makePatName(buffer,ref,sc,layer,isstroke,true);
522 dumpf(dumpchar,data,"/%s %s\n", buffer, isstroke ? "SCN" : "scn" );
523 /* PDF output looks much simpler than postscript. It isn't. It's just */
524 /* that the equivalent pdf dictionaries need to be created as objects*/
525 /* and can't live in the content stream, so they are done elsewhere */
526 } else {
527 dumpf(dumpchar,data, "<<\n /PatternType 2\n /Shading <<\n" );
528 dumpf(dumpchar,data, " /ShadingType %d\n", grad->radius==0?2:3 );
529 dumpf(dumpchar,data, " /ColorSpace /DeviceRGB\n" );
530 if ( grad->radius==0 ) {
531 dumpf(dumpchar,data, " /Coords [%g %g %g %g]\n",
532 grad->start.x, grad->start.y, grad->stop.x, grad->stop.y);
533 } else {
534 dumpf(dumpchar,data, " /Coords [%g %g 0 %g %g %g]\n",
535 grad->start.x, grad->start.y, grad->stop.x, grad->stop.y,
536 grad->radius );
537 }
538 dumpf(dumpchar,data, " /Extend [true true]\n" ); /* implies pad */
539 dumpf(dumpchar,data, " /Function <<\n" );
540 dumpf(dumpchar,data, " /FunctionType 0\n" ); /* Iterpolation between samples */
541 dumpf(dumpchar,data, " /Domain [%g %g]\n", grad->grad_stops[0].offset,
542 grad->grad_stops[grad->stop_cnt-1].offset );
543 dumpf(dumpchar,data, " /Range [0 1.0 0 1.0 0 1.0]\n" );
544 dumpf(dumpchar,data, " /Size [%d]\n", grad->stop_cnt==2?2:101 );
545 dumpf(dumpchar,data, " /BitsPerSample 8\n" );
546 dumpf(dumpchar,data, " /Decode [0 1.0 0 1.0 0 1.0]\n" );
547 dumpf(dumpchar,data, " /DataSource <" );
548 if ( grad->stop_cnt==2 ) {
549 unsigned col = grad->grad_stops[0].col;
550 if ( col==COLOR_INHERITED ) col = 0x000000;
551 dumpf(dumpchar,data,"%02x",(col>>16)&0xff);
552 dumpf(dumpchar,data,"%02x",(col>>8 )&0xff);
553 dumpf(dumpchar,data,"%02x",(col )&0xff);
554 col = grad->grad_stops[1].col;
555 dumpf(dumpchar,data,"%02x",(col>>16)&0xff);
556 dumpf(dumpchar,data,"%02x",(col>>8 )&0xff);
557 dumpf(dumpchar,data,"%02x",(col )&0xff);
558 } else {
559 int i,j;
560 /* Rather than try and figure out the minimum common divisor */
561 /* off all the offsets, I'll just assume they are all percent*/
562 (dumpchar)('\n',data);
563 for ( i=0; i<=100; ++i ) {
564 unsigned col;
565 double t = grad->grad_stops[0].offset +
566 (grad->grad_stops[grad->stop_cnt-1].offset-
567 grad->grad_stops[0].offset)* i/100.0;
568 for ( j=0; j<grad->stop_cnt; ++j )
569 if ( t<=grad->grad_stops[j].offset )
570 break;
571 if ( j==grad->stop_cnt )
572 col = grad->grad_stops[j-1].col;
573 else if ( t==grad->grad_stops[j].offset )
574 col = grad->grad_stops[j].col;
575 else {
576 double percent = (t-grad->grad_stops[j-1].offset)/ (grad->grad_stops[j].offset-grad->grad_stops[j-1].offset);
577 uint32 col1 = grad->grad_stops[j-1].col;
578 uint32 col2 = grad->grad_stops[j ].col;
579 int red, green, blue;
580 if ( col1==COLOR_INHERITED ) col1 = 0x000000;
581 if ( col2==COLOR_INHERITED ) col2 = 0x000000;
582 red = ((col1>>16)&0xff)*(1-percent) + ((col2>>16)&0xff)*percent;
583 green = ((col1>>8 )&0xff)*(1-percent) + ((col2>>8 )&0xff)*percent;
584 blue = ((col1 )&0xff)*(1-percent) + ((col2 )&0xff)*percent;
585 col = (red<<16) | (green<<8) | blue;
586 }
587 if ( col==COLOR_INHERITED ) col = 0x000000;
588 dumpf(dumpchar,data,"%02x",(col>>16)&0xff);
589 dumpf(dumpchar,data,"%02x",(col>>8 )&0xff);
590 dumpf(dumpchar,data,"%02x",(col )&0xff);
591 }
592 }
593 dumpf(dumpchar,data,">\n");
594 dumpf(dumpchar,data, " >>\n" );
595 dumpf(dumpchar,data, " >>\n" );
596 dumpf(dumpchar,data, ">> matrix makepattern setpattern\n" );
597 }
598 }
599
dumpPattern(void (* dumpchar)(int ch,void * data),void * data,struct pattern * pat,RefChar * ref,SplineChar * sc,int layer,int pdfopers,int isstroke)600 static void dumpPattern(void (*dumpchar)(int ch,void *data), void *data,
601 struct pattern *pat, RefChar *ref, SplineChar *sc, int layer, int pdfopers, int isstroke ) {
602 SplineChar *pattern_sc = SFGetChar(sc->parent,-1,pat->pattern);
603 DBounds b;
604 real scale[6], result[6];
605
606 if ( pdfopers ) {
607 char buffer[200];
608 dumpf(dumpchar,data,"/Pattern %s\n", isstroke ? "CS" : "cs" );
609 makePatName(buffer,ref,sc,layer,isstroke,false);
610 dumpf(dumpchar,data,"/%s %s\n", buffer, isstroke ? "SCN" : "scn" );
611 /* PDF output looks much simpler than postscript. It isn't. It's just */
612 /* that the equivalent pdf dictionaries need to be created as objects*/
613 /* and can't live in the content stream, so they are done elsewhere */
614 } else {
615 if ( pattern_sc==NULL )
616 LogError(_("No glyph named %s, used as a pattern in %s\n"), pat->pattern, sc->name);
617 PatternSCBounds(pattern_sc,&b);
618
619 dumpf(dumpchar,data, "<<\n" );
620 dumpf(dumpchar,data, " /PatternType 1\n" );
621 dumpf(dumpchar,data, " /PaintType 1\n" ); /* The intricacies of uncolored tiles are not something into which I wish to delve */
622 dumpf(dumpchar,data, " /TilingType 1\n" );
623 dumpf(dumpchar,data, " /BBox [%g %g %g %g]\n", b.minx, b.miny, b.maxx, b.maxy );
624 dumpf(dumpchar,data, " /XStep %g\n", b.maxx-b.minx );
625 dumpf(dumpchar,data, " /YStep %g\n", b.maxy-b.miny );
626 dumpf(dumpchar,data, " /PaintProc { begin\n" ); /* The begin pops the pattern dictionary off the stack. Don't really use it, but do need the pop */
627 SC_PSDump(dumpchar,data, pattern_sc, true, false, ly_all );
628 dumpf(dumpchar,data, " end }\n" );
629 memset(scale,0,sizeof(scale));
630 scale[0] = pat->width/(b.maxx-b.minx);
631 scale[3] = pat->height/(b.maxy-b.miny);
632 MatMultiply(scale,pat->transform, result);
633 dumpf(dumpchar,data, ">> [%g %g %g %g %g %g] makepattern setpattern\n",
634 result[0], result[1], result[2],
635 result[3], result[4], result[5]);
636 }
637 }
638
dumpbrush(void (* dumpchar)(int ch,void * data),void * data,struct brush * brush,RefChar * ref,SplineChar * sc,int layer,int pdfopers)639 static void dumpbrush(void (*dumpchar)(int ch,void *data), void *data,
640 struct brush *brush, RefChar *ref, SplineChar *sc, int layer, int pdfopers ) {
641 if ( brush->gradient!=NULL )
642 dumpGradient(dumpchar,data,brush->gradient,ref,sc,layer,pdfopers,false);
643 else if ( brush->pattern!=NULL )
644 dumpPattern(dumpchar,data,brush->pattern,ref,sc,layer,pdfopers,false);
645 else if ( brush->col!=COLOR_INHERITED ) {
646 int r, g, b;
647 r = (brush->col>>16)&0xff;
648 g = (brush->col>>8 )&0xff;
649 b = (brush->col )&0xff;
650 if ( r==g && b==g )
651 dumpf(dumpchar,data,(pdfopers ? "%g g\n" : "%g setgray\n"), r/255.0 );
652 else
653 dumpf(dumpchar,data,(pdfopers ? "%g %g %g rg\n" : "%g %g %g setrgbcolor\n"),
654 r/255.0, g/255.0, b/255.0 );
655 if ( pdfopers && (double)brush->opacity<1.0 && brush->opacity>=0 )
656 dumpf(dumpchar,data,"/gs_fill_opacity_%g gs\n", (double)brush->opacity );
657 }
658 }
659
660 /* Grumble. PDF uses different operators for colors for stroke and fill */
dumppenbrush(void (* dumpchar)(int ch,void * data),void * data,struct brush * brush,RefChar * ref,SplineChar * sc,int layer,int pdfopers)661 static void dumppenbrush(void (*dumpchar)(int ch,void *data), void *data,
662 struct brush *brush, RefChar *ref, SplineChar *sc, int layer, int pdfopers ) {
663 if ( brush->gradient!=NULL )
664 dumpGradient(dumpchar,data,brush->gradient,ref,sc,layer,pdfopers,true);
665 else if ( brush->pattern!=NULL )
666 dumpPattern(dumpchar,data,brush->pattern,ref,sc,layer,pdfopers,true);
667 else if ( brush->col!=COLOR_INHERITED ) {
668 int r, g, b;
669 r = (brush->col>>16)&0xff;
670 g = (brush->col>>8 )&0xff;
671 b = (brush->col )&0xff;
672 if ( r==g && b==g )
673 dumpf(dumpchar,data,(pdfopers ? "%g G\n" : "%g setgray\n"), r/255.0 );
674 else
675 dumpf(dumpchar,data,(pdfopers ? "%g %g %g RG\n" : "%g %g %g setrgbcolor\n"),
676 r/255.0, g/255.0, b/255.0 );
677 if ( pdfopers && (double)brush->opacity<1.0 && brush->opacity>=0 )
678 dumpf(dumpchar,data,"/gs_stroke_opacity_%g gs\n", (double)brush->opacity );
679 }
680 }
681
dumppen(void (* dumpchar)(int ch,void * data),void * data,struct pen * pen,RefChar * ref,SplineChar * sc,int layer,int pdfopers)682 static void dumppen(void (*dumpchar)(int ch,void *data), void *data,
683 struct pen *pen, RefChar *ref, SplineChar *sc, int layer, int pdfopers) {
684 dumppenbrush(dumpchar,data,&pen->brush,ref,sc,layer,pdfopers);
685
686 if ( pen->width!=WIDTH_INHERITED )
687 dumpf(dumpchar,data,(pdfopers ? "%g w\n": "%g setlinewidth\n"), (double)pen->width );
688 if ( pen->linejoin!=lj_inherited )
689 dumpf(dumpchar,data,(pdfopers ? "%d j\n": "%d setlinejoin\n"), pen->linejoin );
690 if ( pen->linecap!=lc_inherited )
691 dumpf(dumpchar,data,(pdfopers ? "%d J\n": "%d setlinecap\n"), pen->linecap );
692 if ( pen->trans[0]!=1.0 || pen->trans[3]!=1.0 || pen->trans[1]!=0 || pen->trans[2]!=0 )
693 dumpf(dumpchar,data,(pdfopers ? "%g %g %g %g 0 0 cm\n" : "[%g %g %g %g 0 0] concat\n"),
694 (double) pen->trans[0], (double) pen->trans[1], (double) pen->trans[2], (double) pen->trans[3]);
695 if ( pen->dashes[0]!=0 || pen->dashes[1]!=DASH_INHERITED ) {
696 size_t i;
697 dumpchar('[',data);
698 for ( i=0; i<sizeof(pen->dashes)/sizeof(pen->dashes[0]) && pen->dashes[i]!=0; ++i )
699 dumpf(dumpchar,data,"%d ", pen->dashes[i]);
700 dumpf(dumpchar,data,pdfopers ? "] 0 d\n" : "] 0 setdash\n");
701 }
702 }
703
704 struct psfilter {
705 int ascii85encode, ascii85n, ascii85bytes_per_line;
706 void (*dumpchar)(int ch,void *data);
707 void *data;
708 };
709
InitFilter(struct psfilter * ps,void (* dumpchar)(int ch,void * data),void * data)710 static void InitFilter(struct psfilter *ps,void (*dumpchar)(int ch,void *data), void *data) {
711 ps->ascii85encode = 0;
712 ps->ascii85n = 0;
713 ps->ascii85bytes_per_line = 0;
714 ps->dumpchar = dumpchar;
715 ps->data = data;
716 }
717
Filter(struct psfilter * ps,uint8 ch)718 static void Filter(struct psfilter *ps,uint8 ch) {
719 ps->ascii85encode = (ps->ascii85encode<<8) | ch;
720 if ( ++ps->ascii85n == 4 ) {
721 int ch5, ch4, ch3, ch2, ch1;
722 uint32 val = ps->ascii85encode;
723 if ( val==0 ) {
724 (ps->dumpchar)('z',ps->data);
725 ps->ascii85n = 0;
726 if ( ++ps->ascii85bytes_per_line >= 76 ) {
727 (ps->dumpchar)('\n',ps->data);
728 ps->ascii85bytes_per_line = 0;
729 }
730 } else {
731 ch5 = val%85; val /= 85;
732 ch4 = val%85; val /= 85;
733 ch3 = val%85; val /= 85;
734 ch2 = val%85;
735 ch1 = val/85;
736 dumpf(ps->dumpchar, ps->data, "%c%c%c%c%c",
737 ch1+'!', ch2+'!', ch3+'!', ch4+'!', ch5+'!' );
738 ps->ascii85encode = 0;
739 ps->ascii85n = 0;
740 if (( ps->ascii85bytes_per_line+=5) >= 80 ) {
741 (ps->dumpchar)('\n',ps->data);
742 ps->ascii85bytes_per_line = 0;
743 }
744 }
745 }
746 }
747
FlushFilter(struct psfilter * ps)748 static void FlushFilter(struct psfilter *ps) {
749 uint32 val = ps->ascii85encode;
750 int n = ps->ascii85n;
751 if ( n!=0 ) {
752 int ch4, ch3, ch2, ch1;
753 while ( n++<4 )
754 val<<=8;
755 /* ch5 = val%85; */ val /= 85;
756 ch4 = val%85; val /= 85;
757 ch3 = val%85; val /= 85;
758 ch2 = val%85;
759 ch1 = val/85;
760 (ps->dumpchar)(ch1+'!',ps->data);
761 (ps->dumpchar)(ch2+'!',ps->data);
762 if ( ps->ascii85n>=2 )
763 (ps->dumpchar)(ch3+'!',ps->data);
764 if ( ps->ascii85n>=3 )
765 (ps->dumpchar)(ch4+'!',ps->data);
766 }
767 (ps->dumpchar)('~',ps->data);
768 (ps->dumpchar)('>',ps->data);
769 (ps->dumpchar)('\n',ps->data);
770 }
771
772 /* Inside a font, I can't use a <stdin> as a data source. Probably because */
773 /* the parser doesn't know what to do with those data when building the char */
774 /* proc (as opposed to executing) */
775 /* So I can't use run length filters or other compression technique */
776
FilterStr(struct psfilter * ps,uint8 * pt,int len)777 static void FilterStr(struct psfilter *ps,uint8 *pt, int len ) {
778 uint8 *end = pt+len;
779
780 while ( pt<end )
781 Filter(ps,*pt++);
782 }
783
PSDumpBinaryData(void (* dumpchar)(int ch,void * data),void * data,uint8 * bytes,int rows,int bytes_per_row,int useful_bytes_per_row)784 static void PSDumpBinaryData(void (*dumpchar)(int ch,void *data), void *data,
785 uint8 *bytes,int rows, int bytes_per_row, int useful_bytes_per_row) {
786 struct psfilter ps;
787 int i,j,cnt,group_cnt;
788 const int max_string = 65536;
789
790 if ( useful_bytes_per_row*rows<max_string ) {
791 /* It all fits in one string. Easy peasy */
792 dumpf(dumpchar,data, "{<~" );
793 InitFilter(&ps,dumpchar,data);
794 if (bytes_per_row==useful_bytes_per_row )
795 FilterStr(&ps,(uint8 *) bytes, rows*bytes_per_row);
796 else for ( i=0; i<rows; ++i ) {
797 FilterStr(&ps,(uint8 *) (bytes + i*bytes_per_row),
798 useful_bytes_per_row);
799 }
800 FlushFilter(&ps);
801 dumpchar('}',data);
802 } else {
803 cnt = (max_string-1)/useful_bytes_per_row;
804 if ( cnt==0 ) cnt=1;
805 group_cnt = -1;
806 for ( i=0; i<rows; ) {
807 if ( i+cnt>=rows )
808 dumpf(dumpchar,data, "{currentdict /ff-image-cnt undef <~" );
809 else {
810 dumpf(dumpchar,data, "{{/ff-image-cnt %d def <~", i/cnt );
811 group_cnt = i/cnt;
812 }
813 InitFilter(&ps,dumpchar,data);
814 for ( j=0; j<cnt && i<rows; ++i, ++j ) {
815 FilterStr(&ps,(uint8 *) (bytes + i*bytes_per_row),
816 useful_bytes_per_row);
817 }
818 FlushFilter(&ps);
819 dumpf(dumpchar,data,"}\n");
820 }
821 for ( i=group_cnt-1; i>=0; --i ) {
822 dumpf(dumpchar,data,"ff-image-cnt %d eq 3 1 roll ifelse}\n", i );
823 }
824 dumpf(dumpchar,data,"currentdict /ff-image-cnt known not 3 1 roll ifelse}\n" );
825 }
826 }
827
PSDump24BinaryData(void (* dumpchar)(int ch,void * data),void * data,struct _GImage * base)828 static void PSDump24BinaryData(void (*dumpchar)(int ch,void *data), void *data,
829 struct _GImage *base ) {
830 struct psfilter ps;
831 int i,j,cnt,group_cnt;
832 register uint32 val;
833 register uint32 *pt, *end;
834 const int max_string = 65536;
835
836 if ( 3*base->width*base->height<max_string ) {
837 /* It all fits in one string. Easy peasy */
838 dumpf(dumpchar,data, "{<~" );
839 InitFilter(&ps,dumpchar,data);
840 for ( i=0; i<base->height; ++i ) {
841 pt = (uint32 *) (base->data + i*base->bytes_per_line);
842 end = pt + base->width;
843 while ( pt<end ) {
844 val = *pt++;
845 Filter(&ps,COLOR_RED(val));
846 Filter(&ps,COLOR_GREEN(val));
847 Filter(&ps,COLOR_BLUE(val));
848 }
849 }
850 FlushFilter(&ps);
851 dumpchar('}',data);
852 } else {
853 cnt = (max_string-1)/(3*base->width);
854 if ( cnt==0 ) cnt=1;
855 group_cnt = -1;
856 for ( i=0; i<base->height; ) {
857 if ( i+cnt>=base->height )
858 dumpf(dumpchar,data, "{currentdict /ff-image-cnt undef <~" );
859 else {
860 dumpf(dumpchar,data, "{{/ff-image-cnt %d def <~", i/cnt );
861 group_cnt = i/cnt;
862 }
863 InitFilter(&ps,dumpchar,data);
864 for ( j=0; j<cnt && i<base->height; ++i, ++j ) {
865 pt = (uint32 *) (base->data + i*base->bytes_per_line);
866 end = pt + base->width;
867 while ( pt<end ) {
868 val = *pt++;
869 Filter(&ps,COLOR_RED(val));
870 Filter(&ps,COLOR_GREEN(val));
871 Filter(&ps,COLOR_BLUE(val));
872 }
873 }
874 FlushFilter(&ps);
875 dumpf(dumpchar,data,"}\n");
876 }
877 for ( i=group_cnt-1; i>=0; --i ) {
878 dumpf(dumpchar,data,"ff-image-cnt %d eq 3 1 roll ifelse}\n", i );
879 }
880 dumpf(dumpchar,data,"currentdict /ff-image-cnt known not 3 1 roll ifelse}\n" );
881 }
882 }
883
PSDrawMonoImg(void (* dumpchar)(int ch,void * data),void * data,struct _GImage * base,int use_imagemask)884 static void PSDrawMonoImg(void (*dumpchar)(int ch,void *data), void *data,
885 struct _GImage *base,int use_imagemask) {
886
887 dumpf(dumpchar,data, " %d %d ", base->width, base->height );
888 if ( base->trans==1 )
889 dumpf(dumpchar,data, "false ");
890 else
891 dumpf(dumpchar,data, "true ");
892 dumpf(dumpchar,data, "[%d 0 0 %d 0 %d]\n",
893 base->width, -base->height, base->height);
894 PSDumpBinaryData(dumpchar,data,(uint8 *) base->data,base->height,base->bytes_per_line,(base->width+7)/8);
895
896 dumpf(dumpchar,data, "%s\n",
897 use_imagemask?"imagemask":"image" );
898 }
899
PSSetIndexColors(void (* dumpchar)(int ch,void * data),void * data,GClut * clut)900 static void PSSetIndexColors(void (*dumpchar)(int ch,void *data), void *data,
901 GClut *clut) {
902 int i;
903
904 dumpf(dumpchar,data, "[/Indexed /DeviceRGB %d <\n", clut->clut_len-1 );
905 for ( i=0; i<clut->clut_len; ++i )
906 dumpf(dumpchar,data, "%02X%02X%02X%s", COLOR_RED(clut->clut[i]),
907 COLOR_GREEN(clut->clut[i]), COLOR_BLUE(clut->clut[i]),
908 i%11==10?"\n":" ");
909 dumpf(dumpchar,data,">\n] setcolorspace\n");
910 }
911
PSBuildImageIndexDict(void (* dumpchar)(int ch,void * data),void * data,struct _GImage * base)912 static void PSBuildImageIndexDict(void (*dumpchar)(int ch,void *data), void *data,
913 struct _GImage *base) {
914 /* I need an image dict, otherwise I am restricted to grey scale */
915 dumpf(dumpchar,data, "<<\n" );
916 dumpf(dumpchar,data, " /ImageType 1\n" );
917 dumpf(dumpchar,data, " /Width %d\n", base->width );
918 dumpf(dumpchar,data, " /Height %d\n", base->height );
919 dumpf(dumpchar,data, " /ImageMatrix [%d 0 0 %d 0 %d]\n",
920 base->width, -base->height, base->height);
921 dumpf(dumpchar,data, " /MultipleDataSources false\n" );
922 dumpf(dumpchar,data, " /BitsPerComponent 8\n" );
923 dumpf(dumpchar,data, " /Decode [0 255]\n" );
924 dumpf(dumpchar,data, " /Interpolate false\n" );
925 dumpf(dumpchar,data, " /DataSource " );
926 PSDumpBinaryData(dumpchar,data,base->data,base->height,base->bytes_per_line,
927 base->width);
928 dumpf(dumpchar,data, ">> image\n" );
929 }
930
PSDrawImg(void (* dumpchar)(int ch,void * data),void * data,struct _GImage * base)931 static void PSDrawImg(void (*dumpchar)(int ch,void *data), void *data,
932 struct _GImage *base) {
933
934 if ( base->image_type == it_index ) {
935 PSSetIndexColors(dumpchar,data,base->clut);
936 PSBuildImageIndexDict(dumpchar,data,base);
937 dumpf(dumpchar,data, "[/DeviceRGB] setcolorspace\n" );
938 } else {
939 dumpf(dumpchar,data, "%d %d 8 [%d 0 0 %d 0 %d] ",
940 base->width, base->height, base->width, -base->height, base->height);
941 PSDump24BinaryData(dumpchar,data,base);
942 dumpf(dumpchar,data, "false 3 colorimage\n" );
943 }
944 }
945
dumpimage(void (* dumpchar)(int ch,void * data),void * data,ImageList * imgl,int use_imagemask,int pdfopers,int layer,int icnt,SplineChar * sc)946 static void dumpimage(void (*dumpchar)(int ch,void *data), void *data,
947 ImageList *imgl, int use_imagemask, int pdfopers,
948 int layer, int icnt, SplineChar *sc ) {
949 GImage *image = imgl->image;
950 struct _GImage *base = image->list_len==0?image->u.image:image->u.images[0];
951
952 if ( pdfopers ) {
953 dumpf( dumpchar, data, " q 1 0 0 1 %g %g cm %g 0 0 %g 0 0 cm\n",
954 (double) imgl->xoff, (double) (imgl->yoff-imgl->yscale*base->height),
955 (double) (imgl->xscale*base->width), (double) (imgl->yscale*base->height) );
956 dumpf( dumpchar, data, "/%s_ly%d_%d_image", sc->name, layer, icnt );
957 dumpf( dumpchar, data, " Do " ); /* I think I use this for imagemasks too... */
958 dumpstr(dumpchar,data,"Q\n");
959 } else {
960 dumpf( dumpchar, data, " gsave %g %g translate %g %g scale\n",
961 (double) imgl->xoff, (double) (imgl->yoff-imgl->yscale*base->height),
962 (double) (imgl->xscale*base->width), (double) (imgl->yscale*base->height) );
963 if ( base->image_type==it_mono ) {
964 PSDrawMonoImg(dumpchar,data,base,use_imagemask);
965 } else {
966 /* Just draw the image, ignore the complexity of transparent images */
967 PSDrawImg(dumpchar,data,base);
968 }
969 dumpstr(dumpchar,data,"grestore\n");
970 }
971 }
972
SC_PSDump(void (* dumpchar)(int ch,void * data),void * data,SplineChar * sc,int refs_to_splines,int pdfopers,int layer)973 void SC_PSDump(void (*dumpchar)(int ch,void *data), void *data,
974 SplineChar *sc, int refs_to_splines, int pdfopers, int layer ) {
975 RefChar *ref;
976 real inverse[6];
977 int i, last, first;
978 SplineSet *temp;
979
980 if ( sc==NULL )
981 return;
982 last = first = layer;
983 if ( layer==ly_all )
984 first = last = ly_fore;
985 if ( sc->parent->multilayer ) {
986 first = ly_fore;
987 last = sc->layer_cnt-1;
988 }
989 for ( i=first; i<=last; ++i ) {
990 if ( sc->layers[i].splines!=NULL ) {
991 temp = sc->layers[i].splines;
992 if ( sc->layers[i].order2 ) temp = SplineSetsPSApprox(temp);
993 if ( sc->parent->multilayer ) {
994 dumpstr(dumpchar,data,pdfopers ? "q " : "gsave " );
995 if ( SSHasClip(temp)) {
996 dumpsplineset(dumpchar,data,temp,pdfopers,true, false, true);
997 dumpstr(dumpchar,data,pdfopers ? "W n " : "clip newpath\n" );
998 }
999 dumpsplineset(dumpchar,data,temp,pdfopers,sc->layers[i].dofill,
1000 sc->layers[i].dostroke && sc->layers[i].stroke_pen.linecap==lc_round,
1001 false);
1002 if ( sc->layers[i].dofill && sc->layers[i].dostroke ) {
1003 if ( pdfopers ) {
1004 dumpbrush(dumpchar,data, &sc->layers[i].fill_brush,NULL,sc,i,pdfopers);
1005 dumppen(dumpchar,data, &sc->layers[i].stroke_pen,NULL,sc,i,pdfopers);
1006 dumpstr(dumpchar,data, "B " );
1007 } else if ( sc->layers[i].fillfirst ) {
1008 dumpstr(dumpchar,data, "gsave " );
1009 dumpbrush(dumpchar,data, &sc->layers[i].fill_brush,NULL,sc,i,pdfopers);
1010 dumpstr(dumpchar,data,"fill grestore " );
1011 dumppen(dumpchar,data, &sc->layers[i].stroke_pen,NULL,sc,i,pdfopers);
1012 dumpstr(dumpchar,data,"stroke " );
1013 } else {
1014 dumpstr(dumpchar,data, "gsave " );
1015 dumppen(dumpchar,data, &sc->layers[i].stroke_pen,NULL,sc,i,pdfopers);
1016 dumpstr(dumpchar,data,"stroke grestore " );
1017 dumpbrush(dumpchar,data, &sc->layers[i].fill_brush,NULL,sc,i,pdfopers);
1018 dumpstr(dumpchar,data,"fill " );
1019 }
1020 } else if ( sc->layers[i].dofill ) {
1021 dumpbrush(dumpchar,data, &sc->layers[i].fill_brush,NULL,sc,i,pdfopers);
1022 dumpstr(dumpchar,data,pdfopers ? "f ": "fill " );
1023 } else if ( sc->layers[i].dostroke ) {
1024 dumppen(dumpchar,data, &sc->layers[i].stroke_pen,NULL,sc,i,pdfopers);
1025 dumpstr(dumpchar,data, pdfopers ? "S ": "stroke " );
1026 }
1027 dumpstr(dumpchar,data,pdfopers ? "Q\n" : "grestore\n" );
1028 } else
1029 dumpsplineset(dumpchar,data,temp,pdfopers,!sc->parent->strokedfont,false,
1030 false);
1031 if ( sc->layers[i].order2 ) SplinePointListsFree(temp);
1032 }
1033 if ( sc->layers[i].refs!=NULL ) {
1034 if ( sc->parent->multilayer ) {
1035 dumpstr(dumpchar,data,pdfopers ? "q " : "gsave " );
1036 if ( sc->layers[i].dofill )
1037 dumpbrush(dumpchar,data, &sc->layers[i].fill_brush, NULL, sc, i, pdfopers);
1038 }
1039 if ( refs_to_splines ) {
1040 if ( !pdfopers || !sc->parent->multilayer ) {
1041 /* In PostScript, patterns are transformed by the page's */
1042 /* transformation matrix. In PDF they are not. */
1043 /* Of course if we have no patterns we can still use this code */
1044 for ( ref = sc->layers[i].refs; ref!=NULL; ref=ref->next ) {
1045 dumpstr(dumpchar,data,pdfopers ? "q " : "gsave " );
1046 if ( !MatIsIdentity(ref->transform) ) {
1047 dumpf(dumpchar,data,pdfopers ? "%g %g %g %g %g %g cm " : "[%g %g %g %g %g %g] concat ",
1048 (double) ref->transform[0], (double) ref->transform[1], (double) ref->transform[2],
1049 (double) ref->transform[3], (double) ref->transform[4], (double) ref->transform[5]);
1050 }
1051 SC_PSDump(dumpchar,data,ref->sc,refs_to_splines,pdfopers,ly_all);
1052 dumpstr(dumpchar,data,pdfopers ? "Q\n" : "grestore\n" );
1053 }
1054 } else {
1055 /* If we get here we are outputting pdf, are type3, refs_2_splines */
1056 /* We need different gradients and patterns for different transform */
1057 /* matrices of references */
1058 int j;
1059 for ( ref = sc->layers[i].refs; ref!=NULL; ref=ref->next ) {
1060 for ( j=0; j<ref->layer_cnt; ++j ) {
1061 temp = ref->layers[j].splines;
1062 /*if ( sc->layers[i].order2 )
1063 temp = SplineSetsPSApprox(temp);*/
1064 dumpstr(dumpchar,data,pdfopers ? "q" : "gsave " );
1065 dumpsplineset(dumpchar,data,temp,pdfopers,ref->layers[j].dofill,
1066 ref->layers[j].dostroke && ref->layers[j].stroke_pen.linecap==lc_round,
1067 false);
1068 if ( ref->layers[j].dofill && ref->layers[j].dostroke ) {
1069 dumpbrush(dumpchar,data, &ref->layers[j].fill_brush,ref,ref->sc,j,pdfopers);
1070 dumppen(dumpchar,data, &ref->layers[j].stroke_pen,ref,ref->sc,j,pdfopers);
1071 dumpstr(dumpchar,data, "B " );
1072 } else if ( ref->layers[j].dofill ) {
1073 dumpbrush(dumpchar,data, &ref->layers[j].fill_brush,ref,ref->sc,j,pdfopers);
1074 dumpstr(dumpchar,data,pdfopers ? "f ": "fill " );
1075 } else if ( ref->layers[j].dostroke ) {
1076 dumppen(dumpchar,data, &ref->layers[j].stroke_pen,ref,ref->sc,j,pdfopers);
1077 dumpstr(dumpchar,data, pdfopers ? "S ": "stroke " );
1078 }
1079 dumpstr(dumpchar,data,pdfopers ? "Q\n" : "grestore\n" );
1080 /* if ( sc->layers[layer].order2 )
1081 SplinePointListsFree(temp);*/
1082 }
1083 }
1084 }
1085 } else {
1086 dumpstr(dumpchar,data," pop -1\n" );
1087 for ( ref = sc->layers[i].refs; ref!=NULL; ref=ref->next ) {
1088 if ( ref->transform[0]!=1 || ref->transform[1]!=0 || ref->transform[2]!=0 ||
1089 ref->transform[3]!=1 || ref->transform[4]!=0 || ref->transform[5]!=0 ) {
1090 if ( InvertTransform(inverse,ref->transform)) {
1091 if ( ref->transform[0]!=1 || ref->transform[1]!=0 ||
1092 ref->transform[2]!=0 || ref->transform[3]!=1 )
1093 dumpf(dumpchar,data, " [ %g %g %g %g %g %g ] concat ",
1094 (double) ref->transform[0], (double) ref->transform[1], (double) ref->transform[2],
1095 (double) ref->transform[3], (double) ref->transform[4], (double) ref->transform[5]);
1096 else
1097 dumpf(dumpchar,data, " %g %g translate ",
1098 (double) ref->transform[4], (double) ref->transform[5]);
1099 dumpf(dumpchar,data, "1 index /CharProcs get /%s get exec ",
1100 ref->sc->name );
1101 if ( inverse[0]!=1 || inverse[1]!=0 ||
1102 inverse[2]!=0 || inverse[3]!=1 )
1103 dumpf(dumpchar,data, "[ %g %g %g %g %g %g ] concat \n",
1104 (double) inverse[0], (double) inverse[1], (double) inverse[2], (double) inverse[3], (double) inverse[4], (double) inverse[5]
1105 );
1106 else
1107 dumpf(dumpchar,data, "%g %g translate\n",
1108 (double) inverse[4], (double) inverse[5] );
1109 }
1110 } else
1111 dumpf(dumpchar,data, " 1 index /CharProcs get /%s get exec\n", ref->sc->name );
1112 }
1113 }
1114 if ( sc->parent->multilayer )
1115 dumpstr(dumpchar,data,pdfopers ? "Q\n" : "grestore\n" );
1116 }
1117 if ( sc->layers[i].images!=NULL ) { ImageList *img; int icnt=0;
1118 dumpstr(dumpchar,data,pdfopers ? "q\n" : "gsave\n" );
1119 if ( sc->layers[i].dofill )
1120 dumpbrush(dumpchar,data, &sc->layers[i].fill_brush,NULL,sc,i,pdfopers);
1121 for ( img = sc->layers[i].images; img!=NULL; img=img->next, ++icnt )
1122 dumpimage(dumpchar,data,img,sc->layers[i].dofill,pdfopers,i,icnt,sc);
1123 dumpstr(dumpchar,data,pdfopers ? "Q\n" : "grestore\n" );
1124 }
1125 }
1126 }
1127
SCSetsColor(SplineChar * sc)1128 static int SCSetsColor(SplineChar *sc) {
1129 int l;
1130 RefChar *r;
1131 ImageList *img;
1132
1133 for ( l=ly_fore ; l<sc->layer_cnt; ++l ) {
1134 if ( sc->layers[l].fill_brush.col != COLOR_INHERITED )
1135 return( true );
1136 if ( sc->layers[l].fill_brush.gradient != NULL || sc->layers[l].fill_brush.pattern != NULL )
1137 return( true );
1138 if ( sc->layers[l].stroke_pen.brush.col != COLOR_INHERITED )
1139 return( true );
1140 if ( sc->layers[l].stroke_pen.brush.gradient != NULL || sc->layers[l].stroke_pen.brush.pattern != NULL )
1141 return( true );
1142 for ( img = sc->layers[l].images; img!=NULL; img=img->next ) {
1143 GImage *image = img->image;
1144 struct _GImage *base = image->list_len==0?image->u.image:image->u.images[0];
1145 if ( base->image_type!=it_mono )
1146 return( true );
1147 if ( !sc->layers[l].dofill )
1148 return( true );
1149 }
1150 for ( r = sc->layers[l].refs; r!=NULL; r = r->next )
1151 if ( SCSetsColor(r->sc) )
1152 return( true );
1153 }
1154 return( false );
1155 }
1156
dumpproc(void (* dumpchar)(int ch,void * data),void * data,SplineChar * sc)1157 static void dumpproc(void (*dumpchar)(int ch,void *data), void *data, SplineChar *sc ) {
1158 DBounds b;
1159
1160 SplineCharFindBounds(sc,&b);
1161 dumpf(dumpchar,data," /%s { ",sc->name);
1162 if ( sc->dependents!=NULL )
1163 dumpstr(dumpchar,data,"dup -1 ne { ");
1164 if ( !SCSetsColor(sc) ) {
1165 dumpf(dumpchar,data,"%d 0 %d %d %d %d setcachedevice",
1166 (int) sc->width, (int) floor(b.minx), (int) floor(b.miny),
1167 (int) ceil(b.maxx), (int) ceil(b.maxy) );
1168 } else {
1169 /* can't cache it if we set colour/grey within */
1170 dumpf(dumpchar,data,"%d 0 setcharwidth",
1171 (int) sc->width );
1172 }
1173 if ( sc->dependents!=NULL )
1174 dumpstr(dumpchar,data," } if\n");
1175 else
1176 dumpstr(dumpchar,data,"\n");
1177 SC_PSDump(dumpchar,data,sc,false,false,ly_all);
1178 dumpstr(dumpchar,data," } bind def\n" );
1179 }
1180
dumpcharprocs(void (* dumpchar)(int ch,void * data),void * data,SplineFont * sf)1181 static int dumpcharprocs(void (*dumpchar)(int ch,void *data), void *data, SplineFont *sf ) {
1182 /* for type 3 fonts */
1183 int cnt, i, notdefpos = -1;
1184
1185 cnt = 0;
1186 notdefpos = SFFindNotdef(sf,-2);
1187 for ( i=0; i<sf->glyphcnt; ++i )
1188 if ( SCWorthOutputting(sf->glyphs[i]) ) {
1189 if ( strcmp(sf->glyphs[i]->name,".notdef")!=0 )
1190 ++cnt;
1191 }
1192 ++cnt; /* one notdef entry */
1193
1194 dumpf(dumpchar,data,"/CharProcs %d dict def\nCharProcs begin\n", cnt );
1195 i = 0;
1196 if ( notdefpos!=-1 )
1197 dumpproc(dumpchar,data,sf->glyphs[notdefpos]);
1198 else {
1199 dumpf(dumpchar, data, " /.notdef { %d 0 0 0 0 0 setcachedevice } bind def\n",
1200 sf->ascent+sf->descent );
1201 if ( sf->glyphs[0]!=NULL && strcmp(sf->glyphs[0]->name,".notdef")==0 )
1202 ++i;
1203 }
1204 for ( ; i<sf->glyphcnt; ++i ) if ( i!=notdefpos ) {
1205 if ( SCWorthOutputting(sf->glyphs[i]) )
1206 dumpproc(dumpchar,data,sf->glyphs[i]);
1207 if ( !ff_progress_next())
1208 return( false );
1209 }
1210 dumpstr(dumpchar,data,"end\ncurrentdict end\n" );
1211 dumpf(dumpchar, data, "/%s exch definefont\n", sf->fontname );
1212 return( true );
1213 }
1214
1215 extern const uint8 *const subrs[10];
1216 extern const int subrslens[10];
initsubrs(MMSet * mm)1217 static struct pschars *initsubrs(MMSet *mm) {
1218 int i;
1219 struct pschars *sub;
1220
1221 sub = calloc(1,sizeof(struct pschars));
1222 sub->cnt = 10;
1223 sub->lens = malloc(10*sizeof(int));
1224 sub->values = malloc(10*sizeof(uint8 *));
1225 for ( i=0; i<5; ++i ) {
1226 ++sub->next;
1227 sub->values[i] = (uint8 *) copyn((const char *) subrs[i],subrslens[i]);
1228 sub->lens[i] = subrslens[i];
1229 }
1230 sub->next = 5;
1231 if ( mm!=NULL ) {
1232 static int cnts[] = { 1,2,3,4,6 };
1233 for ( ; i<10 && cnts[i-5]*mm->instance_count<22; ++i ) {
1234 ++sub->next;
1235 sub->values[i] = (uint8 *) copyn((const char *) subrs[i],subrslens[i]);
1236 sub->values[i][0] += cnts[i-5]*mm->instance_count;
1237 sub->lens[i] = subrslens[i];
1238 }
1239 sub->next = 10;
1240 }
1241 return( sub );
1242 }
1243
1244 extern const char **othersubrs_copyright[];
1245 extern const char **othersubrs[];
1246 extern const char *cid_othersubrs[];
dumpothersubrs(void (* dumpchar)(int ch,void * data),void * data,int incid,int needsflex,int needscounters,MMSet * mm)1247 static void dumpothersubrs(void (*dumpchar)(int ch,void *data), void *data,
1248 int incid, int needsflex, int needscounters, MMSet *mm ) {
1249 int i,j;
1250
1251 dumpstr(dumpchar,data,"/OtherSubrs \n" );
1252 if ( incid ) {
1253 for ( i=0; cid_othersubrs[i]!=NULL; ++i ) {
1254 dumpstr(dumpchar,data,cid_othersubrs[i]);
1255 dumpchar('\n',data);
1256 }
1257 } else {
1258 int max_subr, min_subr;
1259
1260 /* I assume I always want the hint replacement subr, (it's small) */
1261 /* but the flex subrs are large, and if I can omit them, I shall */
1262 if ( needsflex ) {
1263 min_subr = 0;
1264 max_subr = 3;
1265 } else {
1266 min_subr = 3;
1267 max_subr = 3;
1268 }
1269 if ( needscounters )
1270 max_subr = 13;
1271 for ( i=0; othersubrs_copyright[0][i]!=NULL; ++i ) {
1272 dumpstr(dumpchar,data,othersubrs_copyright[0][i]);
1273 dumpchar('\n',data);
1274 }
1275 dumpstr(dumpchar,data,"[ "); /* start array */
1276 for ( j=0; j<min_subr; ++j )
1277 dumpstr(dumpchar,data," {}\n");
1278 for ( ; j<=max_subr; ++j )
1279 for ( i=0; othersubrs[j][i]!=NULL; ++i ) {
1280 dumpstr(dumpchar,data,othersubrs[j][i]);
1281 dumpchar('\n',data);
1282 }
1283 if ( mm!=NULL ) {
1284 /* MM other subrs begin at 14, so skip anything up till then */
1285 for ( ; j<=13; ++j )
1286 dumpstr(dumpchar,data," {}\n");
1287 }
1288 if ( mm!=NULL ) {
1289 /* the code for the multiple master subroutines depends on */
1290 /* the number of font instances, so we can't just blithely copy */
1291 /* an example from Adobe (and they don't provide one anyway) */
1292 dumpf(dumpchar, data, "{ %d 1 roll $Blend } bind\n", mm->instance_count );
1293 if ( 2*mm->instance_count<22 )
1294 dumpf(dumpchar, data, "{ exch %d %d roll $Blend exch %d 2 roll $Blend } bind\n",
1295 2*mm->instance_count, 1-mm->instance_count,
1296 mm->instance_count+1);
1297 if ( 3*mm->instance_count<22 )
1298 dumpf(dumpchar, data, "{ 3 -1 roll %d %d roll $Blend 3 -1 roll %d %d roll $Blend 3 -1 roll %d 2 roll $Blend } bind\n",
1299 3*mm->instance_count, 1-mm->instance_count,
1300 2*mm->instance_count+1, 1-mm->instance_count,
1301 mm->instance_count+2);
1302 if ( 4*mm->instance_count<22 )
1303 dumpf(dumpchar, data, "{ 4 -1 roll %d %d roll $Blend 4 -1 roll %d %d roll $Blend 4 -1 roll %d %d roll $Blend 4 -1 roll %d 3 roll $Blend } bind\n",
1304 4*mm->instance_count, 1-mm->instance_count,
1305 3*mm->instance_count+1, 1-mm->instance_count,
1306 2*mm->instance_count+2, 1-mm->instance_count,
1307 mm->instance_count+3);
1308 if ( 6*mm->instance_count<22 )
1309 dumpf(dumpchar, data, "{ 6 -1 roll %d %d roll $Blend 6 -1 roll %d %d roll $Blend 6 -1 roll %d %d roll $Blend 6 -1 roll %d %d roll $Blend 6 -1 roll %d %d roll $Blend 6 -1 roll %d 5 roll $Blend } bind\n",
1310 6*mm->instance_count, 1-mm->instance_count,
1311 5*mm->instance_count+1, 1-mm->instance_count,
1312 4*mm->instance_count+2, 1-mm->instance_count,
1313 3*mm->instance_count+3, 1-mm->instance_count,
1314 2*mm->instance_count+4, 1-mm->instance_count,
1315 mm->instance_count+5);
1316 }
1317 dumpstr(dumpchar,data,"] "); /* End array */
1318 }
1319 dumpstr(dumpchar,data,incid?"def\n":"ND\n" );
1320 }
1321
dumptospace(void (* dumpchar)(int ch,void * data),void * data,char * str)1322 static char *dumptospace(void (*dumpchar)(int ch,void *data), void *data,
1323 char *str) {
1324
1325 while ( *str!=' ' && *str!=']' && *str!='\0' )
1326 dumpchar(*str++,data);
1327 return( str );
1328 }
1329
dumpmmprivatearr(void (* dumpchar)(int ch,void * data),void * data,char * privates[16],int instance_count)1330 static void dumpmmprivatearr(void (*dumpchar)(int ch,void *data), void *data,
1331 char *privates[16], int instance_count) {
1332 int j;
1333
1334 for ( j=0; j<instance_count; ++j )
1335 while ( *privates[j]==' ' ) ++privates[j];
1336
1337 dumpchar('[',data);
1338 if ( *privates[0]=='[' ) {
1339 /* It's an array */
1340 for ( j=0; j<instance_count; ++j )
1341 ++privates[j];
1342 while ( *privates[0]!=']' && *privates[0]!='\0' ) {
1343 for ( j=0; j<instance_count; ++j )
1344 while ( *privates[j]==' ' ) ++privates[j];
1345 if ( *privates[0]==']' || *privates[0]=='\0' )
1346 break;
1347 dumpchar('[',data);
1348 privates[0] = dumptospace(dumpchar,data,privates[0]);
1349 for ( j=1; j<instance_count; ++j ) {
1350 dumpchar(' ',data);
1351 privates[j] = dumptospace(dumpchar,data,privates[j]);
1352 }
1353 dumpchar(']',data);
1354 }
1355 } else {
1356 /* It's not an array */
1357 dumpstr(dumpchar,data,privates[0]);
1358 for ( j=1; j<instance_count; ++j ) {
1359 dumpchar(' ',data);
1360 dumpstr(dumpchar,data,privates[j]);
1361 }
1362 }
1363 dumpchar(']',data);
1364 }
1365
dumpmmprivate(void (* dumpchar)(int ch,void * data),void * data,MMSet * mm)1366 static void dumpmmprivate(void (*dumpchar)(int ch,void *data), void *data,MMSet *mm) {
1367 char *privates[16];
1368 int j,k, missing, allsame;
1369 struct psdict *private = mm->instances[0]->private;
1370
1371 if ( private==NULL )
1372 return;
1373
1374 dumpstr(dumpchar,data,"3 index /Blend get /Private get begin\n");
1375 for ( k=0; k<private->next; ++k ) {
1376 privates[0] = private->values[k];
1377 missing = false; allsame = true;
1378 for ( j=1; j<mm->instance_count; ++j ) {
1379 privates[j] = PSDictHasEntry(mm->instances[j]->private,private->keys[k]);
1380 if ( privates[j]==NULL ) {
1381 missing = true;
1382 break;
1383 } else if ( strcmp(privates[j],privates[0])!=0 )
1384 allsame = false;
1385 }
1386 if ( missing || allsame )
1387 continue;
1388 dumpf(dumpchar,data," /%s ", private->keys[k]);
1389 dumpmmprivatearr(dumpchar,data,privates,mm->instance_count);
1390 dumpstr(dumpchar,data, " def\n" );
1391 }
1392 dumpstr(dumpchar,data,"end\n");
1393 }
1394
FindMaxDiffOfBlues(char * pt,double max_diff)1395 static double FindMaxDiffOfBlues(char *pt, double max_diff) {
1396 char *end;
1397 double p1, p2;
1398
1399 while ( *pt==' ' || *pt=='[' ) ++pt;
1400 for (;;) {
1401 p1 = strtod(pt,&end);
1402 if ( end==pt )
1403 break;
1404 pt = end;
1405 p2 = strtod(pt,&end);
1406 if ( end==pt )
1407 break;
1408 if ( p2-p1 >max_diff ) max_diff = p2-p1;
1409 pt = end;
1410 }
1411 return( max_diff );
1412 }
1413
BlueScaleFigureForced(struct psdict * private_,real bluevalues[],real otherblues[])1414 double BlueScaleFigureForced(struct psdict *private_,real bluevalues[], real otherblues[]) {
1415 double max_diff=0;
1416 char *pt;
1417 int i;
1418
1419 pt = PSDictHasEntry(private_,"BlueValues");
1420 if ( pt!=NULL ) {
1421 max_diff = FindMaxDiffOfBlues(pt,max_diff);
1422 } else if ( bluevalues!=NULL ) {
1423 for ( i=0; i<14 && (bluevalues[i]!=0 || bluevalues[i+1])!=0; i+=2 ) {
1424 if ( bluevalues[i+1] - bluevalues[i]>=max_diff )
1425 max_diff = bluevalues[i+1] - bluevalues[i];
1426 }
1427 }
1428 pt = PSDictHasEntry(private_,"FamilyBlues");
1429 if ( pt!=NULL )
1430 max_diff = FindMaxDiffOfBlues(pt,max_diff);
1431
1432 pt = PSDictHasEntry(private_,"OtherBlues");
1433 if ( pt!=NULL )
1434 max_diff = FindMaxDiffOfBlues(pt,max_diff);
1435 else if ( otherblues!=NULL ) {
1436 for ( i=0; i<10 && (otherblues[i]!=0 || otherblues[i+1]!=0); i+=2 ) {
1437 if ( otherblues[i+1] - otherblues[i]>=max_diff )
1438 max_diff = otherblues[i+1] - otherblues[i];
1439 }
1440 }
1441 pt = PSDictHasEntry(private_,"FamilyOtherBlues");
1442 if ( pt!=NULL )
1443 max_diff = FindMaxDiffOfBlues(pt,max_diff);
1444 if ( max_diff<=0 )
1445 return( -1 );
1446 if ( 1/max_diff > .039625 )
1447 return( -1 );
1448
1449 return rint(240.0*0.99/max_diff)/240.0;
1450 }
1451
BlueScaleFigure(struct psdict * private_,real bluevalues[],real otherblues[])1452 double BlueScaleFigure(struct psdict *private_,real bluevalues[], real otherblues[]) {
1453 if ( PSDictHasEntry(private_,"BlueScale")!=NULL )
1454 return( -1 );
1455 return BlueScaleFigureForced(private_, bluevalues, otherblues);
1456 }
1457
dumpprivatestuff(void (* dumpchar)(int ch,void * data),void * data,SplineFont * sf,struct fddata * incid,int flags,enum fontformat format,EncMap * map,int layer)1458 static int dumpprivatestuff(void (*dumpchar)(int ch,void *data), void *data,
1459 SplineFont *sf, struct fddata *incid, int flags, enum fontformat format,
1460 EncMap *map, int layer ) {
1461 int cnt, mi;
1462 real bluevalues[14], otherblues[10];
1463 real snapcnt[12];
1464 real stemsnaph[12], stemsnapv[12];
1465 real stdhw[1], stdvw[1];
1466 int flex_max;
1467 int i;
1468 int hasblue=0, hash=0, hasv=0, hasshift/*, hasxuid*/, hasbold, haslg;
1469 int isbold=false;
1470 int iscjk;
1471 struct pschars *subrs = NULL, *chars = NULL;
1472 const char *ND="def";
1473 MMSet *mm = (format==ff_mma || format==ff_mmb)? sf->mm : NULL;
1474 double bluescale;
1475
1476 if ( incid==NULL ) {
1477 flex_max = SplineFontIsFlexible(sf,layer,flags);
1478 if ( (subrs = initsubrs(mm))==NULL )
1479 return( false );
1480 iscjk = SFIsCJK(sf,map);
1481 } else {
1482 flex_max = incid->flexmax;
1483 iscjk = incid->iscjk;
1484 }
1485
1486 hasbold = PSDictHasEntry(sf->private,"ForceBold")!=NULL;
1487 hasblue = PSDictHasEntry(sf->private,"BlueValues")!=NULL;
1488 hash = PSDictHasEntry(sf->private,"StdHW")!=NULL;
1489 hasv = PSDictHasEntry(sf->private,"StdVW")!=NULL;
1490 hasshift = PSDictHasEntry(sf->private,"BlueShift")!=NULL;
1491 /*hasxuid = PSDictHasEntry(sf->private,"XUID")!=NULL;*/
1492 haslg = PSDictHasEntry(sf->private,"LanguageGroup")!=NULL;
1493 if ( sf->weight!=NULL &&
1494 (strstrmatch(sf->weight,"Bold")!=NULL ||
1495 strstrmatch(sf->weight,"Heavy")!=NULL ||
1496 strstrmatch(sf->weight,"Black")!=NULL ||
1497 strstrmatch(sf->weight,"Grass")!=NULL ||
1498 strstrmatch(sf->weight,"Fett")!=NULL))
1499 isbold = true;
1500 if ( sf->pfminfo.pfmset && sf->pfminfo.weight>=700 )
1501 isbold = true;
1502
1503 ff_progress_change_stages(2+2-hasblue);
1504 if ( autohint_before_generate && SFNeedsAutoHint(sf) &&
1505 !(flags&ps_flag_nohints)) {
1506 ff_progress_change_line1(_("Auto Hinting Font..."));
1507 SplineFontAutoHint(sf,layer);
1508 }
1509 if ( !ff_progress_next_stage())
1510 {
1511 PSCharsFree(subrs);
1512 return( false );
1513 }
1514
1515 otherblues[0] = otherblues[1] = bluevalues[0] = bluevalues[1] = 0;
1516 if ( !hasblue ) {
1517 FindBlues(sf,layer,bluevalues,otherblues);
1518 if ( !ff_progress_next_stage())
1519 return( false );
1520 }
1521 bluescale = BlueScaleFigure(sf->private,bluevalues,otherblues);
1522
1523 if ( !hash || !hasv )
1524 stdhw[0] = stdvw[0] = 0;
1525 if ( !hash ) {
1526 FindHStems(sf,stemsnaph,snapcnt);
1527 mi = -1;
1528 for ( i=0; i<12 && stemsnaph[i]!=0; ++i )
1529 if ( mi==-1 ) mi = i;
1530 else if ( snapcnt[i]>snapcnt[mi] ) mi = i;
1531 if ( mi!=-1 ) stdhw[0] = stemsnaph[mi];
1532 }
1533
1534 if ( !hasv ) {
1535 FindVStems(sf,stemsnapv,snapcnt);
1536 mi = -1;
1537 for ( i=0; i<12 && stemsnapv[i]!=0 ; ++i )
1538 if ( mi==-1 ) mi = i;
1539 else if ( snapcnt[i]>snapcnt[mi] ) mi = i;
1540 if ( mi!=-1 ) stdvw[0] = stemsnapv[mi];
1541 }
1542
1543 if ( incid==NULL ) {
1544 ff_progress_next_stage();
1545 ff_progress_change_line1(_("Converting PostScript"));
1546 if ( (chars = SplineFont2ChrsSubrs(sf,iscjk,subrs,flags,format,layer))==NULL )
1547 {
1548 PSCharsFree(subrs);
1549 return( false );
1550 }
1551 ff_progress_next_stage();
1552 ff_progress_change_line1(_("Saving PostScript Font"));
1553 }
1554
1555 if ( incid==NULL ) dumpstr(dumpchar,data,"dup\n");
1556 cnt = 0;
1557 if ( !hasblue ) ++cnt; /* bluevalues is required, but might be in private */
1558 if ( !hasshift && flex_max>=7 ) ++cnt; /* BlueShift needs to be specified if flex wants something bigger than default */
1559 if ( bluescale!=-1 ) ++cnt;
1560 ++cnt; /* minfeature is required */
1561 if ( !hasblue && (otherblues[0]!=0 || otherblues[1]!=0) ) ++cnt;
1562 ++cnt; /* password is required */
1563 if ( sf->tempuniqueid!=0 && sf->use_uniqueid )
1564 ++cnt; /* UniqueID should be in both private and public areas */
1565 if ( incid==NULL ) {
1566 ++cnt; /* nd is required */
1567 ++cnt; /* np is required */
1568 ++cnt; /* rd is required */
1569 }
1570 if ( !haslg && iscjk ) ++cnt;
1571 if ( !hash ) {
1572 if ( stdhw[0]!=0 ) ++cnt;
1573 if ( stemsnaph[0]!=0 ) ++cnt;
1574 }
1575 if ( !hasv ) {
1576 if ( stdvw[0]!=0 ) ++cnt;
1577 if ( stemsnapv[0]!=0 ) ++cnt;
1578 }
1579 cnt += sf->private!=NULL?sf->private->next:0;
1580 if ( incid==NULL ) {
1581 ++cnt; /* Subrs entry */
1582 ++cnt; /* Other Subrs */
1583 } else {
1584 cnt += 3; /* subrmap, etc. */
1585 ++cnt; /* Other Subrs */
1586 }
1587 if ( flex_max>0 ) ++cnt;
1588 if ( hasbold || isbold ) ++cnt;
1589
1590 dumpf(dumpchar,data,"/Private %d dict dup begin\n", cnt );
1591 /* These guys are required and fixed */
1592 if ( incid==NULL ) {
1593 dumpstr(dumpchar,data,"/RD{string currentfile exch readstring pop}executeonly def\n" );
1594 dumpstr(dumpchar,data,"/ND{noaccess def}executeonly def\n" );
1595 dumpstr(dumpchar,data,"/NP{noaccess put}executeonly def\n" );
1596 ND = "ND";
1597 }
1598 dumpf(dumpchar,data,"/MinFeature{16 16}%s\n", ND );
1599 dumpstr(dumpchar,data,"/password 5839 def\n" );
1600 if ( !hasblue ) {
1601 dumpblues(dumpchar,data,"BlueValues",bluevalues,14,ND);
1602 if ( otherblues[0]!=0 || otherblues[1]!=0 )
1603 dumpblues(dumpchar,data,"OtherBlues",otherblues,10,ND);
1604 }
1605 if ( !hash ) {
1606 if ( stdhw[0]!=0 )
1607 dumpf(dumpchar,data,"/StdHW [%g] %s\n", (double) stdhw[0], ND );
1608 if ( stemsnaph[0]!=0 )
1609 dumpdblmaxarray(dumpchar,data,"StemSnapH",stemsnaph,12,"", ND);
1610 }
1611 if ( !hasv ) {
1612 if ( stdvw[0]!=0 )
1613 dumpf(dumpchar,data,"/StdVW [%g] %s\n", (double) stdvw[0],ND );
1614 if ( stemsnapv[0]!=0 )
1615 dumpdblmaxarray(dumpchar,data,"StemSnapV",stemsnapv,12,"", ND);
1616 }
1617 if ( !hasshift && flex_max>=7 )
1618 dumpf(dumpchar,data,"/BlueShift %d def\n", flex_max+1 );
1619 if ( bluescale!=-1 )
1620 dumpf(dumpchar,data,"/BlueScale %g def\n", bluescale );
1621 if ( isbold && !hasbold )
1622 dumpf(dumpchar,data,"/ForceBold true def\n" );
1623 if ( !haslg && iscjk )
1624 dumpf(dumpchar,data,"/LanguageGroup 1 def\n" );
1625 if ( sf->tempuniqueid!=0 && sf->tempuniqueid!=-1 && sf->use_uniqueid )
1626 dumpf(dumpchar,data,"/UniqueID %d def\n", sf->tempuniqueid );
1627 if ( sf->private!=NULL ) {
1628 for ( i=0; i<sf->private->next; ++i ) {
1629 dumpf(dumpchar,data,"/%s ", sf->private->keys[i]);
1630 dumpstr(dumpchar,data,sf->private->values[i]);
1631 if ( strcmp(sf->private->keys[i],"BlueValues")==0 ||
1632 strcmp(sf->private->keys[i],"OtherBlues")==0 ||
1633 strcmp(sf->private->keys[i],"StdHW")==0 ||
1634 strcmp(sf->private->keys[i],"StdVW")==0 ||
1635 strcmp(sf->private->keys[i],"StemSnapH")==0 ||
1636 strcmp(sf->private->keys[i],"StemSnapV")==0 )
1637 dumpf(dumpchar,data," %s\n", ND);
1638 else
1639 dumpstr(dumpchar,data," def\n");
1640 }
1641 }
1642
1643 if ( mm!=NULL )
1644 dumpmmprivate(dumpchar,data,mm);
1645
1646 dumpothersubrs(dumpchar,data,incid!=NULL,flex_max>0,iscjk,mm);
1647 if ( incid!=NULL ) {
1648 dumpf(dumpchar,data," /SubrMapOffset %d def\n", incid->subrmapoff );
1649 dumpf(dumpchar,data," /SDBytes %d def\n", incid->sdbytes );
1650 dumpf(dumpchar,data," /SubrCount %d def\n", incid->subrcnt );
1651 dumpstr(dumpchar,data,"end def\n");
1652 } else {
1653 dumpsubrs(dumpchar,data,sf,subrs);
1654 dumpcharstrings(dumpchar,data,sf, chars );
1655 dumpstr(dumpchar,data,"put\n");
1656
1657 PSCharsFree(chars);
1658 PSCharsFree(subrs);
1659 }
1660
1661 ff_progress_change_stages(1);
1662 return( true );
1663 }
1664
dumpfontinfo(void (* dumpchar)(int ch,void * data),void * data,SplineFont * sf,enum fontformat format)1665 static void dumpfontinfo(void (*dumpchar)(int ch,void *data), void *data, SplineFont *sf,
1666 enum fontformat format) {
1667 int cnt;
1668
1669 cnt = 0;
1670 if ( sf->familyname!=NULL ) ++cnt;
1671 if ( sf->fullname!=NULL ) ++cnt;
1672 if ( sf->copyright!=NULL ) ++cnt;
1673 if ( sf->weight!=NULL ) ++cnt;
1674 if ( sf->pfminfo.fstype!=-1 ) ++cnt;
1675 if ( sf->subfontcnt==0 ) {
1676 if ( sf->version!=NULL ) ++cnt;
1677 ++cnt; /* ItalicAngle */
1678 ++cnt; /* isfixedpitch */
1679 if ( sf->upos!=0 ) ++cnt;
1680 if ( sf->uwidth!=0 ) ++cnt;
1681 /* Fontographer also generates em, ascent and descent */
1682 /* em is redundant, we can get that from the fontmatrix */
1683 /* given em we only need one of ascent or descent */
1684 /* On the off chance that fontlab objects to them let's not generate them */
1685 if ( sf->ascent != 8*(sf->ascent+sf->descent)/10 )
1686 ++cnt; /* ascent */
1687 }
1688 if ( format==ff_mma || format==ff_mmb )
1689 cnt += 3;
1690
1691 dumpf(dumpchar,data,"/FontInfo %d dict dup begin\n", cnt );
1692 if ( sf->subfontcnt==0 && sf->version )
1693 dumpf(dumpchar,data," /version (%s) readonly def\n", sf->version );
1694 if ( sf->copyright ) {
1695 dumpf(dumpchar,data," /Notice (");
1696 dumpcarefully(dumpchar,data,sf->copyright);
1697 dumpf(dumpchar,data,") readonly def\n" );
1698 if ( strchr(sf->copyright,'\n')!=NULL || strchr(sf->copyright,'\r')!=NULL )
1699 dumpascomments(dumpchar,data,sf->copyright);
1700 }
1701 if ( sf->fullname ) {
1702 dumpf(dumpchar,data," /FullName (" );
1703 dumpcarefully(dumpchar,data,sf->fullname);
1704 dumpf(dumpchar,data,") readonly def\n" );
1705 }
1706 if ( sf->familyname ) {
1707 dumpf(dumpchar,data," /FamilyName (" );
1708 dumpcarefully(dumpchar,data,sf->familyname);
1709 dumpf(dumpchar,data,") readonly def\n" );
1710 }
1711 if ( sf->weight )
1712 dumpf(dumpchar,data," /Weight (%s) readonly def\n", sf->weight );
1713 if ( sf->pfminfo.fstype!=-1 )
1714 dumpf(dumpchar,data," /FSType %d def\n", sf->pfminfo.fstype );
1715 if ( sf->subfontcnt==0 ) {
1716 dumpf(dumpchar,data," /ItalicAngle %g def\n", (double) sf->italicangle );
1717 dumpf(dumpchar,data," /isFixedPitch %s def\n", SFOneWidth(sf)!=-1?"true":"false" );
1718 if ( format==ff_type42 || format==ff_type42cid ) {
1719 if ( sf->upos )
1720 dumpf(dumpchar,data," /UnderlinePosition %g def\n", (double) (sf->upos/(sf->ascent+sf->descent)) );
1721 if ( sf->uwidth )
1722 dumpf(dumpchar,data," /UnderlineThickness %g def\n", (double) (sf->uwidth/(sf->ascent+sf->descent)) );
1723 } else {
1724 if ( sf->upos )
1725 dumpf(dumpchar,data," /UnderlinePosition %g def\n", (double) sf->upos );
1726 if ( sf->uwidth )
1727 dumpf(dumpchar,data," /UnderlineThickness %g def\n", (double) sf->uwidth );
1728 }
1729 if ( sf->ascent != 8*(sf->ascent+sf->descent)/10 )
1730 dumpf(dumpchar,data," /ascent %d def\n", sf->ascent );
1731 }
1732 if ( format==ff_mma || format==ff_mmb ) {
1733 MMSet *mm = sf->mm;
1734 int j,k;
1735
1736 dumpstr(dumpchar,data," /BlendDesignPositions [" );
1737 for ( j=0; j<mm->instance_count; ++j ) {
1738 dumpstr(dumpchar,data," [" );
1739 for ( k=0; k<mm->axis_count; ++k )
1740 dumpf(dumpchar,data,"%g ", (double) mm->positions[j*mm->axis_count+k]);
1741 dumpstr(dumpchar,data,"]" );
1742 }
1743 dumpstr(dumpchar,data," ] def\n" );
1744
1745 dumpstr(dumpchar,data," /BlendDesignMap [" );
1746 for ( k=0; k<mm->axis_count; ++k ) {
1747 dumpstr(dumpchar,data," [" );
1748 for ( j=0; j<mm->axismaps[k].points; ++j )
1749 dumpf(dumpchar,data,"[%g %g] ",
1750 (double) mm->axismaps[k].designs[j], (double) mm->axismaps[k].blends[j]);
1751 dumpstr(dumpchar,data,"]" );
1752 }
1753 dumpstr(dumpchar,data," ] def\n" );
1754
1755 dumpstr(dumpchar,data," /BlendAxisTypes [" );
1756 for ( k=0; k<mm->axis_count; ++k )
1757 dumpf(dumpchar,data,"/%s ", mm->axes[k]);
1758 dumpstr(dumpchar,data," ] def\n" );
1759 }
1760 dumpstr(dumpchar,data,"end readonly def\n");
1761 }
1762
dumpfontcomments(void (* dumpchar)(int ch,void * data),void * data,SplineFont * sf,int format)1763 static void dumpfontcomments(void (*dumpchar)(int ch,void *data), void *data,
1764 SplineFont *sf, int format ) {
1765 time_t now;
1766 const char *author = GetAuthor();
1767
1768 now = GetTime();
1769 /* Werner points out that the DSC Version comment has a very specific */
1770 /* syntax. We can't just put in a random string, must be <real> <int> */
1771 /* So we can sort of do that for CID fonts (give it a <revsion> of 0 */
1772 /* but for type1s just use a comment rather than a DSC statement */
1773 if (( format==ff_cid || format==ff_cffcid || format==ff_type42cid ) &&
1774 sf->cidregistry!=NULL ) {
1775 dumpf(dumpchar,data, "%%%%Title: (%s %s %s %d)\n",
1776 sf->fontname, sf->cidregistry, sf->ordering, sf->supplement );
1777 dumpf(dumpchar,data, "%%%%Version: %g 0\n", (double)sf->cidversion );
1778 /* CID keyed fonts are language level 3 */
1779 } else {
1780 dumpf(dumpchar,data,"%%%%Title: %s\n", sf->fontname);
1781 dumpf(dumpchar,data,"%%Version: %s\n", sf->version);
1782 }
1783 dumpf(dumpchar,data,"%%%%CreationDate: %s", ctime(&now));
1784 if ( author!=NULL )
1785 dumpf(dumpchar,data,"%%%%Creator: %s\n", author);
1786
1787 if ( format==ff_cid || format==ff_cffcid || format==ff_type42cid ||
1788 format==ff_cff || format==ff_type42 )
1789 dumpf(dumpchar,data, "%%%%LanguageLevel: 3\n" );
1790 else if ( sf->multilayer && format==ff_ptype3 ) {
1791 int gid, ly;
1792 SplineChar *sc;
1793 int had_pat=0, had_grad=0;
1794 for ( gid=0; gid<sf->glyphcnt; ++gid ) if ( (sc=sf->glyphs[gid])!=NULL ) {
1795 for ( ly=ly_fore; ly<sc->layer_cnt; ++ly ) {
1796 if ( sc->layers[ly].fill_brush.gradient!=NULL || sc->layers[ly].stroke_pen.brush.gradient!=NULL ) {
1797 had_grad = true;
1798 break;
1799 }
1800 if ( sc->layers[ly].fill_brush.gradient!=NULL || sc->layers[ly].stroke_pen.brush.gradient!=NULL )
1801 had_pat = true;
1802 }
1803 }
1804 if ( had_grad )
1805 dumpf(dumpchar,data, "%%%%LanguageLevel: 3\n" );
1806 else if ( had_pat )
1807 dumpf(dumpchar,data, "%%%%LanguageLevel: 2\n" );
1808 }
1809
1810 if ( sf->copyright!=NULL ) {
1811 char *pt, *strt=sf->copyright, *npt;
1812 while ( *strt!='\0' ) {
1813 pt = strt;
1814 while ( pt<strt+60 && *pt ) {
1815 npt = strpbrk(pt,"\n\t\r ");
1816 if ( npt==NULL ) npt = strt+strlen(strt);
1817 if ( npt<strt+60 || pt==strt ) {
1818 pt = npt;
1819 if ( isspace(*pt)) {
1820 ++pt;
1821 if ( pt[-1]=='\n' || pt[-1]=='\r' )
1822 break;
1823 }
1824 } else
1825 break;
1826 }
1827 dumpstr(dumpchar,data,strt==sf->copyright ? "%Copyright: ": "%Copyright: ");
1828 dumpstrn(dumpchar,data,strt,*pt?pt-strt-1:pt-strt);
1829 dumpchar('\n',data);
1830 strt = pt;
1831 }
1832 }
1833 if ( sf->comments!=NULL )
1834 dumpascomments(dumpchar,data,sf->comments);
1835 dumpf(dumpchar,data,"%% Generated by FontForge %s (http://fontforge.sf.net/)\n", FONTFORGE_VERSION);
1836 dumpstr(dumpchar,data,"%%EndComments\n\n");
1837 }
1838
1839 extern const char *mmfindfont[], *makeblendedfont[];
dumprequiredfontinfo(void (* dumpchar)(int ch,void * data),void * data,SplineFont * sf,int format,EncMap * map,SplineFont * fullsf,int layer)1840 static void dumprequiredfontinfo(void (*dumpchar)(int ch,void *data), void *data,
1841 SplineFont *sf, int format, EncMap *map, SplineFont *fullsf, int layer ) {
1842 int cnt, i;
1843 double fm[6];
1844 const char (*encoding[256]);
1845 DBounds b;
1846 int uniqueid;
1847 char buffer[50];
1848
1849 dumpf(dumpchar,data,"%%!PS-AdobeFont-1.0: %s %s\n", sf->fontname, sf->version?sf->version:"" );
1850 if ( format==ff_ptype0 && (map->enc->is_unicodebmp || map->enc->is_unicodefull))
1851 dumpf(dumpchar,data,"%%%%DocumentNeededResources: font ZapfDingbats\n" );
1852 /* dumpf(dumpchar,data, "%%%%DocumentSuppliedResources: font %s\n", sf->fontname );*/
1853 /* Werner says the above is not appropriate */
1854 dumpfontcomments(dumpchar,data,sf,format);
1855
1856 cnt = 0;
1857 ++cnt; /* FID, added by definefont and not by us */
1858 ++cnt; /* fonttype */
1859 ++cnt; /* fontmatrix */
1860 if ( sf->fontname!=NULL ) ++cnt;
1861 ++cnt; /* fontinfo */
1862 ++cnt; /* encoding */
1863 ++cnt; /* fontbb */
1864 if ( sf->uniqueid!=-1 && sf->use_uniqueid ) ++cnt;
1865 ++cnt; /* painttype */
1866 if ( sf->strokedfont )
1867 ++cnt; /* StrokeWidth */
1868 if ( format==ff_ptype3 ) {
1869 ++cnt; /* charprocs */
1870 ++cnt; /* buildglyph */
1871 ++cnt; /* buildchar */
1872 } else {
1873 ++cnt; /* private */
1874 ++cnt; /* chars */
1875 }
1876 if ( sf->xuid!=NULL && sf->use_xuid ) ++cnt;
1877 if ( format==ff_mma || format==ff_mmb )
1878 cnt += 7;
1879
1880 if ( sf->uniqueid==0 )
1881 uniqueid = 4000000 + (rand()&0x3ffff);
1882 else
1883 uniqueid = sf->uniqueid ;
1884 sf->tempuniqueid = uniqueid;
1885
1886 if ( format!=ff_ptype3 && uniqueid!=-1 && sf->use_uniqueid ) {
1887 dumpf(dumpchar,data,"FontDirectory/%s known{/%s findfont dup/UniqueID known{dup\n", sf->fontname, sf->fontname);
1888 dumpf(dumpchar,data,"/UniqueID get %d eq exch/FontType get 1 eq and}{pop false}ifelse\n", uniqueid );
1889 dumpf(dumpchar,data,"{save true}{false}ifelse}{false}ifelse\n" );
1890 }
1891
1892 dumpf(dumpchar,data,"%d dict begin\n", cnt );
1893 dumpf(dumpchar,data,"/FontType %d def\n", format==ff_ptype3?3:1 );
1894 fm[0] = fm[3] = 1.0/((sf->ascent+sf->descent));
1895 fm[1] = fm[2] = fm[4] = fm[5] = 0;
1896 dumpdblarray(dumpchar,data,"FontMatrix",fm,6,"readonly ",false);
1897 if ( sf->fontname!=NULL )
1898 dumpf(dumpchar,data,"/FontName /%s def\n", sf->fontname );
1899 SplineFontLayerFindBounds(fullsf==NULL?sf:fullsf,layer,&b);
1900 fm[0] = floor( b.minx);
1901 fm[1] = floor( b.miny);
1902 fm[2] = ceil( b.maxx);
1903 fm[3] = ceil( b.maxy);
1904 dumpdblarray(dumpchar,data,"FontBBox",fm,4,"readonly ", true);
1905 if ( uniqueid!=-1 && sf->use_uniqueid )
1906 dumpf(dumpchar,data,"/UniqueID %d def\n", uniqueid );
1907 if ( sf->xuid!=NULL && sf->use_xuid ) {
1908 dumpf(dumpchar,data,"/XUID %s def\n", sf->xuid );
1909 if ( sf->changed_since_xuidchanged )
1910 SFIncrementXUID(sf);
1911 }
1912 dumpf(dumpchar,data,"/PaintType %d def\n", sf->strokedfont?2:0 );
1913 if ( sf->strokedfont )
1914 dumpf(dumpchar,data,"/StrokeWidth %g def\n", (double) sf->strokewidth );
1915 dumpfontinfo(dumpchar,data,sf,format);
1916 if ( format==ff_mma || format==ff_mmb ) {
1917 MMSet *mm = sf->mm;
1918 int j,k;
1919 DBounds mb[16];
1920
1921 dumpstr(dumpchar,data," /WeightVector [" );
1922 for ( j=0; j<mm->instance_count; ++j ) {
1923 dumpf(dumpchar,data,"%g ", (double) mm->defweights[j]);
1924 }
1925 dumpstr(dumpchar,data," ] def\n" );
1926
1927 dumpstr(dumpchar,data," /$Blend {" );
1928 if ( mm->instance_count==2 )
1929 dumpf(dumpchar,data,"%g mul add", (double) mm->defweights[1]);
1930 else {
1931 dumpf(dumpchar,data,"%g mul exch", (double) mm->defweights[1]);
1932 for ( j=2; j<mm->instance_count-1; ++j )
1933 dumpf(dumpchar,data,"%g mul add exch", (double) mm->defweights[j]);
1934 dumpf(dumpchar,data,"%g mul add add", (double) mm->defweights[j]);
1935 }
1936 dumpstr(dumpchar,data," } bind def\n" );
1937
1938 dumpstr(dumpchar,data," /Blend 3 dict dup begin\n" );
1939 for ( j=0; j<mm->instance_count; ++j )
1940 SplineFontLayerFindBounds(mm->instances[j],layer,&mb[j]);
1941 dumpstr(dumpchar,data," /FontBBox{" );
1942 for ( k=0; k<4; ++k ) {
1943 dumpstr(dumpchar,data,"{" );
1944 for ( j=0; j<mm->instance_count; ++j )
1945 dumpf(dumpchar,data,"%g ", k==0 ? floor(mb[j].minx) :
1946 k==1 ? floor(mb[j].miny) :
1947 k==2 ? ceil(mb[j].maxx) :
1948 ceil(mb[j].maxy));
1949 dumpstr(dumpchar,data,"}" );
1950 }
1951 dumpstr(dumpchar,data,"} def\n" );
1952
1953 dumpf(dumpchar,data," /Private %d dict def\n", sf->private->next+10 );
1954 dumpstr(dumpchar,data," end def %End of Blend dict\n" );
1955
1956 for ( j=0; makeblendedfont[j]!=NULL; ++j ) {
1957 dumpstr(dumpchar,data,makeblendedfont[j]);
1958 (dumpchar)('\n',data);
1959 }
1960
1961 dumpstr(dumpchar,data,"\n /NormalizeDesignVector\n" );
1962 dumpstr(dumpchar,data, mm->ndv );
1963 dumpstr(dumpchar,data," bind def\n" );
1964
1965 dumpstr(dumpchar,data," /ConvertDesignVector\n" );
1966 dumpstr(dumpchar,data, mm->cdv );
1967 dumpstr(dumpchar,data," bind def\n\n" );
1968
1969 for ( j=0; mmfindfont[j]!=NULL; ++j ) {
1970 dumpstr(dumpchar,data,mmfindfont[j]);
1971 (dumpchar)('\n',data);
1972 }
1973 }
1974
1975 for ( i=0; i<256 && i<map->enccount; ++i )
1976 if ( map->map[i]!=-1 && SCWorthOutputting(sf->glyphs[map->map[i]]) )
1977 encoding[i] = sf->glyphs[map->map[i]]->name;
1978 else
1979 encoding[i] = ".notdef";
1980 for ( ; i<256; ++i )
1981 encoding[i] = ".notdef";
1982 if ( isStdEncoding(encoding) )
1983 dumpstr(dumpchar,data,"/Encoding StandardEncoding def\n");
1984 else {
1985 dumpstr(dumpchar,data,"/Encoding 256 array\n" );
1986 /* older versions of dvipdfm assume the following line is present.*/
1987 /* Perhaps others do too? */
1988 dumpstr(dumpchar,data," 0 1 255 { 1 index exch /.notdef put} for\n" );
1989 for ( i=0; i<256; ++i )
1990 if ( strcmp(encoding[i],".notdef")!=0 )
1991 dumpf(dumpchar,data,"dup %d/%s put\n", i, encoding[i] );
1992 dumpstr(dumpchar,data,"readonly def\n" );
1993 }
1994 if ( format==ff_ptype3 ) {
1995 dumpstr(dumpchar,data,"/BuildChar { 1 index /Encoding get exch get 1 index /BuildGlyph get exec } bind def\n" );
1996 dumpstr(dumpchar,data,"% I call all my CharProcs with two arguments, the top of the stack will be\n" );
1997 dumpstr(dumpchar,data,"% 0 and then next thing is the fontdict. If the tos is zero the char will\n" );
1998 dumpstr(dumpchar,data,"% do a setcachedevice, otherwise (for referenced chars) it will not. The\n" );
1999 dumpstr(dumpchar,data,"% fontdict argument is so a char can invoke a referenced char. BuildGlyph\n" );
2000 dumpstr(dumpchar,data,"% itself will remove the arguments from the stack, the CharProc will leave 'em\n" );
2001 if ( sf->multilayer )
2002 *buffer = '\0';
2003 else if ( sf->strokedfont )
2004 sprintf( buffer, "%g setlinewidth stroke", (double) sf->strokewidth );
2005 else
2006 strcpy(buffer, "fill");
2007 dumpf(dumpchar,data,"/BuildGlyph { 2 copy exch /CharProcs get exch 2 copy known not { pop /.notdef} if get exch pop 0 exch exec pop pop %s} bind def\n",
2008 buffer );
2009 }
2010 }
2011
dumpinitialascii(void (* dumpchar)(int ch,void * data),void * data,SplineFont * sf,int format,EncMap * map,SplineFont * fullsf,int layer)2012 static void dumpinitialascii(void (*dumpchar)(int ch,void *data), void *data,
2013 SplineFont *sf, int format, EncMap *map, SplineFont *fullsf, int layer ) {
2014 dumprequiredfontinfo(dumpchar,data,sf,format,map,fullsf,layer);
2015 dumpstr(dumpchar,data,"currentdict end\ncurrentfile eexec\n" );
2016 }
2017
dumpencodedstuff(void (* dumpchar)(int ch,void * data),void * data,SplineFont * sf,int format,int flags,EncMap * map,int layer)2018 static void dumpencodedstuff(void (*dumpchar)(int ch,void *data), void *data,
2019 SplineFont *sf, int format, int flags, EncMap *map, int layer ) {
2020 struct fileencryptdata fed;
2021 void (*func)(int ch,void *data);
2022
2023 func = startfileencoding(dumpchar,data,&fed,format==ff_pfb || format==ff_mmb);
2024 dumpprivatestuff(func,&fed,sf,NULL,flags,format,map,layer);
2025 if ( format==ff_ptype0 ) {
2026 dumpstr(func,&fed, "/" );
2027 dumpstr(func,&fed, sf->fontname );
2028 dumpstr(func,&fed,"Base exch definefont pop\n mark currentfile closefile\n" );
2029 } else
2030 dumpstr(func,&fed,"dup/FontName get exch definefont pop\n mark currentfile closefile\n" );
2031 }
2032
dumpfinalascii(void (* dumpchar)(int ch,void * data),void * data,SplineFont * sf,int format)2033 static void dumpfinalascii(void (*dumpchar)(int ch,void *data), void *data,
2034 SplineFont *sf, int format) {
2035 int i;
2036 int uniqueid = sf->uniqueid ;
2037
2038 /* output 512 zeros */
2039 dumpchar('\n',data);
2040 for ( i = 0; i<8; ++i )
2041 dumpstr(dumpchar,data,"0000000000000000000000000000000000000000000000000000000000000000\n");
2042 dumpstr(dumpchar,data,"cleartomark\n");
2043 if ( format!=ff_ptype3 && uniqueid!=-1 && sf->use_uniqueid )
2044 dumpstr(dumpchar,data,"{restore}if\n");
2045 }
2046
mkheadercopyfile(FILE * temp,FILE * out,int headertype)2047 static void mkheadercopyfile(FILE *temp,FILE *out,int headertype) {
2048 char buffer[8*1024];
2049 int len;
2050
2051 /* output the file header */
2052 putc('\200',out);
2053 putc(headertype,out);
2054 len = ftell(temp); /* output byte count */
2055 putc(len&0xff,out);
2056 putc(((len>>8)&0xff),out);
2057 putc(((len>>16)&0xff),out);
2058 putc(((len>>24)&0xff),out);
2059
2060 fseek(temp,0,SEEK_SET);
2061 while ((len=fread(buffer,sizeof(char),sizeof(buffer),temp))>0 )
2062 fwrite(buffer,sizeof(char),len,out);
2063 fclose(temp); /* deletes the temporary file */
2064 }
2065
dumptype42(FILE * out,SplineFont * sf,int format,int flags,EncMap * map,int layer)2066 static void dumptype42(FILE *out, SplineFont *sf, int format, int flags,
2067 EncMap *map,int layer) {
2068 double fm[6];
2069 DBounds b;
2070 int uniqueid;
2071 int i,cnt,gid,hasnotdef;
2072 SplineFont *cidmaster;
2073
2074 cidmaster = sf->cidmaster;
2075 if ( sf->subfontcnt!=0 ) {
2076 cidmaster = sf;
2077 sf = sf->subfonts[0];
2078 }
2079 if ( format==ff_type42 )
2080 cidmaster = NULL;
2081
2082 if ( format == ff_type42cid ) {
2083 fprintf( out, "%%!PS-Adobe-3.0 Resource-CIDFont\n" );
2084 fprintf( out, "%%%%DocumentNeededResources: ProcSet (CIDInit)\n" );
2085 fprintf( out, "%%%%IncludeResource: ProcSet (CIDInit)\n" );
2086 fprintf( out, "%%%%BeginResource: CIDFont %s\n", (cidmaster!=NULL?cidmaster:sf)->fontname );
2087 } else
2088 fprintf( out, "%%!PS-TrueTypeFont\n" ); /* Ignore the ttf version info */
2089 /* Too hard to do right, and if done right doesn't mean much to */
2090 /* a human observer */
2091 dumpfontcomments((DumpChar)fputc,out,cidmaster!=NULL?cidmaster:sf,format);
2092
2093 if ( format == ff_type42cid ) {
2094 fprintf( out, "/CIDInit /ProcSet findresource begin\n\n" );
2095 fprintf( out, "16 dict begin\n" );
2096 } else
2097 fprintf( out, "12 dict begin\n" );
2098 fprintf( out, " /FontName /%s def\n", sf->fontname );
2099 if ( format==ff_type42cid ) {
2100 fprintf( out, " /CIDFontType 2 def\n" );
2101 /* Adobe Technical Note 5012.Type42_Spec.pdf Sec 5 CIDFontType 2 CID Fonts */
2102 /* page 12 says that the FontType (not CIDFontType) of a TrueType CID font */
2103 /* should be 42. The PLRM (v3) Chap 5 page 370 says the FontType should */
2104 /* 11. Ain't that just grand? */
2105 fprintf( out, " /FontType 11 def\n" );
2106 fprintf( out, " /CIDFontName /%s def\n", sf->fontname );
2107 /* 5012 doesn't mention this, but we probably need these... */
2108 fprintf( out, " /CIDSystemInfo 3 dict dup begin\n" );
2109 if ( cidmaster!=NULL ) {
2110 fprintf( out, " /Registry (%s) def\n", cidmaster->cidregistry );
2111 fprintf( out, " /Ordering (%s) def\n", cidmaster->ordering );
2112 fprintf( out, " /Supplement %d def\n", cidmaster->supplement );
2113 } else {
2114 fprintf( out, " /Registry (Adobe) def\n" );
2115 fprintf( out, " /Ordering (Identity) def\n" );
2116 fprintf( out, " /Supplement 0 def\n" );
2117 }
2118 fprintf( out, " end def\n\n" );
2119 } else
2120 fprintf( out, " /FontType 42 def\n" );
2121 fprintf( out, " /FontMatrix [1 0 0 1 0 0] def\n" );
2122 fprintf( out, " /PaintType 0 def\n" );
2123 SplineFontLayerFindBounds(sf,layer,&b);
2124 /* The Type42 spec says that the bounding box should be scaled by the */
2125 /* 1/emsize (to be numbers near 1.0). The example in the spec does not do */
2126 /* this and gives numbers you'd expect to see in a type1 font */
2127 fm[0] = b.minx / (sf->ascent+sf->descent);
2128 fm[1] = b.miny / (sf->ascent+sf->descent);
2129 fm[2] = b.maxx / (sf->ascent+sf->descent);
2130 fm[3] = b.maxy / (sf->ascent+sf->descent);
2131 fprintf( out, " ");
2132 dumpdblarray((DumpChar) fputc,out,"FontBBox",fm,4,"readonly ", true);
2133 dumpfontinfo((DumpChar) fputc,out,sf,format);
2134
2135 if ( sf->uniqueid==0 )
2136 uniqueid = 4000000 + (rand()&0x3ffff);
2137 else
2138 uniqueid = sf->uniqueid ;
2139 sf->tempuniqueid = uniqueid;
2140 if ( uniqueid!=-1 && sf->use_uniqueid )
2141 fprintf( out, " /UniqueID %d def\n", uniqueid );
2142 if ( sf->xuid!=NULL && sf->use_xuid ) {
2143 fprintf(out," /XUID %s def\n", sf->xuid );
2144 if ( sf->changed_since_xuidchanged )
2145 SFIncrementXUID(sf);
2146 }
2147 if ( format==ff_type42 ) {
2148 fprintf(out," /Encoding 256 array\n" );
2149 /* older versions of dvipdfm assume the following line is present.*/
2150 /* Perhaps others do too? */
2151 fprintf(out," 0 1 255 { 1 index exch /.notdef put} for\n" );
2152 for ( i=0; i<256 && i<map->enccount; ++i ) if ( (gid = map->map[i])!=-1 )
2153 if ( SCWorthOutputting(sf->glyphs[gid]) )
2154 fprintf( out, " dup %d/%s put\n", i, sf->glyphs[gid]->name);
2155 fprintf( out, " readonly def\n" );
2156 }
2157 fprintf( out, " /sfnts [\n" );
2158 _WriteType42SFNTS(out,sf,format,flags,map,layer);
2159 fprintf( out, " ] def\n" );
2160 if ( format==ff_type42 ) {
2161 hasnotdef = false;
2162 for ( i=cnt=0; i<sf->glyphcnt; ++i ) {
2163 if ( sf->glyphs[i]!=NULL && SCWorthOutputting(sf->glyphs[i])) {
2164 ++cnt;
2165 if ( strcmp(sf->glyphs[i]->name,".notdef")==0 )
2166 hasnotdef = true;
2167 }
2168 }
2169 fprintf( out, " /CharStrings %d dict dup begin\n", cnt+1 );
2170 /* Why check to see if there's a notdef char in the font? If there is */
2171 /* we can define the dictionary entry twice */
2172 /* We can, yes, but FreeType gets confused if we do. So let's check */
2173 if ( !hasnotdef )
2174 fprintf( out, " /.notdef 0 def\n" );
2175 for ( i=0; i<sf->glyphcnt; ++i )
2176 if ( sf->glyphs[i]!=NULL && SCWorthOutputting(sf->glyphs[i]))
2177 fprintf( out, " /%s %d def\n", sf->glyphs[i]->name, sf->glyphs[i]->ttf_glyph );
2178 fprintf( out, " end readonly def\n" );
2179 fprintf( out, "FontName currentdict end definefont pop\n" );
2180 } else {
2181 if ( cidmaster!=NULL ) {
2182 for ( i=cnt=0; i<sf->glyphcnt; ++i )
2183 if ( sf->glyphs[i]!=NULL && SCWorthOutputting(sf->glyphs[i]))
2184 ++cnt;
2185 fprintf( out, " /CIDMap %d dict dup begin\n", cnt );
2186 for ( i=0; i<sf->glyphcnt; ++i )
2187 if ( sf->glyphs[i]!=NULL && SCWorthOutputting(sf->glyphs[i]))
2188 fprintf( out, " %d %d def\n", i, sf->glyphs[i]->ttf_glyph );
2189 fprintf( out, " end readonly def\n" );
2190 fprintf( out, " /CIDCount %d def\n", sf->glyphcnt );
2191 fprintf( out, " /GDBytes %d def\n", sf->glyphcnt>65535?3:2 );
2192 } else if ( flags & ps_flag_identitycidmap ) {
2193 for ( i=cnt=0; i<sf->glyphcnt; ++i )
2194 if ( sf->glyphs[i]!=NULL && cnt<sf->glyphs[i]->ttf_glyph )
2195 cnt = sf->glyphs[i]->ttf_glyph;
2196 fprintf( out, " /CIDCount %d def\n", cnt+1 );
2197 fprintf( out, " /GDBytes %d def\n", cnt+1>65535?3:2 );
2198 fprintf( out, " /CIDMap 0 def\n" );
2199 } else { /* Use unicode */
2200 int maxu = 0;
2201 for ( i=cnt=0; i<sf->glyphcnt; ++i )
2202 if ( sf->glyphs[i]!=NULL && SCWorthOutputting(sf->glyphs[i]) &&
2203 sf->glyphs[i]->unicodeenc!=-1 && sf->glyphs[i]->unicodeenc<0x10000 ) {
2204 ++cnt;
2205 if ( sf->glyphs[i]->unicodeenc > maxu )
2206 maxu = sf->glyphs[i]->unicodeenc;
2207 }
2208 fprintf( out, " /CIDMap %d dict dup begin\n", cnt );
2209 fprintf( out, " 0 0 def\n" ); /* .notdef doesn't have a unicode enc, will be missed. Needed */
2210 if ( map->enc->is_unicodebmp || map->enc->is_unicodefull ) {
2211 for ( i=0; i<map->enccount && i<0x10000; ++i ) if ( (gid = map->map[i])!=-1 ) {
2212 if ( SCWorthOutputting(sf->glyphs[gid]))
2213 fprintf( out, " %d %d def\n", i, sf->glyphs[gid]->ttf_glyph );
2214 }
2215 } else {
2216 for ( i=0; i<sf->glyphcnt; ++i )
2217 if ( sf->glyphs[i]!=NULL && SCWorthOutputting(sf->glyphs[i]) &&
2218 sf->glyphs[i]->unicodeenc!=-1 && sf->glyphs[i]->unicodeenc<0x10000 )
2219 fprintf( out, " %d %d def\n", sf->glyphs[i]->unicodeenc, sf->glyphs[i]->ttf_glyph );
2220 }
2221 fprintf( out, " end readonly def\n" );
2222 fprintf( out, " /GDBytes %d def\n", maxu>65535?3:2 );
2223 fprintf( out, " /CIDCount %d def\n", maxu+1 );
2224 }
2225 fprintf( out, "currentdict end dup /CIDFontName get exch /CIDFont defineresource pop\nend\n" );
2226 fprintf( out, "%%%%EndResource\n" );
2227 fprintf( out, "%%%%EOF\n" );
2228 }
2229 }
2230
dumpfontdict(FILE * out,SplineFont * sf,int format,int flags,EncMap * map,SplineFont * fullsf,int layer)2231 static void dumpfontdict(FILE *out, SplineFont *sf, int format, int flags,
2232 EncMap *map, SplineFont *fullsf, int layer ) {
2233
2234 /* a pfb header consists of 6 bytes, the first is 0200, the second is a */
2235 /* binary/ascii flag where 1=>ascii, 2=>binary, 3=>eof??, the next four */
2236 /* are a count of bytes between this header and the next one. First byte */
2237 /* is least significant */
2238 if ( format==ff_pfb || format==ff_mmb ) {
2239 FILE *temp;
2240 temp = GFileTmpfile();
2241 dumpinitialascii((DumpChar) fputc,temp,sf,format,map,fullsf,layer );
2242 mkheadercopyfile(temp,out,1);
2243 temp = GFileTmpfile();
2244 dumpencodedstuff((DumpChar) fputc,temp,sf,format,flags,map,layer);
2245 mkheadercopyfile(temp,out,2);
2246 temp = GFileTmpfile();
2247 dumpfinalascii((DumpChar) fputc,temp,sf,format);
2248 mkheadercopyfile(temp,out,1);
2249 /* final header, 3=>eof??? */
2250 dumpstrn((DumpChar) fputc,out,"\200\003",2);
2251 } else if ( format==ff_ptype3 ) {
2252 dumprequiredfontinfo((DumpChar) fputc,out,sf,ff_ptype3,map,NULL,layer);
2253 dumpcharprocs((DumpChar) fputc,out,sf);
2254 } else if ( format==ff_type42 || format==ff_type42cid ) {
2255 dumptype42(out,sf,format,flags,map,layer);
2256 } else {
2257 dumpinitialascii((DumpChar) (fputc),out,sf,format,map,fullsf,layer );
2258 dumpencodedstuff((DumpChar) (fputc),out,sf,format,flags,map,layer);
2259 dumpfinalascii((DumpChar) (fputc),out,sf,format);
2260 }
2261 }
2262
dumpreencodeproc(FILE * out)2263 static void dumpreencodeproc(FILE *out) {
2264
2265 fprintf( out, "\n/reencodedict 10 dict def\n" );
2266 fprintf( out, "/ReEncode\n" );
2267 fprintf( out, " { reencodedict begin\n" );
2268 fprintf( out, "\t/newencoding exch def\n" );
2269 fprintf( out, "\t/newfontname exch def\n" );
2270 fprintf( out, "\tfindfont /basefontdict exch def\n" );
2271 fprintf( out, "\t/newfont basefontdict maxlength dict def\n" );
2272 fprintf( out, "\tbasefontdict\n" );
2273 fprintf( out, "\t { exch dup dup /FID ne exch /Encoding ne and\n" );
2274 fprintf( out, "\t\t{ exch newfont 3 1 roll put }\n" );
2275 fprintf( out, "\t\t{ pop pop }\n" );
2276 fprintf( out, "\t\tifelse\n" );
2277 fprintf( out, "\t } forall\n" );
2278 fprintf( out, "\tnewfont /FontName newfontname put\n" );
2279 fprintf( out, "\tnewfont /Encoding newencoding put\n" );
2280 fprintf( out, "\tnewfontname newfont definefont pop\n" );
2281 fprintf( out, "\tend\n" );
2282 fprintf( out, " } def\n" );
2283 fprintf( out, "\n" );
2284 }
2285
dumpnotdefenc(FILE * out,SplineFont * sf)2286 static const char *dumpnotdefenc(FILE *out,SplineFont *sf) {
2287 const char *notdefname;
2288 int i;
2289
2290 /* At one point I thought the unicode replacement char 0xfffd */
2291 /* was a good replacement for notdef if the font contained */
2292 /* no notdef. Probably not a good idea for a PS font */
2293 notdefname = ".notdef";
2294 fprintf( out, "/%sBase /%sNotDef [\n", sf->fontname, sf->fontname );
2295 for ( i=0; i<256; ++i )
2296 fprintf( out, " /%s\n", notdefname );
2297 fprintf( out, "] ReEncode\n\n" );
2298 return( notdefname );
2299 }
2300
somecharsused(SplineFont * sf,int bottom,int top,EncMap * map)2301 static int somecharsused(SplineFont *sf, int bottom, int top, EncMap *map) {
2302 int i;
2303
2304 for ( i=bottom; i<=top && i<map->enccount; ++i ) {
2305 if ( map->map[i]!=-1 && SCWorthOutputting(sf->glyphs[map->map[i]]) )
2306 return( true );
2307 }
2308 return( false );
2309 }
2310
dumptype0stuff(FILE * out,SplineFont * sf,EncMap * map)2311 static void dumptype0stuff(FILE *out,SplineFont *sf, EncMap *map) {
2312 const char *notdefname;
2313 int i,j;
2314
2315 dumpreencodeproc(out);
2316 notdefname = dumpnotdefenc(out,sf);
2317 for ( i=1; i<256; ++i ) {
2318 if ( somecharsused(sf,i<<8, (i<<8)+0xff, map)) {
2319 fprintf( out, "/%sBase /%s%d [\n", sf->fontname, sf->fontname, i );
2320 for ( j=0; j<256 && (i<<8)+j<map->enccount; ++j )
2321 if ( map->map[(i<<8)+j]!=-1 && SCWorthOutputting(sf->glyphs[map->map[(i<<8)+j]]) )
2322 fprintf( out, " /%s\n", sf->glyphs[map->map[(i<<8)+j]]->name );
2323 else
2324 fprintf( out, "/%s\n", notdefname );
2325 for ( ; j<256; ++j )
2326 fprintf( out, " /%s\n", notdefname );
2327 fprintf( out, "] ReEncode\n\n" );
2328 } else if ( i==0x27 && (map->enc->is_unicodebmp || map->enc->is_unicodefull)) {
2329 fprintf( out, "%% Add Zapf Dingbats to unicode font at 0x2700\n" );
2330 fprintf( out, "%% But only if on the printer, else use notdef\n" );
2331 fprintf( out, "%% gv, which has no Zapf, maps courier to the name\n" );
2332 fprintf( out, "%% so we must check a bit more than is it null or not...\n" );
2333 /* gv with no ZapfDingbats installed does weird stuff. */
2334 /* If I do "/ZapfDingbats findfont" then it returns "/Courier findfont" the */
2335 /* first time, but the second time it returns null */
2336 /* So even if the printer thinks it's got Zapf we must check to make sure it's*/
2337 /* the real Zapf. We do that by examining the name. If it's ZapfDingbats all*/
2338 /* should be well, if it's Courier, then that counts as non-existant */
2339 fprintf( out, "/ZapfDingbats findfont pop\n" );
2340 fprintf( out, "/ZapfDingbats findfont null eq\n" );
2341 fprintf( out, "{ true }\n" );
2342 fprintf( out, " { /ZapfDingbats findfont /FontName get (ZapfDingbats) ne }\n" );
2343 fprintf( out, " ifelse\n" );
2344 fprintf( out, "{ /%s%d /%sNotDef findfont definefont pop }\n",
2345 sf->fontname, i, sf->fontname);
2346 fprintf( out, " { /ZapfDingbats /%s%d [\n", sf->fontname, i );
2347 for ( j=0; j<0xc0; ++j )
2348 fprintf( out, " /%s\n",
2349 zapfexists[j]?zapfnomen[j]:".notdef" );
2350 for ( ;j<256; ++j )
2351 fprintf( out, " /%s\n", ".notdef" );
2352 fprintf( out, "] ReEncode\n\n" );
2353 fprintf( out, " } ifelse\n\n" );
2354 }
2355 }
2356
2357 fprintf( out, "/%s 21 dict dup begin\n", sf->fontname );
2358 fprintf( out, "/FontInfo /%sBase findfont /FontInfo get def\n", sf->fontname );
2359 fprintf( out, "/PaintType %d def\n", sf->strokedfont?2:0 );
2360 if ( sf->strokedfont )
2361 fprintf( out, "/StrokeWidth %g def\n", (double) sf->strokewidth );
2362 fprintf( out, "/FontType 0 def\n" );
2363 fprintf( out, "/LanguageLevel 2 def\n" );
2364 fprintf( out, "/FontMatrix [1 0 0 1 0 0] readonly def\n" );
2365 fprintf( out, "/FMapType 2 def\n" );
2366 fprintf( out, "/Encoding [\n" );
2367 for ( i=0; i<256; ++i )
2368 fprintf( out, " %d\n", i );
2369 fprintf( out, "] readonly def\n" );
2370 fprintf( out, "/FDepVector [\n" );
2371 fprintf( out, " /%sBase findfont\n", sf->fontname );
2372 for ( i=1; i<256; ++i )
2373 if ( somecharsused(sf,i<<8, (i<<8)+0xff, map) ||
2374 (i==0x27 && (map->enc->is_unicodebmp || map->enc->is_unicodefull)) )
2375 fprintf( out, " /%s%d findfont\n", sf->fontname, i );
2376 else
2377 fprintf( out, " /%sNotDef findfont\n", sf->fontname );
2378 fprintf( out, " ] readonly def\n" );
2379 fprintf( out, "end definefont pop\n" );
2380 fprintf( out, "%%%%EOF\n" );
2381 }
2382
dumpt1str(FILE * binary,uint8 * data,int len,int leniv)2383 static void dumpt1str(FILE *binary,uint8 *data, int len, int leniv) {
2384 if ( leniv==-1 )
2385 fwrite(data,sizeof(uint8),len,binary);
2386 else
2387 encodestrout((DumpChar) fputc,binary,data,len,leniv);
2388 }
2389
dump_index(FILE * binary,int size,int val)2390 static void dump_index(FILE *binary,int size,int val) {
2391
2392 if ( size>=4 )
2393 putc((val>>24)&0xff,binary);
2394 if ( size>=3 )
2395 putc((val>>16)&0xff,binary);
2396 if ( size>=2 )
2397 putc((val>>8)&0xff,binary);
2398 if ( size>=1 ) /* Yes, size may be 0 for the fd index */
2399 putc((val)&0xff,binary);
2400 }
2401
gencidbinarydata(SplineFont * cidmaster,struct cidbytes * cidbytes,int flags,EncMap * map,int layer)2402 static FILE *gencidbinarydata(SplineFont *cidmaster,struct cidbytes *cidbytes,
2403 int flags,EncMap *map,int layer) {
2404 int i,j, leniv, subrtot;
2405 SplineFont *sf;
2406 struct fddata *fd;
2407 FILE *chrs, *subrs, *binary;
2408 char *buffer;
2409 long offset;
2410 char *pt;
2411 struct pschars *chars;
2412 int len;
2413
2414 memset(cidbytes,'\0',sizeof(struct cidbytes));
2415 cidbytes->fdcnt = cidmaster->subfontcnt;
2416 cidbytes->fds = calloc(cidbytes->fdcnt,sizeof(struct fddata));
2417 for ( i=0; i<cidbytes->fdcnt; ++i ) {
2418 sf = cidmaster->subfonts[i];
2419 fd = &cidbytes->fds[i];
2420 fd->flexmax = SplineFontIsFlexible(sf,layer,flags);
2421 fd->subrs = initsubrs(NULL);
2422 if ( fd->subrs==NULL ) {
2423 int j;
2424 for ( j=0; j<i; ++j )
2425 PSCharsFree(cidbytes->fds[j].subrs);
2426 free( cidbytes->fds );
2427 return( NULL );
2428 }
2429 fd->iscjk = SFIsCJK(sf,map);
2430 pt = PSDictHasEntry(sf->private,"lenIV");
2431 if ( pt!=NULL )
2432 fd->leniv = strtol(pt,NULL,10);
2433 else
2434 fd->leniv = 4;
2435 }
2436 ff_progress_change_line1(_("Converting PostScript"));
2437 if ( (chars = CID2ChrsSubrs(cidmaster,cidbytes,flags,layer))==NULL )
2438 return( NULL );
2439 ff_progress_next_stage();
2440 ff_progress_change_line1(_("Saving PostScript Font"));
2441
2442 chrs = GFileTmpfile();
2443 for ( i=0; i<chars->next; ++i ) {
2444 if ( chars->lens[i]!=0 ) {
2445 leniv = cidbytes->fds[cidbytes->fdind[i]].leniv;
2446 dumpt1str(chrs,chars->values[i],chars->lens[i],leniv);
2447 if ( !ff_progress_next()) {
2448 PSCharsFree(chars);
2449 fclose(chrs);
2450 return( NULL );
2451 }
2452 if ( leniv>0 )
2453 chars->lens[i] += leniv;
2454 }
2455 }
2456 subrs = GFileTmpfile(); subrtot = 0;
2457 for ( i=0; i<cidbytes->fdcnt; ++i ) {
2458 fd = &cidbytes->fds[i];
2459 leniv = fd->leniv;
2460 for ( j=0; j<fd->subrs->next; ++j ) {
2461 dumpt1str(subrs,fd->subrs->values[j],fd->subrs->lens[j],leniv);
2462 if ( leniv>0 )
2463 fd->subrs->lens[j] += leniv;
2464 }
2465 fd->subrcnt = j;
2466 subrtot += j;
2467 }
2468
2469 cidbytes->fdbytes = ( cidbytes->fdcnt==1 )? 0 :
2470 ( cidbytes->fdcnt<256 )? 1 : 2;
2471 if ( (cidbytes->cidcnt+1)*(cidbytes->fdbytes+3) + /* size of the CID map region */
2472 (subrtot+1) * 3 + /* size of the Subr map region */
2473 ftell(subrs) + /* size of the subr region */
2474 ftell(chrs) < 0x1000000 ) /* size of the charstring region */ /* Are all our offsets less than 3 bytes? */
2475 cidbytes->gdbytes = 3; /* Adobe's convention is to use 3, so don't bother checking for anything less */
2476 else
2477 cidbytes->gdbytes = 4; /* but I suppose we might need more... */
2478
2479 cidbytes->errors = ferror(chrs) || ferror(subrs);
2480
2481 offset = (cidbytes->cidcnt+1)*(cidbytes->fdbytes+cidbytes->gdbytes) +
2482 (subrtot+1) * cidbytes->gdbytes + ftell(subrs);
2483 binary = GFileTmpfile();
2484 for ( i=0; i<cidbytes->cidcnt; ++i ) {
2485 dump_index(binary,cidbytes->fdbytes,cidbytes->fdind[i]);
2486 dump_index(binary,cidbytes->gdbytes,offset);
2487 offset += chars->lens[i];
2488 }
2489 dump_index(binary,cidbytes->fdbytes,-1); /* Adobe says undefined */
2490 dump_index(binary,cidbytes->gdbytes,offset);
2491 if ( ftell(binary) != (cidbytes->cidcnt+1)*(cidbytes->fdbytes+cidbytes->gdbytes))
2492 IError("CIDMap section the wrong length" );
2493
2494 offset = (cidbytes->cidcnt+1)*(cidbytes->fdbytes+cidbytes->gdbytes) +
2495 (subrtot+1) * cidbytes->gdbytes;
2496 for ( i=0; i<cidbytes->fdcnt; ++i ) {
2497 fd = &cidbytes->fds[i];
2498 fd->subrmapoff = ftell(binary);
2499 fd->sdbytes = cidbytes->gdbytes;
2500 fd->subrcnt = fd->subrs->next;
2501 for ( j=0; j<fd->subrcnt; ++j ) {
2502 dump_index(binary,fd->sdbytes,offset);
2503 offset += fd->subrs->lens[j];
2504 }
2505 PSCharsFree(fd->subrs);
2506 }
2507 dump_index(binary,cidbytes->gdbytes,offset);
2508 if ( ftell(binary) != (cidbytes->cidcnt+1)*(cidbytes->fdbytes+cidbytes->gdbytes) +
2509 (subrtot+1) * cidbytes->gdbytes )
2510 IError("SubrMap section the wrong length" );
2511
2512 buffer = malloc(8192);
2513
2514 rewind(subrs);
2515 while ( (len=fread(buffer,1,8192,subrs))>0 )
2516 fwrite(buffer,1,len,binary);
2517 fclose(subrs);
2518
2519 rewind(chrs);
2520 while ( (len=fread(buffer,1,8192,chrs))>0 )
2521 fwrite(buffer,1,len,binary);
2522 fclose(chrs);
2523
2524 PSCharsFree(chars);
2525 free( cidbytes->fdind ); cidbytes->fdind = NULL;
2526 free( buffer );
2527
2528 cidbytes->errors |= ferror(binary);
2529 return( binary );
2530 }
2531
dumpcidstuff(FILE * out,SplineFont * cidmaster,int flags,EncMap * map,int layer)2532 static int dumpcidstuff(FILE *out,SplineFont *cidmaster,int flags,EncMap *map,int layer) {
2533 int i;
2534 DBounds res;
2535 FILE *binary;
2536 SplineFont *sf;
2537 struct cidbytes cidbytes;
2538 char buffer[4096];
2539 long len;
2540
2541 fprintf( out, "%%!PS-Adobe-3.0 Resource-CIDFont\n" );
2542 fprintf( out, "%%%%DocumentNeededResources: ProcSet (CIDInit)\n" );
2543 /* fprintf( out, "%%%%DocumentSuppliedResources: CIDFont (%s)\n", cidmaster->fontname ); */
2544 /* Werner says this is inappropriate */
2545 fprintf( out, "%%%%IncludeResource: ProcSet (CIDInit)\n" );
2546 fprintf( out, "%%%%BeginResource: CIDFont (%s)\n", cidmaster->fontname );
2547 dumpfontcomments((DumpChar) fputc, out, cidmaster, ff_cid );
2548
2549 fprintf( out, "/CIDInit /ProcSet findresource begin\n\n" );
2550
2551 fprintf( out, "20 dict begin\n\n" );
2552
2553 fprintf( out, "/CIDFontName /%s def\n", cidmaster->fontname );
2554 fprintf( out, "/CIDFontVersion %g def\n", (double)cidmaster->cidversion );
2555 fprintf( out, "/CIDFontType 0 def\n\n" );
2556
2557 fprintf( out, "/CIDSystemInfo 3 dict dup begin\n" );
2558 fprintf( out, " /Registry (%s) def\n", cidmaster->cidregistry );
2559 fprintf( out, " /Ordering (%s) def\n", cidmaster->ordering );
2560 fprintf( out, " /Supplement %d def\n", cidmaster->supplement );
2561 fprintf( out, "end def\n\n" );
2562
2563 CIDLayerFindBounds(cidmaster,layer,&res);
2564 fprintf( out, "/FontBBox [ %g %g %g %g ] def\n",
2565 floor(res.minx), floor(res.miny),
2566 ceil(res.maxx), ceil(res.maxy));
2567
2568 if ( cidmaster->use_uniqueid ) {
2569 fprintf( out,"/UIDBase %d def\n", cidmaster->uniqueid?cidmaster->uniqueid: 4000000 + (rand()&0x3ffff) );
2570 if ( cidmaster->xuid!=NULL && cidmaster->use_xuid ) {
2571 fprintf( out,"/XUID %s def\n", cidmaster->xuid );
2572 /* SFIncrementXUID(cidmaster); */ /* Unique ID managment in CID fonts is too complex for this simple trick to work */
2573 }
2574 }
2575
2576 dumpfontinfo((DumpChar) fputc,out,cidmaster,ff_cid);
2577
2578 if ((binary = gencidbinarydata(cidmaster,&cidbytes,flags,map,layer))==NULL )
2579 return( 0 );
2580
2581 fprintf( out, "\n/CIDMapOffset %d def\n", cidbytes.cidmapoffset );
2582 fprintf( out, "/FDBytes %d def\n", cidbytes.fdbytes );
2583 fprintf( out, "/GDBytes %d def\n", cidbytes.gdbytes );
2584 fprintf( out, "/CIDCount %d def\n\n", cidbytes.cidcnt );
2585
2586 fprintf( out, "/FDArray %d array\n", cidbytes.fdcnt );
2587 for ( i=0; i<cidbytes.fdcnt; ++i ) {
2588 double factor;
2589 sf = cidmaster->subfonts[i];
2590 /* According to the PSRef Man, v3. only FontName, FontMatrix & Private*/
2591 /* should be defined here. But adobe's example fonts have a few */
2592 /* extra entries, so I'll put them in */
2593 fprintf( out, "dup %d\n", i );
2594 fprintf( out, "\n%%ADOBeginFontDict\n" );
2595 fprintf( out, "15 dict\n begin\n" );
2596 fprintf( out, " /FontName /%s def\n", sf->fontname );
2597 fprintf( out, " /FontType 1 def\n" );
2598 factor = 1.0/(sf->ascent+sf->descent);
2599 fprintf( out, " /FontMatrix [ %g 0 0 %g 0 0 ] def\n",
2600 factor, factor );
2601 fprintf( out, "/PaintType %d def\n", sf->strokedfont?2:0 );
2602 if ( sf->strokedfont )
2603 fprintf( out, "/StrokeWidth %g def\n", (double) sf->strokewidth );
2604 fprintf( out, "\n %%ADOBeginPrivateDict\n" );
2605 dumpprivatestuff((DumpChar) fputc,out,sf,&cidbytes.fds[i],flags,ff_cid,map,layer);
2606 fprintf( out, "\n %%ADOEndPrivateDict\n" );
2607 fprintf( out, " currentdict end\n%%ADOEndFontDict\n put\n\n" );
2608 }
2609 fprintf( out, "def\n\n" );
2610
2611 fseek(binary,0,SEEK_END);
2612 len = ftell(binary);
2613 sprintf( buffer, "(Binary) %ld StartData ", len );
2614 fprintf( out, "%%%%BeginData: %ld Binary Bytes\n", (long) (len+strlen(buffer)));
2615 fputs( buffer, out );
2616
2617 fseek(binary,0,SEEK_SET);
2618 while ( (len=fread(buffer,1,sizeof(buffer),binary))>0 )
2619 fwrite(buffer,1,len,out);
2620 cidbytes.errors |= ferror(binary);
2621 fclose(binary);
2622 free(cidbytes.fds);
2623
2624 fprintf( out, "\n%%%%EndData\n%%%%EndResource\n%%%%EOF\n" );
2625 return( !cidbytes.errors );
2626 }
2627
_WritePSFont(FILE * out,SplineFont * sf,enum fontformat format,int flags,EncMap * map,SplineFont * fullsf,int layer)2628 int _WritePSFont(FILE *out,SplineFont *sf,enum fontformat format,int flags,
2629 EncMap *map, SplineFont *fullsf,int layer) {
2630 int err = false;
2631
2632 if ( format!=ff_cid && format!=ff_ptype3 &&
2633 (othersubrs[0]==NULL || othersubrs[0][0]==NULL ||
2634 (othersubrs[0][1]==NULL && strcmp(othersubrs[0][0],"{}")==0)))
2635 flags &= ~ps_flag_noflex;
2636
2637 /* make sure that all reals get output with '.' for decimal points */
2638 locale_t tmplocale; locale_t oldlocale; // Declare temporary locale storage.
2639 switch_to_c_locale(&tmplocale, &oldlocale); // Switch to the C locale temporarily and cache the old locale.
2640 if ( (format==ff_mma || format==ff_mmb) && sf->mm!=NULL )
2641 sf = sf->mm->normal;
2642 if ( format==ff_cid )
2643 err = !dumpcidstuff(out,sf->subfontcnt>0?sf:sf->cidmaster,flags,map,layer);
2644 else {
2645 dumpfontdict(out,sf,format,flags,map,fullsf,layer);
2646 if ( format==ff_ptype0 )
2647 dumptype0stuff(out,sf,map);
2648 }
2649 switch_to_old_locale(&tmplocale, &oldlocale); // Switch to the cached locale.
2650 if ( ferror(out) || err)
2651 return( 0 );
2652
2653 #ifdef __CygWin
2654 /* Modern versions of windows want the execute bit set on a ttf file */
2655 /* It might also be needed for a postscript font, but I haven't checked */
2656 /* It isn't needed on the pfb file, but is on the pfm, so this code */
2657 /* isn't really useful */
2658 /* I've no idea what this corresponds to in windows, nor any idea on */
2659 /* how to set it from the windows UI, but this seems to work */
2660 {
2661 struct stat buf;
2662 fstat(fileno(out),&buf);
2663 fchmod(fileno(out),S_IXUSR | buf.st_mode );
2664 }
2665 #endif
2666
2667 return( true );
2668 }
2669
WritePSFont(char * fontname,SplineFont * sf,enum fontformat format,int flags,EncMap * map,SplineFont * fullsf,int layer)2670 int WritePSFont(char *fontname,SplineFont *sf,enum fontformat format,int flags,
2671 EncMap *map,SplineFont *fullsf,int layer) {
2672 FILE *out;
2673 int ret;
2674
2675 if (( out=fopen(fontname,"wb"))==NULL )
2676 return( 0 );
2677 ret = _WritePSFont(out,sf,format,flags,map,fullsf,layer);
2678 if ( fclose(out)==-1 )
2679 ret = 0;
2680 return( ret );
2681 }
2682
dumpimageproc(FILE * file,BDFChar * bdfc,BDFFont * font)2683 static void dumpimageproc(FILE *file,BDFChar *bdfc,BDFFont *font) {
2684 SplineFont *sf = font->sf;
2685 double scale = (sf->ascent+sf->descent)/font->pixelsize;
2686 int width = bdfc->xmax-bdfc->xmin+1, height = bdfc->ymax-bdfc->ymin+1;
2687 int i;
2688 struct psfilter ps;
2689
2690 /* wx wy ix iy urx ury setcachdevice */
2691 fprintf( file, " /%s { %d 0 %d %d %d %d setcachedevice \n",
2692 bdfc->sc->name, (int) rint(bdfc->width*scale),
2693 (int) rint(bdfc->xmin*scale), (int) rint(bdfc->ymin*scale),
2694 (int) rint((1+bdfc->xmax)*scale), (int) rint((1+bdfc->ymax)*scale));
2695 fprintf( file, "\t%g %g translate %g %g scale %d %d true [%d 0 0 %d 0 0] {<~\n",
2696 bdfc->xmin*scale, bdfc->ymax*scale, /* tx tx Translate */
2697 width*scale, height*scale, /* x y Scale */
2698 width, height,
2699 width, -height);
2700 InitFilter(&ps,(DumpChar) fputc,file);
2701 if ( bdfc->bytes_per_line==(width+7)/8 )
2702 FilterStr(&ps,(uint8 *) bdfc->bitmap, height*bdfc->bytes_per_line);
2703 else for ( i=0; i<height; ++i )
2704 FilterStr(&ps,(uint8 *) (bdfc->bitmap + i*bdfc->bytes_per_line),
2705 (width+7)/8);
2706 FlushFilter(&ps);
2707 fprintf(file,"} imagemask } bind def\n" );
2708 }
2709
PSBitmapDump(char * filename,BDFFont * font,EncMap * map)2710 int PSBitmapDump(char *filename,BDFFont *font, EncMap *map) {
2711 char buffer[300];
2712 FILE *file;
2713 int i, notdefpos, cnt;
2714 int ret = 0;
2715 SplineFont *sf = font->sf;
2716
2717 if ( filename==NULL ) {
2718 sprintf(buffer,"%s-%d.pt3", sf->fontname, font->pixelsize );
2719 filename = buffer;
2720 }
2721 file = fopen(filename,"w" );
2722 if ( file==NULL )
2723 LogError( _("Can't open %s\n"), filename );
2724 else {
2725 for ( i=0; i<font->glyphcnt; i++ ) if ( font->glyphs[i] != NULL )
2726 BCPrepareForOutput( font->glyphs[i],true );
2727 dumprequiredfontinfo((DumpChar) fputc, file, sf, ff_ptype3, map,NULL,ly_fore);
2728
2729 cnt = 0;
2730 notdefpos = SFFindNotdef(sf,-2);
2731 for ( i=0; i<sf->glyphcnt; ++i )
2732 if ( font->glyphs[i]!=NULL ) {
2733 if ( strcmp(font->glyphs[i]->sc->name,".notdef")!=0 )
2734 ++cnt;
2735 }
2736 ++cnt; /* one notdef entry */
2737
2738 fprintf(file,"/CharProcs %d dict def\nCharProcs begin\n", cnt );
2739
2740 if ( notdefpos!=-1 && font->glyphs[notdefpos]!=NULL)
2741 dumpimageproc(file,font->glyphs[notdefpos],font);
2742 else
2743 fprintf( file, " /.notdef { %d 0 0 0 0 0 setcachedevice } bind def\n",
2744 sf->ascent+sf->descent );
2745
2746 for ( i=0; i<sf->glyphcnt; ++i ) if ( i!=notdefpos ) {
2747 if ( font->glyphs[i]!=NULL )
2748 dumpimageproc(file,font->glyphs[i],font);
2749 }
2750 fprintf(file,"end\ncurrentdict end\n" );
2751 fprintf(file,"/%s exch definefont\n", sf->fontname );
2752 ret = ferror(file)==0;
2753 if ( fclose(file)!=0 )
2754 ret = false;
2755 for ( i=0; i<font->glyphcnt; i++ ) if ( font->glyphs[i] != NULL )
2756 BCRestoreAfterOutput( font->glyphs[i] );
2757 }
2758 return( ret );
2759 }
2760