1 % $Id: mp.web,v 1.8 2005/08/24 10:54:02 taco Exp $
2 % MetaPost, by John Hobby. Public domain.
4 % Much of this program was copied with permission from MF.web Version 1.9
5 % It interprets a language very similar to D.E. Knuth's METAFONT, but with
6 % changes designed to make it more suitable for PostScript output.
8 % TeX is a trademark of the American Mathematical Society.
9 % METAFONT is a trademark of Addison-Wesley Publishing Company.
10 % PostScript is a trademark of Adobe Systems Incorporated.
12 % Here is TeX material that gets inserted after \input webmac
13 \def\hang{\hangindent 3em\noindent\ignorespaces}
14 \def\textindent#1{\hangindent2.5em\noindent\hbox to2.5em{\hss#1 }\ignorespaces}
17 \def\ph{\hbox{Pascal-H}}
18 \def\psqrt#1{\sqrt{\mathstrut#1}}
20 \def\pct!{{\char`\%}} % percent sign in ordinary text
21 \font\tenlogo=logo10 % font used for the METAFONT logo
23 \def\MF{{\tenlogo META}\-{\tenlogo FONT}}
24 \def\MP{{\tenlogo META}\-{\tenlogo POST}}
25 \def\<#1>{$\langle#1\rangle$}
26 \def\section{\mathhexbox278}
27 \let\swap=\leftrightarrow
28 \def\round{\mathop{\rm round}\nolimits}
29 \mathchardef\vb="026A % synonym for `\|'
30 \def\[#1]{} % from pascal web
31 \def\(#1){} % this is used to make section names sort themselves better
32 \def\9#1{} % this is used for sort keys in the index via @@:sort key}{entry@@>
34 \let\?=\relax % we want to be able to \write a \?
36 \def\title{MetaPost \ps\ output}
37 \def\topofcontents{\hsize 5.5in
38 \vglue -30pt plus 1fil minus 1.5in
39 \def\?##1]{\hbox to 1in{\hfil##1.\ }}
41 \def\botofcontents{\vskip 0pt plus 1fil minus 1.5in}
49 @d print_err(A) mp_print_err(mp,(A))
50 @d negate(A) (A)=-(A) /* change the sign of a variable */
59 #include "mpbasictypes.h"
60 #include "mppstypes.h"
65 @<Static variables in the outer block@>;
69 typedef struct psout_data_struct {
72 typedef struct psout_data_struct * psout_data;
75 @<Exported function headers@>
77 @ @<Exported function headers@>=
78 void mp_backend_initialize (MP mp) ;
79 void mp_backend_free (MP mp) ;
82 @c void mp_backend_initialize (MP mp) {
83 mp->ps = mp_xmalloc(1,sizeof(psout_data_struct));
84 @<Set initial values@>;
86 void mp_backend_free (MP mp) {
87 @<Dealloc variables@>;
96 @* Traditional {psfonts.map} loading.
98 TODO: It is likely that this code can be removed after a few minor tweaks.
100 @ The file |ps_tab_file| gives a table of \TeX\ font names and corresponding
101 PostScript names for fonts that do not have to be downloaded, i.e., fonts that
102 can be used when |internal[prologues]>0|. Each line consists of a \TeX\ name,
103 one or more spaces, a PostScript name, and possibly a space and some other junk.
104 This routine reads the table, updates |font_ps_name| entries starting after
105 |last_ps_fnum|, and sets |last_ps_fnum:=last_fnum|. If the file |ps_tab_file|
106 is missing, we assume that the existing font names are OK and nothing needs to
109 @d ps_tab_name "psfonts.map" /* locates font name translation table */
112 void mp_read_psname_table (MP mp) ;
114 @ @c void mp_read_psname_table (MP mp) {
115 font_number k; /* font for possible name match */
116 unsigned int lmax; /* upper limit on length of name to match */
117 unsigned int j; /* characters left to read before string gets too long */
118 char *s; /* possible font name to match */
119 text_char c=0; /* character being read from |ps_tab_file| */
120 if ( (mp->ps->ps_tab_file = mp_open_file(mp, ps_tab_name, "r", mp_filetype_fontmap)) ) {
121 @<Set |lmax| to the maximum |font_name| length for fonts
122 |last_ps_fnum+1| through |last_fnum|@>;
123 while (! feof(mp->ps->ps_tab_file) ) {
124 @<Read at most |lmax| characters from |ps_tab_file| into string |s|
125 but |goto common_ending| if there is trouble@>;
126 for (k=mp->last_ps_fnum+1;k<=mp->last_fnum;k++) {
127 if ( mp_xstrcmp(s,mp->font_name[k])==0 ) {
128 @<|flush_string(s)|, read in |font_ps_name[k]|, and
129 |goto common_ending|@>;
134 c = fgetc(mp->ps->ps_tab_file);
136 c = fgetc(mp->ps->ps_tab_file);
138 ungetc(c,mp->ps->ps_tab_file);
141 mp->last_ps_fnum=mp->last_fnum;
142 fclose(mp->ps->ps_tab_file);
147 FILE * ps_tab_file; /* file for font name translation table */
149 @ @<Set |lmax| to the maximum |font_name| length for fonts...@>=
151 for (k=mp->last_ps_fnum+1;k<=mp->last_fnum;k++) {
152 if (strlen(mp->font_name[k])>lmax )
153 lmax=strlen(mp->font_name[k]);
156 @ If we encounter the end of line before we have started reading
157 characters from |ps_tab_file|, we have found an entirely blank
158 line and we skip over it. Otherwise, we abort if the line ends
159 prematurely. If we encounter a comment character, we also skip
160 over the line, since recent versions of \.{dvips} allow comments
161 in the font map file.
163 TODO: this is probably not safe in the case of a really
164 broken font map file.
166 @<Read at most |lmax| characters from |ps_tab_file| into string |s|...@>=
167 s=mp_xmalloc(lmax+1,1);
170 if (c == '\n' || c == '\r' ) {
172 mp_xfree(s); s=NULL; goto COMMON_ENDING;
174 mp_fatal_error(mp, "The psfont map file is bad!");
177 c = fgetc(mp->ps->ps_tab_file);
178 if (c=='%' || c=='*' || c==';' || c=='#' ) {
179 mp_xfree(s); s=NULL; goto COMMON_ENDING;
181 if (c==' ' || c=='\t') break;
183 s[j++] = mp->xord[c];
185 mp_xfree(s); s=NULL; goto COMMON_ENDING;
190 @ PostScript font names should be at most 28 characters long but we allow 32
193 @<|flush_string(s)|, read in |font_ps_name[k]|, and...@>=
198 if (c=='\n' || c == '\r')
199 mp_fatal_error(mp, "The psfont map file is bad!");
200 c = fgetc(mp->ps->ps_tab_file);
201 } while (c==' ' || c=='\t');
202 ps_name = mp_xmalloc(33,1);
206 mp_fatal_error(mp, "The psfont map file is bad!");
208 ps_name[j++] = mp->xord[c];
209 if (c=='\n' || c == '\r')
212 c = fgetc(mp->ps->ps_tab_file);
213 } while (c != ' ' && c != '\t');
215 mp_xfree(mp->font_ps_name[k]);
216 mp->font_ps_name[k]=ps_name;
222 @* \[44a] Dealing with font encodings.
224 First, here are a few helpers for parsing files
226 @d check_buf(size, buf_size)
227 if ((unsigned)(size) > (unsigned)(buf_size)) {
229 snprintf(s,128,"buffer overflow: (%d,%d) at file %s, line %d",
230 size,buf_size, __FILE__, __LINE__ );
231 mp_fatal_error(mp,s);
234 @d append_char_to_buf(c, p, buf, buf_size) do {
237 if (c == 13 || c == EOF)
239 if (c != ' ' || (p > buf && p[-1] != 32)) {
240 check_buf(p - buf + 1, (buf_size));
245 @d append_eol(p, buf, buf_size) do {
246 check_buf(p - buf + 2, (buf_size));
247 if (p - buf > 1 && p[-1] != 10)
249 if (p - buf > 2 && p[-2] == 32) {
256 @d remove_eol(p, buf) do {
262 @d skip(p, c) if (*p == c) p++
263 @d strend(s) strchr(s, 0)
264 @d str_prefix(s1, s2) (strncmp((s1), (s2), strlen(s2)) == 0)
269 boolean loaded; /* the encoding has been loaded? */
270 char *file_name; /* encoding file name */
271 char *enc_name; /* encoding true name */
272 integer objnum; /* object number */
274 integer tounicode; /* object number of associated ToUnicode entry */
284 #define ENC_BUF_SIZE 0x1000
285 char enc_line[ENC_BUF_SIZE];
289 @d enc_getchar() getc(mp->ps->enc_file)
290 @d enc_eof() feof(mp->ps->enc_file)
291 @d enc_close() fclose(mp->ps->enc_file)
294 boolean mp_enc_open (MP mp, char *n) {
295 mp->ps->enc_file=mp_open_file(mp, n, "rb", mp_filetype_encoding);
296 if (mp->ps->enc_file!=NULL)
301 void mp_enc_getline (MP mp) {
306 print_err("unexpected end of file");
309 p = mp->ps->enc_line;
312 append_char_to_buf (c, p, mp->ps->enc_line, ENC_BUF_SIZE);
314 append_eol (p, mp->ps->enc_line, ENC_BUF_SIZE);
315 if (p - mp->ps->enc_line < 2 || *mp->ps->enc_line == '%')
318 void mp_load_enc (MP mp, char *enc_name,
319 char **enc_encname, char **glyph_names){
320 char buf[ENC_BUF_SIZE], *p, *r;
323 int save_selector = mp->selector;
324 if (!mp_enc_open (mp,enc_name)) {
325 mp_print (mp,"cannot open encoding file for reading");
328 mp_normalize_selector(mp);
330 mp_print (mp, enc_name);
332 if (*mp->ps->enc_line != '/' || (r = strchr (mp->ps->enc_line, '[')) == NULL) {
333 remove_eol (r, mp->ps->enc_line);
334 print_err ("invalid encoding vector (a name or `[' missing): `");
335 mp_print(mp,mp->ps->enc_line);
339 while (*(r-1)==' ') r--; /* strip trailing spaces from encoding name */
340 myname = mp_xmalloc(r-mp->ps->enc_line,1);
341 memcpy(myname,mp->ps->enc_line+1,(r-mp->ps->enc_line)-1);
342 *(myname+(r-mp->ps->enc_line-1))=0;
343 *enc_encname = myname;
351 *r != ' ' && *r != 10 && *r != ']' && *r != '/'; *p++ = *r++);
354 if (names_count > 256) {
355 print_err ("encoding vector contains more than 256 names");
358 if (mp_xstrcmp (buf, notdef) != 0)
359 glyph_names[names_count] = mp_xstrdup (buf);
362 if (*r != 10 && *r != '%') {
363 if (str_prefix (r, "] def"))
366 remove_eol (r, mp->ps->enc_line);
368 ("invalid encoding vector: a name or `] def' expected: `");
369 mp_print(mp,mp->ps->enc_line);
375 r = mp->ps->enc_line;
380 mp->selector = save_selector;
382 void mp_read_enc (MP mp, enc_entry * e) {
386 mp_load_enc (mp,e->file_name, &e->enc_name, e->glyph_names);
390 @ |write_enc| is used to write either external encoding (given in map file) or
391 internal encoding (read from the font file); when |glyph_names| is NULL
392 the 2nd argument is a pointer to the encoding entry; otherwise the 3rd is
393 the object number of the Encoding object
396 void mp_write_enc (MP mp, char **glyph_names, enc_entry * e) {
401 if (glyph_names == NULL) {
402 if (e->objnum != 0) /* the encoding has been written already */
410 mp_print(mp,"\n%%%%BeginResource: encoding ");
411 mp_print(mp, e->enc_name);
413 mp_print(mp, e->enc_name);
415 foffset = strlen(e->file_name)+3;
416 for (i = 0; i < 256; i++) {
418 if (s+1+foffset>=80) {
423 mp_print_char(mp,'/');
425 mp_print_char(mp,' ');
429 mp_print_nl (mp,"] def\n");
430 mp_print(mp,"%%%%EndResource");
434 @ All encoding entries go into AVL tree for fast search by name.
437 struct avl_table *enc_tree;
439 @ Memory management functions for avl
441 @<Static variables in the outer block@>=
442 static const char notdef[] = ".notdef";
445 static void *avl_xmalloc (struct libavl_allocator *allocator, size_t size);
446 static void avl_xfree (struct libavl_allocator *allocator, void *block);
449 static void *avl_xmalloc (struct libavl_allocator *allocator, size_t size) {
451 return mp_xmalloc (size,1);
453 static void avl_xfree (struct libavl_allocator *allocator, void *block) {
459 struct libavl_allocator avl_xallocator;
461 @ @<Set initial...@>=
462 mp->ps->avl_xallocator.libavl_malloc=avl_xmalloc;
463 mp->ps->avl_xallocator.libavl_free= avl_xfree;
464 mp->ps->enc_tree = NULL;
467 static int comp_enc_entry (const void *pa, const void *pb, void *p) {
469 return strcmp (((const enc_entry *) pa)->file_name,
470 ((const enc_entry *) pb)->file_name);
472 enc_entry * mp_add_enc (MP mp, char *s) {
476 if (mp->ps->enc_tree == NULL) {
477 mp->ps->enc_tree = avl_create (comp_enc_entry, NULL, &mp->ps->avl_xallocator);
480 p = (enc_entry *) avl_find (mp->ps->enc_tree, &tmp);
481 if (p != NULL) /* encoding already registered */
483 p = mp_xmalloc (1,sizeof (enc_entry));
485 p->file_name = mp_xstrdup (s);
488 p->glyph_names = mp_xmalloc (256,sizeof (char *));
489 for (i = 0; i < 256; i++)
490 p->glyph_names[i] = (char *) notdef;
491 aa = avl_probe (mp->ps->enc_tree, p);
498 static void mp_destroy_enc_entry (void *pa, void *pb) {
502 p = (enc_entry *) pa;
504 mp_xfree (p->file_name);
505 if (p->glyph_names != NULL)
506 for (i = 0; i < 256; i++)
507 if (p->glyph_names[i] != notdef)
508 mp_xfree (p->glyph_names[i]);
509 mp_xfree (p->glyph_names);
514 static void enc_free (MP mp);
516 @ @c static void enc_free (MP mp) {
517 if (mp->ps->enc_tree != NULL)
518 avl_destroy (mp->ps->enc_tree, mp_destroy_enc_entry);
521 @ @<Exported function headers@>=
522 void mp_load_encodings (MP mp, int lastfnum) ;
523 void mp_font_encodings (MP mp, int lastfnum, int encodings_only) ;
525 @ @c void mp_load_encodings (MP mp, int lastfnum) {
529 for (f=null_font+1;f<=lastfnum;f++) {
530 if (mp_has_font_size(mp,f) && mp_has_fm_entry (mp,f,&fm_cur)) {
531 if (fm_cur != NULL &&
532 fm_cur->ps_name != NULL &&
533 is_reencoded (fm_cur)) {
534 e = fm_cur->encoding;
540 void mp_font_encodings (MP mp, int lastfnum, int encodings_only) {
544 for (f=null_font+1;f<=lastfnum;f++) {
545 if (mp_has_font_size(mp,f) && mp_has_fm_entry (mp,f, &fm)) {
546 if (fm != NULL && (fm->ps_name != NULL)) {
547 if (is_reencoded (fm)) {
548 if (encodings_only || (!is_subsetted (fm))) {
550 mp_write_enc (mp,NULL, e);
551 /* clear for next run */
560 @* \[44b] Parsing font map files.
568 @d fm_close() fclose(mp->ps->fm_file)
569 @d fm_getchar() fgetc(mp->ps->fm_file)
570 @d fm_eof() feof(mp->ps->fm_file)
573 enum _mode { FM_DUPIGNORE, FM_REPLACE, FM_DELETE };
574 enum _ltype { MAPFILE, MAPLINE };
575 enum _tfmavail { TFM_UNCHECKED, TFM_FOUND, TFM_NOTFOUND };
576 typedef struct mitem {
577 int mode; /* |FM_DUPIGNORE| or |FM_REPLACE| or |FM_DELETE| */
578 int type; /* map file or map line */
579 char *map_line; /* pointer to map file name or map line */
580 int lineno; /* line number in map file */
586 fm_entry *loaded_tfm_found;
587 fm_entry *avail_tfm_found;
588 fm_entry *non_tfm_found;
589 fm_entry *not_avail_tfm_found;
591 @ @<Set initial...@>=
592 mp->ps->mitem = NULL;
595 static const char nontfm[] = "<nontfm>";
598 @d read_field(r, q, buf) do {
600 while (*r != ' ' && *r != '\0')
608 fm->F = mp_xstrdup(buf);
620 static fm_entry *new_fm_entry (void) {
622 fm = mp_xmalloc (1,sizeof(fm_entry));
627 fm->subset_tag = NULL;
629 fm->tfm_num = null_font;
630 fm->tfm_avail = TFM_UNCHECKED;
638 fm->all_glyphs = false;
645 static void delete_fm_entry (fm_entry * fm) {
646 mp_xfree (fm->tfm_name);
647 mp_xfree (fm->ps_name);
648 mp_xfree (fm->ff_name);
649 mp_xfree (fm->subset_tag);
650 mp_xfree (fm->charset);
654 static ff_entry *new_ff_entry (void) {
656 ff = mp_xmalloc (1,sizeof(ff_entry));
662 static void delete_ff_entry (ff_entry * ff) {
663 mp_xfree (ff->ff_name);
664 mp_xfree (ff->ff_path);
668 static char *mk_base_tfm (MP mp, char *tfmname, int *i) {
669 static char buf[SMALL_BUF_SIZE];
670 char *p = tfmname, *r = strend (p) - 1, *q = r;
671 while (q > p && isdigit (*q))
673 if (!(q > p) || q == r || (*q != '+' && *q != '-'))
675 check_buf (q - p + 1, SMALL_BUF_SIZE);
676 strncpy (buf, p, (size_t) (q - p));
682 @ @<Exported function headers@>=
683 boolean mp_has_fm_entry (MP mp,font_number f, fm_entry **fm);
686 boolean mp_has_fm_entry (MP mp,font_number f, fm_entry **fm) {
687 fm_entry *res = NULL;
688 res = mp_fm_lookup (mp, f);
692 return (res != NULL);
696 struct avl_table *tfm_tree;
697 struct avl_table *ps_tree;
698 struct avl_table *ff_tree;
700 @ @<Set initial...@>=
701 mp->ps->tfm_tree = NULL;
702 mp->ps->ps_tree = NULL;
703 mp->ps->ff_tree = NULL;
705 @ AVL sort |fm_entry| into |tfm_tree| by |tfm_name |
708 static int comp_fm_entry_tfm (const void *pa, const void *pb, void *p) {
710 return strcmp (((const fm_entry *) pa)->tfm_name,
711 ((const fm_entry *) pb)->tfm_name);
714 @ AVL sort |fm_entry| into |ps_tree| by |ps_name|, |slant|, and |extend|
716 @c static int comp_fm_entry_ps (const void *pa, const void *pb, void *p) {
718 const fm_entry *p1 = (const fm_entry *) pa, *p2 = (const fm_entry *) pb;
720 assert (p1->ps_name != NULL && p2->ps_name != NULL);
721 if ((i = strcmp (p1->ps_name, p2->ps_name)))
723 cmp_return (p1->slant, p2->slant);
724 cmp_return (p1->extend, p2->extend);
725 if (p1->tfm_name != NULL && p2->tfm_name != NULL &&
726 (i = strcmp (p1->tfm_name, p2->tfm_name)))
731 @ AVL sort |ff_entry| into |ff_tree| by |ff_name|
733 @c static int comp_ff_entry (const void *pa, const void *pb, void *p) {
735 return strcmp (((const ff_entry *) pa)->ff_name,
736 ((const ff_entry *) pb)->ff_name);
739 @ @c static void create_avl_trees (MP mp) {
740 if (mp->ps->tfm_tree == NULL) {
741 mp->ps->tfm_tree = avl_create (comp_fm_entry_tfm, NULL, &mp->ps->avl_xallocator);
742 assert (mp->ps->tfm_tree != NULL);
744 if (mp->ps->ps_tree == NULL) {
745 mp->ps->ps_tree = avl_create (comp_fm_entry_ps, NULL, &mp->ps->avl_xallocator);
746 assert (mp->ps->ps_tree != NULL);
748 if (mp->ps->ff_tree == NULL) {
749 mp->ps->ff_tree = avl_create (comp_ff_entry, NULL, &mp->ps->avl_xallocator);
750 assert (mp->ps->ff_tree != NULL);
754 @ The function |avl_do_entry| is not completely symmetrical with regards
755 to |tfm_name| and |ps_name handling|, e. g. a duplicate |tfm_name| gives a
756 |goto exit|, and no |ps_name| link is tried. This is to keep it compatible
757 with the original version.
761 @d set_tfmlink(fm) ((fm)->links |= LINK_TFM)
762 @d set_pslink(fm) ((fm)->links |= LINK_PS)
763 @d unset_tfmlink(fm) ((fm)->links &= ~LINK_TFM)
764 @d unset_pslink(fm) ((fm)->links &= ~LINK_PS)
765 @d has_tfmlink(fm) ((fm)->links & LINK_TFM)
766 @d has_pslink(fm) ((fm)->links & LINK_PS)
769 static int avl_do_entry (MP mp, fm_entry * fp, int mode) {
775 /* handle |tfm_name| link */
777 if (strcmp (fp->tfm_name, nontfm)) {
778 p = (fm_entry *) avl_find (mp->ps->tfm_tree, fp);
780 if (mode == FM_DUPIGNORE) {
781 snprintf(s,128,"fontmap entry for `%s' already exists, duplicates ignored",
785 } else { /* mode == |FM_REPLACE| / |FM_DELETE| */
786 if (mp_has_font_size(mp,p->tfm_num)) {
788 "fontmap entry for `%s' has been used, replace/delete not allowed",
793 a = avl_delete (mp->ps->tfm_tree, p);
800 if (mode != FM_DELETE) {
801 aa = avl_probe (mp->ps->tfm_tree, fp);
807 /* handle |ps_name| link */
809 if (fp->ps_name != NULL) {
810 assert (fp->tfm_name != NULL);
811 p = (fm_entry *) avl_find (mp->ps->ps_tree, fp);
813 if (mode == FM_DUPIGNORE) {
815 "ps_name entry for `%s' already exists, duplicates ignored",
819 } else { /* mode == |FM_REPLACE| / |FM_DELETE| */
820 if (mp_has_font_size(mp,p->tfm_num)) {
821 /* REPLACE/DELETE not allowed */
823 "fontmap entry for `%s' has been used, replace/delete not allowed",
828 a = avl_delete (mp->ps->ps_tree, p);
831 if (!has_tfmlink (p))
835 if (mode != FM_DELETE) {
836 aa = avl_probe (mp->ps->ps_tree, fp);
842 if (!has_tfmlink (fp) && !has_pslink (fp)) /* e. g. after |FM_DELETE| */
843 return 1; /* deallocation of |fm_entry| structure required */
848 @ consistency check for map entry, with warn flag
851 static int check_fm_entry (MP mp, fm_entry * fm, boolean warn) {
855 if (fm->ps_name != NULL) {
856 if (is_basefont (fm)) {
857 if (is_fontfile (fm) && !is_included (fm)) {
859 snprintf(s,128, "invalid entry for `%s': "
860 "font file must be included or omitted for base fonts",
866 } else { /* not a base font */
867 /* if no font file given, drop this entry */
868 /* |if (!is_fontfile (fm)) {
871 "invalid entry for `%s': font file missing",
880 if (is_truetype (fm) && is_reencoded (fm) && !is_subsetted (fm)) {
883 "invalid entry for `%s': only subsetted TrueType font can be reencoded",
889 if ((fm->slant != 0 || fm->extend != 0) &&
890 (is_truetype (fm))) {
893 "invalid entry for `%s': "
894 "SlantFont/ExtendFont can be used only with embedded T1 fonts",
900 if (abs (fm->slant) > 1000) {
903 "invalid entry for `%s': too big value of SlantFont (%g)",
904 fm->tfm_name, fm->slant / 1000.0);
909 if (abs (fm->extend) > 2000) {
912 "invalid entry for `%s': too big value of ExtendFont (%g)",
913 fm->tfm_name, fm->extend / 1000.0);
919 !(is_truetype (fm) && is_included (fm) &&
920 is_subsetted (fm) && !is_reencoded (fm))) {
923 "invalid entry for `%s': "
924 "PidEid can be used only with subsetted non-reencoded TrueType fonts",
933 @ returns true if s is one of the 14 std. font names; speed-trimmed.
935 @c static boolean check_basefont (char *s) {
936 static const char *basefont_names[] = {
938 "Courier-Bold", /* 1:12 */
939 "Courier-Oblique", /* 2:15 */
940 "Courier-BoldOblique", /* 3:19 */
941 "Helvetica", /* 4:9 */
942 "Helvetica-Bold", /* 5:14 */
943 "Helvetica-Oblique", /* 6:17 */
944 "Helvetica-BoldOblique", /* 7:21 */
946 "Times-Roman", /* 9:11 */
947 "Times-Bold", /* 10:10 */
948 "Times-Italic", /* 11:12 */
949 "Times-BoldItalic", /* 12:16 */
950 "ZapfDingbats" /* 13:12 */
952 static const int Index[] =
953 { -1, -1, -1, -1, -1, -1, 8, 0, -1, 4, 10, 9, -1, -1, 5, 2, 12, 6,
956 const size_t n = strlen (s);
960 if (n == 12) { /* three names have length 12 */
963 k = 1; /* Courier-Bold */
966 k = 11; /* Times-Italic */
969 k = 13; /* ZapfDingbats */
976 if (k > -1 && !strcmp (basefont_names[k], s))
982 @d is_cfg_comment(c) (c == 10 || c == '*' || c == '#' || c == ';' || c == '%')
984 @c static void fm_scan_line (MP mp) {
985 int a, b, c, j, u = 0, v = 0;
988 char fm_line[FM_BUF_SIZE], buf[FM_BUF_SIZE];
991 switch (mp->ps->mitem->type) {
996 append_char_to_buf (c, p, fm_line, FM_BUF_SIZE);
1003 r = mp->ps->mitem->map_line;
1008 if (*r == '\0' || is_cfg_comment (*r))
1010 fm = new_fm_entry ();
1011 read_field (r, q, buf);
1012 set_field (tfm_name);
1014 read_field (r, q, buf);
1015 if (*buf != '<' && *buf != '"')
1016 set_field (ps_name);
1018 r = p; /* unget the field */
1019 if (isdigit (*r)) { /* font flags given */
1020 fm->flags = atoi (r);
1021 while (isdigit (*r))
1024 while (1) { /* loop through "specials", encoding, font file */
1029 case '"': /* opening quote */
1034 if (sscanf (r, "%f %n", &d, &j) > 0) {
1035 s = r + j; /* jump behind number, eat also blanks, if any */
1036 if (*(s - 1) == 'E' || *(s - 1) == 'e')
1037 s--; /* e. g. 0.5ExtendFont: \%f = 0.5E */
1038 if (str_prefix (s, "SlantFont")) {
1039 d *= 1000.0; /* correct rounding also for neg. numbers */
1040 fm->slant = (integer) (d > 0 ? d + 0.5 : d - 0.5);
1041 r = s + strlen ("SlantFont");
1042 } else if (str_prefix (s, "ExtendFont")) {
1044 fm->extend = (integer) (d > 0 ? d + 0.5 : d - 0.5);
1045 if (fm->extend == 1000)
1047 r = s + strlen ("ExtendFont");
1048 } else { /* unknown name */
1050 *r != ' ' && *r != '"' && *r != '\0';
1051 r++); /* jump over name */
1052 c = *r; /* remember char for temporary end of string */
1054 snprintf(warn_s,128,
1055 "invalid entry for `%s': unknown name `%s' ignored",
1061 for (; *r != ' ' && *r != '"' && *r != '\0'; r++);
1064 if (*r == '"') /* closing quote */
1067 snprintf(warn_s,128,
1068 "invalid entry for `%s': closing quote missing",
1074 case 'P': /* handle cases for subfonts like 'PidEid=3,1' */
1075 if (sscanf (r, "PidEid=%i, %i %n", &a, &b, &c) >= 2) {
1081 default: /* encoding or font file specification */
1085 if (*r == '<' || *r == '[')
1088 read_field (r, q, buf);
1089 /* encoding, formats: '8r.enc' or '<8r.enc' or '<[8r.enc' */
1090 if (strlen (buf) > 4 && strcasecmp (strend (buf) - 4, ".enc") == 0) {
1091 fm->encoding = mp_add_enc (mp, buf);
1092 u = v = 0; /* u, v used if intervening blank: "<< foo" */
1093 } else if (strlen (buf) > 0) { /* file name given */
1094 /* font file, formats:
1095 * subsetting: '<cmr10.pfa'
1096 * no subsetting: '<<cmr10.pfa'
1097 * no embedding: 'cmr10.pfa'
1099 if (a == '<' || u == '<') {
1101 if ((a == '<' && b == 0) || (a == 0 && v == 0))
1103 /* otherwise b == '<' (or '[') => no subsetting */
1105 set_field (ff_name);
1114 if (fm->ps_name != NULL && check_basefont (fm->ps_name))
1116 if (is_fontfile (fm)
1117 && strcasecmp (strend (fm_fontfile (fm)) - 4, ".ttf") == 0)
1119 if (check_fm_entry (mp,fm, true) != 0)
1122 Until here the map line has been completely scanned without errors;
1123 fm points to a valid, freshly filled-out |fm_entry| structure.
1124 Now follows the actual work of registering/deleting.
1126 if (avl_do_entry (mp, fm, mp->ps->mitem->mode) == 0) /* if success */
1129 delete_fm_entry (fm);
1133 @c static void fm_read_info (MP mp) {
1136 if (mp->ps->tfm_tree == NULL)
1137 create_avl_trees (mp);
1138 if (mp->ps->mitem->map_line == NULL) /* nothing to do */
1140 mp->ps->mitem->lineno = 1;
1141 switch (mp->ps->mitem->type) {
1143 n = mp->ps->mitem->map_line;
1144 mp->ps->fm_file = mp_open_file(mp, n, "r", mp_filetype_fontmap);
1145 if (!mp->ps->fm_file) {
1146 snprintf(s,256,"cannot open font map file %s",n);
1149 int save_selector = mp->selector;
1150 mp_normalize_selector(mp);
1153 while (!fm_eof ()) {
1155 mp->ps->mitem->lineno++;
1159 mp->selector = save_selector;
1160 mp->ps->fm_file = NULL;
1169 mp->ps->mitem->map_line = NULL; /* done with this line */
1174 scaled mp_round_xn_over_d (MP mp, scaled x, integer n, integer d) {
1175 boolean positive; /* was |x>=0|? */
1176 unsigned int t,u; /* intermediate quantities */
1177 integer v; /* intermediate quantities */
1181 negate(x); positive=false;
1184 u=(x / 0100000)*n+(t / 0100000);
1185 v=(u % d)*0100000 + (t % 0100000);
1186 if ( u / d>=0100000 ) mp->arith_error=true;
1187 else u=0100000*(u / d) + (v / d);
1191 return ( positive ? u : -u );
1193 static fm_entry *mk_ex_fm (MP mp, font_number f, fm_entry * basefm, int ex) {
1195 integer e = basefm->extend;
1198 fm = new_fm_entry ();
1199 fm->flags = basefm->flags;
1200 fm->encoding = basefm->encoding;
1201 fm->type = basefm->type;
1202 fm->slant = basefm->slant;
1203 fm->extend = mp_round_xn_over_d (mp, e, 1000 + ex, 1000);
1204 /* modify ExtentFont to simulate expansion */
1205 if (fm->extend == 1000)
1207 fm->tfm_name = mp_xstrdup (mp->font_name[f]);
1208 if (basefm->ps_name != NULL)
1209 fm->ps_name = mp_xstrdup (basefm->ps_name);
1210 fm->ff_name = mp_xstrdup (basefm->ff_name);
1213 fm->tfm_avail = TFM_FOUND;
1214 assert (strcmp (fm->tfm_name, nontfm));
1218 @ @c static void init_fm (fm_entry * fm, font_number f) {
1219 if (fm->tfm_num == null_font ) {
1221 fm->tfm_avail = TFM_FOUND;
1226 fm_entry * mp_fm_lookup (MP mp, font_number f);
1229 fm_entry * mp_fm_lookup (MP mp, font_number f) {
1231 fm_entry *fm, *exfm;
1234 if (mp->ps->tfm_tree == NULL)
1235 fm_read_info (mp); /* only to read default map file */
1236 tfm = mp->font_name[f];
1237 assert (strcmp (tfm, nontfm));
1238 /* Look up for full <tfmname>[+-]<expand> */
1240 fm = (fm_entry *) avl_find (mp->ps->tfm_tree, &tmp);
1243 return (fm_entry *) fm;
1245 tfm = mk_base_tfm (mp, mp->font_name[f], &e);
1246 if (tfm == NULL) /* not an expanded font, nothing to do */
1250 fm = (fm_entry *) avl_find (mp->ps->tfm_tree, &tmp);
1251 if (fm != NULL) { /* found an entry with the base tfm name, e.g. cmr10 */
1252 return (fm_entry *) fm; /* font expansion uses the base font */
1253 /* the following code would be obsolete, as would be |mk_ex_fm| */
1254 if (!is_t1fontfile (fm) || !is_included (fm)) {
1257 "font %s cannot be expanded (not an included Type1 font)", tfm);
1261 exfm = mk_ex_fm (mp, f, fm, e); /* copies all fields from fm except tfm name */
1263 ai = avl_do_entry (mp, exfm, FM_DUPIGNORE);
1265 return (fm_entry *) exfm;
1270 @ Early check whether a font file exists. Used e. g. for replacing fonts
1271 of embedded PDF files: Without font file, the font within the embedded
1272 PDF-file is used. Search tree |ff_tree| is used in 1st instance, as it
1273 may be faster than the |kpse_find_file()|, and |kpse_find_file()| is called
1274 only once per font file name + expansion parameter. This might help
1275 keeping speed, if many PDF pages with same fonts are to be embedded.
1277 The |ff_tree| contains only font files, which are actually needed,
1278 so this tree typically is much smaller than the |tfm_tree| or |ps_tree|.
1281 static ff_entry *check_ff_exist (MP mp, fm_entry * fm) {
1286 assert (fm->ff_name != NULL);
1287 tmp.ff_name = fm->ff_name;
1288 ff = (ff_entry *) avl_find (mp->ps->ff_tree, &tmp);
1289 if (ff == NULL) { /* not yet in database */
1290 ff = new_ff_entry ();
1291 ff->ff_name = mp_xstrdup (fm->ff_name);
1292 ff->ff_path = mp_xstrdup (fm->ff_name);
1293 aa = avl_probe (mp->ps->ff_tree, ff);
1294 assert (aa != NULL);
1300 font_number mp_tfm_lookup (MP mp, char *s, scaled fs) {
1301 /* looks up for a TFM with name |s| loaded at |fs| size; if found then flushes |s| */
1303 if ( fs != 0 ) { /* should not be used! */
1304 for (k = null_font + 1;k<=mp->last_fnum;k++) {
1305 if ( mp_xstrcmp( mp->font_name[k], s) && (mp->font_sizes[k] == fs) ) {
1311 for (k = null_font + 1;k<=mp->last_fnum;k++) {
1312 if ( mp_xstrcmp(mp->font_name[k], s) ) {
1321 @ Process map file given by its name or map line contents. Items not
1322 beginning with [+-=] flush default map file, if it has not yet been
1323 read. Leading blanks and blanks immediately following [+-=] are ignored.
1326 @c void mp_process_map_item (MP mp, char *s, int type) {
1330 s++; /* ignore leading blank */
1332 case '+': /* +mapfile.map, +mapline */
1333 mode = FM_DUPIGNORE; /* insert entry, if it is not duplicate */
1336 case '=': /* =mapfile.map, =mapline */
1337 mode = FM_REPLACE; /* try to replace earlier entry */
1340 case '-': /* -mapfile.map, -mapline */
1341 mode = FM_DELETE; /* try to delete entry */
1345 mode = FM_DUPIGNORE; /* like +, but also: */
1346 mp->ps->mitem->map_line = NULL; /* flush default map file name */
1349 s++; /* ignore blank after [+-=] */
1350 p = s; /* map item starts here */
1352 case MAPFILE: /* remove blank at end */
1353 while (*p != '\0' && *p != ' ')
1357 case MAPLINE: /* blank at end allowed */
1362 if (mp->ps->mitem->map_line != NULL) /* read default map file first */
1364 if (*s != '\0') { /* only if real item to process */
1365 mp->ps->mitem->mode = mode;
1366 mp->ps->mitem->type = type;
1367 mp->ps->mitem->map_line = s;
1372 @ @<Exported function headers@>=
1373 void mp_map_file (MP mp, str_number t);
1374 void mp_map_line (MP mp, str_number t);
1375 void mp_init_map_file (MP mp, int is_troff);
1378 void mp_map_file (MP mp, str_number t) {
1379 char *s = mp_xstrdup(mp_str (mp,t));
1380 mp_process_map_item (mp, s, MAPFILE);
1383 void mp_map_line (MP mp, str_number t) {
1384 char *s = mp_xstrdup(mp_str (mp,t));
1385 mp_process_map_item (mp, s, MAPLINE);
1390 @c void mp_init_map_file (MP mp, int is_troff) {
1392 mp->ps->mitem = mp_xmalloc (1,sizeof(mapitem));
1393 mp->ps->mitem->mode = FM_DUPIGNORE;
1394 mp->ps->mitem->type = MAPFILE;
1395 mp->ps->mitem->map_line = NULL;
1396 if ((mp->find_file)("mpost.map", "rb", mp_filetype_fontmap) != NULL) {
1397 mp->ps->mitem->map_line = mp_xstrdup ("mpost.map");
1400 mp->ps->mitem->map_line = mp_xstrdup ("troff.map");
1402 mp->ps->mitem->map_line = mp_xstrdup ("pdftex.map");
1407 @ @<Dealloc variables@>=
1408 if (mp->ps->mitem!=NULL) {
1409 mp_xfree(mp->ps->mitem->map_line);
1410 mp_xfree(mp->ps->mitem);
1416 static void destroy_fm_entry_tfm (void *pa, void *pb) {
1419 fm = (fm_entry *) pa;
1420 if (!has_pslink (fm))
1421 delete_fm_entry (fm);
1425 static void destroy_fm_entry_ps (void *pa, void *pb) {
1428 fm = (fm_entry *) pa;
1429 if (!has_tfmlink (fm))
1430 delete_fm_entry (fm);
1434 static void destroy_ff_entry (void *pa, void *pb) {
1437 ff = (ff_entry *) pa;
1438 delete_ff_entry (ff);
1442 static void fm_free (MP mp);
1445 static void fm_free (MP mp) {
1446 if (mp->ps->tfm_tree != NULL)
1447 avl_destroy (mp->ps->tfm_tree, destroy_fm_entry_tfm);
1448 if (mp->ps->ps_tree != NULL)
1449 avl_destroy (mp->ps->ps_tree, destroy_fm_entry_ps);
1450 if (mp->ps->ff_tree != NULL)
1451 avl_destroy (mp->ps->ff_tree, destroy_ff_entry);
1454 @* \[44c] Helper functions for Type1 fonts.
1457 typedef char char_entry;
1458 typedef unsigned char Byte;
1462 char_entry *char_ptr, *char_array;
1464 char *job_id_string;
1466 @ @<Set initial...@>=
1467 mp->ps->char_array = NULL;
1468 mp->ps->job_id_string = NULL;
1471 @d SMALL_ARRAY_SIZE 256
1475 void mp_set_job_id (MP mp, int year, int month, int day, int time) {
1476 char *name_string, *format_string, *s;
1479 if (mp->ps->job_id_string != NULL)
1481 if ( mp->job_name==NULL )
1482 mp->job_name = mp_xstrdup("mpout");
1483 name_string = mp_xstrdup (mp->job_name);
1484 format_string = mp_xstrdup (mp->mem_ident);
1485 slen = SMALL_BUF_SIZE +
1486 strlen (name_string) +
1487 strlen (format_string);
1488 s = mp_xmalloc (slen, sizeof (char));
1489 i = snprintf (s, slen,
1490 "%.4d/%.2d/%.2d %.2d:%.2d %s %s",
1496 name_string, format_string);
1497 mp->ps->job_id_string = mp_xstrdup (s);
1499 mp_xfree (name_string);
1500 mp_xfree (format_string);
1502 static void fnstr_append (MP mp, const char *s) {
1503 size_t l = strlen (s) + 1;
1504 alloc_array (char, l, SMALL_ARRAY_SIZE);
1505 strcat (mp->ps->char_ptr, s);
1506 mp->ps->char_ptr = strend (mp->ps->char_ptr);
1509 @ @<Exported function headers@>=
1510 void mp_set_job_id (MP mp, int y, int m, int d, int t) ;
1512 @ @<Dealloc variables@>=
1513 mp_xfree(mp->ps->job_id_string);
1515 @ this is not really a true crc32, but it should be just enough to keep
1516 subsets prefixes somewhat disjunct
1519 static unsigned long crc32 (int oldcrc, const Byte *buf, int len) {
1520 unsigned long ret = 0;
1523 ret = (23<<24)+(45<<16)+(67<<8)+89;
1526 ret = (ret<<2)+buf[i];
1529 boolean mp_char_marked (MP mp,font_number f, eight_bits c) {
1530 integer b; /* |char_base[f]| */
1532 if ( (c>=mp->font_bc[f])&&(c<=mp->font_ec[f])&&(mp->font_info[b+c].qqqq.b3!=0) )
1538 static void make_subset_tag (MP mp, fm_entry * fm_cur, char **glyph_names, int tex_font)
1544 if (mp->ps->job_id_string ==NULL)
1545 mp_fatal_error(mp, "no job id!");
1546 l = strlen (mp->ps->job_id_string) + 1;
1548 alloc_array (char, l, SMALL_ARRAY_SIZE);
1549 strcpy (mp->ps->char_array, mp->ps->job_id_string);
1550 mp->ps->char_ptr = strend (mp->ps->char_array);
1551 if (fm_cur->tfm_name != NULL) {
1552 fnstr_append (mp," TFM name: ");
1553 fnstr_append (mp,fm_cur->tfm_name);
1555 fnstr_append (mp," PS name: ");
1556 if (fm_cur->ps_name != NULL)
1557 fnstr_append (mp,fm_cur->ps_name);
1558 fnstr_append (mp," Encoding: ");
1559 if (fm_cur->encoding != NULL && (fm_cur->encoding)->file_name != NULL)
1560 fnstr_append (mp,(fm_cur->encoding)->file_name);
1562 fnstr_append (mp,"built-in");
1563 fnstr_append (mp," CharSet: ");
1564 for (i = 0; i < 256; i++)
1565 if (mp_char_marked (mp,tex_font, i) && glyph_names[i] != notdef) {
1566 if (glyph_names[i]!=NULL) {
1567 fnstr_append (mp,"/");
1568 fnstr_append (mp,glyph_names[i]);
1571 if (fm_cur->charset != NULL) {
1572 fnstr_append (mp," Extra CharSet: ");
1573 fnstr_append (mp, fm_cur->charset);
1575 crc = crc32 (0L, Z_NULL, 0);
1576 crc = crc32 (crc, (Bytef *) mp->ps->char_array, strlen (mp->ps->char_array));
1577 /* we need to fit a 32-bit number into a string of 6 uppercase chars long;
1578 * there are 26 uppercase chars ==> each char represents a number in range
1579 * |0..25|. The maximal number that can be represented by the tag is
1580 * $26^6 - 1$, which is a number between $2^28$ and $2^29$. Thus the bits |29..31|
1581 * of the CRC must be dropped out.
1583 for (i = 0; i < 6; i++) {
1584 tag[i] = 'A' + crc % 26;
1588 fm_cur->subset_tag = mp_xstrdup (tag);
1594 @d external_enc() (fm_cur->encoding)->glyph_names
1595 @d is_used_char(c) mp_char_marked (mp, tex_font, c)
1596 @d end_last_eexec_line()
1597 mp->ps->hexline_length = HEXLINE_WIDTH;
1599 mp->ps->t1_eexec_encrypt = false
1600 @d t1_log(s) mp_print(mp,(char *)s)
1601 @d t1_putchar(c) fputc(c, mp->ps_file)
1602 @d embed_all_glyphs(tex_font) false
1604 @d extra_charset() mp->ps->dvips_extra_charset
1605 @d update_subset_tag()
1606 @d fixedcontent true
1609 #define PRINTF_BUF_SIZE 1024
1610 char *dvips_extra_charset;
1612 unsigned char *grid;
1613 char *ext_glyph_names[256];
1614 char print_buf[PRINTF_BUF_SIZE];
1616 @ @<Set initial ...@>=
1617 mp->ps->dvips_extra_charset=NULL;
1620 @d t1_getchar() fgetc(mp->ps->t1_file)
1621 @d t1_ungetchar(c) ungetc(c, mp->ps->t1_file)
1622 @d t1_eof() feof(mp->ps->t1_file)
1623 @d t1_close() fclose(mp->ps->t1_file)
1624 @d valid_code(c) (c >= 0 && c < 256)
1626 @<Static variables in the outer block@>=
1627 static const char *standard_glyph_names[256] =
1628 { notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1629 notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1630 notdef, notdef, notdef, notdef, notdef, notdef,
1631 notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1632 "space", "exclam", "quotedbl", "numbersign",
1633 "dollar", "percent", "ampersand", "quoteright", "parenleft",
1634 "parenright", "asterisk", "plus", "comma", "hyphen", "period",
1635 "slash", "zero", "one", "two", "three", "four", "five", "six", "seven",
1636 "eight", "nine", "colon", "semicolon", "less",
1637 "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F",
1638 "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q",
1639 "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft",
1640 "backslash", "bracketright", "asciicircum", "underscore",
1641 "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k",
1642 "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v",
1643 "w", "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde",
1644 notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1645 notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1646 notdef, notdef, notdef, notdef, notdef, notdef,
1647 notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1648 notdef, notdef, notdef, "exclamdown", "cent",
1649 "sterling", "fraction", "yen", "florin", "section", "currency",
1650 "quotesingle", "quotedblleft", "guillemotleft",
1651 "guilsinglleft", "guilsinglright", "fi", "fl", notdef, "endash",
1652 "dagger", "daggerdbl", "periodcentered", notdef,
1653 "paragraph", "bullet", "quotesinglbase", "quotedblbase",
1654 "quotedblright", "guillemotright", "ellipsis", "perthousand",
1655 notdef, "questiondown", notdef, "grave", "acute", "circumflex",
1656 "tilde", "macron", "breve", "dotaccent", "dieresis", notdef,
1657 "ring", "cedilla", notdef, "hungarumlaut", "ogonek", "caron", "emdash",
1658 notdef, notdef, notdef, notdef, notdef, notdef,
1659 notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1660 notdef, "AE", notdef, "ordfeminine", notdef, notdef,
1661 notdef, notdef, "Lslash", "Oslash", "OE", "ordmasculine", notdef,
1662 notdef, notdef, notdef, notdef, "ae", notdef, notdef,
1663 notdef, "dotlessi", notdef, notdef, "lslash", "oslash", "oe",
1664 "germandbls", notdef, notdef, notdef, notdef };
1665 static const char charstringname[] = "/CharStrings";
1668 char **t1_glyph_names;
1669 char *t1_builtin_glyph_names[256];
1670 char charsetstr[0x4000];
1671 boolean read_encoding_only;
1675 #define T1_BUF_SIZE 0x10
1679 #define CS_VMOVETO 4
1680 #define CS_RLINETO 5
1681 #define CS_HLINETO 6
1682 #define CS_VLINETO 7
1683 #define CS_RRCURVETO 8
1684 #define CS_CLOSEPATH 9
1685 #define CS_CALLSUBR 10
1686 #define CS_RETURN 11
1687 #define CS_ESCAPE 12
1689 #define CS_ENDCHAR 14
1690 #define CS_RMOVETO 21
1691 #define CS_HMOVETO 22
1692 #define CS_VHCURVETO 30
1693 #define CS_HVCURVETO 31
1694 #define CS_1BYTE_MAX (CS_HVCURVETO + 1)
1696 #define CS_DOTSECTION CS_1BYTE_MAX + 0
1697 #define CS_VSTEM3 CS_1BYTE_MAX + 1
1698 #define CS_HSTEM3 CS_1BYTE_MAX + 2
1699 #define CS_SEAC CS_1BYTE_MAX + 6
1700 #define CS_SBW CS_1BYTE_MAX + 7
1701 #define CS_DIV CS_1BYTE_MAX + 12
1702 #define CS_CALLOTHERSUBR CS_1BYTE_MAX + 16
1703 #define CS_POP CS_1BYTE_MAX + 17
1704 #define CS_SETCURRENTPOINT CS_1BYTE_MAX + 33
1705 #define CS_2BYTE_MAX (CS_SETCURRENTPOINT + 1)
1706 #define CS_MAX CS_2BYTE_MAX
1709 typedef unsigned char byte;
1711 byte nargs; /* number of arguments */
1712 boolean bottom; /* take arguments from bottom of stack? */
1713 boolean clear; /* clear stack? */
1715 } cc_entry; /* CharString Command */
1717 char *glyph_name; /* glyph name (or notdef for Subrs entry) */
1719 unsigned short len; /* length of the whole string */
1720 unsigned short cslen; /* length of the encoded part of the string */
1726 unsigned short t1_dr, t1_er;
1727 unsigned short t1_c1, t1_c2;
1728 unsigned short t1_cslen;
1731 @ @<Set initial...@>=
1732 mp->ps->t1_c1 = 52845;
1733 mp->ps->t1_c2 = 22719;
1736 typedef char t1_line_entry;
1737 typedef char t1_buf_entry;
1740 t1_line_entry *t1_line_ptr, *t1_line_array;
1741 size_t t1_line_limit;
1742 t1_buf_entry *t1_buf_ptr, *t1_buf_array;
1743 size_t t1_buf_limit;
1745 cs_entry *cs_tab, *cs_ptr, *cs_notdef;
1746 char *cs_dict_start, *cs_dict_end;
1747 int cs_count, cs_size, cs_size_pos;
1749 char *subr_array_start, *subr_array_end;
1750 int subr_max, subr_size, subr_size_pos;
1752 @ @<Set initial...@>=
1753 mp->ps->t1_line_array = NULL;
1754 mp->ps->t1_buf_array = NULL;
1757 This list contains the begin/end tokens commonly used in the
1758 /Subrs array of a Type 1 font.
1760 @<Static variables in the outer block@>=
1761 static const char *cs_token_pairs_list[][2] = {
1764 {" RD", "noaccess put"},
1765 {" -|", "noaccess put"},
1770 const char **cs_token_pair;
1771 boolean t1_pfa, t1_cs, t1_scan, t1_eexec_encrypt, t1_synthetic;
1772 int t1_in_eexec; /* 0 before eexec-encrypted, 1 during, 2 after */
1773 long t1_block_length;
1781 @<Set initial ...@>=
1782 mp->ps->hexline_length = HEXLINE_WIDTH;
1785 @d t1_prefix(s) str_prefix(mp->ps->t1_line_array, s)
1786 @d t1_buf_prefix(s) str_prefix(mp->ps->t1_buf_array, s)
1787 @d t1_suffix(s) str_suffix(mp->ps->t1_line_array, mp->ps->t1_line_ptr, s)
1788 @d t1_buf_suffix(s) str_suffix(mp->ps->t1_buf_array, mp->ps->t1_buf_ptr, s)
1789 @d t1_charstrings() strstr(mp->ps->t1_line_array, charstringname)
1790 @d t1_subrs() t1_prefix("/Subrs")
1791 @d t1_end_eexec() t1_suffix("mark currentfile closefile")
1792 @d t1_cleartomark() t1_prefix("cleartomark")
1794 @d isdigit(A) ((A)>='0'&&(A)<='9')
1797 static void end_hexline (MP mp) {
1798 if (mp->ps->hexline_length == HEXLINE_WIDTH) {
1799 fputs ("\n", mp->ps_file);
1800 mp->ps->hexline_length = 0;
1803 static void t1_check_pfa (MP mp) {
1804 const int c = t1_getchar ();
1805 mp->ps->t1_pfa = (c != 128) ? true : false;
1808 static int t1_getbyte (MP mp)
1810 int c = t1_getchar ();
1813 if (mp->ps->t1_block_length == 0) {
1815 mp_fatal_error (mp, "invalid marker");
1822 mp->ps->t1_block_length = t1_getchar () & 0xff;
1823 mp->ps->t1_block_length |= (t1_getchar () & 0xff) << 8;
1824 mp->ps->t1_block_length |= (t1_getchar () & 0xff) << 16;
1825 mp->ps->t1_block_length |= (t1_getchar () & 0xff) << 24;
1828 mp->ps->t1_block_length--;
1831 static int hexval (int c) {
1832 if (c >= 'A' && c <= 'F')
1833 return c - 'A' + 10;
1834 else if (c >= 'a' && c <= 'f')
1835 return c - 'a' + 10;
1836 else if (c >= '0' && c <= '9')
1841 static byte edecrypt (MP mp, byte cipher) {
1843 if (mp->ps->t1_pfa) {
1844 while (cipher == 10 || cipher == 13)
1845 cipher = t1_getbyte (mp);
1846 mp->ps->last_hexbyte = cipher = (hexval (cipher) << 4) + hexval (t1_getbyte (mp));
1848 plain = (cipher ^ (mp->ps->t1_dr >> 8));
1849 mp->ps->t1_dr = (cipher + mp->ps->t1_dr) * mp->ps->t1_c1 + mp->ps->t1_c2;
1852 static byte cdecrypt (MP mp, byte cipher, unsigned short *cr)
1854 const byte plain = (cipher ^ (*cr >> 8));
1855 *cr = (cipher + *cr) * mp->ps->t1_c1 + mp->ps->t1_c2;
1858 static byte eencrypt (MP mp, byte plain)
1860 const byte cipher = (plain ^ (mp->ps->t1_er >> 8));
1861 mp->ps->t1_er = (cipher + mp->ps->t1_er) * mp->ps->t1_c1 + mp->ps->t1_c2;
1865 static byte cencrypt (MP mp, byte plain, unsigned short *cr)
1867 const byte cipher = (plain ^ (*cr >> 8));
1868 *cr = (cipher + *cr) * mp->ps->t1_c1 + mp->ps->t1_c2;
1872 static char *eol (char *s) {
1873 char *p = strend (s);
1874 if (p - s > 1 && p[-1] != 10) {
1880 static float t1_scan_num (MP mp, char *p, char **r)
1885 if (sscanf (p, "%g", &f) != 1) {
1886 remove_eol (p, mp->ps->t1_line_array);
1887 snprintf(s,128, "a number expected: `%s'", mp->ps->t1_line_array);
1888 mp_fatal_error(mp,s);
1891 for (; isdigit (*p) || *p == '.' ||
1892 *p == 'e' || *p == 'E' || *p == '+' || *p == '-'; p++);
1898 static boolean str_suffix (const char *begin_buf, const char *end_buf,
1901 const char *s1 = end_buf - 1, *s2 = strend (s) - 1;
1904 while (s1 >= begin_buf && s2 >= s) {
1913 @d alloc_array(T, n, s) do {
1914 if (mp->ps->T##_array == NULL) {
1915 mp->ps->T##_limit = (s);
1916 if ((unsigned)(n) > mp->ps->T##_limit)
1917 mp->ps->T##_limit = (n);
1918 mp->ps->T##_array = mp_xmalloc (mp->ps->T##_limit,sizeof(T##_entry));
1919 mp->ps->T##_ptr = mp->ps->T##_array;
1921 else if ((unsigned)(mp->ps->T##_ptr - mp->ps->T##_array + (n)) > mp->ps->T##_limit) {
1922 size_t last_ptr_index;
1923 last_ptr_index = mp->ps->T##_ptr - mp->ps->T##_array;
1924 mp->ps->T##_limit *= 2;
1925 if ((unsigned)(mp->ps->T##_ptr - mp->ps->T##_array + (n)) > mp->ps->T##_limit)
1926 mp->ps->T##_limit = mp->ps->T##_ptr - mp->ps->T##_array + (n);
1927 mp->ps->T##_array = mp_xrealloc(mp->ps->T##_array, mp->ps->T##_limit , sizeof (T##_entry));
1928 mp->ps->T##_ptr = mp->ps->T##_array + last_ptr_index;
1932 @d out_eexec_char(A) t1_outhex(mp,(A))
1935 static void t1_outhex (MP mp, byte b)
1937 static char *hexdigits = "0123456789ABCDEF";
1938 t1_putchar (hexdigits[b / 16]);
1939 t1_putchar (hexdigits[b % 16]);
1940 mp->ps->hexline_length += 2;
1943 static void t1_getline (MP mp) {
1944 int c, l, eexec_scan;
1946 static const char eexec_str[] = "currentfile eexec";
1947 static int eexec_len = 17; /* |strlen(eexec_str)| */
1950 mp_fatal_error (mp,"unexpected end of file");
1951 mp->ps->t1_line_ptr = mp->ps->t1_line_array;
1952 alloc_array (t1_line, 1, T1_BUF_SIZE);
1953 mp->ps->t1_cslen = 0;
1955 c = t1_getbyte (mp);
1958 while (!t1_eof ()) {
1959 if (mp->ps->t1_in_eexec == 1)
1960 c = edecrypt (mp,c);
1961 alloc_array (t1_line, 1, T1_BUF_SIZE);
1962 append_char_to_buf (c, mp->ps->t1_line_ptr, mp->ps->t1_line_array, mp->ps->t1_line_limit);
1963 if (mp->ps->t1_in_eexec == 0 && eexec_scan >= 0 && eexec_scan < eexec_len) {
1964 if (mp->ps->t1_line_array[eexec_scan] == eexec_str[eexec_scan])
1969 if (c == 10 || (mp->ps->t1_pfa && eexec_scan == eexec_len && c == 32))
1971 if (mp->ps->t1_cs && mp->ps->t1_cslen == 0 &&
1972 (mp->ps->t1_line_ptr - mp->ps->t1_line_array > 4) &&
1973 (t1_suffix (" RD ") || t1_suffix (" -| "))) {
1974 p = mp->ps->t1_line_ptr - 5;
1977 mp->ps->t1_cslen = l = t1_scan_num (mp, p + 1, 0);
1978 mp->ps->cs_start = mp->ps->t1_line_ptr - mp->ps->t1_line_array;
1979 /* |mp->ps->cs_start| is an index now */
1980 alloc_array (t1_line, l, T1_BUF_SIZE);
1982 *mp->ps->t1_line_ptr++ = edecrypt (mp,t1_getbyte (mp));
1984 c = t1_getbyte (mp);
1986 alloc_array (t1_line, 2, T1_BUF_SIZE); /* |append_eol| can append 2 chars */
1987 append_eol (mp->ps->t1_line_ptr, mp->ps->t1_line_array, mp->ps->t1_line_limit);
1988 if (mp->ps->t1_line_ptr - mp->ps->t1_line_array < 2)
1990 if (eexec_scan == eexec_len)
1991 mp->ps->t1_in_eexec = 1;
1993 /* ensure that |mp->ps->t1_buf_array| has as much room as |t1_line_array| */
1994 mp->ps->t1_buf_ptr = mp->ps->t1_buf_array;
1995 alloc_array (t1_buf, mp->ps->t1_line_limit, mp->ps->t1_line_limit);
1998 static void t1_putline (MP mp)
2000 char *p = mp->ps->t1_line_array;
2001 if (mp->ps->t1_line_ptr - mp->ps->t1_line_array <= 1)
2003 if (mp->ps->t1_eexec_encrypt) {
2004 while (p < mp->ps->t1_line_ptr)
2005 out_eexec_char (eencrypt (mp,*p++));
2007 while (p < mp->ps->t1_line_ptr)
2012 static void t1_puts (MP mp, const char *s)
2014 if (s != mp->ps->t1_line_array)
2015 strcpy (mp->ps->t1_line_array, s);
2016 mp->ps->t1_line_ptr = strend (mp->ps->t1_line_array);
2020 static void t1_printf (MP mp, const char *fmt, ...)
2023 va_start (args, fmt);
2024 vsprintf (mp->ps->t1_line_array, fmt, args);
2025 t1_puts (mp,mp->ps->t1_line_array);
2029 static void t1_init_params (MP mp, char *open_name_prefix,
2030 char *cur_file_name) {
2031 if ((open_name_prefix != NULL) && strlen(open_name_prefix)) {
2032 t1_log (open_name_prefix);
2033 t1_log (cur_file_name);
2035 mp->ps->t1_lenIV = 4;
2036 mp->ps->t1_dr = 55665;
2037 mp->ps->t1_er = 55665;
2038 mp->ps->t1_in_eexec = 0;
2039 mp->ps->t1_cs = false;
2040 mp->ps->t1_scan = true;
2041 mp->ps->t1_synthetic = false;
2042 mp->ps->t1_eexec_encrypt = false;
2043 mp->ps->t1_block_length = 0;
2046 static void t1_close_font_file (MP mp, const char *close_name_suffix) {
2047 if ((close_name_suffix != NULL) && strlen(close_name_suffix)) {
2048 t1_log (close_name_suffix);
2053 static void t1_check_block_len (MP mp, boolean decrypt) {
2056 if (mp->ps->t1_block_length == 0)
2058 c = t1_getbyte (mp);
2060 c = edecrypt (mp,c);
2061 l = mp->ps->t1_block_length;
2062 if (!(l == 0 && (c == 10 || c == 13))) {
2063 snprintf(s,128,"%i bytes more than expected were ignored", l+ 1);
2069 static void t1_start_eexec (MP mp, fm_entry *fm_cur) {
2071 if (!mp->ps->t1_pfa)
2072 t1_check_block_len (mp, false);
2073 for (mp->ps->t1_line_ptr = mp->ps->t1_line_array, i = 0; i < 4; i++) {
2074 edecrypt (mp, t1_getbyte (mp));
2075 *mp->ps->t1_line_ptr++ = 0;
2077 mp->ps->t1_eexec_encrypt = true;
2078 if (!mp->ps->read_encoding_only)
2079 if (is_included (fm_cur))
2080 t1_putline (mp); /* to put the first four bytes */
2082 static void t1_stop_eexec (MP mp) {
2084 end_last_eexec_line ();
2085 if (!mp->ps->t1_pfa)
2086 t1_check_block_len (mp,true);
2088 c = edecrypt (mp, t1_getbyte (mp));
2089 if (!(c == 10 || c == 13)) {
2090 if (mp->ps->last_hexbyte == 0)
2093 mp_warn (mp,"unexpected data after eexec");
2096 mp->ps->t1_cs = false;
2097 mp->ps->t1_in_eexec = 2;
2099 static void t1_modify_fm (MP mp) {
2100 mp->ps->t1_line_ptr = eol (mp->ps->t1_line_array);
2103 static void t1_modify_italic (MP mp) {
2104 mp->ps->t1_line_ptr = eol (mp->ps->t1_line_array);
2109 const char *pdfname;
2119 static key_entry font_keys[FONT_KEYS_NUM] = {
2120 {"Ascent", "Ascender", 0, false},
2121 {"CapHeight", "CapHeight", 0, false},
2122 {"Descent", "Descender", 0, false},
2123 {"FontName", "FontName", 0, false},
2124 {"ItalicAngle", "ItalicAngle", 0, false},
2125 {"StemV", "StdVW", 0, false},
2126 {"XHeight", "XHeight", 0, false},
2127 {"FontBBox", "FontBBox", 0, false},
2139 @d ITALIC_ANGLE_CODE 4
2145 @d FONTBBOX4_CODE 10
2146 @d MAX_KEY_CODE (FONTBBOX1_CODE + 1)
2149 static void t1_scan_keys (MP mp, int tex_font,fm_entry *fm_cur) {
2153 if (fm_extend (fm_cur) != 0 || fm_slant (fm_cur) != 0) {
2154 if (t1_prefix ("/FontMatrix")) {
2158 if (t1_prefix ("/ItalicAngle")) {
2159 t1_modify_italic (mp);
2163 if (t1_prefix ("/FontType")) {
2164 p = mp->ps->t1_line_array + strlen ("FontType") + 1;
2165 if ((i = t1_scan_num (mp,p, 0)) != 1) {
2167 snprintf(s,125,"Type%d fonts unsupported by metapost", i);
2168 mp_fatal_error(mp,s);
2172 for (key = font_keys; key - font_keys < MAX_KEY_CODE; key++)
2173 if (str_prefix (mp->ps->t1_line_array + 1, key->t1name))
2175 if (key - font_keys == MAX_KEY_CODE)
2178 p = mp->ps->t1_line_array + strlen (key->t1name) + 1;
2180 if ((k = key - font_keys) == FONTNAME_CODE) {
2183 remove_eol (p, mp->ps->t1_line_array);
2184 snprintf(s,128,"a name expected: `%s'", mp->ps->t1_line_array);
2185 mp_fatal_error(mp,s);
2187 r = ++p; /* skip the slash */
2188 if (is_included (fm_cur)) {
2189 /* save the fontname */
2190 strncpy (mp->ps->fontname_buf, p, FONTNAME_BUF_SIZE);
2191 for (i=0; mp->ps->fontname_buf[i] != 10; i++);
2192 mp->ps->fontname_buf[i]=0;
2194 if(is_subsetted (fm_cur)) {
2195 if (fm_cur->encoding!=NULL && fm_cur->encoding->glyph_names!=NULL)
2196 make_subset_tag (mp,fm_cur, fm_cur->encoding->glyph_names, tex_font);
2198 make_subset_tag (mp,fm_cur, mp->ps->t1_builtin_glyph_names, tex_font);
2200 alloc_array (t1_line, (r-mp->ps->t1_line_array+6+1+strlen(mp->ps->fontname_buf)+1),
2202 strncpy (r, fm_cur->subset_tag , 6);
2204 strncpy (r+7, mp->ps->fontname_buf, strlen(mp->ps->fontname_buf)+1);
2205 mp->ps->t1_line_ptr = eol (r);
2207 /* |for (q = p; *q != ' ' && *q != 10; *q++);|*/
2209 mp->ps->t1_line_ptr = eol (r);
2214 if ((k == STEMV_CODE || k == FONTBBOX1_CODE)
2215 && (*p == '[' || *p == '{'))
2217 if (k == FONTBBOX1_CODE) {
2218 for (i = 0; i < 4; i++) {
2219 key[i].value = t1_scan_num (mp, p, &r);
2224 key->value = t1_scan_num (mp, p, 0);
2226 static void t1_scan_param (MP mp, int tex_font,fm_entry *fm_cur)
2228 static const char *lenIV = "/lenIV";
2229 if (!mp->ps->t1_scan || *mp->ps->t1_line_array != '/')
2231 if (t1_prefix (lenIV)) {
2232 mp->ps->t1_lenIV = t1_scan_num (mp,mp->ps->t1_line_array + strlen (lenIV), 0);
2235 t1_scan_keys (mp, tex_font,fm_cur);
2237 static void copy_glyph_names (char **glyph_names, int a, int b) {
2238 if (glyph_names[b] != notdef) {
2239 mp_xfree (glyph_names[b]);
2240 glyph_names[b] = (char *) notdef;
2242 if (glyph_names[a] != notdef) {
2243 glyph_names[b] = mp_xstrdup (glyph_names[a]);
2246 static void t1_builtin_enc (MP mp) {
2247 int i, a, b, c, counter = 0;
2250 * At this moment "/Encoding" is the prefix of |mp->ps->t1_line_array|
2252 if (t1_suffix ("def")) { /* predefined encoding */
2253 sscanf (mp->ps->t1_line_array + strlen ("/Encoding"), "%256s", mp->ps->t1_buf_array);
2254 if (strcmp (mp->ps->t1_buf_array, "StandardEncoding") == 0) {
2255 for (i = 0; i < 256; i++)
2256 if (standard_glyph_names[i] == notdef)
2257 mp->ps->t1_builtin_glyph_names[i] = (char *) notdef;
2259 mp->ps->t1_builtin_glyph_names[i] =
2260 mp_xstrdup (standard_glyph_names[i]);
2261 mp->ps->t1_encoding = ENC_STANDARD;
2264 snprintf(s,128, "cannot subset font (unknown predefined encoding `%s')",
2265 mp->ps->t1_buf_array);
2266 mp_fatal_error(mp,s);
2270 mp->ps->t1_encoding = ENC_BUILTIN;
2272 * At this moment "/Encoding" is the prefix of |mp->ps->t1_line_array|, and the encoding is
2273 * not a predefined encoding
2275 * We have two possible forms of Encoding vector. The first case is
2277 * /Encoding [/a /b /c...] readonly def
2279 * and the second case can look like
2281 * /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for
2287 for (i = 0; i < 256; i++)
2288 mp->ps->t1_builtin_glyph_names[i] = (char *) notdef;
2289 if (t1_prefix ("/Encoding [") || t1_prefix ("/Encoding[")) { /* the first case */
2290 r = strchr (mp->ps->t1_line_array, '[') + 1;
2294 for (p = mp->ps->t1_buf_array, r++;
2295 *r != 32 && *r != 10 && *r != ']' && *r != '/';
2299 if (counter > 255) {
2301 (mp, "encoding vector contains more than 256 names");
2303 if (strcmp (mp->ps->t1_buf_array, notdef) != 0)
2304 mp->ps->t1_builtin_glyph_names[counter] = mp_xstrdup (mp->ps->t1_buf_array);
2307 if (*r != 10 && *r != '%') {
2308 if (str_prefix (r, "] def")
2309 || str_prefix (r, "] readonly def"))
2313 remove_eol (r, mp->ps->t1_line_array);
2314 snprintf(s,128,"a name or `] def' or `] readonly def' expected: `%s'",
2315 mp->ps->t1_line_array);
2316 mp_fatal_error(mp,s);
2320 r = mp->ps->t1_line_array;
2322 } else { /* the second case */
2323 p = strchr (mp->ps->t1_line_array, 10);
2327 p = mp->ps->t1_line_array;
2330 check for `dup <index> <glyph> put'
2332 if (sscanf (p, "dup %i%256s put", &i, mp->ps->t1_buf_array) == 2 &&
2333 *mp->ps->t1_buf_array == '/' && valid_code (i)) {
2334 if (strcmp (mp->ps->t1_buf_array + 1, notdef) != 0)
2335 mp->ps->t1_builtin_glyph_names[i] =
2336 mp_xstrdup (mp->ps->t1_buf_array + 1);
2337 p = strstr (p, " put") + strlen (" put");
2341 check for `dup dup <to> exch <from> get put'
2343 else if (sscanf (p, "dup dup %i exch %i get put", &b, &a) == 2
2344 && valid_code (a) && valid_code (b)) {
2345 copy_glyph_names (mp->ps->t1_builtin_glyph_names, a, b);
2346 p = strstr (p, " get put") + strlen (" get put");
2350 check for `dup dup <from> <size> getinterval <to> exch putinterval'
2353 (p, "dup dup %i %i getinterval %i exch putinterval",
2354 &a, &c, &b) == 3 && valid_code (a) && valid_code (b)
2355 && valid_code (c)) {
2356 for (i = 0; i < c; i++)
2357 copy_glyph_names (mp->ps->t1_builtin_glyph_names, a + i, b + i);
2358 p = strstr (p, " putinterval") + strlen (" putinterval");
2362 check for `def' or `readonly def'
2364 else if ((p == mp->ps->t1_line_array || (p > mp->ps->t1_line_array && p[-1] == ' '))
2365 && strcmp (p, "def\n") == 0)
2368 skip an unrecognizable word
2371 while (*p != ' ' && *p != 10)
2379 static void t1_check_end (MP mp) {
2383 if (t1_prefix ("{restore}"))
2389 char *ff_name; /* base name of font file */
2390 char *ff_path; /* full path to font file */
2394 static boolean t1_open_fontfile (MP mp, fm_entry *fm_cur,const char *open_name_prefix) {
2396 ff = check_ff_exist (mp, fm_cur);
2397 if (ff->ff_path != NULL) {
2398 mp->ps->t1_file = mp_open_file(mp,ff->ff_path, "rb", mp_filetype_font);
2400 mp_warn (mp, "cannot open Type 1 font file for reading");
2403 t1_init_params (mp,(char *)open_name_prefix,fm_cur->ff_name);
2404 mp->ps->fontfile_found = true;
2408 static void t1_scan_only (MP mp, int tex_font, fm_entry *fm_cur) {
2411 t1_scan_param (mp,tex_font, fm_cur);
2413 while (mp->ps->t1_in_eexec == 0);
2414 t1_start_eexec (mp,fm_cur);
2417 t1_scan_param (mp,tex_font, fm_cur);
2419 while (!(t1_charstrings () || t1_subrs ()));
2422 static void t1_include (MP mp, int tex_font, fm_entry *fm_cur) {
2425 t1_scan_param (mp,tex_font, fm_cur);
2428 while (mp->ps->t1_in_eexec == 0);
2429 t1_start_eexec (mp,fm_cur);
2432 t1_scan_param (mp,tex_font, fm_cur);
2435 while (!(t1_charstrings () || t1_subrs ()));
2436 mp->ps->t1_cs = true;
2441 while (!t1_end_eexec ());
2443 if (fixedcontent) { /* copy 512 zeros (not needed for PDF) */
2448 while (!t1_cleartomark ());
2449 t1_check_end (mp); /* write "{restore}if" if found */
2454 @d check_subr(SUBR) if (SUBR >= mp->ps->subr_size || SUBR < 0) {
2456 snprintf(s,128,"Subrs array: entry index out of range (%i)",SUBR);
2457 mp_fatal_error(mp,s);
2461 static const char **check_cs_token_pair (MP mp) {
2462 const char **p = (const char **) cs_token_pairs_list;
2463 for (; p[0] != NULL; ++p)
2464 if (t1_buf_prefix (p[0]) && t1_buf_suffix (p[1]))
2469 static void cs_store (MP mp, boolean is_subr) {
2473 for (p = mp->ps->t1_line_array, mp->ps->t1_buf_ptr = mp->ps->t1_buf_array; *p != ' ';
2474 *mp->ps->t1_buf_ptr++ = *p++);
2475 *mp->ps->t1_buf_ptr = 0;
2477 subr = t1_scan_num (mp, p + 1, 0);
2479 ptr = mp->ps->subr_tab + subr;
2481 ptr = mp->ps->cs_ptr++;
2482 if (mp->ps->cs_ptr - mp->ps->cs_tab > mp->ps->cs_size) {
2484 snprintf(s,128,"CharStrings dict: more entries than dict size (%i)",mp->ps->cs_size);
2485 mp_fatal_error(mp,s);
2487 if (strcmp (mp->ps->t1_buf_array + 1, notdef) == 0) /* skip the slash */
2488 ptr->glyph_name = (char *) notdef;
2490 ptr->glyph_name = mp_xstrdup (mp->ps->t1_buf_array + 1);
2492 /* copy " RD " + cs data to |mp->ps->t1_buf_array| */
2493 memcpy (mp->ps->t1_buf_array, mp->ps->t1_line_array + mp->ps->cs_start - 4,
2494 (unsigned) (mp->ps->t1_cslen + 4));
2495 /* copy the end of cs data to |mp->ps->t1_buf_array| */
2496 for (p = mp->ps->t1_line_array + mp->ps->cs_start + mp->ps->t1_cslen, mp->ps->t1_buf_ptr =
2497 mp->ps->t1_buf_array + mp->ps->t1_cslen + 4; *p != 10; *mp->ps->t1_buf_ptr++ = *p++);
2498 *mp->ps->t1_buf_ptr++ = 10;
2499 if (is_subr && mp->ps->cs_token_pair == NULL)
2500 mp->ps->cs_token_pair = check_cs_token_pair (mp);
2501 ptr->len = mp->ps->t1_buf_ptr - mp->ps->t1_buf_array;
2502 ptr->cslen = mp->ps->t1_cslen;
2503 ptr->data = mp_xmalloc (ptr->len , sizeof (byte));
2504 memcpy (ptr->data, mp->ps->t1_buf_array, ptr->len);
2508 #define store_subr(mp) cs_store(mp,true)
2509 #define store_cs(mp) cs_store(mp,false)
2511 #define CC_STACK_SIZE 24
2513 static integer cc_stack[CC_STACK_SIZE], *stack_ptr = cc_stack;
2514 static cc_entry cc_tab[CS_MAX];
2515 static boolean is_cc_init = false;
2519 if (stack_ptr - cc_stack < (N)) \
2523 #define stack_error(N) { \
2525 snprintf(s,255,"CharString: invalid access (%i) to stack (%i entries)", \
2526 (int) N, (int)(stack_ptr - cc_stack)); \
2532 #define cc_get(N) ((N) < 0 ? *(stack_ptr + (N)) : *(cc_stack + (N)))
2534 #define cc_push(V) *stack_ptr++ = V
2535 #define cc_clear() stack_ptr = cc_stack
2537 #define set_cc(N, B, A, C) \
2538 cc_tab[N].nargs = A; \
2539 cc_tab[N].bottom = B; \
2540 cc_tab[N].clear = C; \
2541 cc_tab[N].valid = true
2543 static void cc_init (void) {
2547 for (i = 0; i < CS_MAX; i++)
2548 cc_tab[i].valid = false;
2549 set_cc (CS_HSTEM, true, 2, true);
2550 set_cc (CS_VSTEM, true, 2, true);
2551 set_cc (CS_VMOVETO, true, 1, true);
2552 set_cc (CS_RLINETO, true, 2, true);
2553 set_cc (CS_HLINETO, true, 1, true);
2554 set_cc (CS_VLINETO, true, 1, true);
2555 set_cc (CS_RRCURVETO, true, 6, true);
2556 set_cc (CS_CLOSEPATH, false, 0, true);
2557 set_cc (CS_CALLSUBR, false, 1, false);
2558 set_cc (CS_RETURN, false, 0, false);
2560 |set_cc(CS_ESCAPE, false, 0, false);|
2562 set_cc (CS_HSBW, true, 2, true);
2563 set_cc (CS_ENDCHAR, false, 0, true);
2564 set_cc (CS_RMOVETO, true, 2, true);
2565 set_cc (CS_HMOVETO, true, 1, true);
2566 set_cc (CS_VHCURVETO, true, 4, true);
2567 set_cc (CS_HVCURVETO, true, 4, true);
2568 set_cc (CS_DOTSECTION, false, 0, true);
2569 set_cc (CS_VSTEM3, true, 6, true);
2570 set_cc (CS_HSTEM3, true, 6, true);
2571 set_cc (CS_SEAC, true, 5, true);
2572 set_cc (CS_SBW, true, 4, true);
2573 set_cc (CS_DIV, false, 2, false);
2574 set_cc (CS_CALLOTHERSUBR, false, 0, false);
2575 set_cc (CS_POP, false, 0, false);
2576 set_cc (CS_SETCURRENTPOINT, true, 2, true);
2582 @d cs_getchar(mp) cdecrypt(mp,*data++, &cr)
2584 @d mark_subr(mp,n) cs_mark(mp,0, n)
2585 @d mark_cs(mp,s) cs_mark(mp,s, 0)
2586 @d SMALL_BUF_SIZE 256
2589 static void cs_warn (MP mp, const char *cs_name, int subr, const char *fmt, ...) {
2590 char buf[SMALL_BUF_SIZE];
2593 va_start (args, fmt);
2594 vsprintf (buf, fmt, args);
2596 if (cs_name == NULL) {
2597 snprintf(s,299,"Subr (%i): %s", (int) subr, buf);
2599 snprintf(s,299,"CharString (/%s): %s", cs_name, buf);
2604 static void cs_mark (MP mp, const char *cs_name, int subr)
2610 static integer lastargOtherSubr3 = 3; /* the argument of last call to
2614 if (cs_name == NULL) {
2616 ptr = mp->ps->subr_tab + subr;
2620 if (mp->ps->cs_notdef != NULL &&
2621 (cs_name == notdef || strcmp (cs_name, notdef) == 0))
2622 ptr = mp->ps->cs_notdef;
2624 for (ptr = mp->ps->cs_tab; ptr < mp->ps->cs_ptr; ptr++)
2625 if (strcmp (ptr->glyph_name, cs_name) == 0)
2627 if (ptr == mp->ps->cs_ptr) {
2629 snprintf (s,128,"glyph `%s' undefined", cs_name);
2633 if (ptr->glyph_name == notdef)
2634 mp->ps->cs_notdef = ptr;
2637 /* only marked CharString entries and invalid entries can be skipped;
2638 valid marked subrs must be parsed to keep the stack in sync */
2639 if (!ptr->valid || (ptr->is_used && cs_name != NULL))
2641 ptr->is_used = true;
2643 cs_len = ptr->cslen;
2644 data = ptr->data + 4;
2645 for (i = 0; i < mp->ps->t1_lenIV; i++, cs_len--)
2647 while (cs_len > 0) {
2649 b = cs_getchar (mp);
2653 else if (b <= 250) {
2655 a = ((b - 247) << 8) + 108 + cs_getchar (mp);
2656 } else if (b <= 254) {
2658 a = -((b - 251) << 8) - 108 - cs_getchar (mp);
2661 a = (cs_getchar (mp) & 0xff) << 24;
2662 a |= (cs_getchar (mp) & 0xff) << 16;
2663 a |= (cs_getchar (mp) & 0xff) << 8;
2664 a |= (cs_getchar (mp) & 0xff) << 0;
2665 if (sizeof (integer) > 4 && (a & 0x80000000))
2670 if (b == CS_ESCAPE) {
2671 b = cs_getchar (mp) + CS_1BYTE_MAX;
2675 cs_warn (mp,cs_name, subr, "command value out of range: %i",
2681 cs_warn (mp,cs_name, subr, "command not valid: %i", (int) b);
2685 if (stack_ptr - cc_stack < cc->nargs)
2686 cs_warn (mp,cs_name, subr,
2687 "less arguments on stack (%i) than required (%i)",
2688 (int) (stack_ptr - cc_stack), (int) cc->nargs);
2689 else if (stack_ptr - cc_stack > cc->nargs)
2690 cs_warn (mp,cs_name, subr,
2691 "more arguments on stack (%i) than required (%i)",
2692 (int) (stack_ptr - cc_stack), (int) cc->nargs);
2694 switch (cc - cc_tab) {
2699 if (!mp->ps->subr_tab[a1].valid) {
2700 cs_warn (mp,cs_name, subr, "cannot call subr (%i)", (int) a1);
2708 case CS_CALLOTHERSUBR:
2709 if (cc_get (-1) == 3)
2710 lastargOtherSubr3 = cc_get (-3);
2711 a1 = cc_get (-2) + 2;
2715 cc_push (lastargOtherSubr3);
2716 /* the only case when we care about the value being pushed onto
2717 stack is when POP follows CALLOTHERSUBR (changing hints by
2725 mark_cs (mp,standard_glyph_names[a1]);
2726 mark_cs (mp,standard_glyph_names[a2]);
2735 cs_error: /* an error occured during parsing */
2738 ptr->is_used = false;
2741 static void t1_subset_ascii_part (MP mp, int tex_font, fm_entry *fm_cur)
2745 while (!t1_prefix ("/Encoding")) {
2746 t1_scan_param (mp,tex_font, fm_cur);
2750 t1_builtin_enc (mp);
2751 if (is_reencoded (fm_cur))
2752 mp->ps->t1_glyph_names = external_enc ();
2754 mp->ps->t1_glyph_names = mp->ps->t1_builtin_glyph_names;
2756 |if (is_included (fm_cur) && is_subsetted (fm_cur)) {
2757 make_subset_tag (fm_cur, t1_glyph_names, tex_font);
2758 update_subset_tag ();
2761 if ((!is_subsetted (fm_cur)) && mp->ps->t1_encoding == ENC_STANDARD)
2762 t1_puts (mp,"/Encoding StandardEncoding def\n");
2765 (mp,"/Encoding 256 array\n0 1 255 {1 index exch /.notdef put} for\n");
2766 for (i = 0, j = 0; i < 256; i++) {
2767 if (is_used_char (i) && mp->ps->t1_glyph_names[i] != notdef) {
2769 t1_printf (mp,"dup %i /%s put\n", (int) t1_char (i),
2770 mp->ps->t1_glyph_names[i]);
2773 /* We didn't mark anything for the Encoding array. */
2774 /* We add "dup 0 /.notdef put" for compatibility */
2775 /* with Acrobat 5.0. */
2777 t1_puts (mp,"dup 0 /.notdef put\n");
2778 t1_puts (mp,"readonly def\n");
2782 t1_scan_param (mp,tex_font, fm_cur);
2783 if (!t1_prefix ("/UniqueID")) /* ignore UniqueID for subsetted fonts */
2786 while (mp->ps->t1_in_eexec == 0);
2789 #define t1_subr_flush(mp) t1_flush_cs(mp,true)
2790 #define t1_cs_flush(mp) t1_flush_cs(mp,false)
2792 static void cs_init (MP mp) {
2793 mp->ps->cs_ptr = mp->ps->cs_tab = NULL;
2794 mp->ps->cs_dict_start = mp->ps->cs_dict_end = NULL;
2795 mp->ps->cs_count = mp->ps->cs_size = mp->ps->cs_size_pos = 0;
2796 mp->ps->cs_token_pair = NULL;
2797 mp->ps->subr_tab = NULL;
2798 mp->ps->subr_array_start = mp->ps->subr_array_end = NULL;
2799 mp->ps->subr_max = mp->ps->subr_size = mp->ps->subr_size_pos = 0;
2802 static void init_cs_entry ( cs_entry * cs) {
2804 cs->glyph_name = NULL;
2807 cs->is_used = false;
2811 static void t1_mark_glyphs (MP mp, int tex_font);
2813 static void t1_read_subrs (MP mp, int tex_font, fm_entry *fm_cur)
2818 while (!(t1_charstrings () || t1_subrs ())) {
2819 t1_scan_param (mp,tex_font, fm_cur);
2824 mp->ps->t1_cs = true;
2825 mp->ps->t1_scan = false;
2828 mp->ps->subr_size_pos = strlen ("/Subrs") + 1;
2829 /* |subr_size_pos| points to the number indicating dict size after "/Subrs" */
2830 mp->ps->subr_size = t1_scan_num (mp,mp->ps->t1_line_array + mp->ps->subr_size_pos, 0);
2831 if (mp->ps->subr_size == 0) {
2832 while (!t1_charstrings ())
2836 /* |subr_tab = xtalloc (subr_size, cs_entry);| */
2837 mp->ps->subr_tab = (cs_entry *)mp_xmalloc (mp->ps->subr_size, sizeof (cs_entry));
2838 for (ptr = mp->ps->subr_tab; ptr - mp->ps->subr_tab < mp->ps->subr_size; ptr++)
2839 init_cs_entry (ptr);
2840 mp->ps->subr_array_start = mp_xstrdup (mp->ps->t1_line_array);
2842 while (mp->ps->t1_cslen) {
2846 /* mark the first four entries without parsing */
2847 for (i = 0; i < mp->ps->subr_size && i < 4; i++)
2848 mp->ps->subr_tab[i].is_used = true;
2849 /* the end of the Subrs array might have more than one line so we need to
2850 concatnate them to |subr_array_end|. Unfortunately some fonts don't have
2851 the Subrs array followed by the CharStrings dict immediately (synthetic
2852 fonts). If we cannot find CharStrings in next |POST_SUBRS_SCAN| lines then
2853 we will treat the font as synthetic and ignore everything until next
2856 #define POST_SUBRS_SCAN 5
2858 *mp->ps->t1_buf_array = 0;
2859 for (i = 0; i < POST_SUBRS_SCAN; i++) {
2860 if (t1_charstrings ())
2862 s += mp->ps->t1_line_ptr - mp->ps->t1_line_array;
2863 alloc_array (t1_buf, s, T1_BUF_SIZE);
2864 strcat (mp->ps->t1_buf_array, mp->ps->t1_line_array);
2867 mp->ps->subr_array_end = mp_xstrdup (mp->ps->t1_buf_array);
2868 if (i == POST_SUBRS_SCAN) { /* CharStrings not found;
2869 suppose synthetic font */
2870 for (ptr = mp->ps->subr_tab; ptr - mp->ps->subr_tab < mp->ps->subr_size; ptr++)
2872 mp_xfree (ptr->data);
2873 mp_xfree (mp->ps->subr_tab);
2874 mp_xfree (mp->ps->subr_array_start);
2875 mp_xfree (mp->ps->subr_array_end);
2877 mp->ps->t1_cs = false;
2878 mp->ps->t1_synthetic = true;
2879 while (!(t1_charstrings () || t1_subrs ()))
2886 static void t1_flush_cs (MP mp, boolean is_subr)
2889 byte *r, *return_cs = NULL;
2890 cs_entry *tab, *end_tab, *ptr;
2891 char *start_line, *line_end;
2892 int count, size_pos;
2893 unsigned short cr, cs_len = 0; /* to avoid warning about uninitialized use of |cs_len| */
2895 start_line = mp->ps->subr_array_start;
2896 line_end = mp->ps->subr_array_end;
2897 size_pos = mp->ps->subr_size_pos;
2898 tab = mp->ps->subr_tab;
2899 count = mp->ps->subr_max + 1;
2900 end_tab = mp->ps->subr_tab + count;
2902 start_line = mp->ps->cs_dict_start;
2903 line_end = mp->ps->cs_dict_end;
2904 size_pos = mp->ps->cs_size_pos;
2905 tab = mp->ps->cs_tab;
2906 end_tab = mp->ps->cs_ptr;
2907 count = mp->ps->cs_count;
2909 mp->ps->t1_line_ptr = mp->ps->t1_line_array;
2910 for (p = start_line; p - start_line < size_pos;)
2911 *mp->ps->t1_line_ptr++ = *p++;
2912 while (isdigit (*p))
2914 sprintf (mp->ps->t1_line_ptr, "%u", count);
2915 strcat (mp->ps->t1_line_ptr, p);
2916 mp->ps->t1_line_ptr = eol (mp->ps->t1_line_array);
2919 /* create |return_cs| to replace unsused subr's */
2923 return_cs = mp_xmalloc ( (mp->ps->t1_lenIV + 1) , sizeof(byte));
2924 if ( mp->ps->t1_lenIV > 0) {
2925 for (cs_len = 0, r = return_cs; cs_len < mp->ps->t1_lenIV; cs_len++, r++)
2926 *r = cencrypt (mp,0x00, &cr);
2927 *r = cencrypt (mp,CS_RETURN, &cr);
2929 *return_cs = CS_RETURN;
2934 for (ptr = tab; ptr < end_tab; ptr++) {
2937 sprintf (mp->ps->t1_line_array, "dup %i %u", (int) (ptr - tab),
2940 sprintf (mp->ps->t1_line_array, "/%s %u", ptr->glyph_name, ptr->cslen);
2941 p = strend (mp->ps->t1_line_array);
2942 memcpy (p, ptr->data, ptr->len);
2943 mp->ps->t1_line_ptr = p + ptr->len;
2946 /* replace unsused subr's by |return_cs| */
2948 sprintf (mp->ps->t1_line_array, "dup %i %u%s ", (int) (ptr - tab),
2949 cs_len, mp->ps->cs_token_pair[0]);
2950 p = strend (mp->ps->t1_line_array);
2951 memcpy (p, return_cs, cs_len);
2952 mp->ps->t1_line_ptr = p + cs_len;
2954 sprintf (mp->ps->t1_line_array, " %s", mp->ps->cs_token_pair[1]);
2955 mp->ps->t1_line_ptr = eol (mp->ps->t1_line_array);
2959 mp_xfree (ptr->data);
2960 if (ptr->glyph_name != notdef)
2961 mp_xfree (ptr->glyph_name);
2963 sprintf (mp->ps->t1_line_array, "%s", line_end);
2964 mp->ps->t1_line_ptr = eol (mp->ps->t1_line_array);
2967 mp_xfree (return_cs);
2969 mp_xfree (start_line);
2970 mp_xfree (line_end);
2973 static void t1_mark_glyphs (MP mp, int tex_font)
2976 char *charset = extra_charset ();
2979 if (mp->ps->t1_synthetic || embed_all_glyphs (tex_font)) { /* mark everything */
2980 if (mp->ps->cs_tab != NULL)
2981 for (ptr = mp->ps->cs_tab; ptr < mp->ps->cs_ptr; ptr++)
2983 ptr->is_used = true;
2984 if (mp->ps->subr_tab != NULL) {
2985 for (ptr = mp->ps->subr_tab; ptr - mp->ps->subr_tab < mp->ps->subr_size; ptr++)
2987 ptr->is_used = true;
2988 mp->ps->subr_max = mp->ps->subr_size - 1;
2992 mark_cs (mp,notdef);
2993 for (i = 0; i < 256; i++)
2994 if (is_used_char (i)) {
2995 if (mp->ps->t1_glyph_names[i] == notdef) {
2997 snprintf(s,128, "character %i is mapped to %s", i, notdef);
3000 mark_cs (mp,mp->ps->t1_glyph_names[i]);
3002 if (charset == NULL)
3004 g = s = charset + 1; /* skip the first '/' */
3007 while (*s != '/' && s < r)
3009 *s = 0; /* terminate g by rewriting '/' to 0 */
3014 if (mp->ps->subr_tab != NULL)
3015 for (mp->ps->subr_max = -1, ptr = mp->ps->subr_tab;
3016 ptr - mp->ps->subr_tab < mp->ps->subr_size;
3018 if (ptr->is_used && ptr - mp->ps->subr_tab > mp->ps->subr_max)
3019 mp->ps->subr_max = ptr - mp->ps->subr_tab;
3022 static void t1_subset_charstrings (MP mp, int tex_font)
3025 mp->ps->cs_size_pos =
3026 strstr (mp->ps->t1_line_array, charstringname) + strlen (charstringname)
3027 - mp->ps->t1_line_array + 1;
3028 /* |cs_size_pos| points to the number indicating
3029 dict size after "/CharStrings" */
3030 mp->ps->cs_size = t1_scan_num (mp,mp->ps->t1_line_array + mp->ps->cs_size_pos, 0);
3031 mp->ps->cs_ptr = mp->ps->cs_tab = mp_xmalloc (mp->ps->cs_size, sizeof(cs_entry));
3032 for (ptr = mp->ps->cs_tab; ptr - mp->ps->cs_tab < mp->ps->cs_size; ptr++)
3033 init_cs_entry (ptr);
3034 mp->ps->cs_notdef = NULL;
3035 mp->ps->cs_dict_start = mp_xstrdup (mp->ps->t1_line_array);
3037 while (mp->ps->t1_cslen) {
3041 mp->ps->cs_dict_end = mp_xstrdup (mp->ps->t1_line_array);
3042 t1_mark_glyphs (mp,tex_font);
3043 if (mp->ps->subr_tab != NULL) {
3044 if (mp->ps->cs_token_pair == NULL)
3046 (mp, "This Type 1 font uses mismatched subroutine begin/end token pairs.");
3049 for (mp->ps->cs_count = 0, ptr = mp->ps->cs_tab; ptr < mp->ps->cs_ptr; ptr++)
3055 static void t1_subset_end (MP mp)
3057 if (mp->ps->t1_synthetic) { /* copy to "dup /FontName get exch definefont pop" */
3058 while (!strstr (mp->ps->t1_line_array, "definefont")) {
3062 while (!t1_end_eexec ())
3063 t1_getline (mp); /* ignore the rest */
3064 t1_putline (mp); /* write "mark currentfile closefile" */
3066 while (!t1_end_eexec ()) { /* copy to "mark currentfile closefile" */
3071 if (fixedcontent) { /* copy 512 zeros (not needed for PDF) */
3072 while (!t1_cleartomark ()) {
3076 if (!mp->ps->t1_synthetic) /* don't check "{restore}if" for synthetic fonts */
3077 t1_check_end (mp); /* write "{restore}if" if found */
3081 static int t1_updatefm (MP mp, int f, fm_entry *fm)
3084 mp->ps->read_encoding_only = true;
3085 if (!t1_open_fontfile (mp,fm,NULL)) {
3088 t1_scan_only (mp,f, fm);
3089 s = mp_xstrdup(mp->ps->fontname_buf);
3091 while (*p != ' ' && *p != 0)
3095 t1_close_font_file (mp,"");
3100 static void writet1 (MP mp, int tex_font, fm_entry *fm_cur) {
3101 int save_selector = mp->selector;
3102 mp_normalize_selector(mp);
3103 mp->ps->read_encoding_only = false;
3104 if (!is_included (fm_cur)) { /* scan parameters from font file */
3105 if (!t1_open_fontfile (mp,fm_cur,"{"))
3107 t1_scan_only (mp,tex_font, fm_cur);
3108 t1_close_font_file (mp,"}");
3111 if (!is_subsetted (fm_cur)) { /* include entire font */
3112 if (!t1_open_fontfile (mp,fm_cur,"<<"))
3114 t1_include (mp,tex_font,fm_cur);
3115 t1_close_font_file (mp,">>");
3118 /* partial downloading */
3119 if (!t1_open_fontfile (mp,fm_cur,"<"))
3121 t1_subset_ascii_part (mp,tex_font,fm_cur);
3122 t1_start_eexec (mp,fm_cur);
3125 t1_read_subrs (mp,tex_font, fm_cur);
3126 t1_subset_charstrings (mp,tex_font);
3128 t1_close_font_file (mp,">");
3129 mp->selector = save_selector;
3133 static void t1_free (MP mp);
3136 static void t1_free (MP mp) {
3137 mp_xfree (mp->ps->t1_line_array);
3138 mp_xfree (mp->ps->t1_buf_array);
3142 @* \[44d] Embedding fonts.
3144 @ The |tfm_num| is officially of type |font_number|, but that
3145 type does not exist yet at this point in the output order.
3149 char *tfm_name; /* TFM file name */
3150 char *ps_name; /* PostScript name */
3151 integer flags; /* font flags */
3152 char *ff_name; /* font file name */
3153 char *subset_tag; /* pseudoUniqueTag for subsetted font */
3154 enc_entry *encoding; /* pointer to corresponding encoding */
3155 unsigned int tfm_num; /* number of the TFM refering this entry */
3156 unsigned short type; /* font type (T1/TTF/...) */
3157 short slant; /* SlantFont */
3158 short extend; /* ExtendFont */
3159 integer ff_objnum; /* FontFile object number */
3160 integer fn_objnum; /* FontName/BaseName object number */
3161 integer fd_objnum; /* FontDescriptor object number */
3162 char *charset; /* string containing used glyphs */
3163 boolean all_glyphs; /* embed all glyphs? */
3164 unsigned short links; /* link flags from |tfm_tree| and |ps_tree| */
3165 short tfm_avail; /* flags whether a tfm is available */
3166 short pid; /* Pid for truetype fonts */
3167 short eid; /* Eid for truetype fonts */
3173 #define FONTNAME_BUF_SIZE 128
3174 boolean fontfile_found;
3175 boolean is_otf_font;
3176 char fontname_buf[FONTNAME_BUF_SIZE];
3184 @d set_included(fm) ((fm)->type |= F_INCLUDED)
3185 @d set_subsetted(fm) ((fm)->type |= F_SUBSETTED)
3186 @d set_truetype(fm) ((fm)->type |= F_TRUETYPE)
3187 @d set_basefont(fm) ((fm)->type |= F_BASEFONT)
3189 @d is_included(fm) ((fm)->type & F_INCLUDED)
3190 @d is_subsetted(fm) ((fm)->type & F_SUBSETTED)
3191 @d is_truetype(fm) ((fm)->type & F_TRUETYPE)
3192 @d is_basefont(fm) ((fm)->type & F_BASEFONT)
3193 @d is_reencoded(fm) ((fm)->encoding != NULL)
3194 @d is_fontfile(fm) (fm_fontfile(fm) != NULL)
3195 @d is_t1fontfile(fm) (is_fontfile(fm) && !is_truetype(fm))
3197 @d fm_slant(fm) (fm)->slant
3198 @d fm_extend(fm) (fm)->extend
3199 @d fm_fontfile(fm) (fm)->ff_name
3201 @<Exported function headers@>=
3202 boolean mp_font_is_reencoded (MP mp, int f);
3203 boolean mp_font_is_included (MP mp, int f);
3204 boolean mp_font_is_subsetted (MP mp, int f);
3207 boolean mp_font_is_reencoded (MP mp, int f) {
3209 if (mp_has_font_size(mp,f) && mp_has_fm_entry (mp, f, &fm)) {
3211 && (fm->ps_name != NULL)
3212 && is_reencoded (fm))
3217 boolean mp_font_is_included (MP mp, int f) {
3219 if (mp_has_font_size(mp,f) && mp_has_fm_entry (mp, f, &fm)) {
3221 && (fm->ps_name != NULL && fm->ff_name != NULL)
3222 && is_included (fm))
3227 boolean mp_font_is_subsetted (MP mp, int f) {
3229 if (mp_has_font_size(mp,f) && mp_has_fm_entry (mp, f,&fm)) {
3231 && (fm->ps_name != NULL && fm->ff_name != NULL)
3232 && is_included (fm) && is_subsetted (fm))
3238 @ @<Exported function headers@>=
3239 char * mp_fm_encoding_name (MP mp, int f);
3240 char * mp_fm_font_name (MP mp, int f);
3241 char * mp_fm_font_subset_name (MP mp, int f);
3244 @c char * mp_fm_encoding_name (MP mp, int f) {
3247 if (mp_has_fm_entry (mp, f, &fm)) {
3248 if (fm != NULL && (fm->ps_name != NULL)) {
3249 if (is_reencoded (fm)) {
3251 if (e->enc_name!=NULL)
3252 return mp_xstrdup(e->enc_name);
3258 print_err ("fontmap encoding problems for font ");
3259 mp_print(mp,mp->font_name[f]);
3263 char * mp_fm_font_name (MP mp, int f) {
3265 if (mp_has_fm_entry (mp, f,&fm)) {
3266 if (fm != NULL && (fm->ps_name != NULL)) {
3267 if (mp_font_is_included(mp, f) && !mp->font_ps_name_fixed[f]) {
3268 /* find the real fontname, and update |ps_name| and |subset_tag| if needed */
3269 if (t1_updatefm(mp,f,fm)) {
3270 mp->font_ps_name_fixed[f] = true;
3272 print_err ("font loading problems for font ");
3273 mp_print(mp,mp->font_name[f]);
3277 return mp_xstrdup(fm->ps_name);
3280 print_err ("fontmap name problems for font ");
3281 mp_print(mp,mp->font_name[f]);
3286 char * mp_fm_font_subset_name (MP mp, int f) {
3288 if (mp_has_fm_entry (mp, f, &fm)) {
3289 if (fm != NULL && (fm->ps_name != NULL)) {
3290 if (is_subsetted(fm)) {
3291 char *s = mp_xmalloc(strlen(fm->ps_name)+8,1);
3292 snprintf(s,strlen(fm->ps_name)+8,"%s-%s",fm->subset_tag,fm->ps_name);
3295 return mp_xstrdup(fm->ps_name);
3299 print_err ("fontmap name problems for font ");
3300 mp_print(mp,mp->font_name[f]);
3305 @ @<Exported function headers@>=
3306 integer mp_fm_font_slant (MP mp, int f);
3307 integer mp_fm_font_extend (MP mp, int f);
3310 @c integer mp_fm_font_slant (MP mp, int f) {
3312 if (mp_has_fm_entry (mp, f, &fm)) {
3313 if (fm != NULL && (fm->ps_name != NULL)) {
3319 integer mp_fm_font_extend (MP mp, int f) {
3321 if (mp_has_fm_entry (mp, f, &fm)) {
3322 if (fm != NULL && (fm->ps_name != NULL)) {
3329 @ @<Exported function headers@>=
3330 boolean mp_do_ps_font (MP mp, font_number f);
3332 @ @c boolean mp_do_ps_font (MP mp, font_number f) {
3334 (void)mp_has_fm_entry (mp, f, &fm_cur); /* for side effects */
3337 if (is_truetype(fm_cur) ||
3338 (fm_cur->ps_name == NULL && fm_cur->ff_name == NULL)) {
3341 if (is_included(fm_cur)) {
3342 mp_print_nl(mp,"%%BeginResource: font ");
3343 if (is_subsetted(fm_cur)) {
3344 mp_print(mp, fm_cur->subset_tag);
3345 mp_print_char(mp,'-');
3347 mp_print(mp, fm_cur->ps_name);
3349 writet1 (mp,f,fm_cur);
3350 mp_print_nl(mp,"%%EndResource");
3356 @ Included subset fonts do not need and encoding vector, make
3357 sure we skip that case.
3360 void mp_list_used_resources (MP mp, int prologues, int procset);
3362 @ @c void mp_list_used_resources (MP mp, int prologues, int procset) {
3363 font_number f; /* fonts used in a text node or as loop counters */
3364 int ff; /* a loop counter */
3365 font_number ldf; /* the last \.{DocumentFont} listed (otherwise |null_font|) */
3368 mp_print_nl(mp, "%%DocumentResources: procset mpost");
3370 mp_print_nl(mp, "%%DocumentResources: procset mpost-minimal");
3373 for (f=null_font+1;f<=mp->last_fnum;f++) {
3374 if ( (mp_has_font_size(mp,f))&&(mp_font_is_reencoded(mp,f)) ) {
3375 for (ff=ldf;ff>=null_font;ff--) {
3376 if ( mp_has_font_size(mp,ff) )
3377 if ( mp_xstrcmp(mp->font_enc_name[f],mp->font_enc_name[ff])==0 )
3380 if ( mp_font_is_subsetted(mp,f) )
3382 if ( mp->ps_offset+1+strlen(mp->font_enc_name[f])>
3383 (unsigned)mp->max_print_line )
3384 mp_print_nl(mp, "%%+ encoding");
3387 mp_print_nl(mp, "%%+ encoding");
3389 mp_print_char(mp, ' ');
3390 mp_print(mp, mp->font_enc_name[f]);
3398 for (f=null_font+1;f<=mp->last_fnum;f++) {
3399 if ( mp_has_font_size(mp,f) ) {
3400 for (ff=ldf;ff>=null_font;ff--) {
3401 if ( mp_has_font_size(mp,ff) )
3402 if ( mp_xstrcmp(mp->font_name[f],mp->font_name[ff])==0 )
3405 if ( mp->ps_offset+1+strlen(mp->font_ps_name[f])>
3406 (unsigned)mp->max_print_line )
3407 mp_print_nl(mp, "%%+ font");
3410 mp_print_nl(mp, "%%+ font");
3412 mp_print_char(mp, ' ');
3413 if ( (prologues==3)&&
3414 (mp_font_is_subsetted(mp,f)) )
3415 mp_print(mp, mp_fm_font_subset_name(mp,f));
3417 mp_print(mp, mp->font_ps_name[f]);
3427 void mp_list_supplied_resources (MP mp, int prologues, int procset);
3429 @ @c void mp_list_supplied_resources (MP mp, int prologues, int procset) {
3430 font_number f; /* fonts used in a text node or as loop counters */
3431 int ff; /* a loop counter */
3432 font_number ldf; /* the last \.{DocumentFont} listed (otherwise |null_font|) */
3435 mp_print_nl(mp, "%%DocumentSuppliedResources: procset mpost");
3437 mp_print_nl(mp, "%%DocumentSuppliedResources: procset mpost-minimal");
3440 for (f=null_font+1;f<=mp->last_fnum;f++) {
3441 if ( (mp_has_font_size(mp,f))&&(mp_font_is_reencoded(mp,f)) ) {
3442 for (ff=ldf;ff>= null_font;ff++) {
3443 if ( mp_has_font_size(mp,ff) )
3444 if ( mp_xstrcmp(mp->font_enc_name[f],mp->font_enc_name[ff])==0 )
3447 if ( (prologues==3)&&(mp_font_is_subsetted(mp,f)))
3449 if ( mp->ps_offset+1+strlen(mp->font_enc_name[f])>(unsigned)mp->max_print_line )
3450 mp_print_nl(mp, "%%+ encoding");
3453 mp_print_nl(mp, "%%+ encoding");
3455 mp_print_char(mp, ' ');
3456 mp_print(mp, mp->font_enc_name[f]);
3465 for (f=null_font+1;f<=mp->last_fnum;f++) {
3466 if ( mp_has_font_size(mp,f) ) {
3467 for (ff=ldf;ff>= null_font;ff--) {
3468 if ( mp_has_font_size(mp,ff) )
3469 if ( mp_xstrcmp(mp->font_name[f],mp->font_name[ff])==0 )
3472 if ( ! mp_font_is_included(mp,f) )
3474 if ( mp->ps_offset+1+strlen(mp->font_ps_name[f])>(unsigned)mp->max_print_line )
3475 mp_print_nl(mp, "%%+ font");
3478 mp_print_nl(mp, "%%+ font");
3480 mp_print_char(mp, ' ');
3481 if ( mp_font_is_subsetted(mp,f) )
3482 mp_print(mp, mp_fm_font_subset_name(mp,f));
3484 mp_print(mp, mp->font_ps_name[f]);
3495 void mp_list_needed_resources (MP mp, int prologues);
3497 @ @c void mp_list_needed_resources (MP mp, int prologues) {
3498 font_number f; /* fonts used in a text node or as loop counters */
3499 int ff; /* a loop counter */
3500 font_number ldf; /* the last \.{DocumentFont} listed (otherwise |null_font|) */
3504 for (f=null_font+1;f<=mp->last_fnum;f++ ) {
3505 if ( mp_has_font_size(mp,f)) {
3506 for (ff=ldf;ff>=null_font;ff--) {
3507 if ( mp_has_font_size(mp,ff) )
3508 if ( mp_xstrcmp(mp->font_name[f],mp->font_name[ff])==0 )
3511 if ((prologues==3)&&(mp_font_is_included(mp,f)) )
3513 if ( mp->ps_offset+1+strlen(mp->font_ps_name[f])>(unsigned)mp->max_print_line )
3514 mp_print_nl(mp, "%%+ font");
3517 mp_print_nl(mp, "%%DocumentNeededResources: font");
3519 mp_print_char(mp, ' ');
3520 mp_print(mp, mp->font_ps_name[f]);
3526 if ( ! firstitem ) {
3530 for (f=null_font+1;f<= mp->last_fnum;f++) {
3531 if ( mp_has_font_size(mp,f) ) {
3532 for (ff=ldf;ff>=null_font;ff-- ) {
3533 if ( mp_has_font_size(mp,ff) )
3534 if ( mp_xstrcmp(mp->font_name[f],mp->font_name[ff])==0 )
3537 if ((prologues==3)&&(mp_font_is_included(mp,f)) )
3539 mp_print(mp, "%%IncludeResource: font ");
3540 mp_print(mp, mp->font_ps_name[f]);
3551 void mp_write_font_definition (MP mp, font_number f, int prologues);
3555 @d applied_reencoding(A) ((mp_font_is_reencoded(mp,(A)))&&
3556 ((! mp_font_is_subsetted(mp,(A)))||(prologues==2)))
3558 @c void mp_write_font_definition(MP mp, font_number f, int prologues) {
3559 if ( (applied_reencoding(f))||(mp_fm_font_slant(mp,f)!=0)||
3560 (mp_fm_font_extend(mp,f)!=0)||
3561 (mp_xstrcmp(mp->font_name[f],"psyrgo")==0)||
3562 (mp_xstrcmp(mp->font_name[f],"zpzdr-reversed")==0) ) {
3563 if ( (mp_font_is_subsetted(mp,f))&&
3564 (mp_font_is_included(mp,f))&&(prologues==3))
3565 mp_ps_name_out(mp, mp_fm_font_subset_name(mp,f),true);
3567 mp_ps_name_out(mp, mp->font_ps_name[f],true);
3568 mp_ps_print(mp, " fcp");
3570 if ( applied_reencoding(f) ) {
3571 mp_ps_print(mp, "/Encoding ");
3572 mp_ps_print(mp, mp->font_enc_name[f]);
3573 mp_ps_print(mp, " def ");
3575 if ( mp_fm_font_slant(mp,f)!=0 ) {
3576 mp_print_int(mp, mp_fm_font_slant(mp,f));
3577 mp_ps_print(mp, " SlantFont ");
3579 if ( mp_fm_font_extend(mp,f)!=0 ) {
3580 mp_print_int(mp, mp_fm_font_extend(mp,f));
3581 mp_ps_print(mp, " ExtendFont ");
3583 if ( mp_xstrcmp(mp->font_name[f],"psyrgo")==0 ) {
3584 mp_ps_print(mp, " 890 ScaleFont ");
3585 mp_ps_print(mp, " 277 SlantFont ");
3587 if ( mp_xstrcmp(mp->font_name[f],"zpzdr-reversed")==0 ) {
3588 mp_ps_print(mp, " FontMatrix [-1 0 0 1 0 0] matrix concatmatrix /FontMatrix exch def ");
3589 mp_ps_print(mp, "/Metrics 2 dict dup begin ");
3590 mp_ps_print(mp, "/space[0 -278]def ");
3591 mp_ps_print(mp, "/a12[-904 -939]def ");
3592 mp_ps_print(mp, "end def ");
3594 mp_ps_print(mp, "currentdict end");
3596 mp_ps_print_defined_name(mp,f,prologues);
3597 mp_ps_print(mp, " exch definefont pop");
3603 void mp_ps_print_defined_name (MP mp, font_number f, int prologues);
3606 @c void mp_ps_print_defined_name(MP mp, font_number A, int prologues) {
3607 mp_ps_print(mp, " /");
3608 if ((mp_font_is_subsetted(mp,(A)))&&
3609 (mp_font_is_included(mp,(A)))&&(prologues==3))
3610 mp_print(mp, mp_fm_font_subset_name(mp,(A)));
3612 mp_print(mp, mp->font_ps_name[(A)]);
3613 if ( mp_xstrcmp(mp->font_name[(A)],"psyrgo")==0 )
3614 mp_ps_print(mp, "-Slanted");
3615 if ( mp_xstrcmp(mp->font_name[(A)],"zpzdr-reversed")==0 )
3616 mp_ps_print(mp, "-Reverse");
3617 if ( applied_reencoding((A)) ) {
3618 mp_ps_print(mp, "-");
3619 mp_ps_print(mp, mp->font_enc_name[(A)]);
3621 if ( mp_fm_font_slant(mp,(A))!=0 ) {
3622 mp_ps_print(mp, "-Slant_"); mp_print_int(mp, mp_fm_font_slant(mp,(A))) ;
3624 if ( mp_fm_font_extend(mp,(A))!=0 ) {
3625 mp_ps_print(mp, "-Extend_"); mp_print_int(mp, mp_fm_font_extend(mp,(A)));
3629 @ @<Include encodings and fonts for edge structure~|h|@>=
3630 mp_font_encodings(mp,mp->last_fnum,prologues==2);
3631 @<Embed fonts that are available@>
3633 @ @<Embed fonts that are available@>=
3636 @<Make |cur_fsize| a copy of the |font_sizes| array@>;
3639 for (f=null_font+1;f<=mp->last_fnum;f++) {
3640 if ( cur_fsize[f]!=null ) {
3641 if (prologues==3 ) {
3642 if ( ! mp_do_ps_font(mp,f) ) {
3643 if ( mp_has_fm_entry(mp,f, NULL) ) {
3644 print_err("Font embedding failed");
3649 cur_fsize[f]=link(cur_fsize[f]);
3650 if ( cur_fsize[f]!=null ) { mp_unmark_font(mp, f); done_fonts=false; }
3654 @<Increment |next_size| and apply |mark_string_chars| to all text nodes with
3656 } while (! done_fonts);
3659 @ @<Increment |next_size| and apply |mark_string_chars| to all text nodes...@>=
3662 mp_apply_mark_string_chars(mp, h, next_size);
3665 @ We also need to keep track of which characters are used in text nodes
3666 in the edge structure that is being shipped out. This is done by procedures
3667 that use the left-over |b3| field in the |char_info| words; i.e.,
3668 |char_info(f)(c).b3| gives the status of character |c| in font |f|.
3671 enum {unused=0, used};
3674 void mp_unmark_font (MP mp,font_number f) ;
3677 void mp_unmark_font (MP mp,font_number f) {
3678 int k; /* an index into |font_info| */
3679 for (k= mp->char_base[f]+mp->font_bc[f];
3680 k<=mp->char_base[f]+mp->font_ec[f];
3682 mp->font_info[k].qqqq.b3=unused;
3687 void mp_print_improved_prologue (MP mp, int prologues, int procset,
3688 int groffmode, int null, pointer h) ;
3693 void mp_print_improved_prologue (MP mp, int prologues, int procset,
3694 int groffmode, int null, pointer h) {
3695 quarterword next_size; /* the size index for fonts being listed */
3696 pointer *cur_fsize; /* current positions in |font_sizes| */
3697 boolean done_fonts; /* have we finished listing the fonts in the header? */
3698 font_number f; /* a font number for loops */
3700 cur_fsize = mp_xmalloc((mp->font_max+1),sizeof(pointer));
3702 mp_list_used_resources(mp, prologues, procset);
3703 mp_list_supplied_resources(mp, prologues, procset);
3704 mp_list_needed_resources(mp, prologues);
3705 mp_print_nl(mp, "%%EndComments");
3706 mp_print_nl(mp, "%%BeginProlog");
3708 mp_print_nl(mp, "%%BeginResource: procset mpost");
3710 mp_print_nl(mp, "%%BeginResource: procset mpost-minimal");
3711 mp_print_nl(mp, "/bd{bind def}bind def"
3712 "/fshow {exch findfont exch scalefont setfont show}bd");
3713 if ( procset>0 ) @<Print the procset@>;
3714 mp_print_nl(mp, "/fcp{findfont dup length dict begin"
3715 "{1 index/FID ne{def}{pop pop}ifelse}forall}bd");
3716 mp_print_nl(mp, "/fmc{FontMatrix dup length array copy dup dup}bd"
3717 "/fmd{/FontMatrix exch def}bd");
3718 mp_print_nl(mp, "/Amul{4 -1 roll exch mul 1000 div}bd"
3719 "/ExtendFont{fmc 0 get Amul 0 exch put fmd}bd");
3720 if ( groffmode>0 ) {
3721 mp_print_nl(mp, "/ScaleFont{dup fmc 0 get"
3722 " Amul 0 exch put dup dup 3 get Amul 3 exch put fmd}bd");
3724 mp_print_nl(mp, "/SlantFont{fmc 2 get dup 0 eq{pop 1}if"
3725 " Amul FontMatrix 0 get mul 2 exch put fmd}bd");
3726 mp_print_nl(mp, "%%EndResource");
3727 @<Include encodings and fonts for edge structure~|h|@>;
3728 mp_print_nl(mp, "%%EndProlog");
3729 mp_print_nl(mp, "%%BeginSetup");
3731 for (f=null_font+1;f<=mp->last_fnum;f++) {
3732 if ( mp_has_font_size(mp,f) ) {
3733 if ( mp_has_fm_entry(mp,f,NULL) ) {
3734 mp_write_font_definition(mp,f,(mp->internal[prologues]>>16));
3735 mp_ps_name_out(mp, mp->font_name[f],true);
3736 mp_ps_print_defined_name(mp,f,(mp->internal[prologues]>>16));
3737 mp_ps_print(mp, " def");
3740 snprintf(s,256,"font %s cannot be found in any fontmapfile!", mp->font_name[f]);
3742 mp_ps_name_out(mp, mp->font_name[f],true);
3743 mp_ps_name_out(mp, mp->font_name[f],true);
3744 mp_ps_print(mp, " def");
3749 mp_print_nl(mp, "%%EndSetup");
3750 mp_print_nl(mp, "%%Page: 1 1");
3752 mp_xfree(cur_fsize);
3756 font_number mp_print_font_comments (MP mp , int prologues, int null, pointer h);
3761 font_number mp_print_font_comments (MP mp , int prologues, int null, pointer h) {
3762 quarterword next_size; /* the size index for fonts being listed */
3763 pointer *cur_fsize; /* current positions in |font_sizes| */
3764 int ff; /* a loop counter */
3765 boolean done_fonts; /* have we finished listing the fonts in the header? */
3766 font_number f; /* a font number for loops */
3767 scaled ds; /* design size and scale factor for a text node */
3768 font_number ldf=0; /* the last \.{DocumentFont} listed (otherwise |null_font|) */
3769 cur_fsize = mp_xmalloc((mp->font_max+1),sizeof(pointer));
3770 if ( prologues>0 ) {
3771 @<Give a \.{DocumentFonts} comment listing all fonts with non-null
3772 |font_sizes| and eliminate duplicates@>;
3775 @<Make |cur_fsize| a copy of the |font_sizes| array@>;
3776 do { done_fonts=true;
3777 for (f=null_font+1;f<=mp->last_fnum;f++) {
3778 if ( cur_fsize[f]!=null ) {
3779 @<Print the \.{\%*Font} comment for font |f| and advance |cur_fsize[f]|@>;
3781 if ( cur_fsize[f]!=null ) { mp_unmark_font(mp, f); done_fonts=false; };
3783 if ( ! done_fonts ) {
3784 @<Increment |next_size| and apply |mark_string_chars| to all text nodes with
3787 } while (! done_fonts);
3789 mp_xfree(cur_fsize);
3793 @ @<Make |cur_fsize| a copy of the |font_sizes| array@>=
3794 for (f=null_font+1;f<= mp->last_fnum;f++)
3795 cur_fsize[f]=mp->font_sizes[f]
3797 @ It's not a good idea to make any assumptions about the |font_ps_name| entries,
3798 so we carefully remove duplicates. There is no harm in using a slow, brute-force
3801 @<Give a \.{DocumentFonts} comment listing all fonts with non-null...@>=
3804 for (f=null_font+1;f<= mp->last_fnum;f++) {
3805 if ( mp->font_sizes[f]!=null ) {
3806 if ( ldf==null_font )
3807 mp_print_nl(mp, "%%DocumentFonts:");
3808 for (ff=ldf;ff>=null_font;ff--) {
3809 if ( mp->font_sizes[ff]!=null )
3810 if ( mp_xstrcmp(mp->font_ps_name[f],mp->font_ps_name[ff])==0 )
3813 if ( mp->ps_offset+1+strlen(mp->font_ps_name[f])>(unsigned)mp->max_print_line )
3814 mp_print_nl(mp, "%%+");
3815 mp_print_char(mp, ' ');
3816 mp_print(mp, mp->font_ps_name[f]);
3825 void mp_hex_digit_out (MP mp,small_number d) {
3826 if ( d<10 ) mp_print_char(mp, d+'0');
3827 else mp_print_char(mp, d+'a'-10);
3830 @ We output the marks as a hexadecimal bit string starting at |c| or
3831 |font_bc[f]|, whichever is greater. If the output has to be truncated
3832 to avoid exceeding |emergency_line_length| the return value says where to
3833 start scanning next time.
3836 halfword mp_ps_marks_out (MP mp,font_number f, eight_bits c);
3839 @d emergency_line_length 255
3840 /* \ps\ output lines can be this long in unusual circumstances */
3843 halfword mp_ps_marks_out (MP mp,font_number f, eight_bits c) {
3844 eight_bits bc,ec; /* only encode characters between these bounds */
3845 integer lim; /* the maximum number of marks to encode before truncating */
3846 int p; /* |font_info| index for the current character */
3847 int d,b; /* used to construct a hexadecimal digit */
3848 lim=4*(emergency_line_length-mp->ps_offset-4);
3852 @<Restrict the range |bc..ec| so that it contains no unused characters
3853 at either end and has length at most |lim|@>;
3854 @<Print the initial label indicating that the bitmap starts at |bc|@>;
3855 @<Print a hexadecimal encoding of the marks for characters |bc..ec|@>;
3856 while ( (ec<mp->font_ec[f])&&(mp->font_info[p].qqqq.b3==unused) ) {
3862 @ We could save time by setting the return value before the loop that
3863 decrements |ec|, but there is no point in being so tricky.
3865 @<Restrict the range |bc..ec| so that it contains no unused characters...@>=
3866 p=mp->char_base[f]+bc;
3867 while ( (mp->font_info[p].qqqq.b3==unused)&&(bc<ec) ) {
3870 if ( ec>=bc+lim ) ec=bc+lim-1;
3871 p=mp->char_base[f]+ec;
3872 while ( (mp->font_info[p].qqqq.b3==unused)&&(bc<ec) ) {
3876 @ @<Print the initial label indicating that the bitmap starts at |bc|@>=
3877 mp_print_char(mp, ' ');
3878 mp_hex_digit_out(mp, bc / 16);
3879 mp_hex_digit_out(mp, bc % 16);
3880 mp_print_char(mp, ':')
3884 @<Print a hexadecimal encoding of the marks for characters |bc..ec|@>=
3886 for (p=mp->char_base[f]+bc;p<=mp->char_base[f]+ec;p++) {
3888 mp_hex_digit_out(mp, d);
3891 if ( mp->font_info[p].qqqq.b3!=unused ) d=d+b;
3894 mp_hex_digit_out(mp, d)
3897 @ Here is a simple function that determines whether there are any marked
3898 characters in font~|f| with character code at least~|c|.
3901 boolean mp_check_ps_marks (MP mp,font_number f, integer c) ;
3904 boolean mp_check_ps_marks (MP mp,font_number f, integer c) {
3905 int p; /* |font_info| index for the current character */
3906 for (p=mp->char_base[f]+c;p<=mp->char_base[f]+mp->font_ec[f];p++) {
3907 if ( mp->font_info[p].qqqq.b3==used )
3914 @ If the file name is so long that it can't be printed without exceeding
3915 |emergency_line_length| then there will be missing items in the \.{\%*Font:}
3916 line. We might have to repeat line in order to get the character usage
3917 information to fit within |emergency_line_length|.
3919 TODO: these two defines are also defined in mp.w!
3921 @d link(A) mp->mem[(A)].hh.rh /* the |link| field of a memory word */
3922 @d sc_factor(A) mp->mem[(A)+1].cint /* the scale factor stored in a font size node */
3924 @<Print the \.{\%*Font} comment for font |f| and advance |cur_fsize[f]|@>=
3926 while ( mp_check_ps_marks(mp, f,t) ) {
3927 mp_print_nl(mp, "%*Font: ");
3928 if ( mp->ps_offset+strlen(mp->font_name[f])+12>emergency_line_length )
3930 mp_print(mp, mp->font_name[f]);
3931 mp_print_char(mp, ' ');
3932 ds=(mp->font_dsize[f] + 8) / 16;
3933 mp_print_scaled(mp, mp_take_scaled(mp, ds,sc_factor(cur_fsize[f])));
3934 if ( mp->ps_offset+12>emergency_line_length ) break;
3935 mp_print_char(mp, ' ');
3936 mp_print_scaled(mp, ds);
3937 if ( mp->ps_offset+5>emergency_line_length ) break;
3938 t=mp_ps_marks_out(mp, f,t);
3940 cur_fsize[f]=link(cur_fsize[f]);
3943 @ @<Print the procset@>=
3945 mp_print_nl(mp, "/hlw{0 dtransform exch truncate exch idtransform pop setlinewidth}bd");
3946 mp_print_nl(mp, "/vlw{0 exch dtransform truncate idtransform setlinewidth pop}bd");
3947 mp_print_nl(mp, "/l{lineto}bd/r{rlineto}bd/c{curveto}bd/m{moveto}bd"
3948 "/p{closepath}bd/n{newpath}bd");
3949 mp_print_nl(mp, "/C{setcmykcolor}bd/G{setgray}bd/R{setrgbcolor}bd"
3950 "/lj{setlinejoin}bd/ml{setmiterlimit}bd");
3951 mp_print_nl(mp, "/lc{setlinecap}bd/S{stroke}bd/F{fill}bd/q{gsave}bd"
3952 "/Q{grestore}bd/s{scale}bd/t{concat}bd");
3953 mp_print_nl(mp, "/sd{setdash}bd/rd{[] 0 setdash}bd/P{showpage}bd/B{q F Q}bd/W{clip}bd");
3957 @ The prologue defines \.{fshow} and corrects for the fact that \.{fshow}
3958 arguments use |font_name| instead of |font_ps_name|. Downloaded bitmap fonts
3959 might not have reasonable |font_ps_name| entries, but we just charge ahead
3960 anyway. The user should not make \&{prologues} positive if this will cause
3962 @:prologues_}{\&{prologues} primitive@>
3965 void mp_print_prologue (MP mp, int prologues, int procset, int ldf);
3968 void mp_print_prologue (MP mp, int prologues, int procset, int ldf) {
3970 mp_print(mp, "%%BeginProlog"); mp_print_ln(mp);
3971 if ( (prologues>0)||(procset>0) ) {
3972 if ( ldf!=null_font ) {
3973 if ( prologues>0 ) {
3974 for (f=null_font+1;f<=mp->last_fnum;f++) {
3975 if ( mp_has_font_size(mp,f) ) {
3976 mp_ps_name_out(mp, mp->font_name[f],true);
3977 mp_ps_name_out(mp, mp->font_ps_name[f],true);
3978 mp_ps_print(mp, " def");
3983 mp_print(mp, "/fshow {exch findfont exch scalefont setfont show}bind def");
3989 mp_print_nl(mp, "%%BeginResource: procset mpost");
3990 if ( (prologues>0)&&(ldf!=null_font) )
3992 "/bd{bind def}bind def/fshow {exch findfont exch scalefont setfont show}bd");
3994 mp_print_nl(mp, "/bd{bind def}bind def");
3995 @<Print the procset@>;
3996 mp_print_nl(mp, "%%EndResource");
4000 mp_print(mp, "%%EndProlog");