xref: /plan9/sys/src/cmd/gs/src/gdevpsf1.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1998, 1999, 2000 Aladdin Enterprises.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: gdevpsf1.c,v 1.21 2005/03/17 15:45:52 igor Exp $ */
18 /* Write an embedded Type 1 font */
19 #include "memory_.h"
20 #include <assert.h>
21 #include "gx.h"
22 #include "gserrors.h"
23 #include "gsccode.h"
24 #include "gsmatrix.h"
25 #include "gxfixed.h"
26 #include "gxfont.h"
27 #include "gxfont1.h"
28 #include "gxmatrix.h"		/* for gxtype1.h */
29 #include "gxtype1.h"
30 #include "strimpl.h"		/* required by Watcom compiler (why?) */
31 #include "stream.h"
32 #include "sfilter.h"
33 #include "spsdf.h"
34 #include "sstring.h"
35 #include "spprint.h"
36 #include "gdevpsf.h"
37 
38 /* ------ Utilities shared with CFF writer ------ */
39 
40 /* Gather glyph information for a Type 1 or Type 2 font. */
41 int
psf_type1_glyph_data(gs_font_base * pbfont,gs_glyph glyph,gs_glyph_data_t * pgd,gs_font_type1 ** ppfont)42 psf_type1_glyph_data(gs_font_base *pbfont, gs_glyph glyph,
43 		     gs_glyph_data_t *pgd, gs_font_type1 **ppfont)
44 {
45     gs_font_type1 *const pfont = (gs_font_type1 *)pbfont;
46 
47     *ppfont = pfont;
48     return pfont->data.procs.glyph_data(pfont, glyph, pgd);
49 }
50 int
psf_get_type1_glyphs(psf_outline_glyphs_t * pglyphs,gs_font_type1 * pfont,gs_glyph * subset_glyphs,uint subset_size)51 psf_get_type1_glyphs(psf_outline_glyphs_t *pglyphs, gs_font_type1 *pfont,
52 		     gs_glyph *subset_glyphs, uint subset_size)
53 {
54     return psf_get_outline_glyphs(pglyphs, (gs_font_base *)pfont,
55 				  subset_glyphs, subset_size,
56 				  psf_type1_glyph_data);
57 }
58 
59 /* ------ Main program ------ */
60 
61 /* Write a (named) array of floats. */
62 private int
write_float_array(gs_param_list * plist,const char * key,const float * values,int count)63 write_float_array(gs_param_list *plist, const char *key, const float *values,
64 		  int count)
65 {
66     if (count != 0) {
67 	gs_param_float_array fa;
68 
69 	fa.size = count;
70 	fa.data = values;
71 	return param_write_float_array(plist, key, &fa);
72     }
73     return 0;
74 }
75 
76 /* Write a UniqueID and/or XUID. */
77 private void
write_uid(stream * s,const gs_uid * puid)78 write_uid(stream *s, const gs_uid *puid)
79 {
80     if (uid_is_UniqueID(puid))
81 	pprintld1(s, "/UniqueID %ld def\n", puid->id);
82     else if (uid_is_XUID(puid)) {
83 	uint i, n = uid_XUID_size(puid);
84 
85 	stream_puts(s, "/XUID [");
86 	for (i = 0; i < n; ++i)
87 	    pprintld1(s, "%ld ", uid_XUID_values(puid)[i]);
88 	stream_puts(s, "] readonly def\n");
89     }
90 }
91 
92 /* Write the font name. */
93 private void
write_font_name(stream * s,const gs_font_type1 * pfont,const gs_const_string * alt_font_name)94 write_font_name(stream *s, const gs_font_type1 *pfont,
95 		const gs_const_string *alt_font_name)
96 {
97     if (alt_font_name)
98 	stream_write(s, alt_font_name->data, alt_font_name->size);
99     else
100 	stream_write(s, pfont->font_name.chars, pfont->font_name.size);
101 }
102 /*
103  * Write the Encoding array.  This is a separate procedure only for
104  * readability.
105  */
106 private int
write_Encoding(stream * s,gs_font_type1 * pfont,int options,gs_glyph * subset_glyphs,uint subset_size,gs_glyph notdef)107 write_Encoding(stream *s, gs_font_type1 *pfont, int options,
108 	      gs_glyph *subset_glyphs, uint subset_size, gs_glyph notdef)
109 {
110     stream_puts(s, "/Encoding ");
111     switch (pfont->encoding_index) {
112 	case ENCODING_INDEX_STANDARD:
113 	    stream_puts(s, "StandardEncoding");
114 	    break;
115 	case ENCODING_INDEX_ISOLATIN1:
116 	    /* ATM only recognizes StandardEncoding. */
117 	    if (options & WRITE_TYPE1_POSTSCRIPT) {
118 		stream_puts(s, "ISOLatin1Encoding");
119 		break;
120 	    }
121 	default:{
122 		gs_char i;
123 
124 		stream_puts(s, "256 array\n");
125 		stream_puts(s, "0 1 255 {1 index exch /.notdef put} for\n");
126 		for (i = 0; i < 256; ++i) {
127 		    gs_glyph glyph =
128 			(*pfont->procs.encode_char)
129 			((gs_font *)pfont, (gs_char)i, GLYPH_SPACE_NAME);
130 		    gs_const_string namestr;
131 
132 		    if (subset_glyphs && subset_size) {
133 			/*
134 			 * Only write Encoding entries for glyphs in the
135 			 * subset.  Use binary search to check each glyph,
136 			 * since subset_glyphs are sorted.
137 			 */
138 			if (!psf_sorted_glyphs_include(subset_glyphs,
139 							subset_size, glyph))
140 			    continue;
141 		    }
142 		    if (glyph != gs_no_glyph && glyph != notdef &&
143 			pfont->procs.glyph_name((gs_font *)pfont, glyph,
144 						&namestr) >= 0
145 			) {
146 			pprintd1(s, "dup %d /", (int)i);
147 			stream_write(s, namestr.data, namestr.size);
148 			stream_puts(s, " put\n");
149 		    }
150 		}
151 		stream_puts(s, "readonly");
152 	    }
153     }
154     stream_puts(s, " def\n");
155     return 0;
156 }
157 
158 /*
159  * Write the Private dictionary.  This is a separate procedure only for
160  * readability.  write_CharString is a parameter so that we can encrypt
161  * Subrs and CharStrings when the font's lenIV == -1 but we are writing
162  * the font with lenIV = 0.
163  */
164 private int
write_Private(stream * s,gs_font_type1 * pfont,gs_glyph * subset_glyphs,uint subset_size,gs_glyph notdef,int lenIV,int (* write_CharString)(stream *,const void *,uint),const param_printer_params_t * ppp)165 write_Private(stream *s, gs_font_type1 *pfont,
166 	      gs_glyph *subset_glyphs, uint subset_size,
167 	      gs_glyph notdef, int lenIV,
168 	      int (*write_CharString)(stream *, const void *, uint),
169 	      const param_printer_params_t *ppp)
170 {
171     const gs_type1_data *const pdata = &pfont->data;
172     printer_param_list_t rlist;
173     gs_param_list *const plist = (gs_param_list *)&rlist;
174     int code = s_init_param_printer(&rlist, ppp, s);
175 
176     if (code < 0)
177 	return 0;
178     stream_puts(s, "dup /Private 17 dict dup begin\n");
179     stream_puts(s, "/-|{string currentfile exch readstring pop}executeonly def\n");
180     stream_puts(s, "/|-{noaccess def}executeonly def\n");
181     stream_puts(s, "/|{noaccess put}executeonly def\n");
182     {
183 	private const gs_param_item_t private_items[] = {
184 	    {"BlueFuzz", gs_param_type_int,
185 	     offset_of(gs_type1_data, BlueFuzz)},
186 	    {"BlueScale", gs_param_type_float,
187 	     offset_of(gs_type1_data, BlueScale)},
188 	    {"BlueShift", gs_param_type_float,
189 	     offset_of(gs_type1_data, BlueShift)},
190 	    {"ExpansionFactor", gs_param_type_float,
191 	     offset_of(gs_type1_data, ExpansionFactor)},
192 	    {"ForceBold", gs_param_type_bool,
193 	     offset_of(gs_type1_data, ForceBold)},
194 	    {"LanguageGroup", gs_param_type_int,
195 	     offset_of(gs_type1_data, LanguageGroup)},
196 	    {"RndStemUp", gs_param_type_bool,
197 	     offset_of(gs_type1_data, RndStemUp)},
198 	    gs_param_item_end
199 	};
200 	gs_type1_data defaults;
201 
202 	defaults.BlueFuzz = 1;
203 	defaults.BlueScale = (float)0.039625;
204 	defaults.BlueShift = 7.0;
205 	defaults.ExpansionFactor = (float)0.06;
206 	defaults.ForceBold = false;
207 	defaults.LanguageGroup = 0;
208 	defaults.RndStemUp = true;
209 	code = gs_param_write_items(plist, pdata, &defaults, private_items);
210 	if (code < 0)
211 	    return code;
212 	if (lenIV != 4) {
213 	    code = param_write_int(plist, "lenIV", &lenIV);
214 	    if (code < 0)
215 		return code;
216 	}
217 	write_float_array(plist, "BlueValues", pdata->BlueValues.values,
218 			  pdata->BlueValues.count);
219 	write_float_array(plist, "OtherBlues", pdata->OtherBlues.values,
220 			  pdata->OtherBlues.count);
221 	write_float_array(plist, "FamilyBlues", pdata->FamilyBlues.values,
222 			  pdata->FamilyBlues.count);
223 	write_float_array(plist, "FamilyOtherBlues", pdata->FamilyOtherBlues.values,
224 			  pdata->FamilyOtherBlues.count);
225 	write_float_array(plist, "StdHW", pdata->StdHW.values,
226 			  pdata->StdHW.count);
227 	write_float_array(plist, "StdVW", pdata->StdVW.values,
228 			  pdata->StdVW.count);
229 	write_float_array(plist, "StemSnapH", pdata->StemSnapH.values,
230 			  pdata->StemSnapH.count);
231 	write_float_array(plist, "StemSnapV", pdata->StemSnapV.values,
232 			  pdata->StemSnapV.count);
233     }
234     write_uid(s, &pfont->UID);
235     stream_puts(s, "/MinFeature{16 16} def\n");
236     stream_puts(s, "/password 5839 def\n");
237 
238     /*
239      * Write the Subrs.  We always write them all, even for subsets.
240      * (We will fix this someday.)
241      */
242 
243     {
244 	int n, i;
245 	gs_glyph_data_t gdata;
246 	int code;
247 
248 	gdata.memory = pfont->memory;
249 	for (n = 0;
250 	     (code = pdata->procs.subr_data(pfont, n, false, &gdata)) !=
251 		 gs_error_rangecheck;
252 	     ) {
253 	    ++n;
254 	    if (code >= 0)
255 		gs_glyph_data_free(&gdata, "write_Private(Subrs)");
256 	}
257 	pprintd1(s, "/Subrs %d array\n", n);
258 	for (i = 0; i < n; ++i)
259 	    if ((code = pdata->procs.subr_data(pfont, i, false, &gdata)) >= 0) {
260 		char buf[50];
261 
262 		if (gdata.bits.size) {
263 		    sprintf(buf, "dup %d %u -| ", i, gdata.bits.size);
264 		    stream_puts(s, buf);
265 		    write_CharString(s, gdata.bits.data, gdata.bits.size);
266 		    stream_puts(s, " |\n");
267 		}
268 		gs_glyph_data_free(&gdata, "write_Private(Subrs)");
269 	    }
270 	stream_puts(s, "|-\n");
271     }
272 
273     /* We don't write OtherSubrs -- there had better not be any! */
274 
275     /* Write the CharStrings. */
276 
277     {
278 	int num_chars = 0;
279 	gs_glyph glyph;
280 	psf_glyph_enum_t genum;
281 	gs_glyph_data_t gdata;
282 	int code;
283 
284 	gdata.memory = pfont->memory;
285 	psf_enumerate_glyphs_begin(&genum, (gs_font *)pfont, subset_glyphs,
286 				    (subset_glyphs ? subset_size : 0),
287 				    GLYPH_SPACE_NAME);
288 	for (glyph = gs_no_glyph;
289 	     (code = psf_enumerate_glyphs_next(&genum, &glyph)) != 1;
290 	     )
291 	    if (code == 0 &&
292 		(code = pdata->procs.glyph_data(pfont, glyph, &gdata)) >= 0
293 		) {
294 		++num_chars;
295 		gs_glyph_data_free(&gdata, "write_Private(CharStrings)");
296 	    }
297 	pprintd1(s, "2 index /CharStrings %d dict dup begin\n", num_chars);
298 	psf_enumerate_glyphs_reset(&genum);
299 	for (glyph = gs_no_glyph;
300 	     (code = psf_enumerate_glyphs_next(&genum, &glyph)) != 1;
301 	    )
302 	    if (code == 0 &&
303 		(code = pdata->procs.glyph_data(pfont, glyph, &gdata)) >= 0
304 		) {
305 		gs_const_string gstr;
306 		int code;
307 
308 		code = pfont->procs.glyph_name((gs_font *)pfont, glyph, &gstr);
309 		assert(code >= 0);
310 		stream_puts(s, "/");
311 		stream_write(s, gstr.data, gstr.size);
312 		pprintd1(s, " %d -| ", gdata.bits.size);
313 		write_CharString(s, gdata.bits.data, gdata.bits.size);
314 		stream_puts(s, " |-\n");
315 		gs_glyph_data_free(&gdata, "write_Private(CharStrings)");
316 	    }
317     }
318 
319     /* Wrap up. */
320 
321     stream_puts(s, "end\nend\nreadonly put\nnoaccess put\n");
322     s_release_param_printer(&rlist);
323     return 0;
324 }
325 
326 /* Encrypt and write a CharString. */
327 private int
stream_write_encrypted(stream * s,const void * ptr,uint count)328 stream_write_encrypted(stream *s, const void *ptr, uint count)
329 {
330     const byte *const data = ptr;
331     crypt_state state = crypt_charstring_seed;
332     byte buf[50];		/* arbitrary */
333     uint left, n;
334     int code = 0;
335 
336     for (left = count; left > 0; left -= n) {
337 	n = min(left, sizeof(buf));
338 	gs_type1_encrypt(buf, data + count - left, n, &state);
339 	code = stream_write(s, buf, n);
340     }
341     return code;
342 }
343 
344 /* Write one FontInfo entry. */
345 private void
write_font_info(stream * s,const char * key,const gs_const_string * pvalue,int do_write)346 write_font_info(stream *s, const char *key, const gs_const_string *pvalue,
347 		int do_write)
348 {
349     if (do_write) {
350 	pprints1(s, "\n/%s ", key);
351 	s_write_ps_string(s, pvalue->data, pvalue->size, PRINT_HEX_NOT_OK);
352 	stream_puts(s, " def");
353     }
354 }
355 
356 /* Write the definition of a Type 1 font. */
357 int
psf_write_type1_font(stream * s,gs_font_type1 * pfont,int options,gs_glyph * orig_subset_glyphs,uint orig_subset_size,const gs_const_string * alt_font_name,int lengths[3])358 psf_write_type1_font(stream *s, gs_font_type1 *pfont, int options,
359 		      gs_glyph *orig_subset_glyphs, uint orig_subset_size,
360 		      const gs_const_string *alt_font_name, int lengths[3])
361 {
362     stream *es = s;
363     long start = stell(s);
364     param_printer_params_t ppp;
365     printer_param_list_t rlist;
366     gs_param_list *const plist = (gs_param_list *)&rlist;
367     stream AXE_stream;
368     stream_AXE_state AXE_state;
369     byte AXE_buf[200];		/* arbitrary */
370     stream exE_stream;
371     stream_exE_state exE_state;
372     byte exE_buf[200];		/* arbitrary */
373     psf_outline_glyphs_t glyphs;
374     int lenIV = pfont->data.lenIV;
375     int (*write_CharString)(stream *, const void *, uint) = stream_write;
376     int code = psf_get_type1_glyphs(&glyphs, pfont, orig_subset_glyphs,
377 				     orig_subset_size);
378 
379     if (code < 0)
380 	return code;
381 
382     /* Initialize the parameter printer. */
383 
384     ppp = param_printer_params_default;
385     ppp.item_suffix = " def\n";
386     ppp.print_ok =
387 	(options & WRITE_TYPE1_ASCIIHEX ? 0 : PRINT_BINARY_OK) |
388 	PRINT_HEX_NOT_OK;
389     code = s_init_param_printer(&rlist, &ppp, s);
390     if (code < 0)
391 	return code;
392 
393     /* Write the font header. */
394 
395     stream_puts(s, "%!FontType1-1.0: ");
396     write_font_name(s, pfont, alt_font_name);
397     stream_puts(s, "\n11 dict begin\n");
398 
399     /* Write FontInfo. */
400 
401     stream_puts(s, "/FontInfo 5 dict dup begin");
402     {
403 	gs_font_info_t info;
404 	int code = pfont->procs.font_info((gs_font *)pfont, NULL,
405 			(FONT_INFO_COPYRIGHT | FONT_INFO_NOTICE |
406 			 FONT_INFO_FAMILY_NAME | FONT_INFO_FULL_NAME),
407 					  &info);
408 
409 	if (code >= 0) {
410 	    write_font_info(s, "Copyright", &info.Copyright,
411 			    info.members & FONT_INFO_COPYRIGHT);
412 	    write_font_info(s, "Notice", &info.Notice,
413 			    info.members & FONT_INFO_NOTICE);
414 	    write_font_info(s, "FamilyName", &info.FamilyName,
415 			    info.members & FONT_INFO_FAMILY_NAME);
416 	    write_font_info(s, "FullName", &info.FullName,
417 			    info.members & FONT_INFO_FULL_NAME);
418 	}
419     }
420     stream_puts(s, "\nend readonly def\n");
421 
422     /* Write the main font dictionary. */
423 
424     stream_puts(s, "/FontName /");
425     write_font_name(s, pfont, alt_font_name);
426     stream_puts(s, " def\n");
427     code = write_Encoding(s, pfont, options, glyphs.subset_glyphs,
428 			  glyphs.subset_size, glyphs.notdef);
429     if (code < 0)
430 	return code;
431     pprintg6(s, "/FontMatrix [%g %g %g %g %g %g] readonly def\n",
432 	     pfont->FontMatrix.xx, pfont->FontMatrix.xy,
433 	     pfont->FontMatrix.yx, pfont->FontMatrix.yy,
434 	     pfont->FontMatrix.tx, pfont->FontMatrix.ty);
435     write_uid(s, &pfont->UID);
436     pprintg4(s, "/FontBBox {%g %g %g %g} readonly def\n",
437 	     pfont->FontBBox.p.x, pfont->FontBBox.p.y,
438 	     pfont->FontBBox.q.x, pfont->FontBBox.q.y);
439     {
440 	private const gs_param_item_t font_items[] = {
441 	    {"FontType", gs_param_type_int,
442 	     offset_of(gs_font_type1, FontType)},
443 	    {"PaintType", gs_param_type_int,
444 	     offset_of(gs_font_type1, PaintType)},
445 	    {"StrokeWidth", gs_param_type_float,
446 	     offset_of(gs_font_type1, StrokeWidth)},
447 	    gs_param_item_end
448 	};
449 
450 	code = gs_param_write_items(plist, pfont, NULL, font_items);
451 	if (code < 0)
452 	    return code;
453     }
454     {
455 	const gs_type1_data *const pdata = &pfont->data;
456 
457 	write_float_array(plist, "WeightVector", pdata->WeightVector.values,
458 			  pdata->WeightVector.count);
459     }
460     stream_puts(s, "currentdict end\n");
461 
462     /* Write the Private dictionary. */
463 
464     if (lenIV < 0 && (options & WRITE_TYPE1_WITH_LENIV)) {
465 	/* We'll have to encrypt the CharStrings. */
466 	lenIV = 0;
467 	write_CharString = stream_write_encrypted;
468     }
469     if (options & WRITE_TYPE1_EEXEC) {
470 	stream_puts(s, "currentfile eexec\n");
471 	lengths[0] = stell(s) - start;
472 	start = stell(s);
473 	if (options & WRITE_TYPE1_ASCIIHEX) {
474 	    s_init(&AXE_stream, s->memory);
475 	    s_init_state((stream_state *)&AXE_state, &s_AXE_template, NULL);
476 	    AXE_state.EndOfData = false;
477 	    s_init_filter(&AXE_stream, (stream_state *)&AXE_state,
478 			  AXE_buf, sizeof(AXE_buf), es);
479 	    es = &AXE_stream;
480 	}
481 	s_init(&exE_stream, s->memory);
482 	s_init_state((stream_state *)&exE_state, &s_exE_template, NULL);
483 	exE_state.cstate = 55665;
484 	s_init_filter(&exE_stream, (stream_state *)&exE_state,
485 		      exE_buf, sizeof(exE_buf), es);
486 	es = &exE_stream;
487 	/*
488 	 * Note: eexec encryption always writes/skips 4 initial bytes, not
489 	 * the number of initial bytes given by pdata->lenIV.
490 	 */
491 	stream_puts(es, "****");
492     }
493     code = write_Private(es, pfont, glyphs.subset_glyphs, glyphs.subset_size,
494 			 glyphs.notdef, lenIV, write_CharString, &ppp);
495     if (code < 0)
496 	return code;
497     stream_puts(es, "dup/FontName get exch definefont pop\n");
498     if (options & WRITE_TYPE1_EEXEC) {
499 	if (options & (WRITE_TYPE1_EEXEC_PAD | WRITE_TYPE1_EEXEC_MARK))
500 	    stream_puts(es, "mark ");
501 	stream_puts(es, "currentfile closefile\n");
502 	s_close_filters(&es, s);
503 	lengths[1] = stell(s) - start;
504 	start = stell(s);
505 	if (options & WRITE_TYPE1_EEXEC_PAD) {
506 	    int i;
507 
508 	    for (i = 0; i < 8; ++i)
509 		stream_puts(s, "\n0000000000000000000000000000000000000000000000000000000000000000");
510 	    stream_puts(s, "\ncleartomark\n");
511 	}
512 	lengths[2] = stell(s) - start;
513     } else {
514 	lengths[0] = stell(s) - start;
515 	lengths[1] = lengths[2] = 0;
516     }
517 
518     /* Wrap up. */
519 
520     s_release_param_printer(&rlist);
521     return 0;
522 }
523