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