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 r = (mp->find_file)("mpost.map", "rb", mp_filetype_fontmap);
1404 mp->ps->mitem->map_line = mp_xstrdup ("mpost.map");
1407 mp->ps->mitem->map_line = mp_xstrdup ("troff.map");
1409 mp->ps->mitem->map_line = mp_xstrdup ("pdftex.map");
1414 @ @<Dealloc variables@>=
1415 if (mp->ps->mitem!=NULL) {
1416 mp_xfree(mp->ps->mitem->map_line);
1417 mp_xfree(mp->ps->mitem);
1423 static void destroy_fm_entry_tfm (void *pa, void *pb) {
1426 fm = (fm_entry *) pa;
1427 if (!has_pslink (fm))
1428 delete_fm_entry (fm);
1432 static void destroy_fm_entry_ps (void *pa, void *pb) {
1435 fm = (fm_entry *) pa;
1436 if (!has_tfmlink (fm))
1437 delete_fm_entry (fm);
1441 static void destroy_ff_entry (void *pa, void *pb) {
1444 ff = (ff_entry *) pa;
1445 delete_ff_entry (ff);
1449 static void fm_free (MP mp);
1452 static void fm_free (MP mp) {
1453 if (mp->ps->tfm_tree != NULL)
1454 avl_destroy (mp->ps->tfm_tree, destroy_fm_entry_tfm);
1455 if (mp->ps->ps_tree != NULL)
1456 avl_destroy (mp->ps->ps_tree, destroy_fm_entry_ps);
1457 if (mp->ps->ff_tree != NULL)
1458 avl_destroy (mp->ps->ff_tree, destroy_ff_entry);
1461 @* \[44c] Helper functions for Type1 fonts.
1464 typedef char char_entry;
1465 typedef unsigned char Byte;
1469 char_entry *char_ptr, *char_array;
1471 char *job_id_string;
1473 @ @<Set initial...@>=
1474 mp->ps->char_array = NULL;
1475 mp->ps->job_id_string = NULL;
1478 @d SMALL_ARRAY_SIZE 256
1482 void mp_set_job_id (MP mp, int year, int month, int day, int time) {
1483 char *name_string, *format_string, *s;
1486 if (mp->ps->job_id_string != NULL)
1488 if ( mp->job_name==NULL )
1489 mp->job_name = mp_xstrdup("mpout");
1490 name_string = mp_xstrdup (mp->job_name);
1491 format_string = mp_xstrdup (mp->mem_ident);
1492 slen = SMALL_BUF_SIZE +
1493 strlen (name_string) +
1494 strlen (format_string);
1495 s = mp_xmalloc (slen, sizeof (char));
1496 i = snprintf (s, slen,
1497 "%.4d/%.2d/%.2d %.2d:%.2d %s %s",
1503 name_string, format_string);
1504 mp->ps->job_id_string = mp_xstrdup (s);
1506 mp_xfree (name_string);
1507 mp_xfree (format_string);
1509 static void fnstr_append (MP mp, const char *s) {
1510 size_t l = strlen (s) + 1;
1511 alloc_array (char, l, SMALL_ARRAY_SIZE);
1512 strcat (mp->ps->char_ptr, s);
1513 mp->ps->char_ptr = strend (mp->ps->char_ptr);
1516 @ @<Exported function headers@>=
1517 void mp_set_job_id (MP mp, int y, int m, int d, int t) ;
1519 @ @<Dealloc variables@>=
1520 mp_xfree(mp->ps->job_id_string);
1522 @ this is not really a true crc32, but it should be just enough to keep
1523 subsets prefixes somewhat disjunct
1526 static unsigned long crc32 (int oldcrc, const Byte *buf, int len) {
1527 unsigned long ret = 0;
1530 ret = (23<<24)+(45<<16)+(67<<8)+89;
1533 ret = (ret<<2)+buf[i];
1536 boolean mp_char_marked (MP mp,font_number f, eight_bits c) {
1537 integer b; /* |char_base[f]| */
1539 if ( (c>=mp->font_bc[f])&&(c<=mp->font_ec[f])&&(mp->font_info[b+c].qqqq.b3!=0) )
1545 static void make_subset_tag (MP mp, fm_entry * fm_cur, char **glyph_names, int tex_font)
1551 if (mp->ps->job_id_string ==NULL)
1552 mp_fatal_error(mp, "no job id!");
1553 l = strlen (mp->ps->job_id_string) + 1;
1555 alloc_array (char, l, SMALL_ARRAY_SIZE);
1556 strcpy (mp->ps->char_array, mp->ps->job_id_string);
1557 mp->ps->char_ptr = strend (mp->ps->char_array);
1558 if (fm_cur->tfm_name != NULL) {
1559 fnstr_append (mp," TFM name: ");
1560 fnstr_append (mp,fm_cur->tfm_name);
1562 fnstr_append (mp," PS name: ");
1563 if (fm_cur->ps_name != NULL)
1564 fnstr_append (mp,fm_cur->ps_name);
1565 fnstr_append (mp," Encoding: ");
1566 if (fm_cur->encoding != NULL && (fm_cur->encoding)->file_name != NULL)
1567 fnstr_append (mp,(fm_cur->encoding)->file_name);
1569 fnstr_append (mp,"built-in");
1570 fnstr_append (mp," CharSet: ");
1571 for (i = 0; i < 256; i++)
1572 if (mp_char_marked (mp,tex_font, i) && glyph_names[i] != notdef) {
1573 if (glyph_names[i]!=NULL) {
1574 fnstr_append (mp,"/");
1575 fnstr_append (mp,glyph_names[i]);
1578 if (fm_cur->charset != NULL) {
1579 fnstr_append (mp," Extra CharSet: ");
1580 fnstr_append (mp, fm_cur->charset);
1582 crc = crc32 (0L, Z_NULL, 0);
1583 crc = crc32 (crc, (Bytef *) mp->ps->char_array, strlen (mp->ps->char_array));
1584 /* we need to fit a 32-bit number into a string of 6 uppercase chars long;
1585 * there are 26 uppercase chars ==> each char represents a number in range
1586 * |0..25|. The maximal number that can be represented by the tag is
1587 * $26^6 - 1$, which is a number between $2^28$ and $2^29$. Thus the bits |29..31|
1588 * of the CRC must be dropped out.
1590 for (i = 0; i < 6; i++) {
1591 tag[i] = 'A' + crc % 26;
1595 fm_cur->subset_tag = mp_xstrdup (tag);
1601 @d external_enc() (fm_cur->encoding)->glyph_names
1602 @d is_used_char(c) mp_char_marked (mp, tex_font, c)
1603 @d end_last_eexec_line()
1604 mp->ps->hexline_length = HEXLINE_WIDTH;
1606 mp->ps->t1_eexec_encrypt = false
1607 @d t1_log(s) mp_print(mp,(char *)s)
1608 @d t1_putchar(c) fputc(c, mp->ps_file)
1609 @d embed_all_glyphs(tex_font) false
1611 @d extra_charset() mp->ps->dvips_extra_charset
1612 @d update_subset_tag()
1613 @d fixedcontent true
1616 #define PRINTF_BUF_SIZE 1024
1617 char *dvips_extra_charset;
1619 unsigned char *grid;
1620 char *ext_glyph_names[256];
1621 char print_buf[PRINTF_BUF_SIZE];
1623 @ @<Set initial ...@>=
1624 mp->ps->dvips_extra_charset=NULL;
1627 @d t1_getchar() fgetc(mp->ps->t1_file)
1628 @d t1_ungetchar(c) ungetc(c, mp->ps->t1_file)
1629 @d t1_eof() feof(mp->ps->t1_file)
1630 @d t1_close() fclose(mp->ps->t1_file)
1631 @d valid_code(c) (c >= 0 && c < 256)
1633 @<Static variables in the outer block@>=
1634 static const char *standard_glyph_names[256] =
1635 { notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1636 notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1637 notdef, notdef, notdef, notdef, notdef, notdef,
1638 notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1639 "space", "exclam", "quotedbl", "numbersign",
1640 "dollar", "percent", "ampersand", "quoteright", "parenleft",
1641 "parenright", "asterisk", "plus", "comma", "hyphen", "period",
1642 "slash", "zero", "one", "two", "three", "four", "five", "six", "seven",
1643 "eight", "nine", "colon", "semicolon", "less",
1644 "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F",
1645 "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q",
1646 "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft",
1647 "backslash", "bracketright", "asciicircum", "underscore",
1648 "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k",
1649 "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v",
1650 "w", "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde",
1651 notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1652 notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1653 notdef, notdef, notdef, notdef, notdef, notdef,
1654 notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1655 notdef, notdef, notdef, "exclamdown", "cent",
1656 "sterling", "fraction", "yen", "florin", "section", "currency",
1657 "quotesingle", "quotedblleft", "guillemotleft",
1658 "guilsinglleft", "guilsinglright", "fi", "fl", notdef, "endash",
1659 "dagger", "daggerdbl", "periodcentered", notdef,
1660 "paragraph", "bullet", "quotesinglbase", "quotedblbase",
1661 "quotedblright", "guillemotright", "ellipsis", "perthousand",
1662 notdef, "questiondown", notdef, "grave", "acute", "circumflex",
1663 "tilde", "macron", "breve", "dotaccent", "dieresis", notdef,
1664 "ring", "cedilla", notdef, "hungarumlaut", "ogonek", "caron", "emdash",
1665 notdef, notdef, notdef, notdef, notdef, notdef,
1666 notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1667 notdef, "AE", notdef, "ordfeminine", notdef, notdef,
1668 notdef, notdef, "Lslash", "Oslash", "OE", "ordmasculine", notdef,
1669 notdef, notdef, notdef, notdef, "ae", notdef, notdef,
1670 notdef, "dotlessi", notdef, notdef, "lslash", "oslash", "oe",
1671 "germandbls", notdef, notdef, notdef, notdef };
1672 static const char charstringname[] = "/CharStrings";
1675 char **t1_glyph_names;
1676 char *t1_builtin_glyph_names[256];
1677 char charsetstr[0x4000];
1678 boolean read_encoding_only;
1682 #define T1_BUF_SIZE 0x10
1686 #define CS_VMOVETO 4
1687 #define CS_RLINETO 5
1688 #define CS_HLINETO 6
1689 #define CS_VLINETO 7
1690 #define CS_RRCURVETO 8
1691 #define CS_CLOSEPATH 9
1692 #define CS_CALLSUBR 10
1693 #define CS_RETURN 11
1694 #define CS_ESCAPE 12
1696 #define CS_ENDCHAR 14
1697 #define CS_RMOVETO 21
1698 #define CS_HMOVETO 22
1699 #define CS_VHCURVETO 30
1700 #define CS_HVCURVETO 31
1701 #define CS_1BYTE_MAX (CS_HVCURVETO + 1)
1703 #define CS_DOTSECTION CS_1BYTE_MAX + 0
1704 #define CS_VSTEM3 CS_1BYTE_MAX + 1
1705 #define CS_HSTEM3 CS_1BYTE_MAX + 2
1706 #define CS_SEAC CS_1BYTE_MAX + 6
1707 #define CS_SBW CS_1BYTE_MAX + 7
1708 #define CS_DIV CS_1BYTE_MAX + 12
1709 #define CS_CALLOTHERSUBR CS_1BYTE_MAX + 16
1710 #define CS_POP CS_1BYTE_MAX + 17
1711 #define CS_SETCURRENTPOINT CS_1BYTE_MAX + 33
1712 #define CS_2BYTE_MAX (CS_SETCURRENTPOINT + 1)
1713 #define CS_MAX CS_2BYTE_MAX
1716 typedef unsigned char byte;
1718 byte nargs; /* number of arguments */
1719 boolean bottom; /* take arguments from bottom of stack? */
1720 boolean clear; /* clear stack? */
1722 } cc_entry; /* CharString Command */
1724 char *glyph_name; /* glyph name (or notdef for Subrs entry) */
1726 unsigned short len; /* length of the whole string */
1727 unsigned short cslen; /* length of the encoded part of the string */
1733 unsigned short t1_dr, t1_er;
1734 unsigned short t1_c1, t1_c2;
1735 unsigned short t1_cslen;
1738 @ @<Set initial...@>=
1739 mp->ps->t1_c1 = 52845;
1740 mp->ps->t1_c2 = 22719;
1743 typedef char t1_line_entry;
1744 typedef char t1_buf_entry;
1747 t1_line_entry *t1_line_ptr, *t1_line_array;
1748 size_t t1_line_limit;
1749 t1_buf_entry *t1_buf_ptr, *t1_buf_array;
1750 size_t t1_buf_limit;
1752 cs_entry *cs_tab, *cs_ptr, *cs_notdef;
1753 char *cs_dict_start, *cs_dict_end;
1754 int cs_count, cs_size, cs_size_pos;
1756 char *subr_array_start, *subr_array_end;
1757 int subr_max, subr_size, subr_size_pos;
1759 @ @<Set initial...@>=
1760 mp->ps->t1_line_array = NULL;
1761 mp->ps->t1_buf_array = NULL;
1764 This list contains the begin/end tokens commonly used in the
1765 /Subrs array of a Type 1 font.
1767 @<Static variables in the outer block@>=
1768 static const char *cs_token_pairs_list[][2] = {
1771 {" RD", "noaccess put"},
1772 {" -|", "noaccess put"},
1777 const char **cs_token_pair;
1778 boolean t1_pfa, t1_cs, t1_scan, t1_eexec_encrypt, t1_synthetic;
1779 int t1_in_eexec; /* 0 before eexec-encrypted, 1 during, 2 after */
1780 long t1_block_length;
1788 @<Set initial ...@>=
1789 mp->ps->hexline_length = HEXLINE_WIDTH;
1792 @d t1_prefix(s) str_prefix(mp->ps->t1_line_array, s)
1793 @d t1_buf_prefix(s) str_prefix(mp->ps->t1_buf_array, s)
1794 @d t1_suffix(s) str_suffix(mp->ps->t1_line_array, mp->ps->t1_line_ptr, s)
1795 @d t1_buf_suffix(s) str_suffix(mp->ps->t1_buf_array, mp->ps->t1_buf_ptr, s)
1796 @d t1_charstrings() strstr(mp->ps->t1_line_array, charstringname)
1797 @d t1_subrs() t1_prefix("/Subrs")
1798 @d t1_end_eexec() t1_suffix("mark currentfile closefile")
1799 @d t1_cleartomark() t1_prefix("cleartomark")
1801 @d isdigit(A) ((A)>='0'&&(A)<='9')
1804 static void end_hexline (MP mp) {
1805 if (mp->ps->hexline_length == HEXLINE_WIDTH) {
1806 fputs ("\n", mp->ps_file);
1807 mp->ps->hexline_length = 0;
1810 static void t1_check_pfa (MP mp) {
1811 const int c = t1_getchar ();
1812 mp->ps->t1_pfa = (c != 128) ? true : false;
1815 static int t1_getbyte (MP mp)
1817 int c = t1_getchar ();
1820 if (mp->ps->t1_block_length == 0) {
1822 mp_fatal_error (mp, "invalid marker");
1829 mp->ps->t1_block_length = t1_getchar () & 0xff;
1830 mp->ps->t1_block_length |= (t1_getchar () & 0xff) << 8;
1831 mp->ps->t1_block_length |= (t1_getchar () & 0xff) << 16;
1832 mp->ps->t1_block_length |= (t1_getchar () & 0xff) << 24;
1835 mp->ps->t1_block_length--;
1838 static int hexval (int c) {
1839 if (c >= 'A' && c <= 'F')
1840 return c - 'A' + 10;
1841 else if (c >= 'a' && c <= 'f')
1842 return c - 'a' + 10;
1843 else if (c >= '0' && c <= '9')
1848 static byte edecrypt (MP mp, byte cipher) {
1850 if (mp->ps->t1_pfa) {
1851 while (cipher == 10 || cipher == 13)
1852 cipher = t1_getbyte (mp);
1853 mp->ps->last_hexbyte = cipher = (hexval (cipher) << 4) + hexval (t1_getbyte (mp));
1855 plain = (cipher ^ (mp->ps->t1_dr >> 8));
1856 mp->ps->t1_dr = (cipher + mp->ps->t1_dr) * mp->ps->t1_c1 + mp->ps->t1_c2;
1859 static byte cdecrypt (MP mp, byte cipher, unsigned short *cr)
1861 const byte plain = (cipher ^ (*cr >> 8));
1862 *cr = (cipher + *cr) * mp->ps->t1_c1 + mp->ps->t1_c2;
1865 static byte eencrypt (MP mp, byte plain)
1867 const byte cipher = (plain ^ (mp->ps->t1_er >> 8));
1868 mp->ps->t1_er = (cipher + mp->ps->t1_er) * mp->ps->t1_c1 + mp->ps->t1_c2;
1872 static byte cencrypt (MP mp, byte plain, unsigned short *cr)
1874 const byte cipher = (plain ^ (*cr >> 8));
1875 *cr = (cipher + *cr) * mp->ps->t1_c1 + mp->ps->t1_c2;
1879 static char *eol (char *s) {
1880 char *p = strend (s);
1881 if (p - s > 1 && p[-1] != 10) {
1887 static float t1_scan_num (MP mp, char *p, char **r)
1892 if (sscanf (p, "%g", &f) != 1) {
1893 remove_eol (p, mp->ps->t1_line_array);
1894 snprintf(s,128, "a number expected: `%s'", mp->ps->t1_line_array);
1895 mp_fatal_error(mp,s);
1898 for (; isdigit (*p) || *p == '.' ||
1899 *p == 'e' || *p == 'E' || *p == '+' || *p == '-'; p++);
1905 static boolean str_suffix (const char *begin_buf, const char *end_buf,
1908 const char *s1 = end_buf - 1, *s2 = strend (s) - 1;
1911 while (s1 >= begin_buf && s2 >= s) {
1920 @d alloc_array(T, n, s) do {
1921 if (mp->ps->T##_array == NULL) {
1922 mp->ps->T##_limit = (s);
1923 if ((unsigned)(n) > mp->ps->T##_limit)
1924 mp->ps->T##_limit = (n);
1925 mp->ps->T##_array = mp_xmalloc (mp->ps->T##_limit,sizeof(T##_entry));
1926 mp->ps->T##_ptr = mp->ps->T##_array;
1928 else if ((unsigned)(mp->ps->T##_ptr - mp->ps->T##_array + (n)) > mp->ps->T##_limit) {
1929 size_t last_ptr_index;
1930 last_ptr_index = mp->ps->T##_ptr - mp->ps->T##_array;
1931 mp->ps->T##_limit *= 2;
1932 if ((unsigned)(mp->ps->T##_ptr - mp->ps->T##_array + (n)) > mp->ps->T##_limit)
1933 mp->ps->T##_limit = mp->ps->T##_ptr - mp->ps->T##_array + (n);
1934 mp->ps->T##_array = mp_xrealloc(mp->ps->T##_array, mp->ps->T##_limit , sizeof (T##_entry));
1935 mp->ps->T##_ptr = mp->ps->T##_array + last_ptr_index;
1939 @d out_eexec_char(A) t1_outhex(mp,(A))
1942 static void t1_outhex (MP mp, byte b)
1944 static char *hexdigits = "0123456789ABCDEF";
1945 t1_putchar (hexdigits[b / 16]);
1946 t1_putchar (hexdigits[b % 16]);
1947 mp->ps->hexline_length += 2;
1950 static void t1_getline (MP mp) {
1951 int c, l, eexec_scan;
1953 static const char eexec_str[] = "currentfile eexec";
1954 static int eexec_len = 17; /* |strlen(eexec_str)| */
1957 mp_fatal_error (mp,"unexpected end of file");
1958 mp->ps->t1_line_ptr = mp->ps->t1_line_array;
1959 alloc_array (t1_line, 1, T1_BUF_SIZE);
1960 mp->ps->t1_cslen = 0;
1962 c = t1_getbyte (mp);
1965 while (!t1_eof ()) {
1966 if (mp->ps->t1_in_eexec == 1)
1967 c = edecrypt (mp,c);
1968 alloc_array (t1_line, 1, T1_BUF_SIZE);
1969 append_char_to_buf (c, mp->ps->t1_line_ptr, mp->ps->t1_line_array, mp->ps->t1_line_limit);
1970 if (mp->ps->t1_in_eexec == 0 && eexec_scan >= 0 && eexec_scan < eexec_len) {
1971 if (mp->ps->t1_line_array[eexec_scan] == eexec_str[eexec_scan])
1976 if (c == 10 || (mp->ps->t1_pfa && eexec_scan == eexec_len && c == 32))
1978 if (mp->ps->t1_cs && mp->ps->t1_cslen == 0 &&
1979 (mp->ps->t1_line_ptr - mp->ps->t1_line_array > 4) &&
1980 (t1_suffix (" RD ") || t1_suffix (" -| "))) {
1981 p = mp->ps->t1_line_ptr - 5;
1984 mp->ps->t1_cslen = l = t1_scan_num (mp, p + 1, 0);
1985 mp->ps->cs_start = mp->ps->t1_line_ptr - mp->ps->t1_line_array;
1986 /* |mp->ps->cs_start| is an index now */
1987 alloc_array (t1_line, l, T1_BUF_SIZE);
1989 *mp->ps->t1_line_ptr++ = edecrypt (mp,t1_getbyte (mp));
1991 c = t1_getbyte (mp);
1993 alloc_array (t1_line, 2, T1_BUF_SIZE); /* |append_eol| can append 2 chars */
1994 append_eol (mp->ps->t1_line_ptr, mp->ps->t1_line_array, mp->ps->t1_line_limit);
1995 if (mp->ps->t1_line_ptr - mp->ps->t1_line_array < 2)
1997 if (eexec_scan == eexec_len)
1998 mp->ps->t1_in_eexec = 1;
2000 /* ensure that |mp->ps->t1_buf_array| has as much room as |t1_line_array| */
2001 mp->ps->t1_buf_ptr = mp->ps->t1_buf_array;
2002 alloc_array (t1_buf, mp->ps->t1_line_limit, mp->ps->t1_line_limit);
2005 static void t1_putline (MP mp)
2007 char *p = mp->ps->t1_line_array;
2008 if (mp->ps->t1_line_ptr - mp->ps->t1_line_array <= 1)
2010 if (mp->ps->t1_eexec_encrypt) {
2011 while (p < mp->ps->t1_line_ptr)
2012 out_eexec_char (eencrypt (mp,*p++));
2014 while (p < mp->ps->t1_line_ptr)
2019 static void t1_puts (MP mp, const char *s)
2021 if (s != mp->ps->t1_line_array)
2022 strcpy (mp->ps->t1_line_array, s);
2023 mp->ps->t1_line_ptr = strend (mp->ps->t1_line_array);
2027 static void t1_printf (MP mp, const char *fmt, ...)
2030 va_start (args, fmt);
2031 vsprintf (mp->ps->t1_line_array, fmt, args);
2032 t1_puts (mp,mp->ps->t1_line_array);
2036 static void t1_init_params (MP mp, char *open_name_prefix,
2037 char *cur_file_name) {
2038 if ((open_name_prefix != NULL) && strlen(open_name_prefix)) {
2039 t1_log (open_name_prefix);
2040 t1_log (cur_file_name);
2042 mp->ps->t1_lenIV = 4;
2043 mp->ps->t1_dr = 55665;
2044 mp->ps->t1_er = 55665;
2045 mp->ps->t1_in_eexec = 0;
2046 mp->ps->t1_cs = false;
2047 mp->ps->t1_scan = true;
2048 mp->ps->t1_synthetic = false;
2049 mp->ps->t1_eexec_encrypt = false;
2050 mp->ps->t1_block_length = 0;
2053 static void t1_close_font_file (MP mp, const char *close_name_suffix) {
2054 if ((close_name_suffix != NULL) && strlen(close_name_suffix)) {
2055 t1_log (close_name_suffix);
2060 static void t1_check_block_len (MP mp, boolean decrypt) {
2063 if (mp->ps->t1_block_length == 0)
2065 c = t1_getbyte (mp);
2067 c = edecrypt (mp,c);
2068 l = mp->ps->t1_block_length;
2069 if (!(l == 0 && (c == 10 || c == 13))) {
2070 snprintf(s,128,"%i bytes more than expected were ignored", l+ 1);
2076 static void t1_start_eexec (MP mp, fm_entry *fm_cur) {
2078 if (!mp->ps->t1_pfa)
2079 t1_check_block_len (mp, false);
2080 for (mp->ps->t1_line_ptr = mp->ps->t1_line_array, i = 0; i < 4; i++) {
2081 edecrypt (mp, t1_getbyte (mp));
2082 *mp->ps->t1_line_ptr++ = 0;
2084 mp->ps->t1_eexec_encrypt = true;
2085 if (!mp->ps->read_encoding_only)
2086 if (is_included (fm_cur))
2087 t1_putline (mp); /* to put the first four bytes */
2089 static void t1_stop_eexec (MP mp) {
2091 end_last_eexec_line ();
2092 if (!mp->ps->t1_pfa)
2093 t1_check_block_len (mp,true);
2095 c = edecrypt (mp, t1_getbyte (mp));
2096 if (!(c == 10 || c == 13)) {
2097 if (mp->ps->last_hexbyte == 0)
2100 mp_warn (mp,"unexpected data after eexec");
2103 mp->ps->t1_cs = false;
2104 mp->ps->t1_in_eexec = 2;
2106 static void t1_modify_fm (MP mp) {
2107 mp->ps->t1_line_ptr = eol (mp->ps->t1_line_array);
2110 static void t1_modify_italic (MP mp) {
2111 mp->ps->t1_line_ptr = eol (mp->ps->t1_line_array);
2116 const char *pdfname;
2126 static key_entry font_keys[FONT_KEYS_NUM] = {
2127 {"Ascent", "Ascender", 0, false},
2128 {"CapHeight", "CapHeight", 0, false},
2129 {"Descent", "Descender", 0, false},
2130 {"FontName", "FontName", 0, false},
2131 {"ItalicAngle", "ItalicAngle", 0, false},
2132 {"StemV", "StdVW", 0, false},
2133 {"XHeight", "XHeight", 0, false},
2134 {"FontBBox", "FontBBox", 0, false},
2146 @d ITALIC_ANGLE_CODE 4
2152 @d FONTBBOX4_CODE 10
2153 @d MAX_KEY_CODE (FONTBBOX1_CODE + 1)
2156 static void t1_scan_keys (MP mp, int tex_font,fm_entry *fm_cur) {
2160 if (fm_extend (fm_cur) != 0 || fm_slant (fm_cur) != 0) {
2161 if (t1_prefix ("/FontMatrix")) {
2165 if (t1_prefix ("/ItalicAngle")) {
2166 t1_modify_italic (mp);
2170 if (t1_prefix ("/FontType")) {
2171 p = mp->ps->t1_line_array + strlen ("FontType") + 1;
2172 if ((i = t1_scan_num (mp,p, 0)) != 1) {
2174 snprintf(s,125,"Type%d fonts unsupported by metapost", i);
2175 mp_fatal_error(mp,s);
2179 for (key = font_keys; key - font_keys < MAX_KEY_CODE; key++)
2180 if (str_prefix (mp->ps->t1_line_array + 1, key->t1name))
2182 if (key - font_keys == MAX_KEY_CODE)
2185 p = mp->ps->t1_line_array + strlen (key->t1name) + 1;
2187 if ((k = key - font_keys) == FONTNAME_CODE) {
2190 remove_eol (p, mp->ps->t1_line_array);
2191 snprintf(s,128,"a name expected: `%s'", mp->ps->t1_line_array);
2192 mp_fatal_error(mp,s);
2194 r = ++p; /* skip the slash */
2195 if (is_included (fm_cur)) {
2196 /* save the fontname */
2197 strncpy (mp->ps->fontname_buf, p, FONTNAME_BUF_SIZE);
2198 for (i=0; mp->ps->fontname_buf[i] != 10; i++);
2199 mp->ps->fontname_buf[i]=0;
2201 if(is_subsetted (fm_cur)) {
2202 if (fm_cur->encoding!=NULL && fm_cur->encoding->glyph_names!=NULL)
2203 make_subset_tag (mp,fm_cur, fm_cur->encoding->glyph_names, tex_font);
2205 make_subset_tag (mp,fm_cur, mp->ps->t1_builtin_glyph_names, tex_font);
2207 alloc_array (t1_line, (r-mp->ps->t1_line_array+6+1+strlen(mp->ps->fontname_buf)+1),
2209 strncpy (r, fm_cur->subset_tag , 6);
2211 strncpy (r+7, mp->ps->fontname_buf, strlen(mp->ps->fontname_buf)+1);
2212 mp->ps->t1_line_ptr = eol (r);
2214 /* |for (q = p; *q != ' ' && *q != 10; *q++);|*/
2216 mp->ps->t1_line_ptr = eol (r);
2221 if ((k == STEMV_CODE || k == FONTBBOX1_CODE)
2222 && (*p == '[' || *p == '{'))
2224 if (k == FONTBBOX1_CODE) {
2225 for (i = 0; i < 4; i++) {
2226 key[i].value = t1_scan_num (mp, p, &r);
2231 key->value = t1_scan_num (mp, p, 0);
2233 static void t1_scan_param (MP mp, int tex_font,fm_entry *fm_cur)
2235 static const char *lenIV = "/lenIV";
2236 if (!mp->ps->t1_scan || *mp->ps->t1_line_array != '/')
2238 if (t1_prefix (lenIV)) {
2239 mp->ps->t1_lenIV = t1_scan_num (mp,mp->ps->t1_line_array + strlen (lenIV), 0);
2242 t1_scan_keys (mp, tex_font,fm_cur);
2244 static void copy_glyph_names (char **glyph_names, int a, int b) {
2245 if (glyph_names[b] != notdef) {
2246 mp_xfree (glyph_names[b]);
2247 glyph_names[b] = (char *) notdef;
2249 if (glyph_names[a] != notdef) {
2250 glyph_names[b] = mp_xstrdup (glyph_names[a]);
2253 static void t1_builtin_enc (MP mp) {
2254 int i, a, b, c, counter = 0;
2257 * At this moment "/Encoding" is the prefix of |mp->ps->t1_line_array|
2259 if (t1_suffix ("def")) { /* predefined encoding */
2260 sscanf (mp->ps->t1_line_array + strlen ("/Encoding"), "%256s", mp->ps->t1_buf_array);
2261 if (strcmp (mp->ps->t1_buf_array, "StandardEncoding") == 0) {
2262 for (i = 0; i < 256; i++)
2263 if (standard_glyph_names[i] == notdef)
2264 mp->ps->t1_builtin_glyph_names[i] = (char *) notdef;
2266 mp->ps->t1_builtin_glyph_names[i] =
2267 mp_xstrdup (standard_glyph_names[i]);
2268 mp->ps->t1_encoding = ENC_STANDARD;
2271 snprintf(s,128, "cannot subset font (unknown predefined encoding `%s')",
2272 mp->ps->t1_buf_array);
2273 mp_fatal_error(mp,s);
2277 mp->ps->t1_encoding = ENC_BUILTIN;
2279 * At this moment "/Encoding" is the prefix of |mp->ps->t1_line_array|, and the encoding is
2280 * not a predefined encoding
2282 * We have two possible forms of Encoding vector. The first case is
2284 * /Encoding [/a /b /c...] readonly def
2286 * and the second case can look like
2288 * /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for
2294 for (i = 0; i < 256; i++)
2295 mp->ps->t1_builtin_glyph_names[i] = (char *) notdef;
2296 if (t1_prefix ("/Encoding [") || t1_prefix ("/Encoding[")) { /* the first case */
2297 r = strchr (mp->ps->t1_line_array, '[') + 1;
2301 for (p = mp->ps->t1_buf_array, r++;
2302 *r != 32 && *r != 10 && *r != ']' && *r != '/';
2306 if (counter > 255) {
2308 (mp, "encoding vector contains more than 256 names");
2310 if (strcmp (mp->ps->t1_buf_array, notdef) != 0)
2311 mp->ps->t1_builtin_glyph_names[counter] = mp_xstrdup (mp->ps->t1_buf_array);
2314 if (*r != 10 && *r != '%') {
2315 if (str_prefix (r, "] def")
2316 || str_prefix (r, "] readonly def"))
2320 remove_eol (r, mp->ps->t1_line_array);
2321 snprintf(s,128,"a name or `] def' or `] readonly def' expected: `%s'",
2322 mp->ps->t1_line_array);
2323 mp_fatal_error(mp,s);
2327 r = mp->ps->t1_line_array;
2329 } else { /* the second case */
2330 p = strchr (mp->ps->t1_line_array, 10);
2334 p = mp->ps->t1_line_array;
2337 check for `dup <index> <glyph> put'
2339 if (sscanf (p, "dup %i%256s put", &i, mp->ps->t1_buf_array) == 2 &&
2340 *mp->ps->t1_buf_array == '/' && valid_code (i)) {
2341 if (strcmp (mp->ps->t1_buf_array + 1, notdef) != 0)
2342 mp->ps->t1_builtin_glyph_names[i] =
2343 mp_xstrdup (mp->ps->t1_buf_array + 1);
2344 p = strstr (p, " put") + strlen (" put");
2348 check for `dup dup <to> exch <from> get put'
2350 else if (sscanf (p, "dup dup %i exch %i get put", &b, &a) == 2
2351 && valid_code (a) && valid_code (b)) {
2352 copy_glyph_names (mp->ps->t1_builtin_glyph_names, a, b);
2353 p = strstr (p, " get put") + strlen (" get put");
2357 check for `dup dup <from> <size> getinterval <to> exch putinterval'
2360 (p, "dup dup %i %i getinterval %i exch putinterval",
2361 &a, &c, &b) == 3 && valid_code (a) && valid_code (b)
2362 && valid_code (c)) {
2363 for (i = 0; i < c; i++)
2364 copy_glyph_names (mp->ps->t1_builtin_glyph_names, a + i, b + i);
2365 p = strstr (p, " putinterval") + strlen (" putinterval");
2369 check for `def' or `readonly def'
2371 else if ((p == mp->ps->t1_line_array || (p > mp->ps->t1_line_array && p[-1] == ' '))
2372 && strcmp (p, "def\n") == 0)
2375 skip an unrecognizable word
2378 while (*p != ' ' && *p != 10)
2386 static void t1_check_end (MP mp) {
2390 if (t1_prefix ("{restore}"))
2396 char *ff_name; /* base name of font file */
2397 char *ff_path; /* full path to font file */
2401 static boolean t1_open_fontfile (MP mp, fm_entry *fm_cur,const char *open_name_prefix) {
2403 ff = check_ff_exist (mp, fm_cur);
2404 if (ff->ff_path != NULL) {
2405 mp->ps->t1_file = mp_open_file(mp,ff->ff_path, "rb", mp_filetype_font);
2407 mp_warn (mp, "cannot open Type 1 font file for reading");
2410 t1_init_params (mp,(char *)open_name_prefix,fm_cur->ff_name);
2411 mp->ps->fontfile_found = true;
2415 static void t1_scan_only (MP mp, int tex_font, fm_entry *fm_cur) {
2418 t1_scan_param (mp,tex_font, fm_cur);
2420 while (mp->ps->t1_in_eexec == 0);
2421 t1_start_eexec (mp,fm_cur);
2424 t1_scan_param (mp,tex_font, fm_cur);
2426 while (!(t1_charstrings () || t1_subrs ()));
2429 static void t1_include (MP mp, int tex_font, fm_entry *fm_cur) {
2432 t1_scan_param (mp,tex_font, fm_cur);
2435 while (mp->ps->t1_in_eexec == 0);
2436 t1_start_eexec (mp,fm_cur);
2439 t1_scan_param (mp,tex_font, fm_cur);
2442 while (!(t1_charstrings () || t1_subrs ()));
2443 mp->ps->t1_cs = true;
2448 while (!t1_end_eexec ());
2450 if (fixedcontent) { /* copy 512 zeros (not needed for PDF) */
2455 while (!t1_cleartomark ());
2456 t1_check_end (mp); /* write "{restore}if" if found */
2461 @d check_subr(SUBR) if (SUBR >= mp->ps->subr_size || SUBR < 0) {
2463 snprintf(s,128,"Subrs array: entry index out of range (%i)",SUBR);
2464 mp_fatal_error(mp,s);
2468 static const char **check_cs_token_pair (MP mp) {
2469 const char **p = (const char **) cs_token_pairs_list;
2470 for (; p[0] != NULL; ++p)
2471 if (t1_buf_prefix (p[0]) && t1_buf_suffix (p[1]))
2476 static void cs_store (MP mp, boolean is_subr) {
2480 for (p = mp->ps->t1_line_array, mp->ps->t1_buf_ptr = mp->ps->t1_buf_array; *p != ' ';
2481 *mp->ps->t1_buf_ptr++ = *p++);
2482 *mp->ps->t1_buf_ptr = 0;
2484 subr = t1_scan_num (mp, p + 1, 0);
2486 ptr = mp->ps->subr_tab + subr;
2488 ptr = mp->ps->cs_ptr++;
2489 if (mp->ps->cs_ptr - mp->ps->cs_tab > mp->ps->cs_size) {
2491 snprintf(s,128,"CharStrings dict: more entries than dict size (%i)",mp->ps->cs_size);
2492 mp_fatal_error(mp,s);
2494 if (strcmp (mp->ps->t1_buf_array + 1, notdef) == 0) /* skip the slash */
2495 ptr->glyph_name = (char *) notdef;
2497 ptr->glyph_name = mp_xstrdup (mp->ps->t1_buf_array + 1);
2499 /* copy " RD " + cs data to |mp->ps->t1_buf_array| */
2500 memcpy (mp->ps->t1_buf_array, mp->ps->t1_line_array + mp->ps->cs_start - 4,
2501 (unsigned) (mp->ps->t1_cslen + 4));
2502 /* copy the end of cs data to |mp->ps->t1_buf_array| */
2503 for (p = mp->ps->t1_line_array + mp->ps->cs_start + mp->ps->t1_cslen, mp->ps->t1_buf_ptr =
2504 mp->ps->t1_buf_array + mp->ps->t1_cslen + 4; *p != 10; *mp->ps->t1_buf_ptr++ = *p++);
2505 *mp->ps->t1_buf_ptr++ = 10;
2506 if (is_subr && mp->ps->cs_token_pair == NULL)
2507 mp->ps->cs_token_pair = check_cs_token_pair (mp);
2508 ptr->len = mp->ps->t1_buf_ptr - mp->ps->t1_buf_array;
2509 ptr->cslen = mp->ps->t1_cslen;
2510 ptr->data = mp_xmalloc (ptr->len , sizeof (byte));
2511 memcpy (ptr->data, mp->ps->t1_buf_array, ptr->len);
2515 #define store_subr(mp) cs_store(mp,true)
2516 #define store_cs(mp) cs_store(mp,false)
2518 #define CC_STACK_SIZE 24
2520 static integer cc_stack[CC_STACK_SIZE], *stack_ptr = cc_stack;
2521 static cc_entry cc_tab[CS_MAX];
2522 static boolean is_cc_init = false;
2526 if (stack_ptr - cc_stack < (N)) \
2530 #define stack_error(N) { \
2532 snprintf(s,255,"CharString: invalid access (%i) to stack (%i entries)", \
2533 (int) N, (int)(stack_ptr - cc_stack)); \
2539 #define cc_get(N) ((N) < 0 ? *(stack_ptr + (N)) : *(cc_stack + (N)))
2541 #define cc_push(V) *stack_ptr++ = V
2542 #define cc_clear() stack_ptr = cc_stack
2544 #define set_cc(N, B, A, C) \
2545 cc_tab[N].nargs = A; \
2546 cc_tab[N].bottom = B; \
2547 cc_tab[N].clear = C; \
2548 cc_tab[N].valid = true
2550 static void cc_init (void) {
2554 for (i = 0; i < CS_MAX; i++)
2555 cc_tab[i].valid = false;
2556 set_cc (CS_HSTEM, true, 2, true);
2557 set_cc (CS_VSTEM, true, 2, true);
2558 set_cc (CS_VMOVETO, true, 1, true);
2559 set_cc (CS_RLINETO, true, 2, true);
2560 set_cc (CS_HLINETO, true, 1, true);
2561 set_cc (CS_VLINETO, true, 1, true);
2562 set_cc (CS_RRCURVETO, true, 6, true);
2563 set_cc (CS_CLOSEPATH, false, 0, true);
2564 set_cc (CS_CALLSUBR, false, 1, false);
2565 set_cc (CS_RETURN, false, 0, false);
2567 |set_cc(CS_ESCAPE, false, 0, false);|
2569 set_cc (CS_HSBW, true, 2, true);
2570 set_cc (CS_ENDCHAR, false, 0, true);
2571 set_cc (CS_RMOVETO, true, 2, true);
2572 set_cc (CS_HMOVETO, true, 1, true);
2573 set_cc (CS_VHCURVETO, true, 4, true);
2574 set_cc (CS_HVCURVETO, true, 4, true);
2575 set_cc (CS_DOTSECTION, false, 0, true);
2576 set_cc (CS_VSTEM3, true, 6, true);
2577 set_cc (CS_HSTEM3, true, 6, true);
2578 set_cc (CS_SEAC, true, 5, true);
2579 set_cc (CS_SBW, true, 4, true);
2580 set_cc (CS_DIV, false, 2, false);
2581 set_cc (CS_CALLOTHERSUBR, false, 0, false);
2582 set_cc (CS_POP, false, 0, false);
2583 set_cc (CS_SETCURRENTPOINT, true, 2, true);
2589 @d cs_getchar(mp) cdecrypt(mp,*data++, &cr)
2591 @d mark_subr(mp,n) cs_mark(mp,0, n)
2592 @d mark_cs(mp,s) cs_mark(mp,s, 0)
2593 @d SMALL_BUF_SIZE 256
2596 static void cs_warn (MP mp, const char *cs_name, int subr, const char *fmt, ...) {
2597 char buf[SMALL_BUF_SIZE];
2600 va_start (args, fmt);
2601 vsprintf (buf, fmt, args);
2603 if (cs_name == NULL) {
2604 snprintf(s,299,"Subr (%i): %s", (int) subr, buf);
2606 snprintf(s,299,"CharString (/%s): %s", cs_name, buf);
2611 static void cs_mark (MP mp, const char *cs_name, int subr)
2617 static integer lastargOtherSubr3 = 3; /* the argument of last call to
2621 if (cs_name == NULL) {
2623 ptr = mp->ps->subr_tab + subr;
2627 if (mp->ps->cs_notdef != NULL &&
2628 (cs_name == notdef || strcmp (cs_name, notdef) == 0))
2629 ptr = mp->ps->cs_notdef;
2631 for (ptr = mp->ps->cs_tab; ptr < mp->ps->cs_ptr; ptr++)
2632 if (strcmp (ptr->glyph_name, cs_name) == 0)
2634 if (ptr == mp->ps->cs_ptr) {
2636 snprintf (s,128,"glyph `%s' undefined", cs_name);
2640 if (ptr->glyph_name == notdef)
2641 mp->ps->cs_notdef = ptr;
2644 /* only marked CharString entries and invalid entries can be skipped;
2645 valid marked subrs must be parsed to keep the stack in sync */
2646 if (!ptr->valid || (ptr->is_used && cs_name != NULL))
2648 ptr->is_used = true;
2650 cs_len = ptr->cslen;
2651 data = ptr->data + 4;
2652 for (i = 0; i < mp->ps->t1_lenIV; i++, cs_len--)
2654 while (cs_len > 0) {
2656 b = cs_getchar (mp);
2660 else if (b <= 250) {
2662 a = ((b - 247) << 8) + 108 + cs_getchar (mp);
2663 } else if (b <= 254) {
2665 a = -((b - 251) << 8) - 108 - cs_getchar (mp);
2668 a = (cs_getchar (mp) & 0xff) << 24;
2669 a |= (cs_getchar (mp) & 0xff) << 16;
2670 a |= (cs_getchar (mp) & 0xff) << 8;
2671 a |= (cs_getchar (mp) & 0xff) << 0;
2672 if (sizeof (integer) > 4 && (a & 0x80000000))
2677 if (b == CS_ESCAPE) {
2678 b = cs_getchar (mp) + CS_1BYTE_MAX;
2682 cs_warn (mp,cs_name, subr, "command value out of range: %i",
2688 cs_warn (mp,cs_name, subr, "command not valid: %i", (int) b);
2692 if (stack_ptr - cc_stack < cc->nargs)
2693 cs_warn (mp,cs_name, subr,
2694 "less arguments on stack (%i) than required (%i)",
2695 (int) (stack_ptr - cc_stack), (int) cc->nargs);
2696 else if (stack_ptr - cc_stack > cc->nargs)
2697 cs_warn (mp,cs_name, subr,
2698 "more arguments on stack (%i) than required (%i)",
2699 (int) (stack_ptr - cc_stack), (int) cc->nargs);
2701 switch (cc - cc_tab) {
2706 if (!mp->ps->subr_tab[a1].valid) {
2707 cs_warn (mp,cs_name, subr, "cannot call subr (%i)", (int) a1);
2715 case CS_CALLOTHERSUBR:
2716 if (cc_get (-1) == 3)
2717 lastargOtherSubr3 = cc_get (-3);
2718 a1 = cc_get (-2) + 2;
2722 cc_push (lastargOtherSubr3);
2723 /* the only case when we care about the value being pushed onto
2724 stack is when POP follows CALLOTHERSUBR (changing hints by
2732 mark_cs (mp,standard_glyph_names[a1]);
2733 mark_cs (mp,standard_glyph_names[a2]);
2742 cs_error: /* an error occured during parsing */
2745 ptr->is_used = false;
2748 static void t1_subset_ascii_part (MP mp, int tex_font, fm_entry *fm_cur)
2752 while (!t1_prefix ("/Encoding")) {
2753 t1_scan_param (mp,tex_font, fm_cur);
2757 t1_builtin_enc (mp);
2758 if (is_reencoded (fm_cur))
2759 mp->ps->t1_glyph_names = external_enc ();
2761 mp->ps->t1_glyph_names = mp->ps->t1_builtin_glyph_names;
2763 |if (is_included (fm_cur) && is_subsetted (fm_cur)) {
2764 make_subset_tag (fm_cur, t1_glyph_names, tex_font);
2765 update_subset_tag ();
2768 if ((!is_subsetted (fm_cur)) && mp->ps->t1_encoding == ENC_STANDARD)
2769 t1_puts (mp,"/Encoding StandardEncoding def\n");
2772 (mp,"/Encoding 256 array\n0 1 255 {1 index exch /.notdef put} for\n");
2773 for (i = 0, j = 0; i < 256; i++) {
2774 if (is_used_char (i) && mp->ps->t1_glyph_names[i] != notdef) {
2776 t1_printf (mp,"dup %i /%s put\n", (int) t1_char (i),
2777 mp->ps->t1_glyph_names[i]);
2780 /* We didn't mark anything for the Encoding array. */
2781 /* We add "dup 0 /.notdef put" for compatibility */
2782 /* with Acrobat 5.0. */
2784 t1_puts (mp,"dup 0 /.notdef put\n");
2785 t1_puts (mp,"readonly def\n");
2789 t1_scan_param (mp,tex_font, fm_cur);
2790 if (!t1_prefix ("/UniqueID")) /* ignore UniqueID for subsetted fonts */
2793 while (mp->ps->t1_in_eexec == 0);
2796 #define t1_subr_flush(mp) t1_flush_cs(mp,true)
2797 #define t1_cs_flush(mp) t1_flush_cs(mp,false)
2799 static void cs_init (MP mp) {
2800 mp->ps->cs_ptr = mp->ps->cs_tab = NULL;
2801 mp->ps->cs_dict_start = mp->ps->cs_dict_end = NULL;
2802 mp->ps->cs_count = mp->ps->cs_size = mp->ps->cs_size_pos = 0;
2803 mp->ps->cs_token_pair = NULL;
2804 mp->ps->subr_tab = NULL;
2805 mp->ps->subr_array_start = mp->ps->subr_array_end = NULL;
2806 mp->ps->subr_max = mp->ps->subr_size = mp->ps->subr_size_pos = 0;
2809 static void init_cs_entry ( cs_entry * cs) {
2811 cs->glyph_name = NULL;
2814 cs->is_used = false;
2818 static void t1_mark_glyphs (MP mp, int tex_font);
2820 static void t1_read_subrs (MP mp, int tex_font, fm_entry *fm_cur)
2825 while (!(t1_charstrings () || t1_subrs ())) {
2826 t1_scan_param (mp,tex_font, fm_cur);
2831 mp->ps->t1_cs = true;
2832 mp->ps->t1_scan = false;
2835 mp->ps->subr_size_pos = strlen ("/Subrs") + 1;
2836 /* |subr_size_pos| points to the number indicating dict size after "/Subrs" */
2837 mp->ps->subr_size = t1_scan_num (mp,mp->ps->t1_line_array + mp->ps->subr_size_pos, 0);
2838 if (mp->ps->subr_size == 0) {
2839 while (!t1_charstrings ())
2843 /* |subr_tab = xtalloc (subr_size, cs_entry);| */
2844 mp->ps->subr_tab = (cs_entry *)mp_xmalloc (mp->ps->subr_size, sizeof (cs_entry));
2845 for (ptr = mp->ps->subr_tab; ptr - mp->ps->subr_tab < mp->ps->subr_size; ptr++)
2846 init_cs_entry (ptr);
2847 mp->ps->subr_array_start = mp_xstrdup (mp->ps->t1_line_array);
2849 while (mp->ps->t1_cslen) {
2853 /* mark the first four entries without parsing */
2854 for (i = 0; i < mp->ps->subr_size && i < 4; i++)
2855 mp->ps->subr_tab[i].is_used = true;
2856 /* the end of the Subrs array might have more than one line so we need to
2857 concatnate them to |subr_array_end|. Unfortunately some fonts don't have
2858 the Subrs array followed by the CharStrings dict immediately (synthetic
2859 fonts). If we cannot find CharStrings in next |POST_SUBRS_SCAN| lines then
2860 we will treat the font as synthetic and ignore everything until next
2863 #define POST_SUBRS_SCAN 5
2865 *mp->ps->t1_buf_array = 0;
2866 for (i = 0; i < POST_SUBRS_SCAN; i++) {
2867 if (t1_charstrings ())
2869 s += mp->ps->t1_line_ptr - mp->ps->t1_line_array;
2870 alloc_array (t1_buf, s, T1_BUF_SIZE);
2871 strcat (mp->ps->t1_buf_array, mp->ps->t1_line_array);
2874 mp->ps->subr_array_end = mp_xstrdup (mp->ps->t1_buf_array);
2875 if (i == POST_SUBRS_SCAN) { /* CharStrings not found;
2876 suppose synthetic font */
2877 for (ptr = mp->ps->subr_tab; ptr - mp->ps->subr_tab < mp->ps->subr_size; ptr++)
2879 mp_xfree (ptr->data);
2880 mp_xfree (mp->ps->subr_tab);
2881 mp_xfree (mp->ps->subr_array_start);
2882 mp_xfree (mp->ps->subr_array_end);
2884 mp->ps->t1_cs = false;
2885 mp->ps->t1_synthetic = true;
2886 while (!(t1_charstrings () || t1_subrs ()))
2893 static void t1_flush_cs (MP mp, boolean is_subr)
2896 byte *r, *return_cs = NULL;
2897 cs_entry *tab, *end_tab, *ptr;
2898 char *start_line, *line_end;
2899 int count, size_pos;
2900 unsigned short cr, cs_len = 0; /* to avoid warning about uninitialized use of |cs_len| */
2902 start_line = mp->ps->subr_array_start;
2903 line_end = mp->ps->subr_array_end;
2904 size_pos = mp->ps->subr_size_pos;
2905 tab = mp->ps->subr_tab;
2906 count = mp->ps->subr_max + 1;
2907 end_tab = mp->ps->subr_tab + count;
2909 start_line = mp->ps->cs_dict_start;
2910 line_end = mp->ps->cs_dict_end;
2911 size_pos = mp->ps->cs_size_pos;
2912 tab = mp->ps->cs_tab;
2913 end_tab = mp->ps->cs_ptr;
2914 count = mp->ps->cs_count;
2916 mp->ps->t1_line_ptr = mp->ps->t1_line_array;
2917 for (p = start_line; p - start_line < size_pos;)
2918 *mp->ps->t1_line_ptr++ = *p++;
2919 while (isdigit (*p))
2921 sprintf (mp->ps->t1_line_ptr, "%u", count);
2922 strcat (mp->ps->t1_line_ptr, p);
2923 mp->ps->t1_line_ptr = eol (mp->ps->t1_line_array);
2926 /* create |return_cs| to replace unsused subr's */
2930 return_cs = mp_xmalloc ( (mp->ps->t1_lenIV + 1) , sizeof(byte));
2931 if ( mp->ps->t1_lenIV > 0) {
2932 for (cs_len = 0, r = return_cs; cs_len < mp->ps->t1_lenIV; cs_len++, r++)
2933 *r = cencrypt (mp,0x00, &cr);
2934 *r = cencrypt (mp,CS_RETURN, &cr);
2936 *return_cs = CS_RETURN;
2941 for (ptr = tab; ptr < end_tab; ptr++) {
2944 sprintf (mp->ps->t1_line_array, "dup %i %u", (int) (ptr - tab),
2947 sprintf (mp->ps->t1_line_array, "/%s %u", ptr->glyph_name, ptr->cslen);
2948 p = strend (mp->ps->t1_line_array);
2949 memcpy (p, ptr->data, ptr->len);
2950 mp->ps->t1_line_ptr = p + ptr->len;
2953 /* replace unsused subr's by |return_cs| */
2955 sprintf (mp->ps->t1_line_array, "dup %i %u%s ", (int) (ptr - tab),
2956 cs_len, mp->ps->cs_token_pair[0]);
2957 p = strend (mp->ps->t1_line_array);
2958 memcpy (p, return_cs, cs_len);
2959 mp->ps->t1_line_ptr = p + cs_len;
2961 sprintf (mp->ps->t1_line_array, " %s", mp->ps->cs_token_pair[1]);
2962 mp->ps->t1_line_ptr = eol (mp->ps->t1_line_array);
2966 mp_xfree (ptr->data);
2967 if (ptr->glyph_name != notdef)
2968 mp_xfree (ptr->glyph_name);
2970 sprintf (mp->ps->t1_line_array, "%s", line_end);
2971 mp->ps->t1_line_ptr = eol (mp->ps->t1_line_array);
2974 mp_xfree (return_cs);
2976 mp_xfree (start_line);
2977 mp_xfree (line_end);
2980 static void t1_mark_glyphs (MP mp, int tex_font)
2983 char *charset = extra_charset ();
2986 if (mp->ps->t1_synthetic || embed_all_glyphs (tex_font)) { /* mark everything */
2987 if (mp->ps->cs_tab != NULL)
2988 for (ptr = mp->ps->cs_tab; ptr < mp->ps->cs_ptr; ptr++)
2990 ptr->is_used = true;
2991 if (mp->ps->subr_tab != NULL) {
2992 for (ptr = mp->ps->subr_tab; ptr - mp->ps->subr_tab < mp->ps->subr_size; ptr++)
2994 ptr->is_used = true;
2995 mp->ps->subr_max = mp->ps->subr_size - 1;
2999 mark_cs (mp,notdef);
3000 for (i = 0; i < 256; i++)
3001 if (is_used_char (i)) {
3002 if (mp->ps->t1_glyph_names[i] == notdef) {
3004 snprintf(s,128, "character %i is mapped to %s", i, notdef);
3007 mark_cs (mp,mp->ps->t1_glyph_names[i]);
3009 if (charset == NULL)
3011 g = s = charset + 1; /* skip the first '/' */
3014 while (*s != '/' && s < r)
3016 *s = 0; /* terminate g by rewriting '/' to 0 */
3021 if (mp->ps->subr_tab != NULL)
3022 for (mp->ps->subr_max = -1, ptr = mp->ps->subr_tab;
3023 ptr - mp->ps->subr_tab < mp->ps->subr_size;
3025 if (ptr->is_used && ptr - mp->ps->subr_tab > mp->ps->subr_max)
3026 mp->ps->subr_max = ptr - mp->ps->subr_tab;
3029 static void t1_subset_charstrings (MP mp, int tex_font)
3032 mp->ps->cs_size_pos =
3033 strstr (mp->ps->t1_line_array, charstringname) + strlen (charstringname)
3034 - mp->ps->t1_line_array + 1;
3035 /* |cs_size_pos| points to the number indicating
3036 dict size after "/CharStrings" */
3037 mp->ps->cs_size = t1_scan_num (mp,mp->ps->t1_line_array + mp->ps->cs_size_pos, 0);
3038 mp->ps->cs_ptr = mp->ps->cs_tab = mp_xmalloc (mp->ps->cs_size, sizeof(cs_entry));
3039 for (ptr = mp->ps->cs_tab; ptr - mp->ps->cs_tab < mp->ps->cs_size; ptr++)
3040 init_cs_entry (ptr);
3041 mp->ps->cs_notdef = NULL;
3042 mp->ps->cs_dict_start = mp_xstrdup (mp->ps->t1_line_array);
3044 while (mp->ps->t1_cslen) {
3048 mp->ps->cs_dict_end = mp_xstrdup (mp->ps->t1_line_array);
3049 t1_mark_glyphs (mp,tex_font);
3050 if (mp->ps->subr_tab != NULL) {
3051 if (mp->ps->cs_token_pair == NULL)
3053 (mp, "This Type 1 font uses mismatched subroutine begin/end token pairs.");
3056 for (mp->ps->cs_count = 0, ptr = mp->ps->cs_tab; ptr < mp->ps->cs_ptr; ptr++)
3062 static void t1_subset_end (MP mp)
3064 if (mp->ps->t1_synthetic) { /* copy to "dup /FontName get exch definefont pop" */
3065 while (!strstr (mp->ps->t1_line_array, "definefont")) {
3069 while (!t1_end_eexec ())
3070 t1_getline (mp); /* ignore the rest */
3071 t1_putline (mp); /* write "mark currentfile closefile" */
3073 while (!t1_end_eexec ()) { /* copy to "mark currentfile closefile" */
3078 if (fixedcontent) { /* copy 512 zeros (not needed for PDF) */
3079 while (!t1_cleartomark ()) {
3083 if (!mp->ps->t1_synthetic) /* don't check "{restore}if" for synthetic fonts */
3084 t1_check_end (mp); /* write "{restore}if" if found */
3088 static int t1_updatefm (MP mp, int f, fm_entry *fm)
3091 mp->ps->read_encoding_only = true;
3092 if (!t1_open_fontfile (mp,fm,NULL)) {
3095 t1_scan_only (mp,f, fm);
3096 s = mp_xstrdup(mp->ps->fontname_buf);
3098 while (*p != ' ' && *p != 0)
3102 t1_close_font_file (mp,"");
3107 static void writet1 (MP mp, int tex_font, fm_entry *fm_cur) {
3108 int save_selector = mp->selector;
3109 mp_normalize_selector(mp);
3110 mp->ps->read_encoding_only = false;
3111 if (!is_included (fm_cur)) { /* scan parameters from font file */
3112 if (!t1_open_fontfile (mp,fm_cur,"{"))
3114 t1_scan_only (mp,tex_font, fm_cur);
3115 t1_close_font_file (mp,"}");
3118 if (!is_subsetted (fm_cur)) { /* include entire font */
3119 if (!t1_open_fontfile (mp,fm_cur,"<<"))
3121 t1_include (mp,tex_font,fm_cur);
3122 t1_close_font_file (mp,">>");
3125 /* partial downloading */
3126 if (!t1_open_fontfile (mp,fm_cur,"<"))
3128 t1_subset_ascii_part (mp,tex_font,fm_cur);
3129 t1_start_eexec (mp,fm_cur);
3132 t1_read_subrs (mp,tex_font, fm_cur);
3133 t1_subset_charstrings (mp,tex_font);
3135 t1_close_font_file (mp,">");
3136 mp->selector = save_selector;
3140 static void t1_free (MP mp);
3143 static void t1_free (MP mp) {
3144 mp_xfree (mp->ps->t1_line_array);
3145 mp_xfree (mp->ps->t1_buf_array);
3149 @* \[44d] Embedding fonts.
3151 @ The |tfm_num| is officially of type |font_number|, but that
3152 type does not exist yet at this point in the output order.
3156 char *tfm_name; /* TFM file name */
3157 char *ps_name; /* PostScript name */
3158 integer flags; /* font flags */
3159 char *ff_name; /* font file name */
3160 char *subset_tag; /* pseudoUniqueTag for subsetted font */
3161 enc_entry *encoding; /* pointer to corresponding encoding */
3162 unsigned int tfm_num; /* number of the TFM refering this entry */
3163 unsigned short type; /* font type (T1/TTF/...) */
3164 short slant; /* SlantFont */
3165 short extend; /* ExtendFont */
3166 integer ff_objnum; /* FontFile object number */
3167 integer fn_objnum; /* FontName/BaseName object number */
3168 integer fd_objnum; /* FontDescriptor object number */
3169 char *charset; /* string containing used glyphs */
3170 boolean all_glyphs; /* embed all glyphs? */
3171 unsigned short links; /* link flags from |tfm_tree| and |ps_tree| */
3172 short tfm_avail; /* flags whether a tfm is available */
3173 short pid; /* Pid for truetype fonts */
3174 short eid; /* Eid for truetype fonts */
3180 #define FONTNAME_BUF_SIZE 128
3181 boolean fontfile_found;
3182 boolean is_otf_font;
3183 char fontname_buf[FONTNAME_BUF_SIZE];
3191 @d set_included(fm) ((fm)->type |= F_INCLUDED)
3192 @d set_subsetted(fm) ((fm)->type |= F_SUBSETTED)
3193 @d set_truetype(fm) ((fm)->type |= F_TRUETYPE)
3194 @d set_basefont(fm) ((fm)->type |= F_BASEFONT)
3196 @d is_included(fm) ((fm)->type & F_INCLUDED)
3197 @d is_subsetted(fm) ((fm)->type & F_SUBSETTED)
3198 @d is_truetype(fm) ((fm)->type & F_TRUETYPE)
3199 @d is_basefont(fm) ((fm)->type & F_BASEFONT)
3200 @d is_reencoded(fm) ((fm)->encoding != NULL)
3201 @d is_fontfile(fm) (fm_fontfile(fm) != NULL)
3202 @d is_t1fontfile(fm) (is_fontfile(fm) && !is_truetype(fm))
3204 @d fm_slant(fm) (fm)->slant
3205 @d fm_extend(fm) (fm)->extend
3206 @d fm_fontfile(fm) (fm)->ff_name
3208 @<Exported function headers@>=
3209 boolean mp_font_is_reencoded (MP mp, int f);
3210 boolean mp_font_is_included (MP mp, int f);
3211 boolean mp_font_is_subsetted (MP mp, int f);
3214 boolean mp_font_is_reencoded (MP mp, int f) {
3216 if (mp_has_font_size(mp,f) && mp_has_fm_entry (mp, f, &fm)) {
3218 && (fm->ps_name != NULL)
3219 && is_reencoded (fm))
3224 boolean mp_font_is_included (MP mp, int f) {
3226 if (mp_has_font_size(mp,f) && mp_has_fm_entry (mp, f, &fm)) {
3228 && (fm->ps_name != NULL && fm->ff_name != NULL)
3229 && is_included (fm))
3234 boolean mp_font_is_subsetted (MP mp, int f) {
3236 if (mp_has_font_size(mp,f) && mp_has_fm_entry (mp, f,&fm)) {
3238 && (fm->ps_name != NULL && fm->ff_name != NULL)
3239 && is_included (fm) && is_subsetted (fm))
3245 @ @<Exported function headers@>=
3246 char * mp_fm_encoding_name (MP mp, int f);
3247 char * mp_fm_font_name (MP mp, int f);
3248 char * mp_fm_font_subset_name (MP mp, int f);
3251 @c char * mp_fm_encoding_name (MP mp, int f) {
3254 if (mp_has_fm_entry (mp, f, &fm)) {
3255 if (fm != NULL && (fm->ps_name != NULL)) {
3256 if (is_reencoded (fm)) {
3258 if (e->enc_name!=NULL)
3259 return mp_xstrdup(e->enc_name);
3265 print_err ("fontmap encoding problems for font ");
3266 mp_print(mp,mp->font_name[f]);
3270 char * mp_fm_font_name (MP mp, int f) {
3272 if (mp_has_fm_entry (mp, f,&fm)) {
3273 if (fm != NULL && (fm->ps_name != NULL)) {
3274 if (mp_font_is_included(mp, f) && !mp->font_ps_name_fixed[f]) {
3275 /* find the real fontname, and update |ps_name| and |subset_tag| if needed */
3276 if (t1_updatefm(mp,f,fm)) {
3277 mp->font_ps_name_fixed[f] = true;
3279 print_err ("font loading problems for font ");
3280 mp_print(mp,mp->font_name[f]);
3284 return mp_xstrdup(fm->ps_name);
3287 print_err ("fontmap name problems for font ");
3288 mp_print(mp,mp->font_name[f]);
3293 char * mp_fm_font_subset_name (MP mp, int f) {
3295 if (mp_has_fm_entry (mp, f, &fm)) {
3296 if (fm != NULL && (fm->ps_name != NULL)) {
3297 if (is_subsetted(fm)) {
3298 char *s = mp_xmalloc(strlen(fm->ps_name)+8,1);
3299 snprintf(s,strlen(fm->ps_name)+8,"%s-%s",fm->subset_tag,fm->ps_name);
3302 return mp_xstrdup(fm->ps_name);
3306 print_err ("fontmap name problems for font ");
3307 mp_print(mp,mp->font_name[f]);
3312 @ @<Exported function headers@>=
3313 integer mp_fm_font_slant (MP mp, int f);
3314 integer mp_fm_font_extend (MP mp, int f);
3317 @c integer mp_fm_font_slant (MP mp, int f) {
3319 if (mp_has_fm_entry (mp, f, &fm)) {
3320 if (fm != NULL && (fm->ps_name != NULL)) {
3326 integer mp_fm_font_extend (MP mp, int f) {
3328 if (mp_has_fm_entry (mp, f, &fm)) {
3329 if (fm != NULL && (fm->ps_name != NULL)) {
3336 @ @<Exported function headers@>=
3337 boolean mp_do_ps_font (MP mp, font_number f);
3339 @ @c boolean mp_do_ps_font (MP mp, font_number f) {
3341 (void)mp_has_fm_entry (mp, f, &fm_cur); /* for side effects */
3344 if (is_truetype(fm_cur) ||
3345 (fm_cur->ps_name == NULL && fm_cur->ff_name == NULL)) {
3348 if (is_included(fm_cur)) {
3349 mp_print_nl(mp,"%%BeginResource: font ");
3350 if (is_subsetted(fm_cur)) {
3351 mp_print(mp, fm_cur->subset_tag);
3352 mp_print_char(mp,'-');
3354 mp_print(mp, fm_cur->ps_name);
3356 writet1 (mp,f,fm_cur);
3357 mp_print_nl(mp,"%%EndResource");
3363 @ Included subset fonts do not need and encoding vector, make
3364 sure we skip that case.
3367 void mp_list_used_resources (MP mp, int prologues, int procset);
3369 @ @c void mp_list_used_resources (MP mp, int prologues, int procset) {
3370 font_number f; /* fonts used in a text node or as loop counters */
3371 int ff; /* a loop counter */
3372 font_number ldf; /* the last \.{DocumentFont} listed (otherwise |null_font|) */
3375 mp_print_nl(mp, "%%DocumentResources: procset mpost");
3377 mp_print_nl(mp, "%%DocumentResources: procset mpost-minimal");
3380 for (f=null_font+1;f<=mp->last_fnum;f++) {
3381 if ( (mp_has_font_size(mp,f))&&(mp_font_is_reencoded(mp,f)) ) {
3382 for (ff=ldf;ff>=null_font;ff--) {
3383 if ( mp_has_font_size(mp,ff) )
3384 if ( mp_xstrcmp(mp->font_enc_name[f],mp->font_enc_name[ff])==0 )
3387 if ( mp_font_is_subsetted(mp,f) )
3389 if ( mp->ps_offset+1+strlen(mp->font_enc_name[f])>
3390 (unsigned)mp->max_print_line )
3391 mp_print_nl(mp, "%%+ encoding");
3394 mp_print_nl(mp, "%%+ encoding");
3396 mp_print_char(mp, ' ');
3397 mp_print(mp, mp->font_enc_name[f]);
3405 for (f=null_font+1;f<=mp->last_fnum;f++) {
3406 if ( mp_has_font_size(mp,f) ) {
3407 for (ff=ldf;ff>=null_font;ff--) {
3408 if ( mp_has_font_size(mp,ff) )
3409 if ( mp_xstrcmp(mp->font_name[f],mp->font_name[ff])==0 )
3412 if ( mp->ps_offset+1+strlen(mp->font_ps_name[f])>
3413 (unsigned)mp->max_print_line )
3414 mp_print_nl(mp, "%%+ font");
3417 mp_print_nl(mp, "%%+ font");
3419 mp_print_char(mp, ' ');
3420 if ( (prologues==3)&&
3421 (mp_font_is_subsetted(mp,f)) )
3422 mp_print(mp, mp_fm_font_subset_name(mp,f));
3424 mp_print(mp, mp->font_ps_name[f]);
3434 void mp_list_supplied_resources (MP mp, int prologues, int procset);
3436 @ @c void mp_list_supplied_resources (MP mp, int prologues, int procset) {
3437 font_number f; /* fonts used in a text node or as loop counters */
3438 int ff; /* a loop counter */
3439 font_number ldf; /* the last \.{DocumentFont} listed (otherwise |null_font|) */
3442 mp_print_nl(mp, "%%DocumentSuppliedResources: procset mpost");
3444 mp_print_nl(mp, "%%DocumentSuppliedResources: procset mpost-minimal");
3447 for (f=null_font+1;f<=mp->last_fnum;f++) {
3448 if ( (mp_has_font_size(mp,f))&&(mp_font_is_reencoded(mp,f)) ) {
3449 for (ff=ldf;ff>= null_font;ff++) {
3450 if ( mp_has_font_size(mp,ff) )
3451 if ( mp_xstrcmp(mp->font_enc_name[f],mp->font_enc_name[ff])==0 )
3454 if ( (prologues==3)&&(mp_font_is_subsetted(mp,f)))
3456 if ( mp->ps_offset+1+strlen(mp->font_enc_name[f])>(unsigned)mp->max_print_line )
3457 mp_print_nl(mp, "%%+ encoding");
3460 mp_print_nl(mp, "%%+ encoding");
3462 mp_print_char(mp, ' ');
3463 mp_print(mp, mp->font_enc_name[f]);
3472 for (f=null_font+1;f<=mp->last_fnum;f++) {
3473 if ( mp_has_font_size(mp,f) ) {
3474 for (ff=ldf;ff>= null_font;ff--) {
3475 if ( mp_has_font_size(mp,ff) )
3476 if ( mp_xstrcmp(mp->font_name[f],mp->font_name[ff])==0 )
3479 if ( ! mp_font_is_included(mp,f) )
3481 if ( mp->ps_offset+1+strlen(mp->font_ps_name[f])>(unsigned)mp->max_print_line )
3482 mp_print_nl(mp, "%%+ font");
3485 mp_print_nl(mp, "%%+ font");
3487 mp_print_char(mp, ' ');
3488 if ( mp_font_is_subsetted(mp,f) )
3489 mp_print(mp, mp_fm_font_subset_name(mp,f));
3491 mp_print(mp, mp->font_ps_name[f]);
3502 void mp_list_needed_resources (MP mp, int prologues);
3504 @ @c void mp_list_needed_resources (MP mp, int prologues) {
3505 font_number f; /* fonts used in a text node or as loop counters */
3506 int ff; /* a loop counter */
3507 font_number ldf; /* the last \.{DocumentFont} listed (otherwise |null_font|) */
3511 for (f=null_font+1;f<=mp->last_fnum;f++ ) {
3512 if ( mp_has_font_size(mp,f)) {
3513 for (ff=ldf;ff>=null_font;ff--) {
3514 if ( mp_has_font_size(mp,ff) )
3515 if ( mp_xstrcmp(mp->font_name[f],mp->font_name[ff])==0 )
3518 if ((prologues==3)&&(mp_font_is_included(mp,f)) )
3520 if ( mp->ps_offset+1+strlen(mp->font_ps_name[f])>(unsigned)mp->max_print_line )
3521 mp_print_nl(mp, "%%+ font");
3524 mp_print_nl(mp, "%%DocumentNeededResources: font");
3526 mp_print_char(mp, ' ');
3527 mp_print(mp, mp->font_ps_name[f]);
3533 if ( ! firstitem ) {
3537 for (f=null_font+1;f<= mp->last_fnum;f++) {
3538 if ( mp_has_font_size(mp,f) ) {
3539 for (ff=ldf;ff>=null_font;ff-- ) {
3540 if ( mp_has_font_size(mp,ff) )
3541 if ( mp_xstrcmp(mp->font_name[f],mp->font_name[ff])==0 )
3544 if ((prologues==3)&&(mp_font_is_included(mp,f)) )
3546 mp_print(mp, "%%IncludeResource: font ");
3547 mp_print(mp, mp->font_ps_name[f]);
3558 void mp_write_font_definition (MP mp, font_number f, int prologues);
3562 @d applied_reencoding(A) ((mp_font_is_reencoded(mp,(A)))&&
3563 ((! mp_font_is_subsetted(mp,(A)))||(prologues==2)))
3565 @c void mp_write_font_definition(MP mp, font_number f, int prologues) {
3566 if ( (applied_reencoding(f))||(mp_fm_font_slant(mp,f)!=0)||
3567 (mp_fm_font_extend(mp,f)!=0)||
3568 (mp_xstrcmp(mp->font_name[f],"psyrgo")==0)||
3569 (mp_xstrcmp(mp->font_name[f],"zpzdr-reversed")==0) ) {
3570 if ( (mp_font_is_subsetted(mp,f))&&
3571 (mp_font_is_included(mp,f))&&(prologues==3))
3572 mp_ps_name_out(mp, mp_fm_font_subset_name(mp,f),true);
3574 mp_ps_name_out(mp, mp->font_ps_name[f],true);
3575 mp_ps_print(mp, " fcp");
3577 if ( applied_reencoding(f) ) {
3578 mp_ps_print(mp, "/Encoding ");
3579 mp_ps_print(mp, mp->font_enc_name[f]);
3580 mp_ps_print(mp, " def ");
3582 if ( mp_fm_font_slant(mp,f)!=0 ) {
3583 mp_print_int(mp, mp_fm_font_slant(mp,f));
3584 mp_ps_print(mp, " SlantFont ");
3586 if ( mp_fm_font_extend(mp,f)!=0 ) {
3587 mp_print_int(mp, mp_fm_font_extend(mp,f));
3588 mp_ps_print(mp, " ExtendFont ");
3590 if ( mp_xstrcmp(mp->font_name[f],"psyrgo")==0 ) {
3591 mp_ps_print(mp, " 890 ScaleFont ");
3592 mp_ps_print(mp, " 277 SlantFont ");
3594 if ( mp_xstrcmp(mp->font_name[f],"zpzdr-reversed")==0 ) {
3595 mp_ps_print(mp, " FontMatrix [-1 0 0 1 0 0] matrix concatmatrix /FontMatrix exch def ");
3596 mp_ps_print(mp, "/Metrics 2 dict dup begin ");
3597 mp_ps_print(mp, "/space[0 -278]def ");
3598 mp_ps_print(mp, "/a12[-904 -939]def ");
3599 mp_ps_print(mp, "end def ");
3601 mp_ps_print(mp, "currentdict end");
3603 mp_ps_print_defined_name(mp,f,prologues);
3604 mp_ps_print(mp, " exch definefont pop");
3610 void mp_ps_print_defined_name (MP mp, font_number f, int prologues);
3613 @c void mp_ps_print_defined_name(MP mp, font_number A, int prologues) {
3614 mp_ps_print(mp, " /");
3615 if ((mp_font_is_subsetted(mp,(A)))&&
3616 (mp_font_is_included(mp,(A)))&&(prologues==3))
3617 mp_print(mp, mp_fm_font_subset_name(mp,(A)));
3619 mp_print(mp, mp->font_ps_name[(A)]);
3620 if ( mp_xstrcmp(mp->font_name[(A)],"psyrgo")==0 )
3621 mp_ps_print(mp, "-Slanted");
3622 if ( mp_xstrcmp(mp->font_name[(A)],"zpzdr-reversed")==0 )
3623 mp_ps_print(mp, "-Reverse");
3624 if ( applied_reencoding((A)) ) {
3625 mp_ps_print(mp, "-");
3626 mp_ps_print(mp, mp->font_enc_name[(A)]);
3628 if ( mp_fm_font_slant(mp,(A))!=0 ) {
3629 mp_ps_print(mp, "-Slant_"); mp_print_int(mp, mp_fm_font_slant(mp,(A))) ;
3631 if ( mp_fm_font_extend(mp,(A))!=0 ) {
3632 mp_ps_print(mp, "-Extend_"); mp_print_int(mp, mp_fm_font_extend(mp,(A)));
3636 @ @<Include encodings and fonts for edge structure~|h|@>=
3637 mp_font_encodings(mp,mp->last_fnum,prologues==2);
3638 @<Embed fonts that are available@>
3640 @ @<Embed fonts that are available@>=
3643 @<Make |cur_fsize| a copy of the |font_sizes| array@>;
3646 for (f=null_font+1;f<=mp->last_fnum;f++) {
3647 if ( cur_fsize[f]!=null ) {
3648 if (prologues==3 ) {
3649 if ( ! mp_do_ps_font(mp,f) ) {
3650 if ( mp_has_fm_entry(mp,f, NULL) ) {
3651 print_err("Font embedding failed");
3656 cur_fsize[f]=link(cur_fsize[f]);
3657 if ( cur_fsize[f]!=null ) { mp_unmark_font(mp, f); done_fonts=false; }
3661 @<Increment |next_size| and apply |mark_string_chars| to all text nodes with
3663 } while (! done_fonts);
3666 @ @<Increment |next_size| and apply |mark_string_chars| to all text nodes...@>=
3669 mp_apply_mark_string_chars(mp, h, next_size);
3672 @ We also need to keep track of which characters are used in text nodes
3673 in the edge structure that is being shipped out. This is done by procedures
3674 that use the left-over |b3| field in the |char_info| words; i.e.,
3675 |char_info(f)(c).b3| gives the status of character |c| in font |f|.
3678 enum {unused=0, used};
3681 void mp_unmark_font (MP mp,font_number f) ;
3684 void mp_unmark_font (MP mp,font_number f) {
3685 int k; /* an index into |font_info| */
3686 for (k= mp->char_base[f]+mp->font_bc[f];
3687 k<=mp->char_base[f]+mp->font_ec[f];
3689 mp->font_info[k].qqqq.b3=unused;
3694 void mp_print_improved_prologue (MP mp, int prologues, int procset,
3695 int groffmode, int null, pointer h) ;
3700 void mp_print_improved_prologue (MP mp, int prologues, int procset,
3701 int groffmode, int null, pointer h) {
3702 quarterword next_size; /* the size index for fonts being listed */
3703 pointer *cur_fsize; /* current positions in |font_sizes| */
3704 boolean done_fonts; /* have we finished listing the fonts in the header? */
3705 font_number f; /* a font number for loops */
3707 cur_fsize = mp_xmalloc((mp->font_max+1),sizeof(pointer));
3709 mp_list_used_resources(mp, prologues, procset);
3710 mp_list_supplied_resources(mp, prologues, procset);
3711 mp_list_needed_resources(mp, prologues);
3712 mp_print_nl(mp, "%%EndComments");
3713 mp_print_nl(mp, "%%BeginProlog");
3715 mp_print_nl(mp, "%%BeginResource: procset mpost");
3717 mp_print_nl(mp, "%%BeginResource: procset mpost-minimal");
3718 mp_print_nl(mp, "/bd{bind def}bind def"
3719 "/fshow {exch findfont exch scalefont setfont show}bd");
3720 if ( procset>0 ) @<Print the procset@>;
3721 mp_print_nl(mp, "/fcp{findfont dup length dict begin"
3722 "{1 index/FID ne{def}{pop pop}ifelse}forall}bd");
3723 mp_print_nl(mp, "/fmc{FontMatrix dup length array copy dup dup}bd"
3724 "/fmd{/FontMatrix exch def}bd");
3725 mp_print_nl(mp, "/Amul{4 -1 roll exch mul 1000 div}bd"
3726 "/ExtendFont{fmc 0 get Amul 0 exch put fmd}bd");
3727 if ( groffmode>0 ) {
3728 mp_print_nl(mp, "/ScaleFont{dup fmc 0 get"
3729 " Amul 0 exch put dup dup 3 get Amul 3 exch put fmd}bd");
3731 mp_print_nl(mp, "/SlantFont{fmc 2 get dup 0 eq{pop 1}if"
3732 " Amul FontMatrix 0 get mul 2 exch put fmd}bd");
3733 mp_print_nl(mp, "%%EndResource");
3734 @<Include encodings and fonts for edge structure~|h|@>;
3735 mp_print_nl(mp, "%%EndProlog");
3736 mp_print_nl(mp, "%%BeginSetup");
3738 for (f=null_font+1;f<=mp->last_fnum;f++) {
3739 if ( mp_has_font_size(mp,f) ) {
3740 if ( mp_has_fm_entry(mp,f,NULL) ) {
3741 mp_write_font_definition(mp,f,(mp->internal[prologues]>>16));
3742 mp_ps_name_out(mp, mp->font_name[f],true);
3743 mp_ps_print_defined_name(mp,f,(mp->internal[prologues]>>16));
3744 mp_ps_print(mp, " def");
3747 snprintf(s,256,"font %s cannot be found in any fontmapfile!", mp->font_name[f]);
3749 mp_ps_name_out(mp, mp->font_name[f],true);
3750 mp_ps_name_out(mp, mp->font_name[f],true);
3751 mp_ps_print(mp, " def");
3756 mp_print_nl(mp, "%%EndSetup");
3757 mp_print_nl(mp, "%%Page: 1 1");
3759 mp_xfree(cur_fsize);
3763 font_number mp_print_font_comments (MP mp , int prologues, int null, pointer h);
3768 font_number mp_print_font_comments (MP mp , int prologues, int null, pointer h) {
3769 quarterword next_size; /* the size index for fonts being listed */
3770 pointer *cur_fsize; /* current positions in |font_sizes| */
3771 int ff; /* a loop counter */
3772 boolean done_fonts; /* have we finished listing the fonts in the header? */
3773 font_number f; /* a font number for loops */
3774 scaled ds; /* design size and scale factor for a text node */
3775 font_number ldf=0; /* the last \.{DocumentFont} listed (otherwise |null_font|) */
3776 cur_fsize = mp_xmalloc((mp->font_max+1),sizeof(pointer));
3777 if ( prologues>0 ) {
3778 @<Give a \.{DocumentFonts} comment listing all fonts with non-null
3779 |font_sizes| and eliminate duplicates@>;
3782 @<Make |cur_fsize| a copy of the |font_sizes| array@>;
3783 do { done_fonts=true;
3784 for (f=null_font+1;f<=mp->last_fnum;f++) {
3785 if ( cur_fsize[f]!=null ) {
3786 @<Print the \.{\%*Font} comment for font |f| and advance |cur_fsize[f]|@>;
3788 if ( cur_fsize[f]!=null ) { mp_unmark_font(mp, f); done_fonts=false; };
3790 if ( ! done_fonts ) {
3791 @<Increment |next_size| and apply |mark_string_chars| to all text nodes with
3794 } while (! done_fonts);
3796 mp_xfree(cur_fsize);
3800 @ @<Make |cur_fsize| a copy of the |font_sizes| array@>=
3801 for (f=null_font+1;f<= mp->last_fnum;f++)
3802 cur_fsize[f]=mp->font_sizes[f]
3804 @ It's not a good idea to make any assumptions about the |font_ps_name| entries,
3805 so we carefully remove duplicates. There is no harm in using a slow, brute-force
3808 @<Give a \.{DocumentFonts} comment listing all fonts with non-null...@>=
3811 for (f=null_font+1;f<= mp->last_fnum;f++) {
3812 if ( mp->font_sizes[f]!=null ) {
3813 if ( ldf==null_font )
3814 mp_print_nl(mp, "%%DocumentFonts:");
3815 for (ff=ldf;ff>=null_font;ff--) {
3816 if ( mp->font_sizes[ff]!=null )
3817 if ( mp_xstrcmp(mp->font_ps_name[f],mp->font_ps_name[ff])==0 )
3820 if ( mp->ps_offset+1+strlen(mp->font_ps_name[f])>(unsigned)mp->max_print_line )
3821 mp_print_nl(mp, "%%+");
3822 mp_print_char(mp, ' ');
3823 mp_print(mp, mp->font_ps_name[f]);
3832 void mp_hex_digit_out (MP mp,small_number d) {
3833 if ( d<10 ) mp_print_char(mp, d+'0');
3834 else mp_print_char(mp, d+'a'-10);
3837 @ We output the marks as a hexadecimal bit string starting at |c| or
3838 |font_bc[f]|, whichever is greater. If the output has to be truncated
3839 to avoid exceeding |emergency_line_length| the return value says where to
3840 start scanning next time.
3843 halfword mp_ps_marks_out (MP mp,font_number f, eight_bits c);
3846 @d emergency_line_length 255
3847 /* \ps\ output lines can be this long in unusual circumstances */
3850 halfword mp_ps_marks_out (MP mp,font_number f, eight_bits c) {
3851 eight_bits bc,ec; /* only encode characters between these bounds */
3852 integer lim; /* the maximum number of marks to encode before truncating */
3853 int p; /* |font_info| index for the current character */
3854 int d,b; /* used to construct a hexadecimal digit */
3855 lim=4*(emergency_line_length-mp->ps_offset-4);
3859 @<Restrict the range |bc..ec| so that it contains no unused characters
3860 at either end and has length at most |lim|@>;
3861 @<Print the initial label indicating that the bitmap starts at |bc|@>;
3862 @<Print a hexadecimal encoding of the marks for characters |bc..ec|@>;
3863 while ( (ec<mp->font_ec[f])&&(mp->font_info[p].qqqq.b3==unused) ) {
3869 @ We could save time by setting the return value before the loop that
3870 decrements |ec|, but there is no point in being so tricky.
3872 @<Restrict the range |bc..ec| so that it contains no unused characters...@>=
3873 p=mp->char_base[f]+bc;
3874 while ( (mp->font_info[p].qqqq.b3==unused)&&(bc<ec) ) {
3877 if ( ec>=bc+lim ) ec=bc+lim-1;
3878 p=mp->char_base[f]+ec;
3879 while ( (mp->font_info[p].qqqq.b3==unused)&&(bc<ec) ) {
3883 @ @<Print the initial label indicating that the bitmap starts at |bc|@>=
3884 mp_print_char(mp, ' ');
3885 mp_hex_digit_out(mp, bc / 16);
3886 mp_hex_digit_out(mp, bc % 16);
3887 mp_print_char(mp, ':')
3891 @<Print a hexadecimal encoding of the marks for characters |bc..ec|@>=
3893 for (p=mp->char_base[f]+bc;p<=mp->char_base[f]+ec;p++) {
3895 mp_hex_digit_out(mp, d);
3898 if ( mp->font_info[p].qqqq.b3!=unused ) d=d+b;
3901 mp_hex_digit_out(mp, d)
3904 @ Here is a simple function that determines whether there are any marked
3905 characters in font~|f| with character code at least~|c|.
3908 boolean mp_check_ps_marks (MP mp,font_number f, integer c) ;
3911 boolean mp_check_ps_marks (MP mp,font_number f, integer c) {
3912 int p; /* |font_info| index for the current character */
3913 for (p=mp->char_base[f]+c;p<=mp->char_base[f]+mp->font_ec[f];p++) {
3914 if ( mp->font_info[p].qqqq.b3==used )
3921 @ If the file name is so long that it can't be printed without exceeding
3922 |emergency_line_length| then there will be missing items in the \.{\%*Font:}
3923 line. We might have to repeat line in order to get the character usage
3924 information to fit within |emergency_line_length|.
3926 TODO: these two defines are also defined in mp.w!
3928 @d link(A) mp->mem[(A)].hh.rh /* the |link| field of a memory word */
3929 @d sc_factor(A) mp->mem[(A)+1].cint /* the scale factor stored in a font size node */
3931 @<Print the \.{\%*Font} comment for font |f| and advance |cur_fsize[f]|@>=
3933 while ( mp_check_ps_marks(mp, f,t) ) {
3934 mp_print_nl(mp, "%*Font: ");
3935 if ( mp->ps_offset+strlen(mp->font_name[f])+12>emergency_line_length )
3937 mp_print(mp, mp->font_name[f]);
3938 mp_print_char(mp, ' ');
3939 ds=(mp->font_dsize[f] + 8) / 16;
3940 mp_print_scaled(mp, mp_take_scaled(mp, ds,sc_factor(cur_fsize[f])));
3941 if ( mp->ps_offset+12>emergency_line_length ) break;
3942 mp_print_char(mp, ' ');
3943 mp_print_scaled(mp, ds);
3944 if ( mp->ps_offset+5>emergency_line_length ) break;
3945 t=mp_ps_marks_out(mp, f,t);
3947 cur_fsize[f]=link(cur_fsize[f]);
3950 @ @<Print the procset@>=
3952 mp_print_nl(mp, "/hlw{0 dtransform exch truncate exch idtransform pop setlinewidth}bd");
3953 mp_print_nl(mp, "/vlw{0 exch dtransform truncate idtransform setlinewidth pop}bd");
3954 mp_print_nl(mp, "/l{lineto}bd/r{rlineto}bd/c{curveto}bd/m{moveto}bd"
3955 "/p{closepath}bd/n{newpath}bd");
3956 mp_print_nl(mp, "/C{setcmykcolor}bd/G{setgray}bd/R{setrgbcolor}bd"
3957 "/lj{setlinejoin}bd/ml{setmiterlimit}bd");
3958 mp_print_nl(mp, "/lc{setlinecap}bd/S{stroke}bd/F{fill}bd/q{gsave}bd"
3959 "/Q{grestore}bd/s{scale}bd/t{concat}bd");
3960 mp_print_nl(mp, "/sd{setdash}bd/rd{[] 0 setdash}bd/P{showpage}bd/B{q F Q}bd/W{clip}bd");
3964 @ The prologue defines \.{fshow} and corrects for the fact that \.{fshow}
3965 arguments use |font_name| instead of |font_ps_name|. Downloaded bitmap fonts
3966 might not have reasonable |font_ps_name| entries, but we just charge ahead
3967 anyway. The user should not make \&{prologues} positive if this will cause
3969 @:prologues_}{\&{prologues} primitive@>
3972 void mp_print_prologue (MP mp, int prologues, int procset, int ldf);
3975 void mp_print_prologue (MP mp, int prologues, int procset, int ldf) {
3977 mp_print(mp, "%%BeginProlog"); mp_print_ln(mp);
3978 if ( (prologues>0)||(procset>0) ) {
3979 if ( ldf!=null_font ) {
3980 if ( prologues>0 ) {
3981 for (f=null_font+1;f<=mp->last_fnum;f++) {
3982 if ( mp_has_font_size(mp,f) ) {
3983 mp_ps_name_out(mp, mp->font_name[f],true);
3984 mp_ps_name_out(mp, mp->font_ps_name[f],true);
3985 mp_ps_print(mp, " def");
3990 mp_print(mp, "/fshow {exch findfont exch scalefont setfont show}bind def");
3996 mp_print_nl(mp, "%%BeginResource: procset mpost");
3997 if ( (prologues>0)&&(ldf!=null_font) )
3999 "/bd{bind def}bind def/fshow {exch findfont exch scalefont setfont show}bd");
4001 mp_print_nl(mp, "/bd{bind def}bind def");
4002 @<Print the procset@>;
4003 mp_print_nl(mp, "%%EndResource");
4007 mp_print(mp, "%%EndProlog");