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 */
60 #include "mpmp.h" /* internal header */
61 #include "mppsout.h" /* internal header */
64 @<Static variables in the outer block@>;
66 @ There is a small bit of code from the backend that bleads through
67 to the frontend because I do not know how to set up the includes
68 properly. Those are the definitions of |struct libavl_allocator|
69 and |typedef struct psout_data_struct * psout_data|.
71 The |libavl_allocator| is a trick that makes sure that frontends
72 do not need |avl.h|, and the |psout_data| is needed for the backend
77 typedef struct psout_data_struct {
80 @<Exported function headers@>
82 @ @<Exported function headers@>=
83 void mp_backend_initialize (MP mp) ;
84 void mp_backend_free (MP mp) ;
87 @c void mp_backend_initialize (MP mp) {
88 mp->ps = mp_xmalloc(1,sizeof(psout_data_struct));
89 @<Set initial values@>;
91 void mp_backend_free (MP mp) {
92 @<Dealloc variables@>;
101 @* Traditional {psfonts.map} loading.
103 TODO: It is likely that this code can be removed after a few minor tweaks.
105 @ The file |ps_tab_file| gives a table of \TeX\ font names and corresponding
106 PostScript names for fonts that do not have to be downloaded, i.e., fonts that
107 can be used when |internal[prologues]>0|. Each line consists of a \TeX\ name,
108 one or more spaces, a PostScript name, and possibly a space and some other junk.
109 This routine reads the table, updates |font_ps_name| entries starting after
110 |last_ps_fnum|, and sets |last_ps_fnum:=last_fnum|. If the file |ps_tab_file|
111 is missing, we assume that the existing font names are OK and nothing needs to
114 @d ps_tab_name "psfonts.map" /* locates font name translation table */
117 void mp_read_psname_table (MP mp) ;
119 @ @c void mp_read_psname_table (MP mp) {
120 font_number k; /* font for possible name match */
121 unsigned int lmax; /* upper limit on length of name to match */
122 unsigned int j; /* characters left to read before string gets too long */
123 char *s; /* possible font name to match */
124 text_char c=0; /* character being read from |ps_tab_file| */
125 if ( (mp->ps->ps_tab_file = mp_open_file(mp, ps_tab_name, "r", mp_filetype_fontmap)) ) {
126 @<Set |lmax| to the maximum |font_name| length for fonts
127 |last_ps_fnum+1| through |last_fnum|@>;
128 while (! feof(mp->ps->ps_tab_file) ) {
129 @<Read at most |lmax| characters from |ps_tab_file| into string |s|
130 but |goto common_ending| if there is trouble@>;
131 for (k=mp->last_ps_fnum+1;k<=mp->last_fnum;k++) {
132 if ( mp_xstrcmp(s,mp->font_name[k])==0 ) {
133 @<|flush_string(s)|, read in |font_ps_name[k]|, and
134 |goto common_ending|@>;
139 c = fgetc(mp->ps->ps_tab_file);
141 c = fgetc(mp->ps->ps_tab_file);
143 ungetc(c,mp->ps->ps_tab_file);
146 mp->last_ps_fnum=mp->last_fnum;
147 fclose(mp->ps->ps_tab_file);
152 FILE * ps_tab_file; /* file for font name translation table */
154 @ @<Set |lmax| to the maximum |font_name| length for fonts...@>=
156 for (k=mp->last_ps_fnum+1;k<=mp->last_fnum;k++) {
157 if (strlen(mp->font_name[k])>lmax )
158 lmax=strlen(mp->font_name[k]);
161 @ If we encounter the end of line before we have started reading
162 characters from |ps_tab_file|, we have found an entirely blank
163 line and we skip over it. Otherwise, we abort if the line ends
164 prematurely. If we encounter a comment character, we also skip
165 over the line, since recent versions of \.{dvips} allow comments
166 in the font map file.
168 TODO: this is probably not safe in the case of a really
169 broken font map file.
171 @<Read at most |lmax| characters from |ps_tab_file| into string |s|...@>=
172 s=mp_xmalloc(lmax+1,1);
175 if (c == '\n' || c == '\r' ) {
177 mp_xfree(s); s=NULL; goto COMMON_ENDING;
179 mp_fatal_error(mp, "The psfont map file is bad!");
182 c = fgetc(mp->ps->ps_tab_file);
183 if (c=='%' || c=='*' || c==';' || c=='#' ) {
184 mp_xfree(s); s=NULL; goto COMMON_ENDING;
186 if (c==' ' || c=='\t') break;
188 s[j++] = mp->xord[c];
190 mp_xfree(s); s=NULL; goto COMMON_ENDING;
195 @ PostScript font names should be at most 28 characters long but we allow 32
198 @<|flush_string(s)|, read in |font_ps_name[k]|, and...@>=
203 if (c=='\n' || c == '\r')
204 mp_fatal_error(mp, "The psfont map file is bad!");
205 c = fgetc(mp->ps->ps_tab_file);
206 } while (c==' ' || c=='\t');
207 ps_name = mp_xmalloc(33,1);
211 mp_fatal_error(mp, "The psfont map file is bad!");
213 ps_name[j++] = mp->xord[c];
214 if (c=='\n' || c == '\r')
217 c = fgetc(mp->ps->ps_tab_file);
218 } while (c != ' ' && c != '\t');
220 mp_xfree(mp->font_ps_name[k]);
221 mp->font_ps_name[k]=ps_name;
227 @* \[44a] Dealing with font encodings.
229 First, here are a few helpers for parsing files
231 @d check_buf(size, buf_size)
232 if ((unsigned)(size) > (unsigned)(buf_size)) {
234 snprintf(s,128,"buffer overflow: (%d,%d) at file %s, line %d",
235 size,buf_size, __FILE__, __LINE__ );
236 mp_fatal_error(mp,s);
239 @d append_char_to_buf(c, p, buf, buf_size) do {
242 if (c == 13 || c == EOF)
244 if (c != ' ' || (p > buf && p[-1] != 32)) {
245 check_buf(p - buf + 1, (buf_size));
250 @d append_eol(p, buf, buf_size) do {
251 check_buf(p - buf + 2, (buf_size));
252 if (p - buf > 1 && p[-1] != 10)
254 if (p - buf > 2 && p[-2] == 32) {
261 @d remove_eol(p, buf) do {
267 @d skip(p, c) if (*p == c) p++
268 @d strend(s) strchr(s, 0)
269 @d str_prefix(s1, s2) (strncmp((s1), (s2), strlen(s2)) == 0)
274 boolean loaded; /* the encoding has been loaded? */
275 char *file_name; /* encoding file name */
276 char *enc_name; /* encoding true name */
277 integer objnum; /* object number */
279 integer tounicode; /* object number of associated ToUnicode entry */
289 #define ENC_BUF_SIZE 0x1000
290 char enc_line[ENC_BUF_SIZE];
294 @d enc_getchar() getc(mp->ps->enc_file)
295 @d enc_eof() feof(mp->ps->enc_file)
296 @d enc_close() fclose(mp->ps->enc_file)
299 boolean mp_enc_open (MP mp, char *n) {
300 mp->ps->enc_file=mp_open_file(mp, n, "rb", mp_filetype_encoding);
301 if (mp->ps->enc_file!=NULL)
306 void mp_enc_getline (MP mp) {
311 print_err("unexpected end of file");
314 p = mp->ps->enc_line;
317 append_char_to_buf (c, p, mp->ps->enc_line, ENC_BUF_SIZE);
319 append_eol (p, mp->ps->enc_line, ENC_BUF_SIZE);
320 if (p - mp->ps->enc_line < 2 || *mp->ps->enc_line == '%')
323 void mp_load_enc (MP mp, char *enc_name,
324 char **enc_encname, char **glyph_names){
325 char buf[ENC_BUF_SIZE], *p, *r;
328 int save_selector = mp->selector;
329 if (!mp_enc_open (mp,enc_name)) {
330 mp_print (mp,"cannot open encoding file for reading");
333 mp_normalize_selector(mp);
335 mp_print (mp, enc_name);
337 if (*mp->ps->enc_line != '/' || (r = strchr (mp->ps->enc_line, '[')) == NULL) {
338 remove_eol (r, mp->ps->enc_line);
339 print_err ("invalid encoding vector (a name or `[' missing): `");
340 mp_print(mp,mp->ps->enc_line);
344 while (*(r-1)==' ') r--; /* strip trailing spaces from encoding name */
345 myname = mp_xmalloc(r-mp->ps->enc_line,1);
346 memcpy(myname,mp->ps->enc_line+1,(r-mp->ps->enc_line)-1);
347 *(myname+(r-mp->ps->enc_line-1))=0;
348 *enc_encname = myname;
356 *r != ' ' && *r != 10 && *r != ']' && *r != '/'; *p++ = *r++);
359 if (names_count > 256) {
360 print_err ("encoding vector contains more than 256 names");
363 if (mp_xstrcmp (buf, notdef) != 0)
364 glyph_names[names_count] = mp_xstrdup (buf);
367 if (*r != 10 && *r != '%') {
368 if (str_prefix (r, "] def"))
371 remove_eol (r, mp->ps->enc_line);
373 ("invalid encoding vector: a name or `] def' expected: `");
374 mp_print(mp,mp->ps->enc_line);
380 r = mp->ps->enc_line;
385 mp->selector = save_selector;
387 void mp_read_enc (MP mp, enc_entry * e) {
391 mp_load_enc (mp,e->file_name, &e->enc_name, e->glyph_names);
395 @ |write_enc| is used to write either external encoding (given in map file) or
396 internal encoding (read from the font file); when |glyph_names| is NULL
397 the 2nd argument is a pointer to the encoding entry; otherwise the 3rd is
398 the object number of the Encoding object
401 void mp_write_enc (MP mp, char **glyph_names, enc_entry * e) {
406 if (glyph_names == NULL) {
407 if (e->objnum != 0) /* the encoding has been written already */
415 mp_print(mp,"\n%%%%BeginResource: encoding ");
416 mp_print(mp, e->enc_name);
418 mp_print(mp, e->enc_name);
420 foffset = strlen(e->file_name)+3;
421 for (i = 0; i < 256; i++) {
423 if (s+1+foffset>=80) {
428 mp_print_char(mp,'/');
430 mp_print_char(mp,' ');
434 mp_print_nl (mp,"] def\n");
435 mp_print(mp,"%%%%EndResource");
439 @ All encoding entries go into AVL tree for fast search by name.
442 struct avl_table *enc_tree;
444 @ Memory management functions for avl
446 @<Static variables in the outer block@>=
447 static const char notdef[] = ".notdef";
450 static void *avl_xmalloc (struct libavl_allocator *allocator, size_t size);
451 static void avl_xfree (struct libavl_allocator *allocator, void *block);
454 static void *avl_xmalloc (struct libavl_allocator *allocator, size_t size) {
456 return mp_xmalloc (size,1);
458 static void avl_xfree (struct libavl_allocator *allocator, void *block) {
464 struct libavl_allocator avl_xallocator;
466 @ @<Set initial...@>=
467 mp->ps->avl_xallocator.libavl_malloc=avl_xmalloc;
468 mp->ps->avl_xallocator.libavl_free= avl_xfree;
469 mp->ps->enc_tree = NULL;
472 static int comp_enc_entry (const void *pa, const void *pb, void *p) {
474 return strcmp (((const enc_entry *) pa)->file_name,
475 ((const enc_entry *) pb)->file_name);
477 enc_entry * mp_add_enc (MP mp, char *s) {
481 if (mp->ps->enc_tree == NULL) {
482 mp->ps->enc_tree = avl_create (comp_enc_entry, NULL, &mp->ps->avl_xallocator);
485 p = (enc_entry *) avl_find (mp->ps->enc_tree, &tmp);
486 if (p != NULL) /* encoding already registered */
488 p = mp_xmalloc (1,sizeof (enc_entry));
490 p->file_name = mp_xstrdup (s);
493 p->glyph_names = mp_xmalloc (256,sizeof (char *));
494 for (i = 0; i < 256; i++)
495 p->glyph_names[i] = (char *) notdef;
496 aa = avl_probe (mp->ps->enc_tree, p);
503 static void mp_destroy_enc_entry (void *pa, void *pb) {
507 p = (enc_entry *) pa;
509 mp_xfree (p->file_name);
510 if (p->glyph_names != NULL)
511 for (i = 0; i < 256; i++)
512 if (p->glyph_names[i] != notdef)
513 mp_xfree (p->glyph_names[i]);
514 mp_xfree (p->glyph_names);
519 static void enc_free (MP mp);
521 @ @c static void enc_free (MP mp) {
522 if (mp->ps->enc_tree != NULL)
523 avl_destroy (mp->ps->enc_tree, mp_destroy_enc_entry);
526 @ @<Exported function headers@>=
527 void mp_load_encodings (MP mp, int lastfnum) ;
528 void mp_font_encodings (MP mp, int lastfnum, int encodings_only) ;
530 @ @c void mp_load_encodings (MP mp, int lastfnum) {
534 for (f=null_font+1;f<=lastfnum;f++) {
535 if (mp_has_font_size(mp,f) && mp_has_fm_entry (mp,f,&fm_cur)) {
536 if (fm_cur != NULL &&
537 fm_cur->ps_name != NULL &&
538 is_reencoded (fm_cur)) {
539 e = fm_cur->encoding;
545 void mp_font_encodings (MP mp, int lastfnum, int encodings_only) {
549 for (f=null_font+1;f<=lastfnum;f++) {
550 if (mp_has_font_size(mp,f) && mp_has_fm_entry (mp,f, &fm)) {
551 if (fm != NULL && (fm->ps_name != NULL)) {
552 if (is_reencoded (fm)) {
553 if (encodings_only || (!is_subsetted (fm))) {
555 mp_write_enc (mp,NULL, e);
556 /* clear for next run */
565 @* \[44b] Parsing font map files.
573 @d fm_close() fclose(mp->ps->fm_file)
574 @d fm_getchar() fgetc(mp->ps->fm_file)
575 @d fm_eof() feof(mp->ps->fm_file)
578 enum _mode { FM_DUPIGNORE, FM_REPLACE, FM_DELETE };
579 enum _ltype { MAPFILE, MAPLINE };
580 enum _tfmavail { TFM_UNCHECKED, TFM_FOUND, TFM_NOTFOUND };
581 typedef struct mitem {
582 int mode; /* |FM_DUPIGNORE| or |FM_REPLACE| or |FM_DELETE| */
583 int type; /* map file or map line */
584 char *map_line; /* pointer to map file name or map line */
585 int lineno; /* line number in map file */
591 fm_entry *loaded_tfm_found;
592 fm_entry *avail_tfm_found;
593 fm_entry *non_tfm_found;
594 fm_entry *not_avail_tfm_found;
596 @ @<Set initial...@>=
597 mp->ps->mitem = NULL;
600 static const char nontfm[] = "<nontfm>";
603 @d read_field(r, q, buf) do {
605 while (*r != ' ' && *r != '\0')
613 fm->F = mp_xstrdup(buf);
625 static fm_entry *new_fm_entry (void) {
627 fm = mp_xmalloc (1,sizeof(fm_entry));
632 fm->subset_tag = NULL;
634 fm->tfm_num = null_font;
635 fm->tfm_avail = TFM_UNCHECKED;
643 fm->all_glyphs = false;
650 static void delete_fm_entry (fm_entry * fm) {
651 mp_xfree (fm->tfm_name);
652 mp_xfree (fm->ps_name);
653 mp_xfree (fm->ff_name);
654 mp_xfree (fm->subset_tag);
655 mp_xfree (fm->charset);
659 static ff_entry *new_ff_entry (void) {
661 ff = mp_xmalloc (1,sizeof(ff_entry));
667 static void delete_ff_entry (ff_entry * ff) {
668 mp_xfree (ff->ff_name);
669 mp_xfree (ff->ff_path);
673 static char *mk_base_tfm (MP mp, char *tfmname, int *i) {
674 static char buf[SMALL_BUF_SIZE];
675 char *p = tfmname, *r = strend (p) - 1, *q = r;
676 while (q > p && isdigit (*q))
678 if (!(q > p) || q == r || (*q != '+' && *q != '-'))
680 check_buf (q - p + 1, SMALL_BUF_SIZE);
681 strncpy (buf, p, (size_t) (q - p));
687 @ @<Exported function headers@>=
688 boolean mp_has_fm_entry (MP mp,font_number f, fm_entry **fm);
691 boolean mp_has_fm_entry (MP mp,font_number f, fm_entry **fm) {
692 fm_entry *res = NULL;
693 res = mp_fm_lookup (mp, f);
697 return (res != NULL);
701 struct avl_table *tfm_tree;
702 struct avl_table *ps_tree;
703 struct avl_table *ff_tree;
705 @ @<Set initial...@>=
706 mp->ps->tfm_tree = NULL;
707 mp->ps->ps_tree = NULL;
708 mp->ps->ff_tree = NULL;
710 @ AVL sort |fm_entry| into |tfm_tree| by |tfm_name |
713 static int comp_fm_entry_tfm (const void *pa, const void *pb, void *p) {
715 return strcmp (((const fm_entry *) pa)->tfm_name,
716 ((const fm_entry *) pb)->tfm_name);
719 @ AVL sort |fm_entry| into |ps_tree| by |ps_name|, |slant|, and |extend|
721 @c static int comp_fm_entry_ps (const void *pa, const void *pb, void *p) {
723 const fm_entry *p1 = (const fm_entry *) pa, *p2 = (const fm_entry *) pb;
725 assert (p1->ps_name != NULL && p2->ps_name != NULL);
726 if ((i = strcmp (p1->ps_name, p2->ps_name)))
728 cmp_return (p1->slant, p2->slant);
729 cmp_return (p1->extend, p2->extend);
730 if (p1->tfm_name != NULL && p2->tfm_name != NULL &&
731 (i = strcmp (p1->tfm_name, p2->tfm_name)))
736 @ AVL sort |ff_entry| into |ff_tree| by |ff_name|
738 @c static int comp_ff_entry (const void *pa, const void *pb, void *p) {
740 return strcmp (((const ff_entry *) pa)->ff_name,
741 ((const ff_entry *) pb)->ff_name);
744 @ @c static void create_avl_trees (MP mp) {
745 if (mp->ps->tfm_tree == NULL) {
746 mp->ps->tfm_tree = avl_create (comp_fm_entry_tfm, NULL, &mp->ps->avl_xallocator);
747 assert (mp->ps->tfm_tree != NULL);
749 if (mp->ps->ps_tree == NULL) {
750 mp->ps->ps_tree = avl_create (comp_fm_entry_ps, NULL, &mp->ps->avl_xallocator);
751 assert (mp->ps->ps_tree != NULL);
753 if (mp->ps->ff_tree == NULL) {
754 mp->ps->ff_tree = avl_create (comp_ff_entry, NULL, &mp->ps->avl_xallocator);
755 assert (mp->ps->ff_tree != NULL);
759 @ The function |avl_do_entry| is not completely symmetrical with regards
760 to |tfm_name| and |ps_name handling|, e. g. a duplicate |tfm_name| gives a
761 |goto exit|, and no |ps_name| link is tried. This is to keep it compatible
762 with the original version.
766 @d set_tfmlink(fm) ((fm)->links |= LINK_TFM)
767 @d set_pslink(fm) ((fm)->links |= LINK_PS)
768 @d unset_tfmlink(fm) ((fm)->links &= ~LINK_TFM)
769 @d unset_pslink(fm) ((fm)->links &= ~LINK_PS)
770 @d has_tfmlink(fm) ((fm)->links & LINK_TFM)
771 @d has_pslink(fm) ((fm)->links & LINK_PS)
774 static int avl_do_entry (MP mp, fm_entry * fp, int mode) {
780 /* handle |tfm_name| link */
782 if (strcmp (fp->tfm_name, nontfm)) {
783 p = (fm_entry *) avl_find (mp->ps->tfm_tree, fp);
785 if (mode == FM_DUPIGNORE) {
786 snprintf(s,128,"fontmap entry for `%s' already exists, duplicates ignored",
790 } else { /* mode == |FM_REPLACE| / |FM_DELETE| */
791 if (mp_has_font_size(mp,p->tfm_num)) {
793 "fontmap entry for `%s' has been used, replace/delete not allowed",
798 a = avl_delete (mp->ps->tfm_tree, p);
805 if (mode != FM_DELETE) {
806 aa = avl_probe (mp->ps->tfm_tree, fp);
812 /* handle |ps_name| link */
814 if (fp->ps_name != NULL) {
815 assert (fp->tfm_name != NULL);
816 p = (fm_entry *) avl_find (mp->ps->ps_tree, fp);
818 if (mode == FM_DUPIGNORE) {
820 "ps_name entry for `%s' already exists, duplicates ignored",
824 } else { /* mode == |FM_REPLACE| / |FM_DELETE| */
825 if (mp_has_font_size(mp,p->tfm_num)) {
826 /* REPLACE/DELETE not allowed */
828 "fontmap entry for `%s' has been used, replace/delete not allowed",
833 a = avl_delete (mp->ps->ps_tree, p);
836 if (!has_tfmlink (p))
840 if (mode != FM_DELETE) {
841 aa = avl_probe (mp->ps->ps_tree, fp);
847 if (!has_tfmlink (fp) && !has_pslink (fp)) /* e. g. after |FM_DELETE| */
848 return 1; /* deallocation of |fm_entry| structure required */
853 @ consistency check for map entry, with warn flag
856 static int check_fm_entry (MP mp, fm_entry * fm, boolean warn) {
860 if (fm->ps_name != NULL) {
861 if (is_basefont (fm)) {
862 if (is_fontfile (fm) && !is_included (fm)) {
864 snprintf(s,128, "invalid entry for `%s': "
865 "font file must be included or omitted for base fonts",
871 } else { /* not a base font */
872 /* if no font file given, drop this entry */
873 /* |if (!is_fontfile (fm)) {
876 "invalid entry for `%s': font file missing",
885 if (is_truetype (fm) && is_reencoded (fm) && !is_subsetted (fm)) {
888 "invalid entry for `%s': only subsetted TrueType font can be reencoded",
894 if ((fm->slant != 0 || fm->extend != 0) &&
895 (is_truetype (fm))) {
898 "invalid entry for `%s': "
899 "SlantFont/ExtendFont can be used only with embedded T1 fonts",
905 if (abs (fm->slant) > 1000) {
908 "invalid entry for `%s': too big value of SlantFont (%g)",
909 fm->tfm_name, fm->slant / 1000.0);
914 if (abs (fm->extend) > 2000) {
917 "invalid entry for `%s': too big value of ExtendFont (%g)",
918 fm->tfm_name, fm->extend / 1000.0);
924 !(is_truetype (fm) && is_included (fm) &&
925 is_subsetted (fm) && !is_reencoded (fm))) {
928 "invalid entry for `%s': "
929 "PidEid can be used only with subsetted non-reencoded TrueType fonts",
938 @ returns true if s is one of the 14 std. font names; speed-trimmed.
940 @c static boolean check_basefont (char *s) {
941 static const char *basefont_names[] = {
943 "Courier-Bold", /* 1:12 */
944 "Courier-Oblique", /* 2:15 */
945 "Courier-BoldOblique", /* 3:19 */
946 "Helvetica", /* 4:9 */
947 "Helvetica-Bold", /* 5:14 */
948 "Helvetica-Oblique", /* 6:17 */
949 "Helvetica-BoldOblique", /* 7:21 */
951 "Times-Roman", /* 9:11 */
952 "Times-Bold", /* 10:10 */
953 "Times-Italic", /* 11:12 */
954 "Times-BoldItalic", /* 12:16 */
955 "ZapfDingbats" /* 13:12 */
957 static const int Index[] =
958 { -1, -1, -1, -1, -1, -1, 8, 0, -1, 4, 10, 9, -1, -1, 5, 2, 12, 6,
961 const size_t n = strlen (s);
965 if (n == 12) { /* three names have length 12 */
968 k = 1; /* Courier-Bold */
971 k = 11; /* Times-Italic */
974 k = 13; /* ZapfDingbats */
981 if (k > -1 && !strcmp (basefont_names[k], s))
987 @d is_cfg_comment(c) (c == 10 || c == '*' || c == '#' || c == ';' || c == '%')
989 @c static void fm_scan_line (MP mp) {
990 int a, b, c, j, u = 0, v = 0;
993 char fm_line[FM_BUF_SIZE], buf[FM_BUF_SIZE];
996 switch (mp->ps->mitem->type) {
1001 append_char_to_buf (c, p, fm_line, FM_BUF_SIZE);
1008 r = mp->ps->mitem->map_line;
1013 if (*r == '\0' || is_cfg_comment (*r))
1015 fm = new_fm_entry ();
1016 read_field (r, q, buf);
1017 set_field (tfm_name);
1019 read_field (r, q, buf);
1020 if (*buf != '<' && *buf != '"')
1021 set_field (ps_name);
1023 r = p; /* unget the field */
1024 if (isdigit (*r)) { /* font flags given */
1025 fm->flags = atoi (r);
1026 while (isdigit (*r))
1029 while (1) { /* loop through "specials", encoding, font file */
1034 case '"': /* opening quote */
1039 if (sscanf (r, "%f %n", &d, &j) > 0) {
1040 s = r + j; /* jump behind number, eat also blanks, if any */
1041 if (*(s - 1) == 'E' || *(s - 1) == 'e')
1042 s--; /* e. g. 0.5ExtendFont: \%f = 0.5E */
1043 if (str_prefix (s, "SlantFont")) {
1044 d *= 1000.0; /* correct rounding also for neg. numbers */
1045 fm->slant = (integer) (d > 0 ? d + 0.5 : d - 0.5);
1046 r = s + strlen ("SlantFont");
1047 } else if (str_prefix (s, "ExtendFont")) {
1049 fm->extend = (integer) (d > 0 ? d + 0.5 : d - 0.5);
1050 if (fm->extend == 1000)
1052 r = s + strlen ("ExtendFont");
1053 } else { /* unknown name */
1055 *r != ' ' && *r != '"' && *r != '\0';
1056 r++); /* jump over name */
1057 c = *r; /* remember char for temporary end of string */
1059 snprintf(warn_s,128,
1060 "invalid entry for `%s': unknown name `%s' ignored",
1066 for (; *r != ' ' && *r != '"' && *r != '\0'; r++);
1069 if (*r == '"') /* closing quote */
1072 snprintf(warn_s,128,
1073 "invalid entry for `%s': closing quote missing",
1079 case 'P': /* handle cases for subfonts like 'PidEid=3,1' */
1080 if (sscanf (r, "PidEid=%i, %i %n", &a, &b, &c) >= 2) {
1086 default: /* encoding or font file specification */
1090 if (*r == '<' || *r == '[')
1093 read_field (r, q, buf);
1094 /* encoding, formats: '8r.enc' or '<8r.enc' or '<[8r.enc' */
1095 if (strlen (buf) > 4 && strcasecmp (strend (buf) - 4, ".enc") == 0) {
1096 fm->encoding = mp_add_enc (mp, buf);
1097 u = v = 0; /* u, v used if intervening blank: "<< foo" */
1098 } else if (strlen (buf) > 0) { /* file name given */
1099 /* font file, formats:
1100 * subsetting: '<cmr10.pfa'
1101 * no subsetting: '<<cmr10.pfa'
1102 * no embedding: 'cmr10.pfa'
1104 if (a == '<' || u == '<') {
1106 if ((a == '<' && b == 0) || (a == 0 && v == 0))
1108 /* otherwise b == '<' (or '[') => no subsetting */
1110 set_field (ff_name);
1119 if (fm->ps_name != NULL && check_basefont (fm->ps_name))
1121 if (is_fontfile (fm)
1122 && strcasecmp (strend (fm_fontfile (fm)) - 4, ".ttf") == 0)
1124 if (check_fm_entry (mp,fm, true) != 0)
1127 Until here the map line has been completely scanned without errors;
1128 fm points to a valid, freshly filled-out |fm_entry| structure.
1129 Now follows the actual work of registering/deleting.
1131 if (avl_do_entry (mp, fm, mp->ps->mitem->mode) == 0) /* if success */
1134 delete_fm_entry (fm);
1138 @c static void fm_read_info (MP mp) {
1141 if (mp->ps->tfm_tree == NULL)
1142 create_avl_trees (mp);
1143 if (mp->ps->mitem->map_line == NULL) /* nothing to do */
1145 mp->ps->mitem->lineno = 1;
1146 switch (mp->ps->mitem->type) {
1148 n = mp->ps->mitem->map_line;
1149 mp->ps->fm_file = mp_open_file(mp, n, "r", mp_filetype_fontmap);
1150 if (!mp->ps->fm_file) {
1151 snprintf(s,256,"cannot open font map file %s",n);
1154 int save_selector = mp->selector;
1155 mp_normalize_selector(mp);
1158 while (!fm_eof ()) {
1160 mp->ps->mitem->lineno++;
1164 mp->selector = save_selector;
1165 mp->ps->fm_file = NULL;
1174 mp->ps->mitem->map_line = NULL; /* done with this line */
1179 scaled mp_round_xn_over_d (MP mp, scaled x, integer n, integer d) {
1180 boolean positive; /* was |x>=0|? */
1181 unsigned int t,u; /* intermediate quantities */
1182 integer v; /* intermediate quantities */
1186 negate(x); positive=false;
1189 u=(x / 0100000)*n+(t / 0100000);
1190 v=(u % d)*0100000 + (t % 0100000);
1191 if ( u / d>=0100000 ) mp->arith_error=true;
1192 else u=0100000*(u / d) + (v / d);
1196 return ( positive ? u : -u );
1198 static fm_entry *mk_ex_fm (MP mp, font_number f, fm_entry * basefm, int ex) {
1200 integer e = basefm->extend;
1203 fm = new_fm_entry ();
1204 fm->flags = basefm->flags;
1205 fm->encoding = basefm->encoding;
1206 fm->type = basefm->type;
1207 fm->slant = basefm->slant;
1208 fm->extend = mp_round_xn_over_d (mp, e, 1000 + ex, 1000);
1209 /* modify ExtentFont to simulate expansion */
1210 if (fm->extend == 1000)
1212 fm->tfm_name = mp_xstrdup (mp->font_name[f]);
1213 if (basefm->ps_name != NULL)
1214 fm->ps_name = mp_xstrdup (basefm->ps_name);
1215 fm->ff_name = mp_xstrdup (basefm->ff_name);
1218 fm->tfm_avail = TFM_FOUND;
1219 assert (strcmp (fm->tfm_name, nontfm));
1223 @ @c static void init_fm (fm_entry * fm, font_number f) {
1224 if (fm->tfm_num == null_font ) {
1226 fm->tfm_avail = TFM_FOUND;
1231 fm_entry * mp_fm_lookup (MP mp, font_number f);
1234 fm_entry * mp_fm_lookup (MP mp, font_number f) {
1236 fm_entry *fm, *exfm;
1239 if (mp->ps->tfm_tree == NULL)
1240 fm_read_info (mp); /* only to read default map file */
1241 tfm = mp->font_name[f];
1242 assert (strcmp (tfm, nontfm));
1243 /* Look up for full <tfmname>[+-]<expand> */
1245 fm = (fm_entry *) avl_find (mp->ps->tfm_tree, &tmp);
1248 return (fm_entry *) fm;
1250 tfm = mk_base_tfm (mp, mp->font_name[f], &e);
1251 if (tfm == NULL) /* not an expanded font, nothing to do */
1255 fm = (fm_entry *) avl_find (mp->ps->tfm_tree, &tmp);
1256 if (fm != NULL) { /* found an entry with the base tfm name, e.g. cmr10 */
1257 return (fm_entry *) fm; /* font expansion uses the base font */
1258 /* the following code would be obsolete, as would be |mk_ex_fm| */
1259 if (!is_t1fontfile (fm) || !is_included (fm)) {
1262 "font %s cannot be expanded (not an included Type1 font)", tfm);
1266 exfm = mk_ex_fm (mp, f, fm, e); /* copies all fields from fm except tfm name */
1268 ai = avl_do_entry (mp, exfm, FM_DUPIGNORE);
1270 return (fm_entry *) exfm;
1275 @ Early check whether a font file exists. Used e. g. for replacing fonts
1276 of embedded PDF files: Without font file, the font within the embedded
1277 PDF-file is used. Search tree |ff_tree| is used in 1st instance, as it
1278 may be faster than the |kpse_find_file()|, and |kpse_find_file()| is called
1279 only once per font file name + expansion parameter. This might help
1280 keeping speed, if many PDF pages with same fonts are to be embedded.
1282 The |ff_tree| contains only font files, which are actually needed,
1283 so this tree typically is much smaller than the |tfm_tree| or |ps_tree|.
1286 static ff_entry *check_ff_exist (MP mp, fm_entry * fm) {
1291 assert (fm->ff_name != NULL);
1292 tmp.ff_name = fm->ff_name;
1293 ff = (ff_entry *) avl_find (mp->ps->ff_tree, &tmp);
1294 if (ff == NULL) { /* not yet in database */
1295 ff = new_ff_entry ();
1296 ff->ff_name = mp_xstrdup (fm->ff_name);
1297 ff->ff_path = mp_xstrdup (fm->ff_name);
1298 aa = avl_probe (mp->ps->ff_tree, ff);
1299 assert (aa != NULL);
1305 font_number mp_tfm_lookup (MP mp, char *s, scaled fs) {
1306 /* looks up for a TFM with name |s| loaded at |fs| size; if found then flushes |s| */
1308 if ( fs != 0 ) { /* should not be used! */
1309 for (k = null_font + 1;k<=mp->last_fnum;k++) {
1310 if ( mp_xstrcmp( mp->font_name[k], s) && (mp->font_sizes[k] == fs) ) {
1316 for (k = null_font + 1;k<=mp->last_fnum;k++) {
1317 if ( mp_xstrcmp(mp->font_name[k], s) ) {
1326 @ Process map file given by its name or map line contents. Items not
1327 beginning with [+-=] flush default map file, if it has not yet been
1328 read. Leading blanks and blanks immediately following [+-=] are ignored.
1331 @c void mp_process_map_item (MP mp, char *s, int type) {
1335 s++; /* ignore leading blank */
1337 case '+': /* +mapfile.map, +mapline */
1338 mode = FM_DUPIGNORE; /* insert entry, if it is not duplicate */
1341 case '=': /* =mapfile.map, =mapline */
1342 mode = FM_REPLACE; /* try to replace earlier entry */
1345 case '-': /* -mapfile.map, -mapline */
1346 mode = FM_DELETE; /* try to delete entry */
1350 mode = FM_DUPIGNORE; /* like +, but also: */
1351 mp->ps->mitem->map_line = NULL; /* flush default map file name */
1354 s++; /* ignore blank after [+-=] */
1355 p = s; /* map item starts here */
1357 case MAPFILE: /* remove blank at end */
1358 while (*p != '\0' && *p != ' ')
1362 case MAPLINE: /* blank at end allowed */
1367 if (mp->ps->mitem->map_line != NULL) /* read default map file first */
1369 if (*s != '\0') { /* only if real item to process */
1370 mp->ps->mitem->mode = mode;
1371 mp->ps->mitem->type = type;
1372 mp->ps->mitem->map_line = s;
1377 @ @<Exported function headers@>=
1378 void mp_map_file (MP mp, str_number t);
1379 void mp_map_line (MP mp, str_number t);
1380 void mp_init_map_file (MP mp, int is_troff);
1383 void mp_map_file (MP mp, str_number t) {
1384 char *s = mp_xstrdup(mp_str (mp,t));
1385 mp_process_map_item (mp, s, MAPFILE);
1388 void mp_map_line (MP mp, str_number t) {
1389 char *s = mp_xstrdup(mp_str (mp,t));
1390 mp_process_map_item (mp, s, MAPLINE);
1395 @c void mp_init_map_file (MP mp, int is_troff) {
1397 mp->ps->mitem = mp_xmalloc (1,sizeof(mapitem));
1398 mp->ps->mitem->mode = FM_DUPIGNORE;
1399 mp->ps->mitem->type = MAPFILE;
1400 mp->ps->mitem->map_line = NULL;
1401 if ((mp->find_file)("mpost.map", "rb", mp_filetype_fontmap) != NULL) {
1402 mp->ps->mitem->map_line = mp_xstrdup ("mpost.map");
1405 mp->ps->mitem->map_line = mp_xstrdup ("troff.map");
1407 mp->ps->mitem->map_line = mp_xstrdup ("pdftex.map");
1412 @ @<Dealloc variables@>=
1413 if (mp->ps->mitem!=NULL) {
1414 mp_xfree(mp->ps->mitem->map_line);
1415 mp_xfree(mp->ps->mitem);
1421 static void destroy_fm_entry_tfm (void *pa, void *pb) {
1424 fm = (fm_entry *) pa;
1425 if (!has_pslink (fm))
1426 delete_fm_entry (fm);
1430 static void destroy_fm_entry_ps (void *pa, void *pb) {
1433 fm = (fm_entry *) pa;
1434 if (!has_tfmlink (fm))
1435 delete_fm_entry (fm);
1439 static void destroy_ff_entry (void *pa, void *pb) {
1442 ff = (ff_entry *) pa;
1443 delete_ff_entry (ff);
1447 static void fm_free (MP mp);
1450 static void fm_free (MP mp) {
1451 if (mp->ps->tfm_tree != NULL)
1452 avl_destroy (mp->ps->tfm_tree, destroy_fm_entry_tfm);
1453 if (mp->ps->ps_tree != NULL)
1454 avl_destroy (mp->ps->ps_tree, destroy_fm_entry_ps);
1455 if (mp->ps->ff_tree != NULL)
1456 avl_destroy (mp->ps->ff_tree, destroy_ff_entry);
1459 @* \[44c] Helper functions for Type1 fonts.
1462 typedef char char_entry;
1463 typedef unsigned char Byte;
1467 char_entry *char_ptr, *char_array;
1469 char *job_id_string;
1471 @ @<Set initial...@>=
1472 mp->ps->char_array = NULL;
1473 mp->ps->job_id_string = NULL;
1476 @d SMALL_ARRAY_SIZE 256
1480 void mp_set_job_id (MP mp, int year, int month, int day, int time) {
1481 char *name_string, *format_string, *s;
1484 if (mp->ps->job_id_string != NULL)
1486 if ( mp->job_name==NULL )
1487 mp->job_name = mp_xstrdup("mpout");
1488 name_string = mp_xstrdup (mp->job_name);
1489 format_string = mp_xstrdup (mp->mem_ident);
1490 slen = SMALL_BUF_SIZE +
1491 strlen (name_string) +
1492 strlen (format_string);
1493 s = mp_xmalloc (slen, sizeof (char));
1494 i = snprintf (s, slen,
1495 "%.4d/%.2d/%.2d %.2d:%.2d %s %s",
1501 name_string, format_string);
1502 mp->ps->job_id_string = mp_xstrdup (s);
1504 mp_xfree (name_string);
1505 mp_xfree (format_string);
1507 static void fnstr_append (MP mp, const char *s) {
1508 size_t l = strlen (s) + 1;
1509 alloc_array (char, l, SMALL_ARRAY_SIZE);
1510 strcat (mp->ps->char_ptr, s);
1511 mp->ps->char_ptr = strend (mp->ps->char_ptr);
1514 @ @<Exported function headers@>=
1515 void mp_set_job_id (MP mp, int y, int m, int d, int t) ;
1517 @ @<Dealloc variables@>=
1518 mp_xfree(mp->ps->job_id_string);
1520 @ this is not really a true crc32, but it should be just enough to keep
1521 subsets prefixes somewhat disjunct
1524 static unsigned long crc32 (int oldcrc, const Byte *buf, int len) {
1525 unsigned long ret = 0;
1528 ret = (23<<24)+(45<<16)+(67<<8)+89;
1531 ret = (ret<<2)+buf[i];
1534 boolean mp_char_marked (MP mp,font_number f, eight_bits c) {
1535 integer b; /* |char_base[f]| */
1537 if ( (c>=mp->font_bc[f])&&(c<=mp->font_ec[f])&&(mp->font_info[b+c].qqqq.b3!=0) )
1543 static void make_subset_tag (MP mp, fm_entry * fm_cur, char **glyph_names, int tex_font)
1549 if (mp->ps->job_id_string ==NULL)
1550 mp_fatal_error(mp, "no job id!");
1551 l = strlen (mp->ps->job_id_string) + 1;
1553 alloc_array (char, l, SMALL_ARRAY_SIZE);
1554 strcpy (mp->ps->char_array, mp->ps->job_id_string);
1555 mp->ps->char_ptr = strend (mp->ps->char_array);
1556 if (fm_cur->tfm_name != NULL) {
1557 fnstr_append (mp," TFM name: ");
1558 fnstr_append (mp,fm_cur->tfm_name);
1560 fnstr_append (mp," PS name: ");
1561 if (fm_cur->ps_name != NULL)
1562 fnstr_append (mp,fm_cur->ps_name);
1563 fnstr_append (mp," Encoding: ");
1564 if (fm_cur->encoding != NULL && (fm_cur->encoding)->file_name != NULL)
1565 fnstr_append (mp,(fm_cur->encoding)->file_name);
1567 fnstr_append (mp,"built-in");
1568 fnstr_append (mp," CharSet: ");
1569 for (i = 0; i < 256; i++)
1570 if (mp_char_marked (mp,tex_font, i) && glyph_names[i] != notdef) {
1571 if (glyph_names[i]!=NULL) {
1572 fnstr_append (mp,"/");
1573 fnstr_append (mp,glyph_names[i]);
1576 if (fm_cur->charset != NULL) {
1577 fnstr_append (mp," Extra CharSet: ");
1578 fnstr_append (mp, fm_cur->charset);
1580 crc = crc32 (0L, Z_NULL, 0);
1581 crc = crc32 (crc, (Bytef *) mp->ps->char_array, strlen (mp->ps->char_array));
1582 /* we need to fit a 32-bit number into a string of 6 uppercase chars long;
1583 * there are 26 uppercase chars ==> each char represents a number in range
1584 * |0..25|. The maximal number that can be represented by the tag is
1585 * $26^6 - 1$, which is a number between $2^28$ and $2^29$. Thus the bits |29..31|
1586 * of the CRC must be dropped out.
1588 for (i = 0; i < 6; i++) {
1589 tag[i] = 'A' + crc % 26;
1593 fm_cur->subset_tag = mp_xstrdup (tag);
1599 @d external_enc() (fm_cur->encoding)->glyph_names
1600 @d is_used_char(c) mp_char_marked (mp, tex_font, c)
1601 @d end_last_eexec_line()
1602 mp->ps->hexline_length = HEXLINE_WIDTH;
1604 mp->ps->t1_eexec_encrypt = false
1605 @d t1_log(s) mp_print(mp,(char *)s)
1606 @d t1_putchar(c) fputc(c, mp->ps_file)
1607 @d embed_all_glyphs(tex_font) false
1609 @d extra_charset() mp->ps->dvips_extra_charset
1610 @d update_subset_tag()
1611 @d fixedcontent true
1614 #define PRINTF_BUF_SIZE 1024
1615 char *dvips_extra_charset;
1617 unsigned char *grid;
1618 char *ext_glyph_names[256];
1619 char print_buf[PRINTF_BUF_SIZE];
1621 @ @<Set initial ...@>=
1622 mp->ps->dvips_extra_charset=NULL;
1625 @d t1_getchar() fgetc(mp->ps->t1_file)
1626 @d t1_ungetchar(c) ungetc(c, mp->ps->t1_file)
1627 @d t1_eof() feof(mp->ps->t1_file)
1628 @d t1_close() fclose(mp->ps->t1_file)
1629 @d valid_code(c) (c >= 0 && c < 256)
1631 @<Static variables in the outer block@>=
1632 static const char *standard_glyph_names[256] =
1633 { notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1634 notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1635 notdef, notdef, notdef, notdef, notdef, notdef,
1636 notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1637 "space", "exclam", "quotedbl", "numbersign",
1638 "dollar", "percent", "ampersand", "quoteright", "parenleft",
1639 "parenright", "asterisk", "plus", "comma", "hyphen", "period",
1640 "slash", "zero", "one", "two", "three", "four", "five", "six", "seven",
1641 "eight", "nine", "colon", "semicolon", "less",
1642 "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F",
1643 "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q",
1644 "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft",
1645 "backslash", "bracketright", "asciicircum", "underscore",
1646 "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k",
1647 "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v",
1648 "w", "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde",
1649 notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1650 notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1651 notdef, notdef, notdef, notdef, notdef, notdef,
1652 notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1653 notdef, notdef, notdef, "exclamdown", "cent",
1654 "sterling", "fraction", "yen", "florin", "section", "currency",
1655 "quotesingle", "quotedblleft", "guillemotleft",
1656 "guilsinglleft", "guilsinglright", "fi", "fl", notdef, "endash",
1657 "dagger", "daggerdbl", "periodcentered", notdef,
1658 "paragraph", "bullet", "quotesinglbase", "quotedblbase",
1659 "quotedblright", "guillemotright", "ellipsis", "perthousand",
1660 notdef, "questiondown", notdef, "grave", "acute", "circumflex",
1661 "tilde", "macron", "breve", "dotaccent", "dieresis", notdef,
1662 "ring", "cedilla", notdef, "hungarumlaut", "ogonek", "caron", "emdash",
1663 notdef, notdef, notdef, notdef, notdef, notdef,
1664 notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1665 notdef, "AE", notdef, "ordfeminine", notdef, notdef,
1666 notdef, notdef, "Lslash", "Oslash", "OE", "ordmasculine", notdef,
1667 notdef, notdef, notdef, notdef, "ae", notdef, notdef,
1668 notdef, "dotlessi", notdef, notdef, "lslash", "oslash", "oe",
1669 "germandbls", notdef, notdef, notdef, notdef };
1670 static const char charstringname[] = "/CharStrings";
1673 char **t1_glyph_names;
1674 char *t1_builtin_glyph_names[256];
1675 char charsetstr[0x4000];
1676 boolean read_encoding_only;
1680 #define T1_BUF_SIZE 0x10
1684 #define CS_VMOVETO 4
1685 #define CS_RLINETO 5
1686 #define CS_HLINETO 6
1687 #define CS_VLINETO 7
1688 #define CS_RRCURVETO 8
1689 #define CS_CLOSEPATH 9
1690 #define CS_CALLSUBR 10
1691 #define CS_RETURN 11
1692 #define CS_ESCAPE 12
1694 #define CS_ENDCHAR 14
1695 #define CS_RMOVETO 21
1696 #define CS_HMOVETO 22
1697 #define CS_VHCURVETO 30
1698 #define CS_HVCURVETO 31
1699 #define CS_1BYTE_MAX (CS_HVCURVETO + 1)
1701 #define CS_DOTSECTION CS_1BYTE_MAX + 0
1702 #define CS_VSTEM3 CS_1BYTE_MAX + 1
1703 #define CS_HSTEM3 CS_1BYTE_MAX + 2
1704 #define CS_SEAC CS_1BYTE_MAX + 6
1705 #define CS_SBW CS_1BYTE_MAX + 7
1706 #define CS_DIV CS_1BYTE_MAX + 12
1707 #define CS_CALLOTHERSUBR CS_1BYTE_MAX + 16
1708 #define CS_POP CS_1BYTE_MAX + 17
1709 #define CS_SETCURRENTPOINT CS_1BYTE_MAX + 33
1710 #define CS_2BYTE_MAX (CS_SETCURRENTPOINT + 1)
1711 #define CS_MAX CS_2BYTE_MAX
1714 typedef unsigned char byte;
1716 byte nargs; /* number of arguments */
1717 boolean bottom; /* take arguments from bottom of stack? */
1718 boolean clear; /* clear stack? */
1720 } cc_entry; /* CharString Command */
1722 char *glyph_name; /* glyph name (or notdef for Subrs entry) */
1724 unsigned short len; /* length of the whole string */
1725 unsigned short cslen; /* length of the encoded part of the string */
1731 unsigned short t1_dr, t1_er;
1732 unsigned short t1_c1, t1_c2;
1733 unsigned short t1_cslen;
1736 @ @<Set initial...@>=
1737 mp->ps->t1_c1 = 52845;
1738 mp->ps->t1_c2 = 22719;
1741 typedef char t1_line_entry;
1742 typedef char t1_buf_entry;
1745 t1_line_entry *t1_line_ptr, *t1_line_array;
1746 size_t t1_line_limit;
1747 t1_buf_entry *t1_buf_ptr, *t1_buf_array;
1748 size_t t1_buf_limit;
1750 cs_entry *cs_tab, *cs_ptr, *cs_notdef;
1751 char *cs_dict_start, *cs_dict_end;
1752 int cs_count, cs_size, cs_size_pos;
1754 char *subr_array_start, *subr_array_end;
1755 int subr_max, subr_size, subr_size_pos;
1757 @ @<Set initial...@>=
1758 mp->ps->t1_line_array = NULL;
1759 mp->ps->t1_buf_array = NULL;
1762 This list contains the begin/end tokens commonly used in the
1763 /Subrs array of a Type 1 font.
1765 @<Static variables in the outer block@>=
1766 static const char *cs_token_pairs_list[][2] = {
1769 {" RD", "noaccess put"},
1770 {" -|", "noaccess put"},
1775 const char **cs_token_pair;
1776 boolean t1_pfa, t1_cs, t1_scan, t1_eexec_encrypt, t1_synthetic;
1777 int t1_in_eexec; /* 0 before eexec-encrypted, 1 during, 2 after */
1778 long t1_block_length;
1786 @<Set initial ...@>=
1787 mp->ps->hexline_length = HEXLINE_WIDTH;
1790 @d t1_prefix(s) str_prefix(mp->ps->t1_line_array, s)
1791 @d t1_buf_prefix(s) str_prefix(mp->ps->t1_buf_array, s)
1792 @d t1_suffix(s) str_suffix(mp->ps->t1_line_array, mp->ps->t1_line_ptr, s)
1793 @d t1_buf_suffix(s) str_suffix(mp->ps->t1_buf_array, mp->ps->t1_buf_ptr, s)
1794 @d t1_charstrings() strstr(mp->ps->t1_line_array, charstringname)
1795 @d t1_subrs() t1_prefix("/Subrs")
1796 @d t1_end_eexec() t1_suffix("mark currentfile closefile")
1797 @d t1_cleartomark() t1_prefix("cleartomark")
1799 @d isdigit(A) ((A)>='0'&&(A)<='9')
1802 static void end_hexline (MP mp) {
1803 if (mp->ps->hexline_length == HEXLINE_WIDTH) {
1804 fputs ("\n", mp->ps_file);
1805 mp->ps->hexline_length = 0;
1808 static void t1_check_pfa (MP mp) {
1809 const int c = t1_getchar ();
1810 mp->ps->t1_pfa = (c != 128) ? true : false;
1813 static int t1_getbyte (MP mp)
1815 int c = t1_getchar ();
1818 if (mp->ps->t1_block_length == 0) {
1820 mp_fatal_error (mp, "invalid marker");
1827 mp->ps->t1_block_length = t1_getchar () & 0xff;
1828 mp->ps->t1_block_length |= (t1_getchar () & 0xff) << 8;
1829 mp->ps->t1_block_length |= (t1_getchar () & 0xff) << 16;
1830 mp->ps->t1_block_length |= (t1_getchar () & 0xff) << 24;
1833 mp->ps->t1_block_length--;
1836 static int hexval (int c) {
1837 if (c >= 'A' && c <= 'F')
1838 return c - 'A' + 10;
1839 else if (c >= 'a' && c <= 'f')
1840 return c - 'a' + 10;
1841 else if (c >= '0' && c <= '9')
1846 static byte edecrypt (MP mp, byte cipher) {
1848 if (mp->ps->t1_pfa) {
1849 while (cipher == 10 || cipher == 13)
1850 cipher = t1_getbyte (mp);
1851 mp->ps->last_hexbyte = cipher = (hexval (cipher) << 4) + hexval (t1_getbyte (mp));
1853 plain = (cipher ^ (mp->ps->t1_dr >> 8));
1854 mp->ps->t1_dr = (cipher + mp->ps->t1_dr) * mp->ps->t1_c1 + mp->ps->t1_c2;
1857 static byte cdecrypt (MP mp, byte cipher, unsigned short *cr)
1859 const byte plain = (cipher ^ (*cr >> 8));
1860 *cr = (cipher + *cr) * mp->ps->t1_c1 + mp->ps->t1_c2;
1863 static byte eencrypt (MP mp, byte plain)
1865 const byte cipher = (plain ^ (mp->ps->t1_er >> 8));
1866 mp->ps->t1_er = (cipher + mp->ps->t1_er) * mp->ps->t1_c1 + mp->ps->t1_c2;
1870 static byte cencrypt (MP mp, byte plain, unsigned short *cr)
1872 const byte cipher = (plain ^ (*cr >> 8));
1873 *cr = (cipher + *cr) * mp->ps->t1_c1 + mp->ps->t1_c2;
1877 static char *eol (char *s) {
1878 char *p = strend (s);
1879 if (p - s > 1 && p[-1] != 10) {
1885 static float t1_scan_num (MP mp, char *p, char **r)
1890 if (sscanf (p, "%g", &f) != 1) {
1891 remove_eol (p, mp->ps->t1_line_array);
1892 snprintf(s,128, "a number expected: `%s'", mp->ps->t1_line_array);
1893 mp_fatal_error(mp,s);
1896 for (; isdigit (*p) || *p == '.' ||
1897 *p == 'e' || *p == 'E' || *p == '+' || *p == '-'; p++);
1903 static boolean str_suffix (const char *begin_buf, const char *end_buf,
1906 const char *s1 = end_buf - 1, *s2 = strend (s) - 1;
1909 while (s1 >= begin_buf && s2 >= s) {
1918 @d alloc_array(T, n, s) do {
1919 if (mp->ps->T##_array == NULL) {
1920 mp->ps->T##_limit = (s);
1921 if ((unsigned)(n) > mp->ps->T##_limit)
1922 mp->ps->T##_limit = (n);
1923 mp->ps->T##_array = mp_xmalloc (mp->ps->T##_limit,sizeof(T##_entry));
1924 mp->ps->T##_ptr = mp->ps->T##_array;
1926 else if ((unsigned)(mp->ps->T##_ptr - mp->ps->T##_array + (n)) > mp->ps->T##_limit) {
1927 size_t last_ptr_index;
1928 last_ptr_index = mp->ps->T##_ptr - mp->ps->T##_array;
1929 mp->ps->T##_limit *= 2;
1930 if ((unsigned)(mp->ps->T##_ptr - mp->ps->T##_array + (n)) > mp->ps->T##_limit)
1931 mp->ps->T##_limit = mp->ps->T##_ptr - mp->ps->T##_array + (n);
1932 mp->ps->T##_array = mp_xrealloc(mp->ps->T##_array, mp->ps->T##_limit , sizeof (T##_entry));
1933 mp->ps->T##_ptr = mp->ps->T##_array + last_ptr_index;
1937 @d out_eexec_char(A) t1_outhex(mp,(A))
1940 static void t1_outhex (MP mp, byte b)
1942 static char *hexdigits = "0123456789ABCDEF";
1943 t1_putchar (hexdigits[b / 16]);
1944 t1_putchar (hexdigits[b % 16]);
1945 mp->ps->hexline_length += 2;
1948 static void t1_getline (MP mp) {
1949 int c, l, eexec_scan;
1951 static const char eexec_str[] = "currentfile eexec";
1952 static int eexec_len = 17; /* |strlen(eexec_str)| */
1955 mp_fatal_error (mp,"unexpected end of file");
1956 mp->ps->t1_line_ptr = mp->ps->t1_line_array;
1957 alloc_array (t1_line, 1, T1_BUF_SIZE);
1958 mp->ps->t1_cslen = 0;
1960 c = t1_getbyte (mp);
1963 while (!t1_eof ()) {
1964 if (mp->ps->t1_in_eexec == 1)
1965 c = edecrypt (mp,c);
1966 alloc_array (t1_line, 1, T1_BUF_SIZE);
1967 append_char_to_buf (c, mp->ps->t1_line_ptr, mp->ps->t1_line_array, mp->ps->t1_line_limit);
1968 if (mp->ps->t1_in_eexec == 0 && eexec_scan >= 0 && eexec_scan < eexec_len) {
1969 if (mp->ps->t1_line_array[eexec_scan] == eexec_str[eexec_scan])
1974 if (c == 10 || (mp->ps->t1_pfa && eexec_scan == eexec_len && c == 32))
1976 if (mp->ps->t1_cs && mp->ps->t1_cslen == 0 &&
1977 (mp->ps->t1_line_ptr - mp->ps->t1_line_array > 4) &&
1978 (t1_suffix (" RD ") || t1_suffix (" -| "))) {
1979 p = mp->ps->t1_line_ptr - 5;
1982 mp->ps->t1_cslen = l = t1_scan_num (mp, p + 1, 0);
1983 mp->ps->cs_start = mp->ps->t1_line_ptr - mp->ps->t1_line_array;
1984 /* |mp->ps->cs_start| is an index now */
1985 alloc_array (t1_line, l, T1_BUF_SIZE);
1987 *mp->ps->t1_line_ptr++ = edecrypt (mp,t1_getbyte (mp));
1989 c = t1_getbyte (mp);
1991 alloc_array (t1_line, 2, T1_BUF_SIZE); /* |append_eol| can append 2 chars */
1992 append_eol (mp->ps->t1_line_ptr, mp->ps->t1_line_array, mp->ps->t1_line_limit);
1993 if (mp->ps->t1_line_ptr - mp->ps->t1_line_array < 2)
1995 if (eexec_scan == eexec_len)
1996 mp->ps->t1_in_eexec = 1;
1998 /* ensure that |mp->ps->t1_buf_array| has as much room as |t1_line_array| */
1999 mp->ps->t1_buf_ptr = mp->ps->t1_buf_array;
2000 alloc_array (t1_buf, mp->ps->t1_line_limit, mp->ps->t1_line_limit);
2003 static void t1_putline (MP mp)
2005 char *p = mp->ps->t1_line_array;
2006 if (mp->ps->t1_line_ptr - mp->ps->t1_line_array <= 1)
2008 if (mp->ps->t1_eexec_encrypt) {
2009 while (p < mp->ps->t1_line_ptr)
2010 out_eexec_char (eencrypt (mp,*p++));
2012 while (p < mp->ps->t1_line_ptr)
2017 static void t1_puts (MP mp, const char *s)
2019 if (s != mp->ps->t1_line_array)
2020 strcpy (mp->ps->t1_line_array, s);
2021 mp->ps->t1_line_ptr = strend (mp->ps->t1_line_array);
2025 static void t1_printf (MP mp, const char *fmt, ...)
2028 va_start (args, fmt);
2029 vsprintf (mp->ps->t1_line_array, fmt, args);
2030 t1_puts (mp,mp->ps->t1_line_array);
2034 static void t1_init_params (MP mp, char *open_name_prefix,
2035 char *cur_file_name) {
2036 if ((open_name_prefix != NULL) && strlen(open_name_prefix)) {
2037 t1_log (open_name_prefix);
2038 t1_log (cur_file_name);
2040 mp->ps->t1_lenIV = 4;
2041 mp->ps->t1_dr = 55665;
2042 mp->ps->t1_er = 55665;
2043 mp->ps->t1_in_eexec = 0;
2044 mp->ps->t1_cs = false;
2045 mp->ps->t1_scan = true;
2046 mp->ps->t1_synthetic = false;
2047 mp->ps->t1_eexec_encrypt = false;
2048 mp->ps->t1_block_length = 0;
2051 static void t1_close_font_file (MP mp, const char *close_name_suffix) {
2052 if ((close_name_suffix != NULL) && strlen(close_name_suffix)) {
2053 t1_log (close_name_suffix);
2058 static void t1_check_block_len (MP mp, boolean decrypt) {
2061 if (mp->ps->t1_block_length == 0)
2063 c = t1_getbyte (mp);
2065 c = edecrypt (mp,c);
2066 l = mp->ps->t1_block_length;
2067 if (!(l == 0 && (c == 10 || c == 13))) {
2068 snprintf(s,128,"%i bytes more than expected were ignored", l+ 1);
2074 static void t1_start_eexec (MP mp, fm_entry *fm_cur) {
2076 if (!mp->ps->t1_pfa)
2077 t1_check_block_len (mp, false);
2078 for (mp->ps->t1_line_ptr = mp->ps->t1_line_array, i = 0; i < 4; i++) {
2079 edecrypt (mp, t1_getbyte (mp));
2080 *mp->ps->t1_line_ptr++ = 0;
2082 mp->ps->t1_eexec_encrypt = true;
2083 if (!mp->ps->read_encoding_only)
2084 if (is_included (fm_cur))
2085 t1_putline (mp); /* to put the first four bytes */
2087 static void t1_stop_eexec (MP mp) {
2089 end_last_eexec_line ();
2090 if (!mp->ps->t1_pfa)
2091 t1_check_block_len (mp,true);
2093 c = edecrypt (mp, t1_getbyte (mp));
2094 if (!(c == 10 || c == 13)) {
2095 if (mp->ps->last_hexbyte == 0)
2098 mp_warn (mp,"unexpected data after eexec");
2101 mp->ps->t1_cs = false;
2102 mp->ps->t1_in_eexec = 2;
2104 static void t1_modify_fm (MP mp) {
2105 mp->ps->t1_line_ptr = eol (mp->ps->t1_line_array);
2108 static void t1_modify_italic (MP mp) {
2109 mp->ps->t1_line_ptr = eol (mp->ps->t1_line_array);
2114 const char *pdfname;
2124 static key_entry font_keys[FONT_KEYS_NUM] = {
2125 {"Ascent", "Ascender", 0, false},
2126 {"CapHeight", "CapHeight", 0, false},
2127 {"Descent", "Descender", 0, false},
2128 {"FontName", "FontName", 0, false},
2129 {"ItalicAngle", "ItalicAngle", 0, false},
2130 {"StemV", "StdVW", 0, false},
2131 {"XHeight", "XHeight", 0, false},
2132 {"FontBBox", "FontBBox", 0, false},
2144 @d ITALIC_ANGLE_CODE 4
2150 @d FONTBBOX4_CODE 10
2151 @d MAX_KEY_CODE (FONTBBOX1_CODE + 1)
2154 static void t1_scan_keys (MP mp, int tex_font,fm_entry *fm_cur) {
2158 if (fm_extend (fm_cur) != 0 || fm_slant (fm_cur) != 0) {
2159 if (t1_prefix ("/FontMatrix")) {
2163 if (t1_prefix ("/ItalicAngle")) {
2164 t1_modify_italic (mp);
2168 if (t1_prefix ("/FontType")) {
2169 p = mp->ps->t1_line_array + strlen ("FontType") + 1;
2170 if ((i = t1_scan_num (mp,p, 0)) != 1) {
2172 snprintf(s,125,"Type%d fonts unsupported by metapost", i);
2173 mp_fatal_error(mp,s);
2177 for (key = font_keys; key - font_keys < MAX_KEY_CODE; key++)
2178 if (str_prefix (mp->ps->t1_line_array + 1, key->t1name))
2180 if (key - font_keys == MAX_KEY_CODE)
2183 p = mp->ps->t1_line_array + strlen (key->t1name) + 1;
2185 if ((k = key - font_keys) == FONTNAME_CODE) {
2188 remove_eol (p, mp->ps->t1_line_array);
2189 snprintf(s,128,"a name expected: `%s'", mp->ps->t1_line_array);
2190 mp_fatal_error(mp,s);
2192 r = ++p; /* skip the slash */
2193 if (is_included (fm_cur)) {
2194 /* save the fontname */
2195 strncpy (mp->ps->fontname_buf, p, FONTNAME_BUF_SIZE);
2196 for (i=0; mp->ps->fontname_buf[i] != 10; i++);
2197 mp->ps->fontname_buf[i]=0;
2199 if(is_subsetted (fm_cur)) {
2200 if (fm_cur->encoding!=NULL && fm_cur->encoding->glyph_names!=NULL)
2201 make_subset_tag (mp,fm_cur, fm_cur->encoding->glyph_names, tex_font);
2203 make_subset_tag (mp,fm_cur, mp->ps->t1_builtin_glyph_names, tex_font);
2205 alloc_array (t1_line, (r-mp->ps->t1_line_array+6+1+strlen(mp->ps->fontname_buf)+1),
2207 strncpy (r, fm_cur->subset_tag , 6);
2209 strncpy (r+7, mp->ps->fontname_buf, strlen(mp->ps->fontname_buf)+1);
2210 mp->ps->t1_line_ptr = eol (r);
2212 /* |for (q = p; *q != ' ' && *q != 10; *q++);|*/
2214 mp->ps->t1_line_ptr = eol (r);
2219 if ((k == STEMV_CODE || k == FONTBBOX1_CODE)
2220 && (*p == '[' || *p == '{'))
2222 if (k == FONTBBOX1_CODE) {
2223 for (i = 0; i < 4; i++) {
2224 key[i].value = t1_scan_num (mp, p, &r);
2229 key->value = t1_scan_num (mp, p, 0);
2231 static void t1_scan_param (MP mp, int tex_font,fm_entry *fm_cur)
2233 static const char *lenIV = "/lenIV";
2234 if (!mp->ps->t1_scan || *mp->ps->t1_line_array != '/')
2236 if (t1_prefix (lenIV)) {
2237 mp->ps->t1_lenIV = t1_scan_num (mp,mp->ps->t1_line_array + strlen (lenIV), 0);
2240 t1_scan_keys (mp, tex_font,fm_cur);
2242 static void copy_glyph_names (char **glyph_names, int a, int b) {
2243 if (glyph_names[b] != notdef) {
2244 mp_xfree (glyph_names[b]);
2245 glyph_names[b] = (char *) notdef;
2247 if (glyph_names[a] != notdef) {
2248 glyph_names[b] = mp_xstrdup (glyph_names[a]);
2251 static void t1_builtin_enc (MP mp) {
2252 int i, a, b, c, counter = 0;
2255 * At this moment "/Encoding" is the prefix of |mp->ps->t1_line_array|
2257 if (t1_suffix ("def")) { /* predefined encoding */
2258 sscanf (mp->ps->t1_line_array + strlen ("/Encoding"), "%256s", mp->ps->t1_buf_array);
2259 if (strcmp (mp->ps->t1_buf_array, "StandardEncoding") == 0) {
2260 for (i = 0; i < 256; i++)
2261 if (standard_glyph_names[i] == notdef)
2262 mp->ps->t1_builtin_glyph_names[i] = (char *) notdef;
2264 mp->ps->t1_builtin_glyph_names[i] =
2265 mp_xstrdup (standard_glyph_names[i]);
2266 mp->ps->t1_encoding = ENC_STANDARD;
2269 snprintf(s,128, "cannot subset font (unknown predefined encoding `%s')",
2270 mp->ps->t1_buf_array);
2271 mp_fatal_error(mp,s);
2275 mp->ps->t1_encoding = ENC_BUILTIN;
2277 * At this moment "/Encoding" is the prefix of |mp->ps->t1_line_array|, and the encoding is
2278 * not a predefined encoding
2280 * We have two possible forms of Encoding vector. The first case is
2282 * /Encoding [/a /b /c...] readonly def
2284 * and the second case can look like
2286 * /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for
2292 for (i = 0; i < 256; i++)
2293 mp->ps->t1_builtin_glyph_names[i] = (char *) notdef;
2294 if (t1_prefix ("/Encoding [") || t1_prefix ("/Encoding[")) { /* the first case */
2295 r = strchr (mp->ps->t1_line_array, '[') + 1;
2299 for (p = mp->ps->t1_buf_array, r++;
2300 *r != 32 && *r != 10 && *r != ']' && *r != '/';
2304 if (counter > 255) {
2306 (mp, "encoding vector contains more than 256 names");
2308 if (strcmp (mp->ps->t1_buf_array, notdef) != 0)
2309 mp->ps->t1_builtin_glyph_names[counter] = mp_xstrdup (mp->ps->t1_buf_array);
2312 if (*r != 10 && *r != '%') {
2313 if (str_prefix (r, "] def")
2314 || str_prefix (r, "] readonly def"))
2318 remove_eol (r, mp->ps->t1_line_array);
2319 snprintf(s,128,"a name or `] def' or `] readonly def' expected: `%s'",
2320 mp->ps->t1_line_array);
2321 mp_fatal_error(mp,s);
2325 r = mp->ps->t1_line_array;
2327 } else { /* the second case */
2328 p = strchr (mp->ps->t1_line_array, 10);
2332 p = mp->ps->t1_line_array;
2335 check for `dup <index> <glyph> put'
2337 if (sscanf (p, "dup %i%256s put", &i, mp->ps->t1_buf_array) == 2 &&
2338 *mp->ps->t1_buf_array == '/' && valid_code (i)) {
2339 if (strcmp (mp->ps->t1_buf_array + 1, notdef) != 0)
2340 mp->ps->t1_builtin_glyph_names[i] =
2341 mp_xstrdup (mp->ps->t1_buf_array + 1);
2342 p = strstr (p, " put") + strlen (" put");
2346 check for `dup dup <to> exch <from> get put'
2348 else if (sscanf (p, "dup dup %i exch %i get put", &b, &a) == 2
2349 && valid_code (a) && valid_code (b)) {
2350 copy_glyph_names (mp->ps->t1_builtin_glyph_names, a, b);
2351 p = strstr (p, " get put") + strlen (" get put");
2355 check for `dup dup <from> <size> getinterval <to> exch putinterval'
2358 (p, "dup dup %i %i getinterval %i exch putinterval",
2359 &a, &c, &b) == 3 && valid_code (a) && valid_code (b)
2360 && valid_code (c)) {
2361 for (i = 0; i < c; i++)
2362 copy_glyph_names (mp->ps->t1_builtin_glyph_names, a + i, b + i);
2363 p = strstr (p, " putinterval") + strlen (" putinterval");
2367 check for `def' or `readonly def'
2369 else if ((p == mp->ps->t1_line_array || (p > mp->ps->t1_line_array && p[-1] == ' '))
2370 && strcmp (p, "def\n") == 0)
2373 skip an unrecognizable word
2376 while (*p != ' ' && *p != 10)
2384 static void t1_check_end (MP mp) {
2388 if (t1_prefix ("{restore}"))
2394 char *ff_name; /* base name of font file */
2395 char *ff_path; /* full path to font file */
2399 static boolean t1_open_fontfile (MP mp, fm_entry *fm_cur,const char *open_name_prefix) {
2401 ff = check_ff_exist (mp, fm_cur);
2402 if (ff->ff_path != NULL) {
2403 mp->ps->t1_file = mp_open_file(mp,ff->ff_path, "rb", mp_filetype_font);
2405 mp_warn (mp, "cannot open Type 1 font file for reading");
2408 t1_init_params (mp,(char *)open_name_prefix,fm_cur->ff_name);
2409 mp->ps->fontfile_found = true;
2413 static void t1_scan_only (MP mp, int tex_font, fm_entry *fm_cur) {
2416 t1_scan_param (mp,tex_font, fm_cur);
2418 while (mp->ps->t1_in_eexec == 0);
2419 t1_start_eexec (mp,fm_cur);
2422 t1_scan_param (mp,tex_font, fm_cur);
2424 while (!(t1_charstrings () || t1_subrs ()));
2427 static void t1_include (MP mp, int tex_font, fm_entry *fm_cur) {
2430 t1_scan_param (mp,tex_font, fm_cur);
2433 while (mp->ps->t1_in_eexec == 0);
2434 t1_start_eexec (mp,fm_cur);
2437 t1_scan_param (mp,tex_font, fm_cur);
2440 while (!(t1_charstrings () || t1_subrs ()));
2441 mp->ps->t1_cs = true;
2446 while (!t1_end_eexec ());
2448 if (fixedcontent) { /* copy 512 zeros (not needed for PDF) */
2453 while (!t1_cleartomark ());
2454 t1_check_end (mp); /* write "{restore}if" if found */
2459 @d check_subr(SUBR) if (SUBR >= mp->ps->subr_size || SUBR < 0) {
2461 snprintf(s,128,"Subrs array: entry index out of range (%i)",SUBR);
2462 mp_fatal_error(mp,s);
2466 static const char **check_cs_token_pair (MP mp) {
2467 const char **p = (const char **) cs_token_pairs_list;
2468 for (; p[0] != NULL; ++p)
2469 if (t1_buf_prefix (p[0]) && t1_buf_suffix (p[1]))
2474 static void cs_store (MP mp, boolean is_subr) {
2478 for (p = mp->ps->t1_line_array, mp->ps->t1_buf_ptr = mp->ps->t1_buf_array; *p != ' ';
2479 *mp->ps->t1_buf_ptr++ = *p++);
2480 *mp->ps->t1_buf_ptr = 0;
2482 subr = t1_scan_num (mp, p + 1, 0);
2484 ptr = mp->ps->subr_tab + subr;
2486 ptr = mp->ps->cs_ptr++;
2487 if (mp->ps->cs_ptr - mp->ps->cs_tab > mp->ps->cs_size) {
2489 snprintf(s,128,"CharStrings dict: more entries than dict size (%i)",mp->ps->cs_size);
2490 mp_fatal_error(mp,s);
2492 if (strcmp (mp->ps->t1_buf_array + 1, notdef) == 0) /* skip the slash */
2493 ptr->glyph_name = (char *) notdef;
2495 ptr->glyph_name = mp_xstrdup (mp->ps->t1_buf_array + 1);
2497 /* copy " RD " + cs data to |mp->ps->t1_buf_array| */
2498 memcpy (mp->ps->t1_buf_array, mp->ps->t1_line_array + mp->ps->cs_start - 4,
2499 (unsigned) (mp->ps->t1_cslen + 4));
2500 /* copy the end of cs data to |mp->ps->t1_buf_array| */
2501 for (p = mp->ps->t1_line_array + mp->ps->cs_start + mp->ps->t1_cslen, mp->ps->t1_buf_ptr =
2502 mp->ps->t1_buf_array + mp->ps->t1_cslen + 4; *p != 10; *mp->ps->t1_buf_ptr++ = *p++);
2503 *mp->ps->t1_buf_ptr++ = 10;
2504 if (is_subr && mp->ps->cs_token_pair == NULL)
2505 mp->ps->cs_token_pair = check_cs_token_pair (mp);
2506 ptr->len = mp->ps->t1_buf_ptr - mp->ps->t1_buf_array;
2507 ptr->cslen = mp->ps->t1_cslen;
2508 ptr->data = mp_xmalloc (ptr->len , sizeof (byte));
2509 memcpy (ptr->data, mp->ps->t1_buf_array, ptr->len);
2513 #define store_subr(mp) cs_store(mp,true)
2514 #define store_cs(mp) cs_store(mp,false)
2516 #define CC_STACK_SIZE 24
2518 static integer cc_stack[CC_STACK_SIZE], *stack_ptr = cc_stack;
2519 static cc_entry cc_tab[CS_MAX];
2520 static boolean is_cc_init = false;
2524 if (stack_ptr - cc_stack < (N)) \
2528 #define stack_error(N) { \
2530 snprintf(s,255,"CharString: invalid access (%i) to stack (%i entries)", \
2531 (int) N, (int)(stack_ptr - cc_stack)); \
2537 #define cc_get(N) ((N) < 0 ? *(stack_ptr + (N)) : *(cc_stack + (N)))
2539 #define cc_push(V) *stack_ptr++ = V
2540 #define cc_clear() stack_ptr = cc_stack
2542 #define set_cc(N, B, A, C) \
2543 cc_tab[N].nargs = A; \
2544 cc_tab[N].bottom = B; \
2545 cc_tab[N].clear = C; \
2546 cc_tab[N].valid = true
2548 static void cc_init (void) {
2552 for (i = 0; i < CS_MAX; i++)
2553 cc_tab[i].valid = false;
2554 set_cc (CS_HSTEM, true, 2, true);
2555 set_cc (CS_VSTEM, true, 2, true);
2556 set_cc (CS_VMOVETO, true, 1, true);
2557 set_cc (CS_RLINETO, true, 2, true);
2558 set_cc (CS_HLINETO, true, 1, true);
2559 set_cc (CS_VLINETO, true, 1, true);
2560 set_cc (CS_RRCURVETO, true, 6, true);
2561 set_cc (CS_CLOSEPATH, false, 0, true);
2562 set_cc (CS_CALLSUBR, false, 1, false);
2563 set_cc (CS_RETURN, false, 0, false);
2565 |set_cc(CS_ESCAPE, false, 0, false);|
2567 set_cc (CS_HSBW, true, 2, true);
2568 set_cc (CS_ENDCHAR, false, 0, true);
2569 set_cc (CS_RMOVETO, true, 2, true);
2570 set_cc (CS_HMOVETO, true, 1, true);
2571 set_cc (CS_VHCURVETO, true, 4, true);
2572 set_cc (CS_HVCURVETO, true, 4, true);
2573 set_cc (CS_DOTSECTION, false, 0, true);
2574 set_cc (CS_VSTEM3, true, 6, true);
2575 set_cc (CS_HSTEM3, true, 6, true);
2576 set_cc (CS_SEAC, true, 5, true);
2577 set_cc (CS_SBW, true, 4, true);
2578 set_cc (CS_DIV, false, 2, false);
2579 set_cc (CS_CALLOTHERSUBR, false, 0, false);
2580 set_cc (CS_POP, false, 0, false);
2581 set_cc (CS_SETCURRENTPOINT, true, 2, true);
2587 @d cs_getchar(mp) cdecrypt(mp,*data++, &cr)
2589 @d mark_subr(mp,n) cs_mark(mp,0, n)
2590 @d mark_cs(mp,s) cs_mark(mp,s, 0)
2591 @d SMALL_BUF_SIZE 256
2594 static void cs_warn (MP mp, const char *cs_name, int subr, const char *fmt, ...) {
2595 char buf[SMALL_BUF_SIZE];
2598 va_start (args, fmt);
2599 vsprintf (buf, fmt, args);
2601 if (cs_name == NULL) {
2602 snprintf(s,299,"Subr (%i): %s", (int) subr, buf);
2604 snprintf(s,299,"CharString (/%s): %s", cs_name, buf);
2609 static void cs_mark (MP mp, const char *cs_name, int subr)
2615 static integer lastargOtherSubr3 = 3; /* the argument of last call to
2619 if (cs_name == NULL) {
2621 ptr = mp->ps->subr_tab + subr;
2625 if (mp->ps->cs_notdef != NULL &&
2626 (cs_name == notdef || strcmp (cs_name, notdef) == 0))
2627 ptr = mp->ps->cs_notdef;
2629 for (ptr = mp->ps->cs_tab; ptr < mp->ps->cs_ptr; ptr++)
2630 if (strcmp (ptr->glyph_name, cs_name) == 0)
2632 if (ptr == mp->ps->cs_ptr) {
2634 snprintf (s,128,"glyph `%s' undefined", cs_name);
2638 if (ptr->glyph_name == notdef)
2639 mp->ps->cs_notdef = ptr;
2642 /* only marked CharString entries and invalid entries can be skipped;
2643 valid marked subrs must be parsed to keep the stack in sync */
2644 if (!ptr->valid || (ptr->is_used && cs_name != NULL))
2646 ptr->is_used = true;
2648 cs_len = ptr->cslen;
2649 data = ptr->data + 4;
2650 for (i = 0; i < mp->ps->t1_lenIV; i++, cs_len--)
2652 while (cs_len > 0) {
2654 b = cs_getchar (mp);
2658 else if (b <= 250) {
2660 a = ((b - 247) << 8) + 108 + cs_getchar (mp);
2661 } else if (b <= 254) {
2663 a = -((b - 251) << 8) - 108 - cs_getchar (mp);
2666 a = (cs_getchar (mp) & 0xff) << 24;
2667 a |= (cs_getchar (mp) & 0xff) << 16;
2668 a |= (cs_getchar (mp) & 0xff) << 8;
2669 a |= (cs_getchar (mp) & 0xff) << 0;
2670 if (sizeof (integer) > 4 && (a & 0x80000000))
2675 if (b == CS_ESCAPE) {
2676 b = cs_getchar (mp) + CS_1BYTE_MAX;
2680 cs_warn (mp,cs_name, subr, "command value out of range: %i",
2686 cs_warn (mp,cs_name, subr, "command not valid: %i", (int) b);
2690 if (stack_ptr - cc_stack < cc->nargs)
2691 cs_warn (mp,cs_name, subr,
2692 "less arguments on stack (%i) than required (%i)",
2693 (int) (stack_ptr - cc_stack), (int) cc->nargs);
2694 else if (stack_ptr - cc_stack > cc->nargs)
2695 cs_warn (mp,cs_name, subr,
2696 "more arguments on stack (%i) than required (%i)",
2697 (int) (stack_ptr - cc_stack), (int) cc->nargs);
2699 switch (cc - cc_tab) {
2704 if (!mp->ps->subr_tab[a1].valid) {
2705 cs_warn (mp,cs_name, subr, "cannot call subr (%i)", (int) a1);
2713 case CS_CALLOTHERSUBR:
2714 if (cc_get (-1) == 3)
2715 lastargOtherSubr3 = cc_get (-3);
2716 a1 = cc_get (-2) + 2;
2720 cc_push (lastargOtherSubr3);
2721 /* the only case when we care about the value being pushed onto
2722 stack is when POP follows CALLOTHERSUBR (changing hints by
2730 mark_cs (mp,standard_glyph_names[a1]);
2731 mark_cs (mp,standard_glyph_names[a2]);
2740 cs_error: /* an error occured during parsing */
2743 ptr->is_used = false;
2746 static void t1_subset_ascii_part (MP mp, int tex_font, fm_entry *fm_cur)
2750 while (!t1_prefix ("/Encoding")) {
2751 t1_scan_param (mp,tex_font, fm_cur);
2755 t1_builtin_enc (mp);
2756 if (is_reencoded (fm_cur))
2757 mp->ps->t1_glyph_names = external_enc ();
2759 mp->ps->t1_glyph_names = mp->ps->t1_builtin_glyph_names;
2761 |if (is_included (fm_cur) && is_subsetted (fm_cur)) {
2762 make_subset_tag (fm_cur, t1_glyph_names, tex_font);
2763 update_subset_tag ();
2766 if ((!is_subsetted (fm_cur)) && mp->ps->t1_encoding == ENC_STANDARD)
2767 t1_puts (mp,"/Encoding StandardEncoding def\n");
2770 (mp,"/Encoding 256 array\n0 1 255 {1 index exch /.notdef put} for\n");
2771 for (i = 0, j = 0; i < 256; i++) {
2772 if (is_used_char (i) && mp->ps->t1_glyph_names[i] != notdef) {
2774 t1_printf (mp,"dup %i /%s put\n", (int) t1_char (i),
2775 mp->ps->t1_glyph_names[i]);
2778 /* We didn't mark anything for the Encoding array. */
2779 /* We add "dup 0 /.notdef put" for compatibility */
2780 /* with Acrobat 5.0. */
2782 t1_puts (mp,"dup 0 /.notdef put\n");
2783 t1_puts (mp,"readonly def\n");
2787 t1_scan_param (mp,tex_font, fm_cur);
2788 if (!t1_prefix ("/UniqueID")) /* ignore UniqueID for subsetted fonts */
2791 while (mp->ps->t1_in_eexec == 0);
2794 #define t1_subr_flush(mp) t1_flush_cs(mp,true)
2795 #define t1_cs_flush(mp) t1_flush_cs(mp,false)
2797 static void cs_init (MP mp) {
2798 mp->ps->cs_ptr = mp->ps->cs_tab = NULL;
2799 mp->ps->cs_dict_start = mp->ps->cs_dict_end = NULL;
2800 mp->ps->cs_count = mp->ps->cs_size = mp->ps->cs_size_pos = 0;
2801 mp->ps->cs_token_pair = NULL;
2802 mp->ps->subr_tab = NULL;
2803 mp->ps->subr_array_start = mp->ps->subr_array_end = NULL;
2804 mp->ps->subr_max = mp->ps->subr_size = mp->ps->subr_size_pos = 0;
2807 static void init_cs_entry ( cs_entry * cs) {
2809 cs->glyph_name = NULL;
2812 cs->is_used = false;
2816 static void t1_mark_glyphs (MP mp, int tex_font);
2818 static void t1_read_subrs (MP mp, int tex_font, fm_entry *fm_cur)
2823 while (!(t1_charstrings () || t1_subrs ())) {
2824 t1_scan_param (mp,tex_font, fm_cur);
2829 mp->ps->t1_cs = true;
2830 mp->ps->t1_scan = false;
2833 mp->ps->subr_size_pos = strlen ("/Subrs") + 1;
2834 /* |subr_size_pos| points to the number indicating dict size after "/Subrs" */
2835 mp->ps->subr_size = t1_scan_num (mp,mp->ps->t1_line_array + mp->ps->subr_size_pos, 0);
2836 if (mp->ps->subr_size == 0) {
2837 while (!t1_charstrings ())
2841 /* |subr_tab = xtalloc (subr_size, cs_entry);| */
2842 mp->ps->subr_tab = (cs_entry *)mp_xmalloc (mp->ps->subr_size, sizeof (cs_entry));
2843 for (ptr = mp->ps->subr_tab; ptr - mp->ps->subr_tab < mp->ps->subr_size; ptr++)
2844 init_cs_entry (ptr);
2845 mp->ps->subr_array_start = mp_xstrdup (mp->ps->t1_line_array);
2847 while (mp->ps->t1_cslen) {
2851 /* mark the first four entries without parsing */
2852 for (i = 0; i < mp->ps->subr_size && i < 4; i++)
2853 mp->ps->subr_tab[i].is_used = true;
2854 /* the end of the Subrs array might have more than one line so we need to
2855 concatnate them to |subr_array_end|. Unfortunately some fonts don't have
2856 the Subrs array followed by the CharStrings dict immediately (synthetic
2857 fonts). If we cannot find CharStrings in next |POST_SUBRS_SCAN| lines then
2858 we will treat the font as synthetic and ignore everything until next
2861 #define POST_SUBRS_SCAN 5
2863 *mp->ps->t1_buf_array = 0;
2864 for (i = 0; i < POST_SUBRS_SCAN; i++) {
2865 if (t1_charstrings ())
2867 s += mp->ps->t1_line_ptr - mp->ps->t1_line_array;
2868 alloc_array (t1_buf, s, T1_BUF_SIZE);
2869 strcat (mp->ps->t1_buf_array, mp->ps->t1_line_array);
2872 mp->ps->subr_array_end = mp_xstrdup (mp->ps->t1_buf_array);
2873 if (i == POST_SUBRS_SCAN) { /* CharStrings not found;
2874 suppose synthetic font */
2875 for (ptr = mp->ps->subr_tab; ptr - mp->ps->subr_tab < mp->ps->subr_size; ptr++)
2877 mp_xfree (ptr->data);
2878 mp_xfree (mp->ps->subr_tab);
2879 mp_xfree (mp->ps->subr_array_start);
2880 mp_xfree (mp->ps->subr_array_end);
2882 mp->ps->t1_cs = false;
2883 mp->ps->t1_synthetic = true;
2884 while (!(t1_charstrings () || t1_subrs ()))
2891 static void t1_flush_cs (MP mp, boolean is_subr)
2894 byte *r, *return_cs = NULL;
2895 cs_entry *tab, *end_tab, *ptr;
2896 char *start_line, *line_end;
2897 int count, size_pos;
2898 unsigned short cr, cs_len = 0; /* to avoid warning about uninitialized use of |cs_len| */
2900 start_line = mp->ps->subr_array_start;
2901 line_end = mp->ps->subr_array_end;
2902 size_pos = mp->ps->subr_size_pos;
2903 tab = mp->ps->subr_tab;
2904 count = mp->ps->subr_max + 1;
2905 end_tab = mp->ps->subr_tab + count;
2907 start_line = mp->ps->cs_dict_start;
2908 line_end = mp->ps->cs_dict_end;
2909 size_pos = mp->ps->cs_size_pos;
2910 tab = mp->ps->cs_tab;
2911 end_tab = mp->ps->cs_ptr;
2912 count = mp->ps->cs_count;
2914 mp->ps->t1_line_ptr = mp->ps->t1_line_array;
2915 for (p = start_line; p - start_line < size_pos;)
2916 *mp->ps->t1_line_ptr++ = *p++;
2917 while (isdigit (*p))
2919 sprintf (mp->ps->t1_line_ptr, "%u", count);
2920 strcat (mp->ps->t1_line_ptr, p);
2921 mp->ps->t1_line_ptr = eol (mp->ps->t1_line_array);
2924 /* create |return_cs| to replace unsused subr's */
2928 return_cs = mp_xmalloc ( (mp->ps->t1_lenIV + 1) , sizeof(byte));
2929 if ( mp->ps->t1_lenIV > 0) {
2930 for (cs_len = 0, r = return_cs; cs_len < mp->ps->t1_lenIV; cs_len++, r++)
2931 *r = cencrypt (mp,0x00, &cr);
2932 *r = cencrypt (mp,CS_RETURN, &cr);
2934 *return_cs = CS_RETURN;
2939 for (ptr = tab; ptr < end_tab; ptr++) {
2942 sprintf (mp->ps->t1_line_array, "dup %i %u", (int) (ptr - tab),
2945 sprintf (mp->ps->t1_line_array, "/%s %u", ptr->glyph_name, ptr->cslen);
2946 p = strend (mp->ps->t1_line_array);
2947 memcpy (p, ptr->data, ptr->len);
2948 mp->ps->t1_line_ptr = p + ptr->len;
2951 /* replace unsused subr's by |return_cs| */
2953 sprintf (mp->ps->t1_line_array, "dup %i %u%s ", (int) (ptr - tab),
2954 cs_len, mp->ps->cs_token_pair[0]);
2955 p = strend (mp->ps->t1_line_array);
2956 memcpy (p, return_cs, cs_len);
2957 mp->ps->t1_line_ptr = p + cs_len;
2959 sprintf (mp->ps->t1_line_array, " %s", mp->ps->cs_token_pair[1]);
2960 mp->ps->t1_line_ptr = eol (mp->ps->t1_line_array);
2964 mp_xfree (ptr->data);
2965 if (ptr->glyph_name != notdef)
2966 mp_xfree (ptr->glyph_name);
2968 sprintf (mp->ps->t1_line_array, "%s", line_end);
2969 mp->ps->t1_line_ptr = eol (mp->ps->t1_line_array);
2972 mp_xfree (return_cs);
2974 mp_xfree (start_line);
2975 mp_xfree (line_end);
2978 static void t1_mark_glyphs (MP mp, int tex_font)
2981 char *charset = extra_charset ();
2984 if (mp->ps->t1_synthetic || embed_all_glyphs (tex_font)) { /* mark everything */
2985 if (mp->ps->cs_tab != NULL)
2986 for (ptr = mp->ps->cs_tab; ptr < mp->ps->cs_ptr; ptr++)
2988 ptr->is_used = true;
2989 if (mp->ps->subr_tab != NULL) {
2990 for (ptr = mp->ps->subr_tab; ptr - mp->ps->subr_tab < mp->ps->subr_size; ptr++)
2992 ptr->is_used = true;
2993 mp->ps->subr_max = mp->ps->subr_size - 1;
2997 mark_cs (mp,notdef);
2998 for (i = 0; i < 256; i++)
2999 if (is_used_char (i)) {
3000 if (mp->ps->t1_glyph_names[i] == notdef) {
3002 snprintf(s,128, "character %i is mapped to %s", i, notdef);
3005 mark_cs (mp,mp->ps->t1_glyph_names[i]);
3007 if (charset == NULL)
3009 g = s = charset + 1; /* skip the first '/' */
3012 while (*s != '/' && s < r)
3014 *s = 0; /* terminate g by rewriting '/' to 0 */
3019 if (mp->ps->subr_tab != NULL)
3020 for (mp->ps->subr_max = -1, ptr = mp->ps->subr_tab;
3021 ptr - mp->ps->subr_tab < mp->ps->subr_size;
3023 if (ptr->is_used && ptr - mp->ps->subr_tab > mp->ps->subr_max)
3024 mp->ps->subr_max = ptr - mp->ps->subr_tab;
3027 static void t1_subset_charstrings (MP mp, int tex_font)
3030 mp->ps->cs_size_pos =
3031 strstr (mp->ps->t1_line_array, charstringname) + strlen (charstringname)
3032 - mp->ps->t1_line_array + 1;
3033 /* |cs_size_pos| points to the number indicating
3034 dict size after "/CharStrings" */
3035 mp->ps->cs_size = t1_scan_num (mp,mp->ps->t1_line_array + mp->ps->cs_size_pos, 0);
3036 mp->ps->cs_ptr = mp->ps->cs_tab = mp_xmalloc (mp->ps->cs_size, sizeof(cs_entry));
3037 for (ptr = mp->ps->cs_tab; ptr - mp->ps->cs_tab < mp->ps->cs_size; ptr++)
3038 init_cs_entry (ptr);
3039 mp->ps->cs_notdef = NULL;
3040 mp->ps->cs_dict_start = mp_xstrdup (mp->ps->t1_line_array);
3042 while (mp->ps->t1_cslen) {
3046 mp->ps->cs_dict_end = mp_xstrdup (mp->ps->t1_line_array);
3047 t1_mark_glyphs (mp,tex_font);
3048 if (mp->ps->subr_tab != NULL) {
3049 if (mp->ps->cs_token_pair == NULL)
3051 (mp, "This Type 1 font uses mismatched subroutine begin/end token pairs.");
3054 for (mp->ps->cs_count = 0, ptr = mp->ps->cs_tab; ptr < mp->ps->cs_ptr; ptr++)
3060 static void t1_subset_end (MP mp)
3062 if (mp->ps->t1_synthetic) { /* copy to "dup /FontName get exch definefont pop" */
3063 while (!strstr (mp->ps->t1_line_array, "definefont")) {
3067 while (!t1_end_eexec ())
3068 t1_getline (mp); /* ignore the rest */
3069 t1_putline (mp); /* write "mark currentfile closefile" */
3071 while (!t1_end_eexec ()) { /* copy to "mark currentfile closefile" */
3076 if (fixedcontent) { /* copy 512 zeros (not needed for PDF) */
3077 while (!t1_cleartomark ()) {
3081 if (!mp->ps->t1_synthetic) /* don't check "{restore}if" for synthetic fonts */
3082 t1_check_end (mp); /* write "{restore}if" if found */
3086 static int t1_updatefm (MP mp, int f, fm_entry *fm)
3089 mp->ps->read_encoding_only = true;
3090 if (!t1_open_fontfile (mp,fm,NULL)) {
3093 t1_scan_only (mp,f, fm);
3094 s = mp_xstrdup(mp->ps->fontname_buf);
3096 while (*p != ' ' && *p != 0)
3100 t1_close_font_file (mp,"");
3105 static void writet1 (MP mp, int tex_font, fm_entry *fm_cur) {
3106 int save_selector = mp->selector;
3107 mp_normalize_selector(mp);
3108 mp->ps->read_encoding_only = false;
3109 if (!is_included (fm_cur)) { /* scan parameters from font file */
3110 if (!t1_open_fontfile (mp,fm_cur,"{"))
3112 t1_scan_only (mp,tex_font, fm_cur);
3113 t1_close_font_file (mp,"}");
3116 if (!is_subsetted (fm_cur)) { /* include entire font */
3117 if (!t1_open_fontfile (mp,fm_cur,"<<"))
3119 t1_include (mp,tex_font,fm_cur);
3120 t1_close_font_file (mp,">>");
3123 /* partial downloading */
3124 if (!t1_open_fontfile (mp,fm_cur,"<"))
3126 t1_subset_ascii_part (mp,tex_font,fm_cur);
3127 t1_start_eexec (mp,fm_cur);
3130 t1_read_subrs (mp,tex_font, fm_cur);
3131 t1_subset_charstrings (mp,tex_font);
3133 t1_close_font_file (mp,">");
3134 mp->selector = save_selector;
3138 static void t1_free (MP mp);
3141 static void t1_free (MP mp) {
3142 mp_xfree (mp->ps->t1_line_array);
3143 mp_xfree (mp->ps->t1_buf_array);
3147 @* \[44d] Embedding fonts.
3149 @ The |tfm_num| is officially of type |font_number|, but that
3150 type does not exist yet at this point in the output order.
3154 char *tfm_name; /* TFM file name */
3155 char *ps_name; /* PostScript name */
3156 integer flags; /* font flags */
3157 char *ff_name; /* font file name */
3158 char *subset_tag; /* pseudoUniqueTag for subsetted font */
3159 enc_entry *encoding; /* pointer to corresponding encoding */
3160 unsigned int tfm_num; /* number of the TFM refering this entry */
3161 unsigned short type; /* font type (T1/TTF/...) */
3162 short slant; /* SlantFont */
3163 short extend; /* ExtendFont */
3164 integer ff_objnum; /* FontFile object number */
3165 integer fn_objnum; /* FontName/BaseName object number */
3166 integer fd_objnum; /* FontDescriptor object number */
3167 char *charset; /* string containing used glyphs */
3168 boolean all_glyphs; /* embed all glyphs? */
3169 unsigned short links; /* link flags from |tfm_tree| and |ps_tree| */
3170 short tfm_avail; /* flags whether a tfm is available */
3171 short pid; /* Pid for truetype fonts */
3172 short eid; /* Eid for truetype fonts */
3178 #define FONTNAME_BUF_SIZE 128
3179 boolean fontfile_found;
3180 boolean is_otf_font;
3181 char fontname_buf[FONTNAME_BUF_SIZE];
3189 @d set_included(fm) ((fm)->type |= F_INCLUDED)
3190 @d set_subsetted(fm) ((fm)->type |= F_SUBSETTED)
3191 @d set_truetype(fm) ((fm)->type |= F_TRUETYPE)
3192 @d set_basefont(fm) ((fm)->type |= F_BASEFONT)
3194 @d is_included(fm) ((fm)->type & F_INCLUDED)
3195 @d is_subsetted(fm) ((fm)->type & F_SUBSETTED)
3196 @d is_truetype(fm) ((fm)->type & F_TRUETYPE)
3197 @d is_basefont(fm) ((fm)->type & F_BASEFONT)
3198 @d is_reencoded(fm) ((fm)->encoding != NULL)
3199 @d is_fontfile(fm) (fm_fontfile(fm) != NULL)
3200 @d is_t1fontfile(fm) (is_fontfile(fm) && !is_truetype(fm))
3202 @d fm_slant(fm) (fm)->slant
3203 @d fm_extend(fm) (fm)->extend
3204 @d fm_fontfile(fm) (fm)->ff_name
3206 @<Exported function headers@>=
3207 boolean mp_font_is_reencoded (MP mp, int f);
3208 boolean mp_font_is_included (MP mp, int f);
3209 boolean mp_font_is_subsetted (MP mp, int f);
3212 boolean mp_font_is_reencoded (MP mp, int f) {
3214 if (mp_has_font_size(mp,f) && mp_has_fm_entry (mp, f, &fm)) {
3216 && (fm->ps_name != NULL)
3217 && is_reencoded (fm))
3222 boolean mp_font_is_included (MP mp, int f) {
3224 if (mp_has_font_size(mp,f) && mp_has_fm_entry (mp, f, &fm)) {
3226 && (fm->ps_name != NULL && fm->ff_name != NULL)
3227 && is_included (fm))
3232 boolean mp_font_is_subsetted (MP mp, int f) {
3234 if (mp_has_font_size(mp,f) && mp_has_fm_entry (mp, f,&fm)) {
3236 && (fm->ps_name != NULL && fm->ff_name != NULL)
3237 && is_included (fm) && is_subsetted (fm))
3243 @ @<Exported function headers@>=
3244 char * mp_fm_encoding_name (MP mp, int f);
3245 char * mp_fm_font_name (MP mp, int f);
3246 char * mp_fm_font_subset_name (MP mp, int f);
3249 @c char * mp_fm_encoding_name (MP mp, int f) {
3252 if (mp_has_fm_entry (mp, f, &fm)) {
3253 if (fm != NULL && (fm->ps_name != NULL)) {
3254 if (is_reencoded (fm)) {
3256 if (e->enc_name!=NULL)
3257 return mp_xstrdup(e->enc_name);
3263 print_err ("fontmap encoding problems for font ");
3264 mp_print(mp,mp->font_name[f]);
3268 char * mp_fm_font_name (MP mp, int f) {
3270 if (mp_has_fm_entry (mp, f,&fm)) {
3271 if (fm != NULL && (fm->ps_name != NULL)) {
3272 if (mp_font_is_included(mp, f) && !mp->font_ps_name_fixed[f]) {
3273 /* find the real fontname, and update |ps_name| and |subset_tag| if needed */
3274 if (t1_updatefm(mp,f,fm)) {
3275 mp->font_ps_name_fixed[f] = true;
3277 print_err ("font loading problems for font ");
3278 mp_print(mp,mp->font_name[f]);
3282 return mp_xstrdup(fm->ps_name);
3285 print_err ("fontmap name problems for font ");
3286 mp_print(mp,mp->font_name[f]);
3291 char * mp_fm_font_subset_name (MP mp, int f) {
3293 if (mp_has_fm_entry (mp, f, &fm)) {
3294 if (fm != NULL && (fm->ps_name != NULL)) {
3295 if (is_subsetted(fm)) {
3296 char *s = mp_xmalloc(strlen(fm->ps_name)+8,1);
3297 snprintf(s,strlen(fm->ps_name)+8,"%s-%s",fm->subset_tag,fm->ps_name);
3300 return mp_xstrdup(fm->ps_name);
3304 print_err ("fontmap name problems for font ");
3305 mp_print(mp,mp->font_name[f]);
3310 @ @<Exported function headers@>=
3311 integer mp_fm_font_slant (MP mp, int f);
3312 integer mp_fm_font_extend (MP mp, int f);
3315 @c integer mp_fm_font_slant (MP mp, int f) {
3317 if (mp_has_fm_entry (mp, f, &fm)) {
3318 if (fm != NULL && (fm->ps_name != NULL)) {
3324 integer mp_fm_font_extend (MP mp, int f) {
3326 if (mp_has_fm_entry (mp, f, &fm)) {
3327 if (fm != NULL && (fm->ps_name != NULL)) {
3334 @ @<Exported function headers@>=
3335 boolean mp_do_ps_font (MP mp, font_number f);
3337 @ @c boolean mp_do_ps_font (MP mp, font_number f) {
3339 (void)mp_has_fm_entry (mp, f, &fm_cur); /* for side effects */
3342 if (is_truetype(fm_cur) ||
3343 (fm_cur->ps_name == NULL && fm_cur->ff_name == NULL)) {
3346 if (is_included(fm_cur)) {
3347 mp_print_nl(mp,"%%BeginResource: font ");
3348 if (is_subsetted(fm_cur)) {
3349 mp_print(mp, fm_cur->subset_tag);
3350 mp_print_char(mp,'-');
3352 mp_print(mp, fm_cur->ps_name);
3354 writet1 (mp,f,fm_cur);
3355 mp_print_nl(mp,"%%EndResource");
3361 @ Included subset fonts do not need and encoding vector, make
3362 sure we skip that case.
3365 void mp_list_used_resources (MP mp, int prologues, int procset);
3367 @ @c void mp_list_used_resources (MP mp, int prologues, int procset) {
3368 font_number f; /* fonts used in a text node or as loop counters */
3369 int ff; /* a loop counter */
3370 font_number ldf; /* the last \.{DocumentFont} listed (otherwise |null_font|) */
3373 mp_print_nl(mp, "%%DocumentResources: procset mpost");
3375 mp_print_nl(mp, "%%DocumentResources: procset mpost-minimal");
3378 for (f=null_font+1;f<=mp->last_fnum;f++) {
3379 if ( (mp_has_font_size(mp,f))&&(mp_font_is_reencoded(mp,f)) ) {
3380 for (ff=ldf;ff>=null_font;ff--) {
3381 if ( mp_has_font_size(mp,ff) )
3382 if ( mp_xstrcmp(mp->font_enc_name[f],mp->font_enc_name[ff])==0 )
3385 if ( mp_font_is_subsetted(mp,f) )
3387 if ( mp->ps_offset+1+strlen(mp->font_enc_name[f])>
3388 (unsigned)mp->max_print_line )
3389 mp_print_nl(mp, "%%+ encoding");
3392 mp_print_nl(mp, "%%+ encoding");
3394 mp_print_char(mp, ' ');
3395 mp_print(mp, mp->font_enc_name[f]);
3403 for (f=null_font+1;f<=mp->last_fnum;f++) {
3404 if ( mp_has_font_size(mp,f) ) {
3405 for (ff=ldf;ff>=null_font;ff--) {
3406 if ( mp_has_font_size(mp,ff) )
3407 if ( mp_xstrcmp(mp->font_name[f],mp->font_name[ff])==0 )
3410 if ( mp->ps_offset+1+strlen(mp->font_ps_name[f])>
3411 (unsigned)mp->max_print_line )
3412 mp_print_nl(mp, "%%+ font");
3415 mp_print_nl(mp, "%%+ font");
3417 mp_print_char(mp, ' ');
3418 if ( (prologues==3)&&
3419 (mp_font_is_subsetted(mp,f)) )
3420 mp_print(mp, mp_fm_font_subset_name(mp,f));
3422 mp_print(mp, mp->font_ps_name[f]);
3432 void mp_list_supplied_resources (MP mp, int prologues, int procset);
3434 @ @c void mp_list_supplied_resources (MP mp, int prologues, int procset) {
3435 font_number f; /* fonts used in a text node or as loop counters */
3436 int ff; /* a loop counter */
3437 font_number ldf; /* the last \.{DocumentFont} listed (otherwise |null_font|) */
3440 mp_print_nl(mp, "%%DocumentSuppliedResources: procset mpost");
3442 mp_print_nl(mp, "%%DocumentSuppliedResources: procset mpost-minimal");
3445 for (f=null_font+1;f<=mp->last_fnum;f++) {
3446 if ( (mp_has_font_size(mp,f))&&(mp_font_is_reencoded(mp,f)) ) {
3447 for (ff=ldf;ff>= null_font;ff++) {
3448 if ( mp_has_font_size(mp,ff) )
3449 if ( mp_xstrcmp(mp->font_enc_name[f],mp->font_enc_name[ff])==0 )
3452 if ( (prologues==3)&&(mp_font_is_subsetted(mp,f)))
3454 if ( mp->ps_offset+1+strlen(mp->font_enc_name[f])>(unsigned)mp->max_print_line )
3455 mp_print_nl(mp, "%%+ encoding");
3458 mp_print_nl(mp, "%%+ encoding");
3460 mp_print_char(mp, ' ');
3461 mp_print(mp, mp->font_enc_name[f]);
3470 for (f=null_font+1;f<=mp->last_fnum;f++) {
3471 if ( mp_has_font_size(mp,f) ) {
3472 for (ff=ldf;ff>= null_font;ff--) {
3473 if ( mp_has_font_size(mp,ff) )
3474 if ( mp_xstrcmp(mp->font_name[f],mp->font_name[ff])==0 )
3477 if ( ! mp_font_is_included(mp,f) )
3479 if ( mp->ps_offset+1+strlen(mp->font_ps_name[f])>(unsigned)mp->max_print_line )
3480 mp_print_nl(mp, "%%+ font");
3483 mp_print_nl(mp, "%%+ font");
3485 mp_print_char(mp, ' ');
3486 if ( mp_font_is_subsetted(mp,f) )
3487 mp_print(mp, mp_fm_font_subset_name(mp,f));
3489 mp_print(mp, mp->font_ps_name[f]);
3500 void mp_list_needed_resources (MP mp, int prologues);
3502 @ @c void mp_list_needed_resources (MP mp, int prologues) {
3503 font_number f; /* fonts used in a text node or as loop counters */
3504 int ff; /* a loop counter */
3505 font_number ldf; /* the last \.{DocumentFont} listed (otherwise |null_font|) */
3509 for (f=null_font+1;f<=mp->last_fnum;f++ ) {
3510 if ( mp_has_font_size(mp,f)) {
3511 for (ff=ldf;ff>=null_font;ff--) {
3512 if ( mp_has_font_size(mp,ff) )
3513 if ( mp_xstrcmp(mp->font_name[f],mp->font_name[ff])==0 )
3516 if ((prologues==3)&&(mp_font_is_included(mp,f)) )
3518 if ( mp->ps_offset+1+strlen(mp->font_ps_name[f])>(unsigned)mp->max_print_line )
3519 mp_print_nl(mp, "%%+ font");
3522 mp_print_nl(mp, "%%DocumentNeededResources: font");
3524 mp_print_char(mp, ' ');
3525 mp_print(mp, mp->font_ps_name[f]);
3531 if ( ! firstitem ) {
3535 for (f=null_font+1;f<= mp->last_fnum;f++) {
3536 if ( mp_has_font_size(mp,f) ) {
3537 for (ff=ldf;ff>=null_font;ff-- ) {
3538 if ( mp_has_font_size(mp,ff) )
3539 if ( mp_xstrcmp(mp->font_name[f],mp->font_name[ff])==0 )
3542 if ((prologues==3)&&(mp_font_is_included(mp,f)) )
3544 mp_print(mp, "%%IncludeResource: font ");
3545 mp_print(mp, mp->font_ps_name[f]);
3556 void mp_write_font_definition (MP mp, font_number f, int prologues);
3560 @d applied_reencoding(A) ((mp_font_is_reencoded(mp,(A)))&&
3561 ((! mp_font_is_subsetted(mp,(A)))||(prologues==2)))
3563 @c void mp_write_font_definition(MP mp, font_number f, int prologues) {
3564 if ( (applied_reencoding(f))||(mp_fm_font_slant(mp,f)!=0)||
3565 (mp_fm_font_extend(mp,f)!=0)||
3566 (mp_xstrcmp(mp->font_name[f],"psyrgo")==0)||
3567 (mp_xstrcmp(mp->font_name[f],"zpzdr-reversed")==0) ) {
3568 if ( (mp_font_is_subsetted(mp,f))&&
3569 (mp_font_is_included(mp,f))&&(prologues==3))
3570 mp_ps_name_out(mp, mp_fm_font_subset_name(mp,f),true);
3572 mp_ps_name_out(mp, mp->font_ps_name[f],true);
3573 mp_ps_print(mp, " fcp");
3575 if ( applied_reencoding(f) ) {
3576 mp_ps_print(mp, "/Encoding ");
3577 mp_ps_print(mp, mp->font_enc_name[f]);
3578 mp_ps_print(mp, " def ");
3580 if ( mp_fm_font_slant(mp,f)!=0 ) {
3581 mp_print_int(mp, mp_fm_font_slant(mp,f));
3582 mp_ps_print(mp, " SlantFont ");
3584 if ( mp_fm_font_extend(mp,f)!=0 ) {
3585 mp_print_int(mp, mp_fm_font_extend(mp,f));
3586 mp_ps_print(mp, " ExtendFont ");
3588 if ( mp_xstrcmp(mp->font_name[f],"psyrgo")==0 ) {
3589 mp_ps_print(mp, " 890 ScaleFont ");
3590 mp_ps_print(mp, " 277 SlantFont ");
3592 if ( mp_xstrcmp(mp->font_name[f],"zpzdr-reversed")==0 ) {
3593 mp_ps_print(mp, " FontMatrix [-1 0 0 1 0 0] matrix concatmatrix /FontMatrix exch def ");
3594 mp_ps_print(mp, "/Metrics 2 dict dup begin ");
3595 mp_ps_print(mp, "/space[0 -278]def ");
3596 mp_ps_print(mp, "/a12[-904 -939]def ");
3597 mp_ps_print(mp, "end def ");
3599 mp_ps_print(mp, "currentdict end");
3601 mp_ps_print_defined_name(mp,f,prologues);
3602 mp_ps_print(mp, " exch definefont pop");
3608 void mp_ps_print_defined_name (MP mp, font_number f, int prologues);
3611 @c void mp_ps_print_defined_name(MP mp, font_number A, int prologues) {
3612 mp_ps_print(mp, " /");
3613 if ((mp_font_is_subsetted(mp,(A)))&&
3614 (mp_font_is_included(mp,(A)))&&(prologues==3))
3615 mp_print(mp, mp_fm_font_subset_name(mp,(A)));
3617 mp_print(mp, mp->font_ps_name[(A)]);
3618 if ( mp_xstrcmp(mp->font_name[(A)],"psyrgo")==0 )
3619 mp_ps_print(mp, "-Slanted");
3620 if ( mp_xstrcmp(mp->font_name[(A)],"zpzdr-reversed")==0 )
3621 mp_ps_print(mp, "-Reverse");
3622 if ( applied_reencoding((A)) ) {
3623 mp_ps_print(mp, "-");
3624 mp_ps_print(mp, mp->font_enc_name[(A)]);
3626 if ( mp_fm_font_slant(mp,(A))!=0 ) {
3627 mp_ps_print(mp, "-Slant_"); mp_print_int(mp, mp_fm_font_slant(mp,(A))) ;
3629 if ( mp_fm_font_extend(mp,(A))!=0 ) {
3630 mp_ps_print(mp, "-Extend_"); mp_print_int(mp, mp_fm_font_extend(mp,(A)));
3634 @ @<Include encodings and fonts for edge structure~|h|@>=
3635 mp_font_encodings(mp,mp->last_fnum,prologues==2);
3636 @<Embed fonts that are available@>
3638 @ @<Embed fonts that are available@>=
3641 @<Make |cur_fsize| a copy of the |font_sizes| array@>;
3644 for (f=null_font+1;f<=mp->last_fnum;f++) {
3645 if ( cur_fsize[f]!=null ) {
3646 if (prologues==3 ) {
3647 if ( ! mp_do_ps_font(mp,f) ) {
3648 if ( mp_has_fm_entry(mp,f, NULL) ) {
3649 print_err("Font embedding failed");
3654 cur_fsize[f]=link(cur_fsize[f]);
3655 if ( cur_fsize[f]!=null ) { mp_unmark_font(mp, f); done_fonts=false; }
3659 @<Increment |next_size| and apply |mark_string_chars| to all text nodes with
3661 } while (! done_fonts);
3664 @ @<Increment |next_size| and apply |mark_string_chars| to all text nodes...@>=
3667 mp_apply_mark_string_chars(mp, h, next_size);
3670 @ We also need to keep track of which characters are used in text nodes
3671 in the edge structure that is being shipped out. This is done by procedures
3672 that use the left-over |b3| field in the |char_info| words; i.e.,
3673 |char_info(f)(c).b3| gives the status of character |c| in font |f|.
3676 enum {unused=0, used};
3679 void mp_unmark_font (MP mp,font_number f) ;
3682 void mp_unmark_font (MP mp,font_number f) {
3683 int k; /* an index into |font_info| */
3684 for (k= mp->char_base[f]+mp->font_bc[f];
3685 k<=mp->char_base[f]+mp->font_ec[f];
3687 mp->font_info[k].qqqq.b3=unused;
3692 void mp_print_improved_prologue (MP mp, int prologues, int procset,
3693 int groffmode, int null, pointer h) ;
3698 void mp_print_improved_prologue (MP mp, int prologues, int procset,
3699 int groffmode, int null, pointer h) {
3700 quarterword next_size; /* the size index for fonts being listed */
3701 pointer *cur_fsize; /* current positions in |font_sizes| */
3702 boolean done_fonts; /* have we finished listing the fonts in the header? */
3703 font_number f; /* a font number for loops */
3705 cur_fsize = mp_xmalloc((mp->font_max+1),sizeof(pointer));
3707 mp_list_used_resources(mp, prologues, procset);
3708 mp_list_supplied_resources(mp, prologues, procset);
3709 mp_list_needed_resources(mp, prologues);
3710 mp_print_nl(mp, "%%EndComments");
3711 mp_print_nl(mp, "%%BeginProlog");
3713 mp_print_nl(mp, "%%BeginResource: procset mpost");
3715 mp_print_nl(mp, "%%BeginResource: procset mpost-minimal");
3716 mp_print_nl(mp, "/bd{bind def}bind def"
3717 "/fshow {exch findfont exch scalefont setfont show}bd");
3718 if ( procset>0 ) @<Print the procset@>;
3719 mp_print_nl(mp, "/fcp{findfont dup length dict begin"
3720 "{1 index/FID ne{def}{pop pop}ifelse}forall}bd");
3721 mp_print_nl(mp, "/fmc{FontMatrix dup length array copy dup dup}bd"
3722 "/fmd{/FontMatrix exch def}bd");
3723 mp_print_nl(mp, "/Amul{4 -1 roll exch mul 1000 div}bd"
3724 "/ExtendFont{fmc 0 get Amul 0 exch put fmd}bd");
3725 if ( groffmode>0 ) {
3726 mp_print_nl(mp, "/ScaleFont{dup fmc 0 get"
3727 " Amul 0 exch put dup dup 3 get Amul 3 exch put fmd}bd");
3729 mp_print_nl(mp, "/SlantFont{fmc 2 get dup 0 eq{pop 1}if"
3730 " Amul FontMatrix 0 get mul 2 exch put fmd}bd");
3731 mp_print_nl(mp, "%%EndResource");
3732 @<Include encodings and fonts for edge structure~|h|@>;
3733 mp_print_nl(mp, "%%EndProlog");
3734 mp_print_nl(mp, "%%BeginSetup");
3736 for (f=null_font+1;f<=mp->last_fnum;f++) {
3737 if ( mp_has_font_size(mp,f) ) {
3738 if ( mp_has_fm_entry(mp,f,NULL) ) {
3739 mp_write_font_definition(mp,f,(mp->internal[prologues]>>16));
3740 mp_ps_name_out(mp, mp->font_name[f],true);
3741 mp_ps_print_defined_name(mp,f,(mp->internal[prologues]>>16));
3742 mp_ps_print(mp, " def");
3745 snprintf(s,256,"font %s cannot be found in any fontmapfile!", mp->font_name[f]);
3747 mp_ps_name_out(mp, mp->font_name[f],true);
3748 mp_ps_name_out(mp, mp->font_name[f],true);
3749 mp_ps_print(mp, " def");
3754 mp_print_nl(mp, "%%EndSetup");
3755 mp_print_nl(mp, "%%Page: 1 1");
3757 mp_xfree(cur_fsize);
3761 font_number mp_print_font_comments (MP mp , int prologues, int null, pointer h);
3766 font_number mp_print_font_comments (MP mp , int prologues, int null, pointer h) {
3767 quarterword next_size; /* the size index for fonts being listed */
3768 pointer *cur_fsize; /* current positions in |font_sizes| */
3769 int ff; /* a loop counter */
3770 boolean done_fonts; /* have we finished listing the fonts in the header? */
3771 font_number f; /* a font number for loops */
3772 scaled ds; /* design size and scale factor for a text node */
3773 font_number ldf=0; /* the last \.{DocumentFont} listed (otherwise |null_font|) */
3774 cur_fsize = mp_xmalloc((mp->font_max+1),sizeof(pointer));
3775 if ( prologues>0 ) {
3776 @<Give a \.{DocumentFonts} comment listing all fonts with non-null
3777 |font_sizes| and eliminate duplicates@>;
3780 @<Make |cur_fsize| a copy of the |font_sizes| array@>;
3781 do { done_fonts=true;
3782 for (f=null_font+1;f<=mp->last_fnum;f++) {
3783 if ( cur_fsize[f]!=null ) {
3784 @<Print the \.{\%*Font} comment for font |f| and advance |cur_fsize[f]|@>;
3786 if ( cur_fsize[f]!=null ) { mp_unmark_font(mp, f); done_fonts=false; };
3788 if ( ! done_fonts ) {
3789 @<Increment |next_size| and apply |mark_string_chars| to all text nodes with
3792 } while (! done_fonts);
3794 mp_xfree(cur_fsize);
3798 @ @<Make |cur_fsize| a copy of the |font_sizes| array@>=
3799 for (f=null_font+1;f<= mp->last_fnum;f++)
3800 cur_fsize[f]=mp->font_sizes[f]
3802 @ It's not a good idea to make any assumptions about the |font_ps_name| entries,
3803 so we carefully remove duplicates. There is no harm in using a slow, brute-force
3806 @<Give a \.{DocumentFonts} comment listing all fonts with non-null...@>=
3809 for (f=null_font+1;f<= mp->last_fnum;f++) {
3810 if ( mp->font_sizes[f]!=null ) {
3811 if ( ldf==null_font )
3812 mp_print_nl(mp, "%%DocumentFonts:");
3813 for (ff=ldf;ff>=null_font;ff--) {
3814 if ( mp->font_sizes[ff]!=null )
3815 if ( mp_xstrcmp(mp->font_ps_name[f],mp->font_ps_name[ff])==0 )
3818 if ( mp->ps_offset+1+strlen(mp->font_ps_name[f])>(unsigned)mp->max_print_line )
3819 mp_print_nl(mp, "%%+");
3820 mp_print_char(mp, ' ');
3821 mp_print(mp, mp->font_ps_name[f]);
3830 void mp_hex_digit_out (MP mp,small_number d) {
3831 if ( d<10 ) mp_print_char(mp, d+'0');
3832 else mp_print_char(mp, d+'a'-10);
3835 @ We output the marks as a hexadecimal bit string starting at |c| or
3836 |font_bc[f]|, whichever is greater. If the output has to be truncated
3837 to avoid exceeding |emergency_line_length| the return value says where to
3838 start scanning next time.
3841 halfword mp_ps_marks_out (MP mp,font_number f, eight_bits c);
3844 @d emergency_line_length 255
3845 /* \ps\ output lines can be this long in unusual circumstances */
3848 halfword mp_ps_marks_out (MP mp,font_number f, eight_bits c) {
3849 eight_bits bc,ec; /* only encode characters between these bounds */
3850 integer lim; /* the maximum number of marks to encode before truncating */
3851 int p; /* |font_info| index for the current character */
3852 int d,b; /* used to construct a hexadecimal digit */
3853 lim=4*(emergency_line_length-mp->ps_offset-4);
3857 @<Restrict the range |bc..ec| so that it contains no unused characters
3858 at either end and has length at most |lim|@>;
3859 @<Print the initial label indicating that the bitmap starts at |bc|@>;
3860 @<Print a hexadecimal encoding of the marks for characters |bc..ec|@>;
3861 while ( (ec<mp->font_ec[f])&&(mp->font_info[p].qqqq.b3==unused) ) {
3867 @ We could save time by setting the return value before the loop that
3868 decrements |ec|, but there is no point in being so tricky.
3870 @<Restrict the range |bc..ec| so that it contains no unused characters...@>=
3871 p=mp->char_base[f]+bc;
3872 while ( (mp->font_info[p].qqqq.b3==unused)&&(bc<ec) ) {
3875 if ( ec>=bc+lim ) ec=bc+lim-1;
3876 p=mp->char_base[f]+ec;
3877 while ( (mp->font_info[p].qqqq.b3==unused)&&(bc<ec) ) {
3881 @ @<Print the initial label indicating that the bitmap starts at |bc|@>=
3882 mp_print_char(mp, ' ');
3883 mp_hex_digit_out(mp, bc / 16);
3884 mp_hex_digit_out(mp, bc % 16);
3885 mp_print_char(mp, ':')
3889 @<Print a hexadecimal encoding of the marks for characters |bc..ec|@>=
3891 for (p=mp->char_base[f]+bc;p<=mp->char_base[f]+ec;p++) {
3893 mp_hex_digit_out(mp, d);
3896 if ( mp->font_info[p].qqqq.b3!=unused ) d=d+b;
3899 mp_hex_digit_out(mp, d)
3902 @ Here is a simple function that determines whether there are any marked
3903 characters in font~|f| with character code at least~|c|.
3906 boolean mp_check_ps_marks (MP mp,font_number f, integer c) ;
3909 boolean mp_check_ps_marks (MP mp,font_number f, integer c) {
3910 int p; /* |font_info| index for the current character */
3911 for (p=mp->char_base[f]+c;p<=mp->char_base[f]+mp->font_ec[f];p++) {
3912 if ( mp->font_info[p].qqqq.b3==used )
3919 @ If the file name is so long that it can't be printed without exceeding
3920 |emergency_line_length| then there will be missing items in the \.{\%*Font:}
3921 line. We might have to repeat line in order to get the character usage
3922 information to fit within |emergency_line_length|.
3924 TODO: these two defines are also defined in mp.w!
3926 @d link(A) mp->mem[(A)].hh.rh /* the |link| field of a memory word */
3927 @d sc_factor(A) mp->mem[(A)+1].cint /* the scale factor stored in a font size node */
3929 @<Print the \.{\%*Font} comment for font |f| and advance |cur_fsize[f]|@>=
3931 while ( mp_check_ps_marks(mp, f,t) ) {
3932 mp_print_nl(mp, "%*Font: ");
3933 if ( mp->ps_offset+strlen(mp->font_name[f])+12>emergency_line_length )
3935 mp_print(mp, mp->font_name[f]);
3936 mp_print_char(mp, ' ');
3937 ds=(mp->font_dsize[f] + 8) / 16;
3938 mp_print_scaled(mp, mp_take_scaled(mp, ds,sc_factor(cur_fsize[f])));
3939 if ( mp->ps_offset+12>emergency_line_length ) break;
3940 mp_print_char(mp, ' ');
3941 mp_print_scaled(mp, ds);
3942 if ( mp->ps_offset+5>emergency_line_length ) break;
3943 t=mp_ps_marks_out(mp, f,t);
3945 cur_fsize[f]=link(cur_fsize[f]);
3948 @ @<Print the procset@>=
3950 mp_print_nl(mp, "/hlw{0 dtransform exch truncate exch idtransform pop setlinewidth}bd");
3951 mp_print_nl(mp, "/vlw{0 exch dtransform truncate idtransform setlinewidth pop}bd");
3952 mp_print_nl(mp, "/l{lineto}bd/r{rlineto}bd/c{curveto}bd/m{moveto}bd"
3953 "/p{closepath}bd/n{newpath}bd");
3954 mp_print_nl(mp, "/C{setcmykcolor}bd/G{setgray}bd/R{setrgbcolor}bd"
3955 "/lj{setlinejoin}bd/ml{setmiterlimit}bd");
3956 mp_print_nl(mp, "/lc{setlinecap}bd/S{stroke}bd/F{fill}bd/q{gsave}bd"
3957 "/Q{grestore}bd/s{scale}bd/t{concat}bd");
3958 mp_print_nl(mp, "/sd{setdash}bd/rd{[] 0 setdash}bd/P{showpage}bd/B{q F Q}bd/W{clip}bd");
3962 @ The prologue defines \.{fshow} and corrects for the fact that \.{fshow}
3963 arguments use |font_name| instead of |font_ps_name|. Downloaded bitmap fonts
3964 might not have reasonable |font_ps_name| entries, but we just charge ahead
3965 anyway. The user should not make \&{prologues} positive if this will cause
3967 @:prologues_}{\&{prologues} primitive@>
3970 void mp_print_prologue (MP mp, int prologues, int procset, int ldf);
3973 void mp_print_prologue (MP mp, int prologues, int procset, int ldf) {
3975 mp_print(mp, "%%BeginProlog"); mp_print_ln(mp);
3976 if ( (prologues>0)||(procset>0) ) {
3977 if ( ldf!=null_font ) {
3978 if ( prologues>0 ) {
3979 for (f=null_font+1;f<=mp->last_fnum;f++) {
3980 if ( mp_has_font_size(mp,f) ) {
3981 mp_ps_name_out(mp, mp->font_name[f],true);
3982 mp_ps_name_out(mp, mp->font_ps_name[f],true);
3983 mp_ps_print(mp, " def");
3988 mp_print(mp, "/fshow {exch findfont exch scalefont setfont show}bind def");
3994 mp_print_nl(mp, "%%BeginResource: procset mpost");
3995 if ( (prologues>0)&&(ldf!=null_font) )
3997 "/bd{bind def}bind def/fshow {exch findfont exch scalefont setfont show}bd");
3999 mp_print_nl(mp, "/bd{bind def}bind def");
4000 @<Print the procset@>;
4001 mp_print_nl(mp, "%%EndResource");
4005 mp_print(mp, "%%EndProlog");