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 */
63 @<Static variables in the outer block@>;
67 /* this is a trick that makes sure that frontends do not need avl.h */
68 # ifndef LIBAVL_ALLOCATOR
69 # define LIBAVL_ALLOCATOR
70 struct libavl_allocator {
71 void *(*libavl_malloc) (struct libavl_allocator *, size_t libavl_size);
72 void (*libavl_free) (struct libavl_allocator *, void *libavl_block);
75 typedef struct psout_data_struct {
78 typedef struct psout_data_struct * psout_data;
81 @<Exported function headers@>
83 @ @<Exported function headers@>=
84 void mp_backend_initialize (MP mp) ;
85 void mp_backend_free (MP mp) ;
88 @c void mp_backend_initialize (MP mp) {
89 mp->ps = mp_xmalloc(1,sizeof(psout_data_struct));
90 @<Set initial values@>;
92 void mp_backend_free (MP mp) {
93 @<Dealloc variables@>;
102 @* Traditional {psfonts.map} loading.
104 TODO: It is likely that this code can be removed after a few minor tweaks.
106 @ The file |ps_tab_file| gives a table of \TeX\ font names and corresponding
107 PostScript names for fonts that do not have to be downloaded, i.e., fonts that
108 can be used when |internal[prologues]>0|. Each line consists of a \TeX\ name,
109 one or more spaces, a PostScript name, and possibly a space and some other junk.
110 This routine reads the table, updates |font_ps_name| entries starting after
111 |last_ps_fnum|, and sets |last_ps_fnum:=last_fnum|. If the file |ps_tab_file|
112 is missing, we assume that the existing font names are OK and nothing needs to
115 @d ps_tab_name "psfonts.map" /* locates font name translation table */
118 void mp_read_psname_table (MP mp) ;
120 @ @c void mp_read_psname_table (MP mp) {
121 font_number k; /* font for possible name match */
122 unsigned int lmax; /* upper limit on length of name to match */
123 unsigned int j; /* characters left to read before string gets too long */
124 char *s; /* possible font name to match */
125 text_char c=0; /* character being read from |ps_tab_file| */
126 if ( (mp->ps->ps_tab_file = mp_open_file(mp, ps_tab_name, "r", mp_filetype_fontmap)) ) {
127 @<Set |lmax| to the maximum |font_name| length for fonts
128 |last_ps_fnum+1| through |last_fnum|@>;
129 while (! feof(mp->ps->ps_tab_file) ) {
130 @<Read at most |lmax| characters from |ps_tab_file| into string |s|
131 but |goto common_ending| if there is trouble@>;
132 for (k=mp->last_ps_fnum+1;k<=mp->last_fnum;k++) {
133 if ( mp_xstrcmp(s,mp->font_name[k])==0 ) {
134 @<|flush_string(s)|, read in |font_ps_name[k]|, and
135 |goto common_ending|@>;
140 c = fgetc(mp->ps->ps_tab_file);
142 c = fgetc(mp->ps->ps_tab_file);
144 ungetc(c,mp->ps->ps_tab_file);
147 mp->last_ps_fnum=mp->last_fnum;
148 fclose(mp->ps->ps_tab_file);
153 FILE * ps_tab_file; /* file for font name translation table */
155 @ @<Set |lmax| to the maximum |font_name| length for fonts...@>=
157 for (k=mp->last_ps_fnum+1;k<=mp->last_fnum;k++) {
158 if (strlen(mp->font_name[k])>lmax )
159 lmax=strlen(mp->font_name[k]);
162 @ If we encounter the end of line before we have started reading
163 characters from |ps_tab_file|, we have found an entirely blank
164 line and we skip over it. Otherwise, we abort if the line ends
165 prematurely. If we encounter a comment character, we also skip
166 over the line, since recent versions of \.{dvips} allow comments
167 in the font map file.
169 TODO: this is probably not safe in the case of a really
170 broken font map file.
172 @<Read at most |lmax| characters from |ps_tab_file| into string |s|...@>=
173 s=mp_xmalloc(lmax+1,1);
176 if (c == '\n' || c == '\r' ) {
178 mp_xfree(s); s=NULL; goto COMMON_ENDING;
180 mp_fatal_error(mp, "The psfont map file is bad!");
183 c = fgetc(mp->ps->ps_tab_file);
184 if (c=='%' || c=='*' || c==';' || c=='#' ) {
185 mp_xfree(s); s=NULL; goto COMMON_ENDING;
187 if (c==' ' || c=='\t') break;
189 s[j++] = mp->xord[c];
191 mp_xfree(s); s=NULL; goto COMMON_ENDING;
196 @ PostScript font names should be at most 28 characters long but we allow 32
199 @<|flush_string(s)|, read in |font_ps_name[k]|, and...@>=
204 if (c=='\n' || c == '\r')
205 mp_fatal_error(mp, "The psfont map file is bad!");
206 c = fgetc(mp->ps->ps_tab_file);
207 } while (c==' ' || c=='\t');
208 ps_name = mp_xmalloc(33,1);
212 mp_fatal_error(mp, "The psfont map file is bad!");
214 ps_name[j++] = mp->xord[c];
215 if (c=='\n' || c == '\r')
218 c = fgetc(mp->ps->ps_tab_file);
219 } while (c != ' ' && c != '\t');
221 mp_xfree(mp->font_ps_name[k]);
222 mp->font_ps_name[k]=ps_name;
228 @* \[44a] Dealing with font encodings.
230 First, here are a few helpers for parsing files
232 @d check_buf(size, buf_size)
233 if ((unsigned)(size) > (unsigned)(buf_size)) {
235 snprintf(s,128,"buffer overflow: (%d,%d) at file %s, line %d",
236 size,buf_size, __FILE__, __LINE__ );
237 mp_fatal_error(mp,s);
240 @d append_char_to_buf(c, p, buf, buf_size) do {
243 if (c == 13 || c == EOF)
245 if (c != ' ' || (p > buf && p[-1] != 32)) {
246 check_buf(p - buf + 1, (buf_size));
251 @d append_eol(p, buf, buf_size) do {
252 check_buf(p - buf + 2, (buf_size));
253 if (p - buf > 1 && p[-1] != 10)
255 if (p - buf > 2 && p[-2] == 32) {
262 @d remove_eol(p, buf) do {
268 @d skip(p, c) if (*p == c) p++
269 @d strend(s) strchr(s, 0)
270 @d str_prefix(s1, s2) (strncmp((s1), (s2), strlen(s2)) == 0)
275 boolean loaded; /* the encoding has been loaded? */
276 char *file_name; /* encoding file name */
277 char *enc_name; /* encoding true name */
278 integer objnum; /* object number */
280 integer tounicode; /* object number of associated ToUnicode entry */
290 #define ENC_BUF_SIZE 0x1000
291 char enc_line[ENC_BUF_SIZE];
295 @d enc_getchar() getc(mp->ps->enc_file)
296 @d enc_eof() feof(mp->ps->enc_file)
297 @d enc_close() fclose(mp->ps->enc_file)
300 boolean mp_enc_open (MP mp, char *n) {
301 mp->ps->enc_file=mp_open_file(mp, n, "rb", mp_filetype_encoding);
302 if (mp->ps->enc_file!=NULL)
307 void mp_enc_getline (MP mp) {
312 print_err("unexpected end of file");
315 p = mp->ps->enc_line;
318 append_char_to_buf (c, p, mp->ps->enc_line, ENC_BUF_SIZE);
320 append_eol (p, mp->ps->enc_line, ENC_BUF_SIZE);
321 if (p - mp->ps->enc_line < 2 || *mp->ps->enc_line == '%')
324 void mp_load_enc (MP mp, char *enc_name,
325 char **enc_encname, char **glyph_names){
326 char buf[ENC_BUF_SIZE], *p, *r;
329 int save_selector = mp->selector;
330 if (!mp_enc_open (mp,enc_name)) {
331 mp_print (mp,"cannot open encoding file for reading");
334 mp_normalize_selector(mp);
336 mp_print (mp, enc_name);
338 if (*mp->ps->enc_line != '/' || (r = strchr (mp->ps->enc_line, '[')) == NULL) {
339 remove_eol (r, mp->ps->enc_line);
340 print_err ("invalid encoding vector (a name or `[' missing): `");
341 mp_print(mp,mp->ps->enc_line);
345 while (*(r-1)==' ') r--; /* strip trailing spaces from encoding name */
346 myname = mp_xmalloc(r-mp->ps->enc_line,1);
347 memcpy(myname,mp->ps->enc_line+1,(r-mp->ps->enc_line)-1);
348 *(myname+(r-mp->ps->enc_line-1))=0;
349 *enc_encname = myname;
357 *r != ' ' && *r != 10 && *r != ']' && *r != '/'; *p++ = *r++);
360 if (names_count > 256) {
361 print_err ("encoding vector contains more than 256 names");
364 if (mp_xstrcmp (buf, notdef) != 0)
365 glyph_names[names_count] = mp_xstrdup (buf);
368 if (*r != 10 && *r != '%') {
369 if (str_prefix (r, "] def"))
372 remove_eol (r, mp->ps->enc_line);
374 ("invalid encoding vector: a name or `] def' expected: `");
375 mp_print(mp,mp->ps->enc_line);
381 r = mp->ps->enc_line;
386 mp->selector = save_selector;
388 void mp_read_enc (MP mp, enc_entry * e) {
392 mp_load_enc (mp,e->file_name, &e->enc_name, e->glyph_names);
396 @ |write_enc| is used to write either external encoding (given in map file) or
397 internal encoding (read from the font file); when |glyph_names| is NULL
398 the 2nd argument is a pointer to the encoding entry; otherwise the 3rd is
399 the object number of the Encoding object
402 void mp_write_enc (MP mp, char **glyph_names, enc_entry * e) {
407 if (glyph_names == NULL) {
408 if (e->objnum != 0) /* the encoding has been written already */
416 mp_print(mp,"\n%%%%BeginResource: encoding ");
417 mp_print(mp, e->enc_name);
419 mp_print(mp, e->enc_name);
421 foffset = strlen(e->file_name)+3;
422 for (i = 0; i < 256; i++) {
424 if (s+1+foffset>=80) {
429 mp_print_char(mp,'/');
431 mp_print_char(mp,' ');
435 mp_print_nl (mp,"] def\n");
436 mp_print(mp,"%%%%EndResource");
440 @ All encoding entries go into AVL tree for fast search by name.
443 struct avl_table *enc_tree;
445 @ Memory management functions for avl
447 @<Static variables in the outer block@>=
448 static const char notdef[] = ".notdef";
451 static void *avl_xmalloc (struct libavl_allocator *allocator, size_t size);
452 static void avl_xfree (struct libavl_allocator *allocator, void *block);
455 static void *avl_xmalloc (struct libavl_allocator *allocator, size_t size) {
457 return mp_xmalloc (size,1);
459 static void avl_xfree (struct libavl_allocator *allocator, void *block) {
465 struct libavl_allocator avl_xallocator;
467 @ @<Set initial...@>=
468 mp->ps->avl_xallocator.libavl_malloc=avl_xmalloc;
469 mp->ps->avl_xallocator.libavl_free= avl_xfree;
470 mp->ps->enc_tree = NULL;
473 static int comp_enc_entry (const void *pa, const void *pb, void *p) {
475 return strcmp (((const enc_entry *) pa)->file_name,
476 ((const enc_entry *) pb)->file_name);
478 enc_entry * mp_add_enc (MP mp, char *s) {
482 if (mp->ps->enc_tree == NULL) {
483 mp->ps->enc_tree = avl_create (comp_enc_entry, NULL, &mp->ps->avl_xallocator);
486 p = (enc_entry *) avl_find (mp->ps->enc_tree, &tmp);
487 if (p != NULL) /* encoding already registered */
489 p = mp_xmalloc (1,sizeof (enc_entry));
491 p->file_name = mp_xstrdup (s);
494 p->glyph_names = mp_xmalloc (256,sizeof (char *));
495 for (i = 0; i < 256; i++)
496 p->glyph_names[i] = (char *) notdef;
497 aa = avl_probe (mp->ps->enc_tree, p);
504 static void mp_destroy_enc_entry (void *pa, void *pb) {
508 p = (enc_entry *) pa;
510 mp_xfree (p->file_name);
511 if (p->glyph_names != NULL)
512 for (i = 0; i < 256; i++)
513 if (p->glyph_names[i] != notdef)
514 mp_xfree (p->glyph_names[i]);
515 mp_xfree (p->glyph_names);
520 static void enc_free (MP mp);
522 @ @c static void enc_free (MP mp) {
523 if (mp->ps->enc_tree != NULL)
524 avl_destroy (mp->ps->enc_tree, mp_destroy_enc_entry);
527 @ @<Exported function headers@>=
528 void mp_load_encodings (MP mp, int lastfnum) ;
529 void mp_font_encodings (MP mp, int lastfnum, int encodings_only) ;
531 @ @c void mp_load_encodings (MP mp, int lastfnum) {
535 for (f=null_font+1;f<=lastfnum;f++) {
536 if (mp_has_font_size(mp,f) && mp_has_fm_entry (mp,f,&fm_cur)) {
537 if (fm_cur != NULL &&
538 fm_cur->ps_name != NULL &&
539 is_reencoded (fm_cur)) {
540 e = fm_cur->encoding;
546 void mp_font_encodings (MP mp, int lastfnum, int encodings_only) {
550 for (f=null_font+1;f<=lastfnum;f++) {
551 if (mp_has_font_size(mp,f) && mp_has_fm_entry (mp,f, &fm)) {
552 if (fm != NULL && (fm->ps_name != NULL)) {
553 if (is_reencoded (fm)) {
554 if (encodings_only || (!is_subsetted (fm))) {
556 mp_write_enc (mp,NULL, e);
557 /* clear for next run */
566 @* \[44b] Parsing font map files.
574 @d fm_close() fclose(mp->ps->fm_file)
575 @d fm_getchar() fgetc(mp->ps->fm_file)
576 @d fm_eof() feof(mp->ps->fm_file)
579 enum _mode { FM_DUPIGNORE, FM_REPLACE, FM_DELETE };
580 enum _ltype { MAPFILE, MAPLINE };
581 enum _tfmavail { TFM_UNCHECKED, TFM_FOUND, TFM_NOTFOUND };
582 typedef struct mitem {
583 int mode; /* |FM_DUPIGNORE| or |FM_REPLACE| or |FM_DELETE| */
584 int type; /* map file or map line */
585 char *map_line; /* pointer to map file name or map line */
586 int lineno; /* line number in map file */
592 fm_entry *loaded_tfm_found;
593 fm_entry *avail_tfm_found;
594 fm_entry *non_tfm_found;
595 fm_entry *not_avail_tfm_found;
597 @ @<Set initial...@>=
598 mp->ps->mitem = NULL;
601 static const char nontfm[] = "<nontfm>";
604 @d read_field(r, q, buf) do {
606 while (*r != ' ' && *r != '\0')
614 fm->F = mp_xstrdup(buf);
626 static fm_entry *new_fm_entry (void) {
628 fm = mp_xmalloc (1,sizeof(fm_entry));
633 fm->subset_tag = NULL;
635 fm->tfm_num = null_font;
636 fm->tfm_avail = TFM_UNCHECKED;
644 fm->all_glyphs = false;
651 static void delete_fm_entry (fm_entry * fm) {
652 mp_xfree (fm->tfm_name);
653 mp_xfree (fm->ps_name);
654 mp_xfree (fm->ff_name);
655 mp_xfree (fm->subset_tag);
656 mp_xfree (fm->charset);
660 static ff_entry *new_ff_entry (void) {
662 ff = mp_xmalloc (1,sizeof(ff_entry));
668 static void delete_ff_entry (ff_entry * ff) {
669 mp_xfree (ff->ff_name);
670 mp_xfree (ff->ff_path);
674 static char *mk_base_tfm (MP mp, char *tfmname, int *i) {
675 static char buf[SMALL_BUF_SIZE];
676 char *p = tfmname, *r = strend (p) - 1, *q = r;
677 while (q > p && isdigit (*q))
679 if (!(q > p) || q == r || (*q != '+' && *q != '-'))
681 check_buf (q - p + 1, SMALL_BUF_SIZE);
682 strncpy (buf, p, (size_t) (q - p));
688 @ @<Exported function headers@>=
689 boolean mp_has_fm_entry (MP mp,font_number f, fm_entry **fm);
692 boolean mp_has_fm_entry (MP mp,font_number f, fm_entry **fm) {
693 fm_entry *res = NULL;
694 res = mp_fm_lookup (mp, f);
698 return (res != NULL);
702 struct avl_table *tfm_tree;
703 struct avl_table *ps_tree;
704 struct avl_table *ff_tree;
706 @ @<Set initial...@>=
707 mp->ps->tfm_tree = NULL;
708 mp->ps->ps_tree = NULL;
709 mp->ps->ff_tree = NULL;
711 @ AVL sort |fm_entry| into |tfm_tree| by |tfm_name |
714 static int comp_fm_entry_tfm (const void *pa, const void *pb, void *p) {
716 return strcmp (((const fm_entry *) pa)->tfm_name,
717 ((const fm_entry *) pb)->tfm_name);
720 @ AVL sort |fm_entry| into |ps_tree| by |ps_name|, |slant|, and |extend|
722 @c static int comp_fm_entry_ps (const void *pa, const void *pb, void *p) {
724 const fm_entry *p1 = (const fm_entry *) pa, *p2 = (const fm_entry *) pb;
726 assert (p1->ps_name != NULL && p2->ps_name != NULL);
727 if ((i = strcmp (p1->ps_name, p2->ps_name)))
729 cmp_return (p1->slant, p2->slant);
730 cmp_return (p1->extend, p2->extend);
731 if (p1->tfm_name != NULL && p2->tfm_name != NULL &&
732 (i = strcmp (p1->tfm_name, p2->tfm_name)))
737 @ AVL sort |ff_entry| into |ff_tree| by |ff_name|
739 @c static int comp_ff_entry (const void *pa, const void *pb, void *p) {
741 return strcmp (((const ff_entry *) pa)->ff_name,
742 ((const ff_entry *) pb)->ff_name);
745 @ @c static void create_avl_trees (MP mp) {
746 if (mp->ps->tfm_tree == NULL) {
747 mp->ps->tfm_tree = avl_create (comp_fm_entry_tfm, NULL, &mp->ps->avl_xallocator);
748 assert (mp->ps->tfm_tree != NULL);
750 if (mp->ps->ps_tree == NULL) {
751 mp->ps->ps_tree = avl_create (comp_fm_entry_ps, NULL, &mp->ps->avl_xallocator);
752 assert (mp->ps->ps_tree != NULL);
754 if (mp->ps->ff_tree == NULL) {
755 mp->ps->ff_tree = avl_create (comp_ff_entry, NULL, &mp->ps->avl_xallocator);
756 assert (mp->ps->ff_tree != NULL);
760 @ The function |avl_do_entry| is not completely symmetrical with regards
761 to |tfm_name| and |ps_name handling|, e. g. a duplicate |tfm_name| gives a
762 |goto exit|, and no |ps_name| link is tried. This is to keep it compatible
763 with the original version.
767 @d set_tfmlink(fm) ((fm)->links |= LINK_TFM)
768 @d set_pslink(fm) ((fm)->links |= LINK_PS)
769 @d unset_tfmlink(fm) ((fm)->links &= ~LINK_TFM)
770 @d unset_pslink(fm) ((fm)->links &= ~LINK_PS)
771 @d has_tfmlink(fm) ((fm)->links & LINK_TFM)
772 @d has_pslink(fm) ((fm)->links & LINK_PS)
775 static int avl_do_entry (MP mp, fm_entry * fp, int mode) {
781 /* handle |tfm_name| link */
783 if (strcmp (fp->tfm_name, nontfm)) {
784 p = (fm_entry *) avl_find (mp->ps->tfm_tree, fp);
786 if (mode == FM_DUPIGNORE) {
787 snprintf(s,128,"fontmap entry for `%s' already exists, duplicates ignored",
791 } else { /* mode == |FM_REPLACE| / |FM_DELETE| */
792 if (mp_has_font_size(mp,p->tfm_num)) {
794 "fontmap entry for `%s' has been used, replace/delete not allowed",
799 a = avl_delete (mp->ps->tfm_tree, p);
806 if (mode != FM_DELETE) {
807 aa = avl_probe (mp->ps->tfm_tree, fp);
813 /* handle |ps_name| link */
815 if (fp->ps_name != NULL) {
816 assert (fp->tfm_name != NULL);
817 p = (fm_entry *) avl_find (mp->ps->ps_tree, fp);
819 if (mode == FM_DUPIGNORE) {
821 "ps_name entry for `%s' already exists, duplicates ignored",
825 } else { /* mode == |FM_REPLACE| / |FM_DELETE| */
826 if (mp_has_font_size(mp,p->tfm_num)) {
827 /* REPLACE/DELETE not allowed */
829 "fontmap entry for `%s' has been used, replace/delete not allowed",
834 a = avl_delete (mp->ps->ps_tree, p);
837 if (!has_tfmlink (p))
841 if (mode != FM_DELETE) {
842 aa = avl_probe (mp->ps->ps_tree, fp);
848 if (!has_tfmlink (fp) && !has_pslink (fp)) /* e. g. after |FM_DELETE| */
849 return 1; /* deallocation of |fm_entry| structure required */
854 @ consistency check for map entry, with warn flag
857 static int check_fm_entry (MP mp, fm_entry * fm, boolean warn) {
861 if (fm->ps_name != NULL) {
862 if (is_basefont (fm)) {
863 if (is_fontfile (fm) && !is_included (fm)) {
865 snprintf(s,128, "invalid entry for `%s': "
866 "font file must be included or omitted for base fonts",
872 } else { /* not a base font */
873 /* if no font file given, drop this entry */
874 /* |if (!is_fontfile (fm)) {
877 "invalid entry for `%s': font file missing",
886 if (is_truetype (fm) && is_reencoded (fm) && !is_subsetted (fm)) {
889 "invalid entry for `%s': only subsetted TrueType font can be reencoded",
895 if ((fm->slant != 0 || fm->extend != 0) &&
896 (is_truetype (fm))) {
899 "invalid entry for `%s': "
900 "SlantFont/ExtendFont can be used only with embedded T1 fonts",
906 if (abs (fm->slant) > 1000) {
909 "invalid entry for `%s': too big value of SlantFont (%g)",
910 fm->tfm_name, fm->slant / 1000.0);
915 if (abs (fm->extend) > 2000) {
918 "invalid entry for `%s': too big value of ExtendFont (%g)",
919 fm->tfm_name, fm->extend / 1000.0);
925 !(is_truetype (fm) && is_included (fm) &&
926 is_subsetted (fm) && !is_reencoded (fm))) {
929 "invalid entry for `%s': "
930 "PidEid can be used only with subsetted non-reencoded TrueType fonts",
939 @ returns true if s is one of the 14 std. font names; speed-trimmed.
941 @c static boolean check_basefont (char *s) {
942 static const char *basefont_names[] = {
944 "Courier-Bold", /* 1:12 */
945 "Courier-Oblique", /* 2:15 */
946 "Courier-BoldOblique", /* 3:19 */
947 "Helvetica", /* 4:9 */
948 "Helvetica-Bold", /* 5:14 */
949 "Helvetica-Oblique", /* 6:17 */
950 "Helvetica-BoldOblique", /* 7:21 */
952 "Times-Roman", /* 9:11 */
953 "Times-Bold", /* 10:10 */
954 "Times-Italic", /* 11:12 */
955 "Times-BoldItalic", /* 12:16 */
956 "ZapfDingbats" /* 13:12 */
958 static const int Index[] =
959 { -1, -1, -1, -1, -1, -1, 8, 0, -1, 4, 10, 9, -1, -1, 5, 2, 12, 6,
962 const size_t n = strlen (s);
966 if (n == 12) { /* three names have length 12 */
969 k = 1; /* Courier-Bold */
972 k = 11; /* Times-Italic */
975 k = 13; /* ZapfDingbats */
982 if (k > -1 && !strcmp (basefont_names[k], s))
988 @d is_cfg_comment(c) (c == 10 || c == '*' || c == '#' || c == ';' || c == '%')
990 @c static void fm_scan_line (MP mp) {
991 int a, b, c, j, u = 0, v = 0;
994 char fm_line[FM_BUF_SIZE], buf[FM_BUF_SIZE];
997 switch (mp->ps->mitem->type) {
1002 append_char_to_buf (c, p, fm_line, FM_BUF_SIZE);
1009 r = mp->ps->mitem->map_line;
1014 if (*r == '\0' || is_cfg_comment (*r))
1016 fm = new_fm_entry ();
1017 read_field (r, q, buf);
1018 set_field (tfm_name);
1020 read_field (r, q, buf);
1021 if (*buf != '<' && *buf != '"')
1022 set_field (ps_name);
1024 r = p; /* unget the field */
1025 if (isdigit (*r)) { /* font flags given */
1026 fm->flags = atoi (r);
1027 while (isdigit (*r))
1030 while (1) { /* loop through "specials", encoding, font file */
1035 case '"': /* opening quote */
1040 if (sscanf (r, "%f %n", &d, &j) > 0) {
1041 s = r + j; /* jump behind number, eat also blanks, if any */
1042 if (*(s - 1) == 'E' || *(s - 1) == 'e')
1043 s--; /* e. g. 0.5ExtendFont: \%f = 0.5E */
1044 if (str_prefix (s, "SlantFont")) {
1045 d *= 1000.0; /* correct rounding also for neg. numbers */
1046 fm->slant = (integer) (d > 0 ? d + 0.5 : d - 0.5);
1047 r = s + strlen ("SlantFont");
1048 } else if (str_prefix (s, "ExtendFont")) {
1050 fm->extend = (integer) (d > 0 ? d + 0.5 : d - 0.5);
1051 if (fm->extend == 1000)
1053 r = s + strlen ("ExtendFont");
1054 } else { /* unknown name */
1056 *r != ' ' && *r != '"' && *r != '\0';
1057 r++); /* jump over name */
1058 c = *r; /* remember char for temporary end of string */
1060 snprintf(warn_s,128,
1061 "invalid entry for `%s': unknown name `%s' ignored",
1067 for (; *r != ' ' && *r != '"' && *r != '\0'; r++);
1070 if (*r == '"') /* closing quote */
1073 snprintf(warn_s,128,
1074 "invalid entry for `%s': closing quote missing",
1080 case 'P': /* handle cases for subfonts like 'PidEid=3,1' */
1081 if (sscanf (r, "PidEid=%i, %i %n", &a, &b, &c) >= 2) {
1087 default: /* encoding or font file specification */
1091 if (*r == '<' || *r == '[')
1094 read_field (r, q, buf);
1095 /* encoding, formats: '8r.enc' or '<8r.enc' or '<[8r.enc' */
1096 if (strlen (buf) > 4 && strcasecmp (strend (buf) - 4, ".enc") == 0) {
1097 fm->encoding = mp_add_enc (mp, buf);
1098 u = v = 0; /* u, v used if intervening blank: "<< foo" */
1099 } else if (strlen (buf) > 0) { /* file name given */
1100 /* font file, formats:
1101 * subsetting: '<cmr10.pfa'
1102 * no subsetting: '<<cmr10.pfa'
1103 * no embedding: 'cmr10.pfa'
1105 if (a == '<' || u == '<') {
1107 if ((a == '<' && b == 0) || (a == 0 && v == 0))
1109 /* otherwise b == '<' (or '[') => no subsetting */
1111 set_field (ff_name);
1120 if (fm->ps_name != NULL && check_basefont (fm->ps_name))
1122 if (is_fontfile (fm)
1123 && strcasecmp (strend (fm_fontfile (fm)) - 4, ".ttf") == 0)
1125 if (check_fm_entry (mp,fm, true) != 0)
1128 Until here the map line has been completely scanned without errors;
1129 fm points to a valid, freshly filled-out |fm_entry| structure.
1130 Now follows the actual work of registering/deleting.
1132 if (avl_do_entry (mp, fm, mp->ps->mitem->mode) == 0) /* if success */
1135 delete_fm_entry (fm);
1139 @c static void fm_read_info (MP mp) {
1142 if (mp->ps->tfm_tree == NULL)
1143 create_avl_trees (mp);
1144 if (mp->ps->mitem->map_line == NULL) /* nothing to do */
1146 mp->ps->mitem->lineno = 1;
1147 switch (mp->ps->mitem->type) {
1149 n = mp->ps->mitem->map_line;
1150 mp->ps->fm_file = mp_open_file(mp, n, "r", mp_filetype_fontmap);
1151 if (!mp->ps->fm_file) {
1152 snprintf(s,256,"cannot open font map file %s",n);
1155 int save_selector = mp->selector;
1156 mp_normalize_selector(mp);
1159 while (!fm_eof ()) {
1161 mp->ps->mitem->lineno++;
1165 mp->selector = save_selector;
1166 mp->ps->fm_file = NULL;
1175 mp->ps->mitem->map_line = NULL; /* done with this line */
1180 scaled mp_round_xn_over_d (MP mp, scaled x, integer n, integer d) {
1181 boolean positive; /* was |x>=0|? */
1182 unsigned int t,u; /* intermediate quantities */
1183 integer v; /* intermediate quantities */
1187 negate(x); positive=false;
1190 u=(x / 0100000)*n+(t / 0100000);
1191 v=(u % d)*0100000 + (t % 0100000);
1192 if ( u / d>=0100000 ) mp->arith_error=true;
1193 else u=0100000*(u / d) + (v / d);
1197 return ( positive ? u : -u );
1199 static fm_entry *mk_ex_fm (MP mp, font_number f, fm_entry * basefm, int ex) {
1201 integer e = basefm->extend;
1204 fm = new_fm_entry ();
1205 fm->flags = basefm->flags;
1206 fm->encoding = basefm->encoding;
1207 fm->type = basefm->type;
1208 fm->slant = basefm->slant;
1209 fm->extend = mp_round_xn_over_d (mp, e, 1000 + ex, 1000);
1210 /* modify ExtentFont to simulate expansion */
1211 if (fm->extend == 1000)
1213 fm->tfm_name = mp_xstrdup (mp->font_name[f]);
1214 if (basefm->ps_name != NULL)
1215 fm->ps_name = mp_xstrdup (basefm->ps_name);
1216 fm->ff_name = mp_xstrdup (basefm->ff_name);
1219 fm->tfm_avail = TFM_FOUND;
1220 assert (strcmp (fm->tfm_name, nontfm));
1224 @ @c static void init_fm (fm_entry * fm, font_number f) {
1225 if (fm->tfm_num == null_font ) {
1227 fm->tfm_avail = TFM_FOUND;
1232 fm_entry * mp_fm_lookup (MP mp, font_number f);
1235 fm_entry * mp_fm_lookup (MP mp, font_number f) {
1237 fm_entry *fm, *exfm;
1240 if (mp->ps->tfm_tree == NULL)
1241 fm_read_info (mp); /* only to read default map file */
1242 tfm = mp->font_name[f];
1243 assert (strcmp (tfm, nontfm));
1244 /* Look up for full <tfmname>[+-]<expand> */
1246 fm = (fm_entry *) avl_find (mp->ps->tfm_tree, &tmp);
1249 return (fm_entry *) fm;
1251 tfm = mk_base_tfm (mp, mp->font_name[f], &e);
1252 if (tfm == NULL) /* not an expanded font, nothing to do */
1256 fm = (fm_entry *) avl_find (mp->ps->tfm_tree, &tmp);
1257 if (fm != NULL) { /* found an entry with the base tfm name, e.g. cmr10 */
1258 return (fm_entry *) fm; /* font expansion uses the base font */
1259 /* the following code would be obsolete, as would be |mk_ex_fm| */
1260 if (!is_t1fontfile (fm) || !is_included (fm)) {
1263 "font %s cannot be expanded (not an included Type1 font)", tfm);
1267 exfm = mk_ex_fm (mp, f, fm, e); /* copies all fields from fm except tfm name */
1269 ai = avl_do_entry (mp, exfm, FM_DUPIGNORE);
1271 return (fm_entry *) exfm;
1276 @ Early check whether a font file exists. Used e. g. for replacing fonts
1277 of embedded PDF files: Without font file, the font within the embedded
1278 PDF-file is used. Search tree |ff_tree| is used in 1st instance, as it
1279 may be faster than the |kpse_find_file()|, and |kpse_find_file()| is called
1280 only once per font file name + expansion parameter. This might help
1281 keeping speed, if many PDF pages with same fonts are to be embedded.
1283 The |ff_tree| contains only font files, which are actually needed,
1284 so this tree typically is much smaller than the |tfm_tree| or |ps_tree|.
1287 static ff_entry *check_ff_exist (MP mp, fm_entry * fm) {
1292 assert (fm->ff_name != NULL);
1293 tmp.ff_name = fm->ff_name;
1294 ff = (ff_entry *) avl_find (mp->ps->ff_tree, &tmp);
1295 if (ff == NULL) { /* not yet in database */
1296 ff = new_ff_entry ();
1297 ff->ff_name = mp_xstrdup (fm->ff_name);
1298 ff->ff_path = mp_xstrdup (fm->ff_name);
1299 aa = avl_probe (mp->ps->ff_tree, ff);
1300 assert (aa != NULL);
1306 font_number mp_tfm_lookup (MP mp, char *s, scaled fs) {
1307 /* looks up for a TFM with name |s| loaded at |fs| size; if found then flushes |s| */
1309 if ( fs != 0 ) { /* should not be used! */
1310 for (k = null_font + 1;k<=mp->last_fnum;k++) {
1311 if ( mp_xstrcmp( mp->font_name[k], s) && (mp->font_sizes[k] == fs) ) {
1317 for (k = null_font + 1;k<=mp->last_fnum;k++) {
1318 if ( mp_xstrcmp(mp->font_name[k], s) ) {
1327 @ Process map file given by its name or map line contents. Items not
1328 beginning with [+-=] flush default map file, if it has not yet been
1329 read. Leading blanks and blanks immediately following [+-=] are ignored.
1332 @c void mp_process_map_item (MP mp, char *s, int type) {
1336 s++; /* ignore leading blank */
1338 case '+': /* +mapfile.map, +mapline */
1339 mode = FM_DUPIGNORE; /* insert entry, if it is not duplicate */
1342 case '=': /* =mapfile.map, =mapline */
1343 mode = FM_REPLACE; /* try to replace earlier entry */
1346 case '-': /* -mapfile.map, -mapline */
1347 mode = FM_DELETE; /* try to delete entry */
1351 mode = FM_DUPIGNORE; /* like +, but also: */
1352 mp->ps->mitem->map_line = NULL; /* flush default map file name */
1355 s++; /* ignore blank after [+-=] */
1356 p = s; /* map item starts here */
1358 case MAPFILE: /* remove blank at end */
1359 while (*p != '\0' && *p != ' ')
1363 case MAPLINE: /* blank at end allowed */
1368 if (mp->ps->mitem->map_line != NULL) /* read default map file first */
1370 if (*s != '\0') { /* only if real item to process */
1371 mp->ps->mitem->mode = mode;
1372 mp->ps->mitem->type = type;
1373 mp->ps->mitem->map_line = s;
1378 @ @<Exported function headers@>=
1379 void mp_map_file (MP mp, str_number t);
1380 void mp_map_line (MP mp, str_number t);
1381 void mp_init_map_file (MP mp, int is_troff);
1384 void mp_map_file (MP mp, str_number t) {
1385 char *s = mp_xstrdup(mp_str (mp,t));
1386 mp_process_map_item (mp, s, MAPFILE);
1389 void mp_map_line (MP mp, str_number t) {
1390 char *s = mp_xstrdup(mp_str (mp,t));
1391 mp_process_map_item (mp, s, MAPLINE);
1396 @c void mp_init_map_file (MP mp, int is_troff) {
1398 mp->ps->mitem = mp_xmalloc (1,sizeof(mapitem));
1399 mp->ps->mitem->mode = FM_DUPIGNORE;
1400 mp->ps->mitem->type = MAPFILE;
1401 mp->ps->mitem->map_line = NULL;
1402 if ((mp->find_file)("mpost.map", "rb", mp_filetype_fontmap) != NULL) {
1403 mp->ps->mitem->map_line = mp_xstrdup ("mpost.map");
1406 mp->ps->mitem->map_line = mp_xstrdup ("troff.map");
1408 mp->ps->mitem->map_line = mp_xstrdup ("pdftex.map");
1413 @ @<Dealloc variables@>=
1414 if (mp->ps->mitem!=NULL) {
1415 mp_xfree(mp->ps->mitem->map_line);
1416 mp_xfree(mp->ps->mitem);
1422 static void destroy_fm_entry_tfm (void *pa, void *pb) {
1425 fm = (fm_entry *) pa;
1426 if (!has_pslink (fm))
1427 delete_fm_entry (fm);
1431 static void destroy_fm_entry_ps (void *pa, void *pb) {
1434 fm = (fm_entry *) pa;
1435 if (!has_tfmlink (fm))
1436 delete_fm_entry (fm);
1440 static void destroy_ff_entry (void *pa, void *pb) {
1443 ff = (ff_entry *) pa;
1444 delete_ff_entry (ff);
1448 static void fm_free (MP mp);
1451 static void fm_free (MP mp) {
1452 if (mp->ps->tfm_tree != NULL)
1453 avl_destroy (mp->ps->tfm_tree, destroy_fm_entry_tfm);
1454 if (mp->ps->ps_tree != NULL)
1455 avl_destroy (mp->ps->ps_tree, destroy_fm_entry_ps);
1456 if (mp->ps->ff_tree != NULL)
1457 avl_destroy (mp->ps->ff_tree, destroy_ff_entry);
1460 @* \[44c] Helper functions for Type1 fonts.
1463 typedef char char_entry;
1464 typedef unsigned char Byte;
1468 char_entry *char_ptr, *char_array;
1470 char *job_id_string;
1472 @ @<Set initial...@>=
1473 mp->ps->char_array = NULL;
1474 mp->ps->job_id_string = NULL;
1477 @d SMALL_ARRAY_SIZE 256
1481 void mp_set_job_id (MP mp, int year, int month, int day, int time) {
1482 char *name_string, *format_string, *s;
1485 if (mp->ps->job_id_string != NULL)
1487 if ( mp->job_name==NULL )
1488 mp->job_name = mp_xstrdup("mpout");
1489 name_string = mp_xstrdup (mp->job_name);
1490 format_string = mp_xstrdup (mp->mem_ident);
1491 slen = SMALL_BUF_SIZE +
1492 strlen (name_string) +
1493 strlen (format_string);
1494 s = mp_xmalloc (slen, sizeof (char));
1495 i = snprintf (s, slen,
1496 "%.4d/%.2d/%.2d %.2d:%.2d %s %s",
1502 name_string, format_string);
1503 mp->ps->job_id_string = mp_xstrdup (s);
1505 mp_xfree (name_string);
1506 mp_xfree (format_string);
1508 static void fnstr_append (MP mp, const char *s) {
1509 size_t l = strlen (s) + 1;
1510 alloc_array (char, l, SMALL_ARRAY_SIZE);
1511 strcat (mp->ps->char_ptr, s);
1512 mp->ps->char_ptr = strend (mp->ps->char_ptr);
1515 @ @<Exported function headers@>=
1516 void mp_set_job_id (MP mp, int y, int m, int d, int t) ;
1518 @ @<Dealloc variables@>=
1519 mp_xfree(mp->ps->job_id_string);
1521 @ this is not really a true crc32, but it should be just enough to keep
1522 subsets prefixes somewhat disjunct
1525 static unsigned long crc32 (int oldcrc, const Byte *buf, int len) {
1526 unsigned long ret = 0;
1529 ret = (23<<24)+(45<<16)+(67<<8)+89;
1532 ret = (ret<<2)+buf[i];
1535 boolean mp_char_marked (MP mp,font_number f, eight_bits c) {
1536 integer b; /* |char_base[f]| */
1538 if ( (c>=mp->font_bc[f])&&(c<=mp->font_ec[f])&&(mp->font_info[b+c].qqqq.b3!=0) )
1544 static void make_subset_tag (MP mp, fm_entry * fm_cur, char **glyph_names, int tex_font)
1550 if (mp->ps->job_id_string ==NULL)
1551 mp_fatal_error(mp, "no job id!");
1552 l = strlen (mp->ps->job_id_string) + 1;
1554 alloc_array (char, l, SMALL_ARRAY_SIZE);
1555 strcpy (mp->ps->char_array, mp->ps->job_id_string);
1556 mp->ps->char_ptr = strend (mp->ps->char_array);
1557 if (fm_cur->tfm_name != NULL) {
1558 fnstr_append (mp," TFM name: ");
1559 fnstr_append (mp,fm_cur->tfm_name);
1561 fnstr_append (mp," PS name: ");
1562 if (fm_cur->ps_name != NULL)
1563 fnstr_append (mp,fm_cur->ps_name);
1564 fnstr_append (mp," Encoding: ");
1565 if (fm_cur->encoding != NULL && (fm_cur->encoding)->file_name != NULL)
1566 fnstr_append (mp,(fm_cur->encoding)->file_name);
1568 fnstr_append (mp,"built-in");
1569 fnstr_append (mp," CharSet: ");
1570 for (i = 0; i < 256; i++)
1571 if (mp_char_marked (mp,tex_font, i) && glyph_names[i] != notdef) {
1572 if (glyph_names[i]!=NULL) {
1573 fnstr_append (mp,"/");
1574 fnstr_append (mp,glyph_names[i]);
1577 if (fm_cur->charset != NULL) {
1578 fnstr_append (mp," Extra CharSet: ");
1579 fnstr_append (mp, fm_cur->charset);
1581 crc = crc32 (0L, Z_NULL, 0);
1582 crc = crc32 (crc, (Bytef *) mp->ps->char_array, strlen (mp->ps->char_array));
1583 /* we need to fit a 32-bit number into a string of 6 uppercase chars long;
1584 * there are 26 uppercase chars ==> each char represents a number in range
1585 * |0..25|. The maximal number that can be represented by the tag is
1586 * $26^6 - 1$, which is a number between $2^28$ and $2^29$. Thus the bits |29..31|
1587 * of the CRC must be dropped out.
1589 for (i = 0; i < 6; i++) {
1590 tag[i] = 'A' + crc % 26;
1594 fm_cur->subset_tag = mp_xstrdup (tag);
1600 @d external_enc() (fm_cur->encoding)->glyph_names
1601 @d is_used_char(c) mp_char_marked (mp, tex_font, c)
1602 @d end_last_eexec_line()
1603 mp->ps->hexline_length = HEXLINE_WIDTH;
1605 mp->ps->t1_eexec_encrypt = false
1606 @d t1_log(s) mp_print(mp,(char *)s)
1607 @d t1_putchar(c) fputc(c, mp->ps_file)
1608 @d embed_all_glyphs(tex_font) false
1610 @d extra_charset() mp->ps->dvips_extra_charset
1611 @d update_subset_tag()
1612 @d fixedcontent true
1615 #define PRINTF_BUF_SIZE 1024
1616 char *dvips_extra_charset;
1618 unsigned char *grid;
1619 char *ext_glyph_names[256];
1620 char print_buf[PRINTF_BUF_SIZE];
1622 @ @<Set initial ...@>=
1623 mp->ps->dvips_extra_charset=NULL;
1626 @d t1_getchar() fgetc(mp->ps->t1_file)
1627 @d t1_ungetchar(c) ungetc(c, mp->ps->t1_file)
1628 @d t1_eof() feof(mp->ps->t1_file)
1629 @d t1_close() fclose(mp->ps->t1_file)
1630 @d valid_code(c) (c >= 0 && c < 256)
1632 @<Static variables in the outer block@>=
1633 static const char *standard_glyph_names[256] =
1634 { notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1635 notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1636 notdef, notdef, notdef, notdef, notdef, notdef,
1637 notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1638 "space", "exclam", "quotedbl", "numbersign",
1639 "dollar", "percent", "ampersand", "quoteright", "parenleft",
1640 "parenright", "asterisk", "plus", "comma", "hyphen", "period",
1641 "slash", "zero", "one", "two", "three", "four", "five", "six", "seven",
1642 "eight", "nine", "colon", "semicolon", "less",
1643 "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F",
1644 "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q",
1645 "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft",
1646 "backslash", "bracketright", "asciicircum", "underscore",
1647 "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k",
1648 "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v",
1649 "w", "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde",
1650 notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1651 notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1652 notdef, notdef, notdef, notdef, notdef, notdef,
1653 notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1654 notdef, notdef, notdef, "exclamdown", "cent",
1655 "sterling", "fraction", "yen", "florin", "section", "currency",
1656 "quotesingle", "quotedblleft", "guillemotleft",
1657 "guilsinglleft", "guilsinglright", "fi", "fl", notdef, "endash",
1658 "dagger", "daggerdbl", "periodcentered", notdef,
1659 "paragraph", "bullet", "quotesinglbase", "quotedblbase",
1660 "quotedblright", "guillemotright", "ellipsis", "perthousand",
1661 notdef, "questiondown", notdef, "grave", "acute", "circumflex",
1662 "tilde", "macron", "breve", "dotaccent", "dieresis", notdef,
1663 "ring", "cedilla", notdef, "hungarumlaut", "ogonek", "caron", "emdash",
1664 notdef, notdef, notdef, notdef, notdef, notdef,
1665 notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1666 notdef, "AE", notdef, "ordfeminine", notdef, notdef,
1667 notdef, notdef, "Lslash", "Oslash", "OE", "ordmasculine", notdef,
1668 notdef, notdef, notdef, notdef, "ae", notdef, notdef,
1669 notdef, "dotlessi", notdef, notdef, "lslash", "oslash", "oe",
1670 "germandbls", notdef, notdef, notdef, notdef };
1671 static const char charstringname[] = "/CharStrings";
1674 char **t1_glyph_names;
1675 char *t1_builtin_glyph_names[256];
1676 char charsetstr[0x4000];
1677 boolean read_encoding_only;
1681 #define T1_BUF_SIZE 0x10
1685 #define CS_VMOVETO 4
1686 #define CS_RLINETO 5
1687 #define CS_HLINETO 6
1688 #define CS_VLINETO 7
1689 #define CS_RRCURVETO 8
1690 #define CS_CLOSEPATH 9
1691 #define CS_CALLSUBR 10
1692 #define CS_RETURN 11
1693 #define CS_ESCAPE 12
1695 #define CS_ENDCHAR 14
1696 #define CS_RMOVETO 21
1697 #define CS_HMOVETO 22
1698 #define CS_VHCURVETO 30
1699 #define CS_HVCURVETO 31
1700 #define CS_1BYTE_MAX (CS_HVCURVETO + 1)
1702 #define CS_DOTSECTION CS_1BYTE_MAX + 0
1703 #define CS_VSTEM3 CS_1BYTE_MAX + 1
1704 #define CS_HSTEM3 CS_1BYTE_MAX + 2
1705 #define CS_SEAC CS_1BYTE_MAX + 6
1706 #define CS_SBW CS_1BYTE_MAX + 7
1707 #define CS_DIV CS_1BYTE_MAX + 12
1708 #define CS_CALLOTHERSUBR CS_1BYTE_MAX + 16
1709 #define CS_POP CS_1BYTE_MAX + 17
1710 #define CS_SETCURRENTPOINT CS_1BYTE_MAX + 33
1711 #define CS_2BYTE_MAX (CS_SETCURRENTPOINT + 1)
1712 #define CS_MAX CS_2BYTE_MAX
1715 typedef unsigned char byte;
1717 byte nargs; /* number of arguments */
1718 boolean bottom; /* take arguments from bottom of stack? */
1719 boolean clear; /* clear stack? */
1721 } cc_entry; /* CharString Command */
1723 char *glyph_name; /* glyph name (or notdef for Subrs entry) */
1725 unsigned short len; /* length of the whole string */
1726 unsigned short cslen; /* length of the encoded part of the string */
1732 unsigned short t1_dr, t1_er;
1733 unsigned short t1_c1, t1_c2;
1734 unsigned short t1_cslen;
1737 @ @<Set initial...@>=
1738 mp->ps->t1_c1 = 52845;
1739 mp->ps->t1_c2 = 22719;
1742 typedef char t1_line_entry;
1743 typedef char t1_buf_entry;
1746 t1_line_entry *t1_line_ptr, *t1_line_array;
1747 size_t t1_line_limit;
1748 t1_buf_entry *t1_buf_ptr, *t1_buf_array;
1749 size_t t1_buf_limit;
1751 cs_entry *cs_tab, *cs_ptr, *cs_notdef;
1752 char *cs_dict_start, *cs_dict_end;
1753 int cs_count, cs_size, cs_size_pos;
1755 char *subr_array_start, *subr_array_end;
1756 int subr_max, subr_size, subr_size_pos;
1758 @ @<Set initial...@>=
1759 mp->ps->t1_line_array = NULL;
1760 mp->ps->t1_buf_array = NULL;
1763 This list contains the begin/end tokens commonly used in the
1764 /Subrs array of a Type 1 font.
1766 @<Static variables in the outer block@>=
1767 static const char *cs_token_pairs_list[][2] = {
1770 {" RD", "noaccess put"},
1771 {" -|", "noaccess put"},
1776 const char **cs_token_pair;
1777 boolean t1_pfa, t1_cs, t1_scan, t1_eexec_encrypt, t1_synthetic;
1778 int t1_in_eexec; /* 0 before eexec-encrypted, 1 during, 2 after */
1779 long t1_block_length;
1787 @<Set initial ...@>=
1788 mp->ps->hexline_length = HEXLINE_WIDTH;
1791 @d t1_prefix(s) str_prefix(mp->ps->t1_line_array, s)
1792 @d t1_buf_prefix(s) str_prefix(mp->ps->t1_buf_array, s)
1793 @d t1_suffix(s) str_suffix(mp->ps->t1_line_array, mp->ps->t1_line_ptr, s)
1794 @d t1_buf_suffix(s) str_suffix(mp->ps->t1_buf_array, mp->ps->t1_buf_ptr, s)
1795 @d t1_charstrings() strstr(mp->ps->t1_line_array, charstringname)
1796 @d t1_subrs() t1_prefix("/Subrs")
1797 @d t1_end_eexec() t1_suffix("mark currentfile closefile")
1798 @d t1_cleartomark() t1_prefix("cleartomark")
1800 @d isdigit(A) ((A)>='0'&&(A)<='9')
1803 static void end_hexline (MP mp) {
1804 if (mp->ps->hexline_length == HEXLINE_WIDTH) {
1805 fputs ("\n", mp->ps_file);
1806 mp->ps->hexline_length = 0;
1809 static void t1_check_pfa (MP mp) {
1810 const int c = t1_getchar ();
1811 mp->ps->t1_pfa = (c != 128) ? true : false;
1814 static int t1_getbyte (MP mp)
1816 int c = t1_getchar ();
1819 if (mp->ps->t1_block_length == 0) {
1821 mp_fatal_error (mp, "invalid marker");
1828 mp->ps->t1_block_length = t1_getchar () & 0xff;
1829 mp->ps->t1_block_length |= (t1_getchar () & 0xff) << 8;
1830 mp->ps->t1_block_length |= (t1_getchar () & 0xff) << 16;
1831 mp->ps->t1_block_length |= (t1_getchar () & 0xff) << 24;
1834 mp->ps->t1_block_length--;
1837 static int hexval (int c) {
1838 if (c >= 'A' && c <= 'F')
1839 return c - 'A' + 10;
1840 else if (c >= 'a' && c <= 'f')
1841 return c - 'a' + 10;
1842 else if (c >= '0' && c <= '9')
1847 static byte edecrypt (MP mp, byte cipher) {
1849 if (mp->ps->t1_pfa) {
1850 while (cipher == 10 || cipher == 13)
1851 cipher = t1_getbyte (mp);
1852 mp->ps->last_hexbyte = cipher = (hexval (cipher) << 4) + hexval (t1_getbyte (mp));
1854 plain = (cipher ^ (mp->ps->t1_dr >> 8));
1855 mp->ps->t1_dr = (cipher + mp->ps->t1_dr) * mp->ps->t1_c1 + mp->ps->t1_c2;
1858 static byte cdecrypt (MP mp, byte cipher, unsigned short *cr)
1860 const byte plain = (cipher ^ (*cr >> 8));
1861 *cr = (cipher + *cr) * mp->ps->t1_c1 + mp->ps->t1_c2;
1864 static byte eencrypt (MP mp, byte plain)
1866 const byte cipher = (plain ^ (mp->ps->t1_er >> 8));
1867 mp->ps->t1_er = (cipher + mp->ps->t1_er) * mp->ps->t1_c1 + mp->ps->t1_c2;
1871 static byte cencrypt (MP mp, byte plain, unsigned short *cr)
1873 const byte cipher = (plain ^ (*cr >> 8));
1874 *cr = (cipher + *cr) * mp->ps->t1_c1 + mp->ps->t1_c2;
1878 static char *eol (char *s) {
1879 char *p = strend (s);
1880 if (p - s > 1 && p[-1] != 10) {
1886 static float t1_scan_num (MP mp, char *p, char **r)
1891 if (sscanf (p, "%g", &f) != 1) {
1892 remove_eol (p, mp->ps->t1_line_array);
1893 snprintf(s,128, "a number expected: `%s'", mp->ps->t1_line_array);
1894 mp_fatal_error(mp,s);
1897 for (; isdigit (*p) || *p == '.' ||
1898 *p == 'e' || *p == 'E' || *p == '+' || *p == '-'; p++);
1904 static boolean str_suffix (const char *begin_buf, const char *end_buf,
1907 const char *s1 = end_buf - 1, *s2 = strend (s) - 1;
1910 while (s1 >= begin_buf && s2 >= s) {
1919 @d alloc_array(T, n, s) do {
1920 if (mp->ps->T##_array == NULL) {
1921 mp->ps->T##_limit = (s);
1922 if ((unsigned)(n) > mp->ps->T##_limit)
1923 mp->ps->T##_limit = (n);
1924 mp->ps->T##_array = mp_xmalloc (mp->ps->T##_limit,sizeof(T##_entry));
1925 mp->ps->T##_ptr = mp->ps->T##_array;
1927 else if ((unsigned)(mp->ps->T##_ptr - mp->ps->T##_array + (n)) > mp->ps->T##_limit) {
1928 size_t last_ptr_index;
1929 last_ptr_index = mp->ps->T##_ptr - mp->ps->T##_array;
1930 mp->ps->T##_limit *= 2;
1931 if ((unsigned)(mp->ps->T##_ptr - mp->ps->T##_array + (n)) > mp->ps->T##_limit)
1932 mp->ps->T##_limit = mp->ps->T##_ptr - mp->ps->T##_array + (n);
1933 mp->ps->T##_array = mp_xrealloc(mp->ps->T##_array, mp->ps->T##_limit , sizeof (T##_entry));
1934 mp->ps->T##_ptr = mp->ps->T##_array + last_ptr_index;
1938 @d out_eexec_char(A) t1_outhex(mp,(A))
1941 static void t1_outhex (MP mp, byte b)
1943 static char *hexdigits = "0123456789ABCDEF";
1944 t1_putchar (hexdigits[b / 16]);
1945 t1_putchar (hexdigits[b % 16]);
1946 mp->ps->hexline_length += 2;
1949 static void t1_getline (MP mp) {
1950 int c, l, eexec_scan;
1952 static const char eexec_str[] = "currentfile eexec";
1953 static int eexec_len = 17; /* |strlen(eexec_str)| */
1956 mp_fatal_error (mp,"unexpected end of file");
1957 mp->ps->t1_line_ptr = mp->ps->t1_line_array;
1958 alloc_array (t1_line, 1, T1_BUF_SIZE);
1959 mp->ps->t1_cslen = 0;
1961 c = t1_getbyte (mp);
1964 while (!t1_eof ()) {
1965 if (mp->ps->t1_in_eexec == 1)
1966 c = edecrypt (mp,c);
1967 alloc_array (t1_line, 1, T1_BUF_SIZE);
1968 append_char_to_buf (c, mp->ps->t1_line_ptr, mp->ps->t1_line_array, mp->ps->t1_line_limit);
1969 if (mp->ps->t1_in_eexec == 0 && eexec_scan >= 0 && eexec_scan < eexec_len) {
1970 if (mp->ps->t1_line_array[eexec_scan] == eexec_str[eexec_scan])
1975 if (c == 10 || (mp->ps->t1_pfa && eexec_scan == eexec_len && c == 32))
1977 if (mp->ps->t1_cs && mp->ps->t1_cslen == 0 &&
1978 (mp->ps->t1_line_ptr - mp->ps->t1_line_array > 4) &&
1979 (t1_suffix (" RD ") || t1_suffix (" -| "))) {
1980 p = mp->ps->t1_line_ptr - 5;
1983 mp->ps->t1_cslen = l = t1_scan_num (mp, p + 1, 0);
1984 mp->ps->cs_start = mp->ps->t1_line_ptr - mp->ps->t1_line_array;
1985 /* |mp->ps->cs_start| is an index now */
1986 alloc_array (t1_line, l, T1_BUF_SIZE);
1988 *mp->ps->t1_line_ptr++ = edecrypt (mp,t1_getbyte (mp));
1990 c = t1_getbyte (mp);
1992 alloc_array (t1_line, 2, T1_BUF_SIZE); /* |append_eol| can append 2 chars */
1993 append_eol (mp->ps->t1_line_ptr, mp->ps->t1_line_array, mp->ps->t1_line_limit);
1994 if (mp->ps->t1_line_ptr - mp->ps->t1_line_array < 2)
1996 if (eexec_scan == eexec_len)
1997 mp->ps->t1_in_eexec = 1;
1999 /* ensure that |mp->ps->t1_buf_array| has as much room as |t1_line_array| */
2000 mp->ps->t1_buf_ptr = mp->ps->t1_buf_array;
2001 alloc_array (t1_buf, mp->ps->t1_line_limit, mp->ps->t1_line_limit);
2004 static void t1_putline (MP mp)
2006 char *p = mp->ps->t1_line_array;
2007 if (mp->ps->t1_line_ptr - mp->ps->t1_line_array <= 1)
2009 if (mp->ps->t1_eexec_encrypt) {
2010 while (p < mp->ps->t1_line_ptr)
2011 out_eexec_char (eencrypt (mp,*p++));
2013 while (p < mp->ps->t1_line_ptr)
2018 static void t1_puts (MP mp, const char *s)
2020 if (s != mp->ps->t1_line_array)
2021 strcpy (mp->ps->t1_line_array, s);
2022 mp->ps->t1_line_ptr = strend (mp->ps->t1_line_array);
2026 static void t1_printf (MP mp, const char *fmt, ...)
2029 va_start (args, fmt);
2030 vsprintf (mp->ps->t1_line_array, fmt, args);
2031 t1_puts (mp,mp->ps->t1_line_array);
2035 static void t1_init_params (MP mp, char *open_name_prefix,
2036 char *cur_file_name) {
2037 if ((open_name_prefix != NULL) && strlen(open_name_prefix)) {
2038 t1_log (open_name_prefix);
2039 t1_log (cur_file_name);
2041 mp->ps->t1_lenIV = 4;
2042 mp->ps->t1_dr = 55665;
2043 mp->ps->t1_er = 55665;
2044 mp->ps->t1_in_eexec = 0;
2045 mp->ps->t1_cs = false;
2046 mp->ps->t1_scan = true;
2047 mp->ps->t1_synthetic = false;
2048 mp->ps->t1_eexec_encrypt = false;
2049 mp->ps->t1_block_length = 0;
2052 static void t1_close_font_file (MP mp, const char *close_name_suffix) {
2053 if ((close_name_suffix != NULL) && strlen(close_name_suffix)) {
2054 t1_log (close_name_suffix);
2059 static void t1_check_block_len (MP mp, boolean decrypt) {
2062 if (mp->ps->t1_block_length == 0)
2064 c = t1_getbyte (mp);
2066 c = edecrypt (mp,c);
2067 l = mp->ps->t1_block_length;
2068 if (!(l == 0 && (c == 10 || c == 13))) {
2069 snprintf(s,128,"%i bytes more than expected were ignored", l+ 1);
2075 static void t1_start_eexec (MP mp, fm_entry *fm_cur) {
2077 if (!mp->ps->t1_pfa)
2078 t1_check_block_len (mp, false);
2079 for (mp->ps->t1_line_ptr = mp->ps->t1_line_array, i = 0; i < 4; i++) {
2080 edecrypt (mp, t1_getbyte (mp));
2081 *mp->ps->t1_line_ptr++ = 0;
2083 mp->ps->t1_eexec_encrypt = true;
2084 if (!mp->ps->read_encoding_only)
2085 if (is_included (fm_cur))
2086 t1_putline (mp); /* to put the first four bytes */
2088 static void t1_stop_eexec (MP mp) {
2090 end_last_eexec_line ();
2091 if (!mp->ps->t1_pfa)
2092 t1_check_block_len (mp,true);
2094 c = edecrypt (mp, t1_getbyte (mp));
2095 if (!(c == 10 || c == 13)) {
2096 if (mp->ps->last_hexbyte == 0)
2099 mp_warn (mp,"unexpected data after eexec");
2102 mp->ps->t1_cs = false;
2103 mp->ps->t1_in_eexec = 2;
2105 static void t1_modify_fm (MP mp) {
2106 mp->ps->t1_line_ptr = eol (mp->ps->t1_line_array);
2109 static void t1_modify_italic (MP mp) {
2110 mp->ps->t1_line_ptr = eol (mp->ps->t1_line_array);
2115 const char *pdfname;
2125 static key_entry font_keys[FONT_KEYS_NUM] = {
2126 {"Ascent", "Ascender", 0, false},
2127 {"CapHeight", "CapHeight", 0, false},
2128 {"Descent", "Descender", 0, false},
2129 {"FontName", "FontName", 0, false},
2130 {"ItalicAngle", "ItalicAngle", 0, false},
2131 {"StemV", "StdVW", 0, false},
2132 {"XHeight", "XHeight", 0, false},
2133 {"FontBBox", "FontBBox", 0, false},
2145 @d ITALIC_ANGLE_CODE 4
2151 @d FONTBBOX4_CODE 10
2152 @d MAX_KEY_CODE (FONTBBOX1_CODE + 1)
2155 static void t1_scan_keys (MP mp, int tex_font,fm_entry *fm_cur) {
2159 if (fm_extend (fm_cur) != 0 || fm_slant (fm_cur) != 0) {
2160 if (t1_prefix ("/FontMatrix")) {
2164 if (t1_prefix ("/ItalicAngle")) {
2165 t1_modify_italic (mp);
2169 if (t1_prefix ("/FontType")) {
2170 p = mp->ps->t1_line_array + strlen ("FontType") + 1;
2171 if ((i = t1_scan_num (mp,p, 0)) != 1) {
2173 snprintf(s,125,"Type%d fonts unsupported by metapost", i);
2174 mp_fatal_error(mp,s);
2178 for (key = font_keys; key - font_keys < MAX_KEY_CODE; key++)
2179 if (str_prefix (mp->ps->t1_line_array + 1, key->t1name))
2181 if (key - font_keys == MAX_KEY_CODE)
2184 p = mp->ps->t1_line_array + strlen (key->t1name) + 1;
2186 if ((k = key - font_keys) == FONTNAME_CODE) {
2189 remove_eol (p, mp->ps->t1_line_array);
2190 snprintf(s,128,"a name expected: `%s'", mp->ps->t1_line_array);
2191 mp_fatal_error(mp,s);
2193 r = ++p; /* skip the slash */
2194 if (is_included (fm_cur)) {
2195 /* save the fontname */
2196 strncpy (mp->ps->fontname_buf, p, FONTNAME_BUF_SIZE);
2197 for (i=0; mp->ps->fontname_buf[i] != 10; i++);
2198 mp->ps->fontname_buf[i]=0;
2200 if(is_subsetted (fm_cur)) {
2201 if (fm_cur->encoding!=NULL && fm_cur->encoding->glyph_names!=NULL)
2202 make_subset_tag (mp,fm_cur, fm_cur->encoding->glyph_names, tex_font);
2204 make_subset_tag (mp,fm_cur, mp->ps->t1_builtin_glyph_names, tex_font);
2206 alloc_array (t1_line, (r-mp->ps->t1_line_array+6+1+strlen(mp->ps->fontname_buf)+1),
2208 strncpy (r, fm_cur->subset_tag , 6);
2210 strncpy (r+7, mp->ps->fontname_buf, strlen(mp->ps->fontname_buf)+1);
2211 mp->ps->t1_line_ptr = eol (r);
2213 /* |for (q = p; *q != ' ' && *q != 10; *q++);|*/
2215 mp->ps->t1_line_ptr = eol (r);
2220 if ((k == STEMV_CODE || k == FONTBBOX1_CODE)
2221 && (*p == '[' || *p == '{'))
2223 if (k == FONTBBOX1_CODE) {
2224 for (i = 0; i < 4; i++) {
2225 key[i].value = t1_scan_num (mp, p, &r);
2230 key->value = t1_scan_num (mp, p, 0);
2232 static void t1_scan_param (MP mp, int tex_font,fm_entry *fm_cur)
2234 static const char *lenIV = "/lenIV";
2235 if (!mp->ps->t1_scan || *mp->ps->t1_line_array != '/')
2237 if (t1_prefix (lenIV)) {
2238 mp->ps->t1_lenIV = t1_scan_num (mp,mp->ps->t1_line_array + strlen (lenIV), 0);
2241 t1_scan_keys (mp, tex_font,fm_cur);
2243 static void copy_glyph_names (char **glyph_names, int a, int b) {
2244 if (glyph_names[b] != notdef) {
2245 mp_xfree (glyph_names[b]);
2246 glyph_names[b] = (char *) notdef;
2248 if (glyph_names[a] != notdef) {
2249 glyph_names[b] = mp_xstrdup (glyph_names[a]);
2252 static void t1_builtin_enc (MP mp) {
2253 int i, a, b, c, counter = 0;
2256 * At this moment "/Encoding" is the prefix of |mp->ps->t1_line_array|
2258 if (t1_suffix ("def")) { /* predefined encoding */
2259 sscanf (mp->ps->t1_line_array + strlen ("/Encoding"), "%256s", mp->ps->t1_buf_array);
2260 if (strcmp (mp->ps->t1_buf_array, "StandardEncoding") == 0) {
2261 for (i = 0; i < 256; i++)
2262 if (standard_glyph_names[i] == notdef)
2263 mp->ps->t1_builtin_glyph_names[i] = (char *) notdef;
2265 mp->ps->t1_builtin_glyph_names[i] =
2266 mp_xstrdup (standard_glyph_names[i]);
2267 mp->ps->t1_encoding = ENC_STANDARD;
2270 snprintf(s,128, "cannot subset font (unknown predefined encoding `%s')",
2271 mp->ps->t1_buf_array);
2272 mp_fatal_error(mp,s);
2276 mp->ps->t1_encoding = ENC_BUILTIN;
2278 * At this moment "/Encoding" is the prefix of |mp->ps->t1_line_array|, and the encoding is
2279 * not a predefined encoding
2281 * We have two possible forms of Encoding vector. The first case is
2283 * /Encoding [/a /b /c...] readonly def
2285 * and the second case can look like
2287 * /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for
2293 for (i = 0; i < 256; i++)
2294 mp->ps->t1_builtin_glyph_names[i] = (char *) notdef;
2295 if (t1_prefix ("/Encoding [") || t1_prefix ("/Encoding[")) { /* the first case */
2296 r = strchr (mp->ps->t1_line_array, '[') + 1;
2300 for (p = mp->ps->t1_buf_array, r++;
2301 *r != 32 && *r != 10 && *r != ']' && *r != '/';
2305 if (counter > 255) {
2307 (mp, "encoding vector contains more than 256 names");
2309 if (strcmp (mp->ps->t1_buf_array, notdef) != 0)
2310 mp->ps->t1_builtin_glyph_names[counter] = mp_xstrdup (mp->ps->t1_buf_array);
2313 if (*r != 10 && *r != '%') {
2314 if (str_prefix (r, "] def")
2315 || str_prefix (r, "] readonly def"))
2319 remove_eol (r, mp->ps->t1_line_array);
2320 snprintf(s,128,"a name or `] def' or `] readonly def' expected: `%s'",
2321 mp->ps->t1_line_array);
2322 mp_fatal_error(mp,s);
2326 r = mp->ps->t1_line_array;
2328 } else { /* the second case */
2329 p = strchr (mp->ps->t1_line_array, 10);
2333 p = mp->ps->t1_line_array;
2336 check for `dup <index> <glyph> put'
2338 if (sscanf (p, "dup %i%256s put", &i, mp->ps->t1_buf_array) == 2 &&
2339 *mp->ps->t1_buf_array == '/' && valid_code (i)) {
2340 if (strcmp (mp->ps->t1_buf_array + 1, notdef) != 0)
2341 mp->ps->t1_builtin_glyph_names[i] =
2342 mp_xstrdup (mp->ps->t1_buf_array + 1);
2343 p = strstr (p, " put") + strlen (" put");
2347 check for `dup dup <to> exch <from> get put'
2349 else if (sscanf (p, "dup dup %i exch %i get put", &b, &a) == 2
2350 && valid_code (a) && valid_code (b)) {
2351 copy_glyph_names (mp->ps->t1_builtin_glyph_names, a, b);
2352 p = strstr (p, " get put") + strlen (" get put");
2356 check for `dup dup <from> <size> getinterval <to> exch putinterval'
2359 (p, "dup dup %i %i getinterval %i exch putinterval",
2360 &a, &c, &b) == 3 && valid_code (a) && valid_code (b)
2361 && valid_code (c)) {
2362 for (i = 0; i < c; i++)
2363 copy_glyph_names (mp->ps->t1_builtin_glyph_names, a + i, b + i);
2364 p = strstr (p, " putinterval") + strlen (" putinterval");
2368 check for `def' or `readonly def'
2370 else if ((p == mp->ps->t1_line_array || (p > mp->ps->t1_line_array && p[-1] == ' '))
2371 && strcmp (p, "def\n") == 0)
2374 skip an unrecognizable word
2377 while (*p != ' ' && *p != 10)
2385 static void t1_check_end (MP mp) {
2389 if (t1_prefix ("{restore}"))
2395 char *ff_name; /* base name of font file */
2396 char *ff_path; /* full path to font file */
2400 static boolean t1_open_fontfile (MP mp, fm_entry *fm_cur,const char *open_name_prefix) {
2402 ff = check_ff_exist (mp, fm_cur);
2403 if (ff->ff_path != NULL) {
2404 mp->ps->t1_file = mp_open_file(mp,ff->ff_path, "rb", mp_filetype_font);
2406 mp_warn (mp, "cannot open Type 1 font file for reading");
2409 t1_init_params (mp,(char *)open_name_prefix,fm_cur->ff_name);
2410 mp->ps->fontfile_found = true;
2414 static void t1_scan_only (MP mp, int tex_font, fm_entry *fm_cur) {
2417 t1_scan_param (mp,tex_font, fm_cur);
2419 while (mp->ps->t1_in_eexec == 0);
2420 t1_start_eexec (mp,fm_cur);
2423 t1_scan_param (mp,tex_font, fm_cur);
2425 while (!(t1_charstrings () || t1_subrs ()));
2428 static void t1_include (MP mp, int tex_font, fm_entry *fm_cur) {
2431 t1_scan_param (mp,tex_font, fm_cur);
2434 while (mp->ps->t1_in_eexec == 0);
2435 t1_start_eexec (mp,fm_cur);
2438 t1_scan_param (mp,tex_font, fm_cur);
2441 while (!(t1_charstrings () || t1_subrs ()));
2442 mp->ps->t1_cs = true;
2447 while (!t1_end_eexec ());
2449 if (fixedcontent) { /* copy 512 zeros (not needed for PDF) */
2454 while (!t1_cleartomark ());
2455 t1_check_end (mp); /* write "{restore}if" if found */
2460 @d check_subr(SUBR) if (SUBR >= mp->ps->subr_size || SUBR < 0) {
2462 snprintf(s,128,"Subrs array: entry index out of range (%i)",SUBR);
2463 mp_fatal_error(mp,s);
2467 static const char **check_cs_token_pair (MP mp) {
2468 const char **p = (const char **) cs_token_pairs_list;
2469 for (; p[0] != NULL; ++p)
2470 if (t1_buf_prefix (p[0]) && t1_buf_suffix (p[1]))
2475 static void cs_store (MP mp, boolean is_subr) {
2479 for (p = mp->ps->t1_line_array, mp->ps->t1_buf_ptr = mp->ps->t1_buf_array; *p != ' ';
2480 *mp->ps->t1_buf_ptr++ = *p++);
2481 *mp->ps->t1_buf_ptr = 0;
2483 subr = t1_scan_num (mp, p + 1, 0);
2485 ptr = mp->ps->subr_tab + subr;
2487 ptr = mp->ps->cs_ptr++;
2488 if (mp->ps->cs_ptr - mp->ps->cs_tab > mp->ps->cs_size) {
2490 snprintf(s,128,"CharStrings dict: more entries than dict size (%i)",mp->ps->cs_size);
2491 mp_fatal_error(mp,s);
2493 if (strcmp (mp->ps->t1_buf_array + 1, notdef) == 0) /* skip the slash */
2494 ptr->glyph_name = (char *) notdef;
2496 ptr->glyph_name = mp_xstrdup (mp->ps->t1_buf_array + 1);
2498 /* copy " RD " + cs data to |mp->ps->t1_buf_array| */
2499 memcpy (mp->ps->t1_buf_array, mp->ps->t1_line_array + mp->ps->cs_start - 4,
2500 (unsigned) (mp->ps->t1_cslen + 4));
2501 /* copy the end of cs data to |mp->ps->t1_buf_array| */
2502 for (p = mp->ps->t1_line_array + mp->ps->cs_start + mp->ps->t1_cslen, mp->ps->t1_buf_ptr =
2503 mp->ps->t1_buf_array + mp->ps->t1_cslen + 4; *p != 10; *mp->ps->t1_buf_ptr++ = *p++);
2504 *mp->ps->t1_buf_ptr++ = 10;
2505 if (is_subr && mp->ps->cs_token_pair == NULL)
2506 mp->ps->cs_token_pair = check_cs_token_pair (mp);
2507 ptr->len = mp->ps->t1_buf_ptr - mp->ps->t1_buf_array;
2508 ptr->cslen = mp->ps->t1_cslen;
2509 ptr->data = mp_xmalloc (ptr->len , sizeof (byte));
2510 memcpy (ptr->data, mp->ps->t1_buf_array, ptr->len);
2514 #define store_subr(mp) cs_store(mp,true)
2515 #define store_cs(mp) cs_store(mp,false)
2517 #define CC_STACK_SIZE 24
2519 static integer cc_stack[CC_STACK_SIZE], *stack_ptr = cc_stack;
2520 static cc_entry cc_tab[CS_MAX];
2521 static boolean is_cc_init = false;
2525 if (stack_ptr - cc_stack < (N)) \
2529 #define stack_error(N) { \
2531 snprintf(s,255,"CharString: invalid access (%i) to stack (%i entries)", \
2532 (int) N, (int)(stack_ptr - cc_stack)); \
2538 #define cc_get(N) ((N) < 0 ? *(stack_ptr + (N)) : *(cc_stack + (N)))
2540 #define cc_push(V) *stack_ptr++ = V
2541 #define cc_clear() stack_ptr = cc_stack
2543 #define set_cc(N, B, A, C) \
2544 cc_tab[N].nargs = A; \
2545 cc_tab[N].bottom = B; \
2546 cc_tab[N].clear = C; \
2547 cc_tab[N].valid = true
2549 static void cc_init (void) {
2553 for (i = 0; i < CS_MAX; i++)
2554 cc_tab[i].valid = false;
2555 set_cc (CS_HSTEM, true, 2, true);
2556 set_cc (CS_VSTEM, true, 2, true);
2557 set_cc (CS_VMOVETO, true, 1, true);
2558 set_cc (CS_RLINETO, true, 2, true);
2559 set_cc (CS_HLINETO, true, 1, true);
2560 set_cc (CS_VLINETO, true, 1, true);
2561 set_cc (CS_RRCURVETO, true, 6, true);
2562 set_cc (CS_CLOSEPATH, false, 0, true);
2563 set_cc (CS_CALLSUBR, false, 1, false);
2564 set_cc (CS_RETURN, false, 0, false);
2566 |set_cc(CS_ESCAPE, false, 0, false);|
2568 set_cc (CS_HSBW, true, 2, true);
2569 set_cc (CS_ENDCHAR, false, 0, true);
2570 set_cc (CS_RMOVETO, true, 2, true);
2571 set_cc (CS_HMOVETO, true, 1, true);
2572 set_cc (CS_VHCURVETO, true, 4, true);
2573 set_cc (CS_HVCURVETO, true, 4, true);
2574 set_cc (CS_DOTSECTION, false, 0, true);
2575 set_cc (CS_VSTEM3, true, 6, true);
2576 set_cc (CS_HSTEM3, true, 6, true);
2577 set_cc (CS_SEAC, true, 5, true);
2578 set_cc (CS_SBW, true, 4, true);
2579 set_cc (CS_DIV, false, 2, false);
2580 set_cc (CS_CALLOTHERSUBR, false, 0, false);
2581 set_cc (CS_POP, false, 0, false);
2582 set_cc (CS_SETCURRENTPOINT, true, 2, true);
2588 @d cs_getchar(mp) cdecrypt(mp,*data++, &cr)
2590 @d mark_subr(mp,n) cs_mark(mp,0, n)
2591 @d mark_cs(mp,s) cs_mark(mp,s, 0)
2592 @d SMALL_BUF_SIZE 256
2595 static void cs_warn (MP mp, const char *cs_name, int subr, const char *fmt, ...) {
2596 char buf[SMALL_BUF_SIZE];
2599 va_start (args, fmt);
2600 vsprintf (buf, fmt, args);
2602 if (cs_name == NULL) {
2603 snprintf(s,299,"Subr (%i): %s", (int) subr, buf);
2605 snprintf(s,299,"CharString (/%s): %s", cs_name, buf);
2610 static void cs_mark (MP mp, const char *cs_name, int subr)
2616 static integer lastargOtherSubr3 = 3; /* the argument of last call to
2620 if (cs_name == NULL) {
2622 ptr = mp->ps->subr_tab + subr;
2626 if (mp->ps->cs_notdef != NULL &&
2627 (cs_name == notdef || strcmp (cs_name, notdef) == 0))
2628 ptr = mp->ps->cs_notdef;
2630 for (ptr = mp->ps->cs_tab; ptr < mp->ps->cs_ptr; ptr++)
2631 if (strcmp (ptr->glyph_name, cs_name) == 0)
2633 if (ptr == mp->ps->cs_ptr) {
2635 snprintf (s,128,"glyph `%s' undefined", cs_name);
2639 if (ptr->glyph_name == notdef)
2640 mp->ps->cs_notdef = ptr;
2643 /* only marked CharString entries and invalid entries can be skipped;
2644 valid marked subrs must be parsed to keep the stack in sync */
2645 if (!ptr->valid || (ptr->is_used && cs_name != NULL))
2647 ptr->is_used = true;
2649 cs_len = ptr->cslen;
2650 data = ptr->data + 4;
2651 for (i = 0; i < mp->ps->t1_lenIV; i++, cs_len--)
2653 while (cs_len > 0) {
2655 b = cs_getchar (mp);
2659 else if (b <= 250) {
2661 a = ((b - 247) << 8) + 108 + cs_getchar (mp);
2662 } else if (b <= 254) {
2664 a = -((b - 251) << 8) - 108 - cs_getchar (mp);
2667 a = (cs_getchar (mp) & 0xff) << 24;
2668 a |= (cs_getchar (mp) & 0xff) << 16;
2669 a |= (cs_getchar (mp) & 0xff) << 8;
2670 a |= (cs_getchar (mp) & 0xff) << 0;
2671 if (sizeof (integer) > 4 && (a & 0x80000000))
2676 if (b == CS_ESCAPE) {
2677 b = cs_getchar (mp) + CS_1BYTE_MAX;
2681 cs_warn (mp,cs_name, subr, "command value out of range: %i",
2687 cs_warn (mp,cs_name, subr, "command not valid: %i", (int) b);
2691 if (stack_ptr - cc_stack < cc->nargs)
2692 cs_warn (mp,cs_name, subr,
2693 "less arguments on stack (%i) than required (%i)",
2694 (int) (stack_ptr - cc_stack), (int) cc->nargs);
2695 else if (stack_ptr - cc_stack > cc->nargs)
2696 cs_warn (mp,cs_name, subr,
2697 "more arguments on stack (%i) than required (%i)",
2698 (int) (stack_ptr - cc_stack), (int) cc->nargs);
2700 switch (cc - cc_tab) {
2705 if (!mp->ps->subr_tab[a1].valid) {
2706 cs_warn (mp,cs_name, subr, "cannot call subr (%i)", (int) a1);
2714 case CS_CALLOTHERSUBR:
2715 if (cc_get (-1) == 3)
2716 lastargOtherSubr3 = cc_get (-3);
2717 a1 = cc_get (-2) + 2;
2721 cc_push (lastargOtherSubr3);
2722 /* the only case when we care about the value being pushed onto
2723 stack is when POP follows CALLOTHERSUBR (changing hints by
2731 mark_cs (mp,standard_glyph_names[a1]);
2732 mark_cs (mp,standard_glyph_names[a2]);
2741 cs_error: /* an error occured during parsing */
2744 ptr->is_used = false;
2747 static void t1_subset_ascii_part (MP mp, int tex_font, fm_entry *fm_cur)
2751 while (!t1_prefix ("/Encoding")) {
2752 t1_scan_param (mp,tex_font, fm_cur);
2756 t1_builtin_enc (mp);
2757 if (is_reencoded (fm_cur))
2758 mp->ps->t1_glyph_names = external_enc ();
2760 mp->ps->t1_glyph_names = mp->ps->t1_builtin_glyph_names;
2762 |if (is_included (fm_cur) && is_subsetted (fm_cur)) {
2763 make_subset_tag (fm_cur, t1_glyph_names, tex_font);
2764 update_subset_tag ();
2767 if ((!is_subsetted (fm_cur)) && mp->ps->t1_encoding == ENC_STANDARD)
2768 t1_puts (mp,"/Encoding StandardEncoding def\n");
2771 (mp,"/Encoding 256 array\n0 1 255 {1 index exch /.notdef put} for\n");
2772 for (i = 0, j = 0; i < 256; i++) {
2773 if (is_used_char (i) && mp->ps->t1_glyph_names[i] != notdef) {
2775 t1_printf (mp,"dup %i /%s put\n", (int) t1_char (i),
2776 mp->ps->t1_glyph_names[i]);
2779 /* We didn't mark anything for the Encoding array. */
2780 /* We add "dup 0 /.notdef put" for compatibility */
2781 /* with Acrobat 5.0. */
2783 t1_puts (mp,"dup 0 /.notdef put\n");
2784 t1_puts (mp,"readonly def\n");
2788 t1_scan_param (mp,tex_font, fm_cur);
2789 if (!t1_prefix ("/UniqueID")) /* ignore UniqueID for subsetted fonts */
2792 while (mp->ps->t1_in_eexec == 0);
2795 #define t1_subr_flush(mp) t1_flush_cs(mp,true)
2796 #define t1_cs_flush(mp) t1_flush_cs(mp,false)
2798 static void cs_init (MP mp) {
2799 mp->ps->cs_ptr = mp->ps->cs_tab = NULL;
2800 mp->ps->cs_dict_start = mp->ps->cs_dict_end = NULL;
2801 mp->ps->cs_count = mp->ps->cs_size = mp->ps->cs_size_pos = 0;
2802 mp->ps->cs_token_pair = NULL;
2803 mp->ps->subr_tab = NULL;
2804 mp->ps->subr_array_start = mp->ps->subr_array_end = NULL;
2805 mp->ps->subr_max = mp->ps->subr_size = mp->ps->subr_size_pos = 0;
2808 static void init_cs_entry ( cs_entry * cs) {
2810 cs->glyph_name = NULL;
2813 cs->is_used = false;
2817 static void t1_mark_glyphs (MP mp, int tex_font);
2819 static void t1_read_subrs (MP mp, int tex_font, fm_entry *fm_cur)
2824 while (!(t1_charstrings () || t1_subrs ())) {
2825 t1_scan_param (mp,tex_font, fm_cur);
2830 mp->ps->t1_cs = true;
2831 mp->ps->t1_scan = false;
2834 mp->ps->subr_size_pos = strlen ("/Subrs") + 1;
2835 /* |subr_size_pos| points to the number indicating dict size after "/Subrs" */
2836 mp->ps->subr_size = t1_scan_num (mp,mp->ps->t1_line_array + mp->ps->subr_size_pos, 0);
2837 if (mp->ps->subr_size == 0) {
2838 while (!t1_charstrings ())
2842 /* |subr_tab = xtalloc (subr_size, cs_entry);| */
2843 mp->ps->subr_tab = (cs_entry *)mp_xmalloc (mp->ps->subr_size, sizeof (cs_entry));
2844 for (ptr = mp->ps->subr_tab; ptr - mp->ps->subr_tab < mp->ps->subr_size; ptr++)
2845 init_cs_entry (ptr);
2846 mp->ps->subr_array_start = mp_xstrdup (mp->ps->t1_line_array);
2848 while (mp->ps->t1_cslen) {
2852 /* mark the first four entries without parsing */
2853 for (i = 0; i < mp->ps->subr_size && i < 4; i++)
2854 mp->ps->subr_tab[i].is_used = true;
2855 /* the end of the Subrs array might have more than one line so we need to
2856 concatnate them to |subr_array_end|. Unfortunately some fonts don't have
2857 the Subrs array followed by the CharStrings dict immediately (synthetic
2858 fonts). If we cannot find CharStrings in next |POST_SUBRS_SCAN| lines then
2859 we will treat the font as synthetic and ignore everything until next
2862 #define POST_SUBRS_SCAN 5
2864 *mp->ps->t1_buf_array = 0;
2865 for (i = 0; i < POST_SUBRS_SCAN; i++) {
2866 if (t1_charstrings ())
2868 s += mp->ps->t1_line_ptr - mp->ps->t1_line_array;
2869 alloc_array (t1_buf, s, T1_BUF_SIZE);
2870 strcat (mp->ps->t1_buf_array, mp->ps->t1_line_array);
2873 mp->ps->subr_array_end = mp_xstrdup (mp->ps->t1_buf_array);
2874 if (i == POST_SUBRS_SCAN) { /* CharStrings not found;
2875 suppose synthetic font */
2876 for (ptr = mp->ps->subr_tab; ptr - mp->ps->subr_tab < mp->ps->subr_size; ptr++)
2878 mp_xfree (ptr->data);
2879 mp_xfree (mp->ps->subr_tab);
2880 mp_xfree (mp->ps->subr_array_start);
2881 mp_xfree (mp->ps->subr_array_end);
2883 mp->ps->t1_cs = false;
2884 mp->ps->t1_synthetic = true;
2885 while (!(t1_charstrings () || t1_subrs ()))
2892 static void t1_flush_cs (MP mp, boolean is_subr)
2895 byte *r, *return_cs = NULL;
2896 cs_entry *tab, *end_tab, *ptr;
2897 char *start_line, *line_end;
2898 int count, size_pos;
2899 unsigned short cr, cs_len = 0; /* to avoid warning about uninitialized use of |cs_len| */
2901 start_line = mp->ps->subr_array_start;
2902 line_end = mp->ps->subr_array_end;
2903 size_pos = mp->ps->subr_size_pos;
2904 tab = mp->ps->subr_tab;
2905 count = mp->ps->subr_max + 1;
2906 end_tab = mp->ps->subr_tab + count;
2908 start_line = mp->ps->cs_dict_start;
2909 line_end = mp->ps->cs_dict_end;
2910 size_pos = mp->ps->cs_size_pos;
2911 tab = mp->ps->cs_tab;
2912 end_tab = mp->ps->cs_ptr;
2913 count = mp->ps->cs_count;
2915 mp->ps->t1_line_ptr = mp->ps->t1_line_array;
2916 for (p = start_line; p - start_line < size_pos;)
2917 *mp->ps->t1_line_ptr++ = *p++;
2918 while (isdigit (*p))
2920 sprintf (mp->ps->t1_line_ptr, "%u", count);
2921 strcat (mp->ps->t1_line_ptr, p);
2922 mp->ps->t1_line_ptr = eol (mp->ps->t1_line_array);
2925 /* create |return_cs| to replace unsused subr's */
2929 return_cs = mp_xmalloc ( (mp->ps->t1_lenIV + 1) , sizeof(byte));
2930 if ( mp->ps->t1_lenIV > 0) {
2931 for (cs_len = 0, r = return_cs; cs_len < mp->ps->t1_lenIV; cs_len++, r++)
2932 *r = cencrypt (mp,0x00, &cr);
2933 *r = cencrypt (mp,CS_RETURN, &cr);
2935 *return_cs = CS_RETURN;
2940 for (ptr = tab; ptr < end_tab; ptr++) {
2943 sprintf (mp->ps->t1_line_array, "dup %i %u", (int) (ptr - tab),
2946 sprintf (mp->ps->t1_line_array, "/%s %u", ptr->glyph_name, ptr->cslen);
2947 p = strend (mp->ps->t1_line_array);
2948 memcpy (p, ptr->data, ptr->len);
2949 mp->ps->t1_line_ptr = p + ptr->len;
2952 /* replace unsused subr's by |return_cs| */
2954 sprintf (mp->ps->t1_line_array, "dup %i %u%s ", (int) (ptr - tab),
2955 cs_len, mp->ps->cs_token_pair[0]);
2956 p = strend (mp->ps->t1_line_array);
2957 memcpy (p, return_cs, cs_len);
2958 mp->ps->t1_line_ptr = p + cs_len;
2960 sprintf (mp->ps->t1_line_array, " %s", mp->ps->cs_token_pair[1]);
2961 mp->ps->t1_line_ptr = eol (mp->ps->t1_line_array);
2965 mp_xfree (ptr->data);
2966 if (ptr->glyph_name != notdef)
2967 mp_xfree (ptr->glyph_name);
2969 sprintf (mp->ps->t1_line_array, "%s", line_end);
2970 mp->ps->t1_line_ptr = eol (mp->ps->t1_line_array);
2973 mp_xfree (return_cs);
2975 mp_xfree (start_line);
2976 mp_xfree (line_end);
2979 static void t1_mark_glyphs (MP mp, int tex_font)
2982 char *charset = extra_charset ();
2985 if (mp->ps->t1_synthetic || embed_all_glyphs (tex_font)) { /* mark everything */
2986 if (mp->ps->cs_tab != NULL)
2987 for (ptr = mp->ps->cs_tab; ptr < mp->ps->cs_ptr; ptr++)
2989 ptr->is_used = true;
2990 if (mp->ps->subr_tab != NULL) {
2991 for (ptr = mp->ps->subr_tab; ptr - mp->ps->subr_tab < mp->ps->subr_size; ptr++)
2993 ptr->is_used = true;
2994 mp->ps->subr_max = mp->ps->subr_size - 1;
2998 mark_cs (mp,notdef);
2999 for (i = 0; i < 256; i++)
3000 if (is_used_char (i)) {
3001 if (mp->ps->t1_glyph_names[i] == notdef) {
3003 snprintf(s,128, "character %i is mapped to %s", i, notdef);
3006 mark_cs (mp,mp->ps->t1_glyph_names[i]);
3008 if (charset == NULL)
3010 g = s = charset + 1; /* skip the first '/' */
3013 while (*s != '/' && s < r)
3015 *s = 0; /* terminate g by rewriting '/' to 0 */
3020 if (mp->ps->subr_tab != NULL)
3021 for (mp->ps->subr_max = -1, ptr = mp->ps->subr_tab;
3022 ptr - mp->ps->subr_tab < mp->ps->subr_size;
3024 if (ptr->is_used && ptr - mp->ps->subr_tab > mp->ps->subr_max)
3025 mp->ps->subr_max = ptr - mp->ps->subr_tab;
3028 static void t1_subset_charstrings (MP mp, int tex_font)
3031 mp->ps->cs_size_pos =
3032 strstr (mp->ps->t1_line_array, charstringname) + strlen (charstringname)
3033 - mp->ps->t1_line_array + 1;
3034 /* |cs_size_pos| points to the number indicating
3035 dict size after "/CharStrings" */
3036 mp->ps->cs_size = t1_scan_num (mp,mp->ps->t1_line_array + mp->ps->cs_size_pos, 0);
3037 mp->ps->cs_ptr = mp->ps->cs_tab = mp_xmalloc (mp->ps->cs_size, sizeof(cs_entry));
3038 for (ptr = mp->ps->cs_tab; ptr - mp->ps->cs_tab < mp->ps->cs_size; ptr++)
3039 init_cs_entry (ptr);
3040 mp->ps->cs_notdef = NULL;
3041 mp->ps->cs_dict_start = mp_xstrdup (mp->ps->t1_line_array);
3043 while (mp->ps->t1_cslen) {
3047 mp->ps->cs_dict_end = mp_xstrdup (mp->ps->t1_line_array);
3048 t1_mark_glyphs (mp,tex_font);
3049 if (mp->ps->subr_tab != NULL) {
3050 if (mp->ps->cs_token_pair == NULL)
3052 (mp, "This Type 1 font uses mismatched subroutine begin/end token pairs.");
3055 for (mp->ps->cs_count = 0, ptr = mp->ps->cs_tab; ptr < mp->ps->cs_ptr; ptr++)
3061 static void t1_subset_end (MP mp)
3063 if (mp->ps->t1_synthetic) { /* copy to "dup /FontName get exch definefont pop" */
3064 while (!strstr (mp->ps->t1_line_array, "definefont")) {
3068 while (!t1_end_eexec ())
3069 t1_getline (mp); /* ignore the rest */
3070 t1_putline (mp); /* write "mark currentfile closefile" */
3072 while (!t1_end_eexec ()) { /* copy to "mark currentfile closefile" */
3077 if (fixedcontent) { /* copy 512 zeros (not needed for PDF) */
3078 while (!t1_cleartomark ()) {
3082 if (!mp->ps->t1_synthetic) /* don't check "{restore}if" for synthetic fonts */
3083 t1_check_end (mp); /* write "{restore}if" if found */
3087 static int t1_updatefm (MP mp, int f, fm_entry *fm)
3090 mp->ps->read_encoding_only = true;
3091 if (!t1_open_fontfile (mp,fm,NULL)) {
3094 t1_scan_only (mp,f, fm);
3095 s = mp_xstrdup(mp->ps->fontname_buf);
3097 while (*p != ' ' && *p != 0)
3101 t1_close_font_file (mp,"");
3106 static void writet1 (MP mp, int tex_font, fm_entry *fm_cur) {
3107 int save_selector = mp->selector;
3108 mp_normalize_selector(mp);
3109 mp->ps->read_encoding_only = false;
3110 if (!is_included (fm_cur)) { /* scan parameters from font file */
3111 if (!t1_open_fontfile (mp,fm_cur,"{"))
3113 t1_scan_only (mp,tex_font, fm_cur);
3114 t1_close_font_file (mp,"}");
3117 if (!is_subsetted (fm_cur)) { /* include entire font */
3118 if (!t1_open_fontfile (mp,fm_cur,"<<"))
3120 t1_include (mp,tex_font,fm_cur);
3121 t1_close_font_file (mp,">>");
3124 /* partial downloading */
3125 if (!t1_open_fontfile (mp,fm_cur,"<"))
3127 t1_subset_ascii_part (mp,tex_font,fm_cur);
3128 t1_start_eexec (mp,fm_cur);
3131 t1_read_subrs (mp,tex_font, fm_cur);
3132 t1_subset_charstrings (mp,tex_font);
3134 t1_close_font_file (mp,">");
3135 mp->selector = save_selector;
3139 static void t1_free (MP mp);
3142 static void t1_free (MP mp) {
3143 mp_xfree (mp->ps->t1_line_array);
3144 mp_xfree (mp->ps->t1_buf_array);
3148 @* \[44d] Embedding fonts.
3150 @ The |tfm_num| is officially of type |font_number|, but that
3151 type does not exist yet at this point in the output order.
3155 char *tfm_name; /* TFM file name */
3156 char *ps_name; /* PostScript name */
3157 integer flags; /* font flags */
3158 char *ff_name; /* font file name */
3159 char *subset_tag; /* pseudoUniqueTag for subsetted font */
3160 enc_entry *encoding; /* pointer to corresponding encoding */
3161 unsigned int tfm_num; /* number of the TFM refering this entry */
3162 unsigned short type; /* font type (T1/TTF/...) */
3163 short slant; /* SlantFont */
3164 short extend; /* ExtendFont */
3165 integer ff_objnum; /* FontFile object number */
3166 integer fn_objnum; /* FontName/BaseName object number */
3167 integer fd_objnum; /* FontDescriptor object number */
3168 char *charset; /* string containing used glyphs */
3169 boolean all_glyphs; /* embed all glyphs? */
3170 unsigned short links; /* link flags from |tfm_tree| and |ps_tree| */
3171 short tfm_avail; /* flags whether a tfm is available */
3172 short pid; /* Pid for truetype fonts */
3173 short eid; /* Eid for truetype fonts */
3179 #define FONTNAME_BUF_SIZE 128
3180 boolean fontfile_found;
3181 boolean is_otf_font;
3182 char fontname_buf[FONTNAME_BUF_SIZE];
3190 @d set_included(fm) ((fm)->type |= F_INCLUDED)
3191 @d set_subsetted(fm) ((fm)->type |= F_SUBSETTED)
3192 @d set_truetype(fm) ((fm)->type |= F_TRUETYPE)
3193 @d set_basefont(fm) ((fm)->type |= F_BASEFONT)
3195 @d is_included(fm) ((fm)->type & F_INCLUDED)
3196 @d is_subsetted(fm) ((fm)->type & F_SUBSETTED)
3197 @d is_truetype(fm) ((fm)->type & F_TRUETYPE)
3198 @d is_basefont(fm) ((fm)->type & F_BASEFONT)
3199 @d is_reencoded(fm) ((fm)->encoding != NULL)
3200 @d is_fontfile(fm) (fm_fontfile(fm) != NULL)
3201 @d is_t1fontfile(fm) (is_fontfile(fm) && !is_truetype(fm))
3203 @d fm_slant(fm) (fm)->slant
3204 @d fm_extend(fm) (fm)->extend
3205 @d fm_fontfile(fm) (fm)->ff_name
3207 @<Exported function headers@>=
3208 boolean mp_font_is_reencoded (MP mp, int f);
3209 boolean mp_font_is_included (MP mp, int f);
3210 boolean mp_font_is_subsetted (MP mp, int f);
3213 boolean mp_font_is_reencoded (MP mp, int f) {
3215 if (mp_has_font_size(mp,f) && mp_has_fm_entry (mp, f, &fm)) {
3217 && (fm->ps_name != NULL)
3218 && is_reencoded (fm))
3223 boolean mp_font_is_included (MP mp, int f) {
3225 if (mp_has_font_size(mp,f) && mp_has_fm_entry (mp, f, &fm)) {
3227 && (fm->ps_name != NULL && fm->ff_name != NULL)
3228 && is_included (fm))
3233 boolean mp_font_is_subsetted (MP mp, int f) {
3235 if (mp_has_font_size(mp,f) && mp_has_fm_entry (mp, f,&fm)) {
3237 && (fm->ps_name != NULL && fm->ff_name != NULL)
3238 && is_included (fm) && is_subsetted (fm))
3244 @ @<Exported function headers@>=
3245 char * mp_fm_encoding_name (MP mp, int f);
3246 char * mp_fm_font_name (MP mp, int f);
3247 char * mp_fm_font_subset_name (MP mp, int f);
3250 @c char * mp_fm_encoding_name (MP mp, int f) {
3253 if (mp_has_fm_entry (mp, f, &fm)) {
3254 if (fm != NULL && (fm->ps_name != NULL)) {
3255 if (is_reencoded (fm)) {
3257 if (e->enc_name!=NULL)
3258 return mp_xstrdup(e->enc_name);
3264 print_err ("fontmap encoding problems for font ");
3265 mp_print(mp,mp->font_name[f]);
3269 char * mp_fm_font_name (MP mp, int f) {
3271 if (mp_has_fm_entry (mp, f,&fm)) {
3272 if (fm != NULL && (fm->ps_name != NULL)) {
3273 if (mp_font_is_included(mp, f) && !mp->font_ps_name_fixed[f]) {
3274 /* find the real fontname, and update |ps_name| and |subset_tag| if needed */
3275 if (t1_updatefm(mp,f,fm)) {
3276 mp->font_ps_name_fixed[f] = true;
3278 print_err ("font loading problems for font ");
3279 mp_print(mp,mp->font_name[f]);
3283 return mp_xstrdup(fm->ps_name);
3286 print_err ("fontmap name problems for font ");
3287 mp_print(mp,mp->font_name[f]);
3292 char * mp_fm_font_subset_name (MP mp, int f) {
3294 if (mp_has_fm_entry (mp, f, &fm)) {
3295 if (fm != NULL && (fm->ps_name != NULL)) {
3296 if (is_subsetted(fm)) {
3297 char *s = mp_xmalloc(strlen(fm->ps_name)+8,1);
3298 snprintf(s,strlen(fm->ps_name)+8,"%s-%s",fm->subset_tag,fm->ps_name);
3301 return mp_xstrdup(fm->ps_name);
3305 print_err ("fontmap name problems for font ");
3306 mp_print(mp,mp->font_name[f]);
3311 @ @<Exported function headers@>=
3312 integer mp_fm_font_slant (MP mp, int f);
3313 integer mp_fm_font_extend (MP mp, int f);
3316 @c integer mp_fm_font_slant (MP mp, int f) {
3318 if (mp_has_fm_entry (mp, f, &fm)) {
3319 if (fm != NULL && (fm->ps_name != NULL)) {
3325 integer mp_fm_font_extend (MP mp, int f) {
3327 if (mp_has_fm_entry (mp, f, &fm)) {
3328 if (fm != NULL && (fm->ps_name != NULL)) {
3335 @ @<Exported function headers@>=
3336 boolean mp_do_ps_font (MP mp, font_number f);
3338 @ @c boolean mp_do_ps_font (MP mp, font_number f) {
3340 (void)mp_has_fm_entry (mp, f, &fm_cur); /* for side effects */
3343 if (is_truetype(fm_cur) ||
3344 (fm_cur->ps_name == NULL && fm_cur->ff_name == NULL)) {
3347 if (is_included(fm_cur)) {
3348 mp_print_nl(mp,"%%BeginResource: font ");
3349 if (is_subsetted(fm_cur)) {
3350 mp_print(mp, fm_cur->subset_tag);
3351 mp_print_char(mp,'-');
3353 mp_print(mp, fm_cur->ps_name);
3355 writet1 (mp,f,fm_cur);
3356 mp_print_nl(mp,"%%EndResource");
3362 @ Included subset fonts do not need and encoding vector, make
3363 sure we skip that case.
3366 void mp_list_used_resources (MP mp, int prologues, int procset);
3368 @ @c void mp_list_used_resources (MP mp, int prologues, int procset) {
3369 font_number f; /* fonts used in a text node or as loop counters */
3370 int ff; /* a loop counter */
3371 font_number ldf; /* the last \.{DocumentFont} listed (otherwise |null_font|) */
3374 mp_print_nl(mp, "%%DocumentResources: procset mpost");
3376 mp_print_nl(mp, "%%DocumentResources: procset mpost-minimal");
3379 for (f=null_font+1;f<=mp->last_fnum;f++) {
3380 if ( (mp_has_font_size(mp,f))&&(mp_font_is_reencoded(mp,f)) ) {
3381 for (ff=ldf;ff>=null_font;ff--) {
3382 if ( mp_has_font_size(mp,ff) )
3383 if ( mp_xstrcmp(mp->font_enc_name[f],mp->font_enc_name[ff])==0 )
3386 if ( mp_font_is_subsetted(mp,f) )
3388 if ( mp->ps_offset+1+strlen(mp->font_enc_name[f])>
3389 (unsigned)mp->max_print_line )
3390 mp_print_nl(mp, "%%+ encoding");
3393 mp_print_nl(mp, "%%+ encoding");
3395 mp_print_char(mp, ' ');
3396 mp_print(mp, mp->font_enc_name[f]);
3404 for (f=null_font+1;f<=mp->last_fnum;f++) {
3405 if ( mp_has_font_size(mp,f) ) {
3406 for (ff=ldf;ff>=null_font;ff--) {
3407 if ( mp_has_font_size(mp,ff) )
3408 if ( mp_xstrcmp(mp->font_name[f],mp->font_name[ff])==0 )
3411 if ( mp->ps_offset+1+strlen(mp->font_ps_name[f])>
3412 (unsigned)mp->max_print_line )
3413 mp_print_nl(mp, "%%+ font");
3416 mp_print_nl(mp, "%%+ font");
3418 mp_print_char(mp, ' ');
3419 if ( (prologues==3)&&
3420 (mp_font_is_subsetted(mp,f)) )
3421 mp_print(mp, mp_fm_font_subset_name(mp,f));
3423 mp_print(mp, mp->font_ps_name[f]);
3433 void mp_list_supplied_resources (MP mp, int prologues, int procset);
3435 @ @c void mp_list_supplied_resources (MP mp, int prologues, int procset) {
3436 font_number f; /* fonts used in a text node or as loop counters */
3437 int ff; /* a loop counter */
3438 font_number ldf; /* the last \.{DocumentFont} listed (otherwise |null_font|) */
3441 mp_print_nl(mp, "%%DocumentSuppliedResources: procset mpost");
3443 mp_print_nl(mp, "%%DocumentSuppliedResources: procset mpost-minimal");
3446 for (f=null_font+1;f<=mp->last_fnum;f++) {
3447 if ( (mp_has_font_size(mp,f))&&(mp_font_is_reencoded(mp,f)) ) {
3448 for (ff=ldf;ff>= null_font;ff++) {
3449 if ( mp_has_font_size(mp,ff) )
3450 if ( mp_xstrcmp(mp->font_enc_name[f],mp->font_enc_name[ff])==0 )
3453 if ( (prologues==3)&&(mp_font_is_subsetted(mp,f)))
3455 if ( mp->ps_offset+1+strlen(mp->font_enc_name[f])>(unsigned)mp->max_print_line )
3456 mp_print_nl(mp, "%%+ encoding");
3459 mp_print_nl(mp, "%%+ encoding");
3461 mp_print_char(mp, ' ');
3462 mp_print(mp, mp->font_enc_name[f]);
3471 for (f=null_font+1;f<=mp->last_fnum;f++) {
3472 if ( mp_has_font_size(mp,f) ) {
3473 for (ff=ldf;ff>= null_font;ff--) {
3474 if ( mp_has_font_size(mp,ff) )
3475 if ( mp_xstrcmp(mp->font_name[f],mp->font_name[ff])==0 )
3478 if ( ! mp_font_is_included(mp,f) )
3480 if ( mp->ps_offset+1+strlen(mp->font_ps_name[f])>(unsigned)mp->max_print_line )
3481 mp_print_nl(mp, "%%+ font");
3484 mp_print_nl(mp, "%%+ font");
3486 mp_print_char(mp, ' ');
3487 if ( mp_font_is_subsetted(mp,f) )
3488 mp_print(mp, mp_fm_font_subset_name(mp,f));
3490 mp_print(mp, mp->font_ps_name[f]);
3501 void mp_list_needed_resources (MP mp, int prologues);
3503 @ @c void mp_list_needed_resources (MP mp, int prologues) {
3504 font_number f; /* fonts used in a text node or as loop counters */
3505 int ff; /* a loop counter */
3506 font_number ldf; /* the last \.{DocumentFont} listed (otherwise |null_font|) */
3510 for (f=null_font+1;f<=mp->last_fnum;f++ ) {
3511 if ( mp_has_font_size(mp,f)) {
3512 for (ff=ldf;ff>=null_font;ff--) {
3513 if ( mp_has_font_size(mp,ff) )
3514 if ( mp_xstrcmp(mp->font_name[f],mp->font_name[ff])==0 )
3517 if ((prologues==3)&&(mp_font_is_included(mp,f)) )
3519 if ( mp->ps_offset+1+strlen(mp->font_ps_name[f])>(unsigned)mp->max_print_line )
3520 mp_print_nl(mp, "%%+ font");
3523 mp_print_nl(mp, "%%DocumentNeededResources: font");
3525 mp_print_char(mp, ' ');
3526 mp_print(mp, mp->font_ps_name[f]);
3532 if ( ! firstitem ) {
3536 for (f=null_font+1;f<= mp->last_fnum;f++) {
3537 if ( mp_has_font_size(mp,f) ) {
3538 for (ff=ldf;ff>=null_font;ff-- ) {
3539 if ( mp_has_font_size(mp,ff) )
3540 if ( mp_xstrcmp(mp->font_name[f],mp->font_name[ff])==0 )
3543 if ((prologues==3)&&(mp_font_is_included(mp,f)) )
3545 mp_print(mp, "%%IncludeResource: font ");
3546 mp_print(mp, mp->font_ps_name[f]);
3557 void mp_write_font_definition (MP mp, font_number f, int prologues);
3561 @d applied_reencoding(A) ((mp_font_is_reencoded(mp,(A)))&&
3562 ((! mp_font_is_subsetted(mp,(A)))||(prologues==2)))
3564 @c void mp_write_font_definition(MP mp, font_number f, int prologues) {
3565 if ( (applied_reencoding(f))||(mp_fm_font_slant(mp,f)!=0)||
3566 (mp_fm_font_extend(mp,f)!=0)||
3567 (mp_xstrcmp(mp->font_name[f],"psyrgo")==0)||
3568 (mp_xstrcmp(mp->font_name[f],"zpzdr-reversed")==0) ) {
3569 if ( (mp_font_is_subsetted(mp,f))&&
3570 (mp_font_is_included(mp,f))&&(prologues==3))
3571 mp_ps_name_out(mp, mp_fm_font_subset_name(mp,f),true);
3573 mp_ps_name_out(mp, mp->font_ps_name[f],true);
3574 mp_ps_print(mp, " fcp");
3576 if ( applied_reencoding(f) ) {
3577 mp_ps_print(mp, "/Encoding ");
3578 mp_ps_print(mp, mp->font_enc_name[f]);
3579 mp_ps_print(mp, " def ");
3581 if ( mp_fm_font_slant(mp,f)!=0 ) {
3582 mp_print_int(mp, mp_fm_font_slant(mp,f));
3583 mp_ps_print(mp, " SlantFont ");
3585 if ( mp_fm_font_extend(mp,f)!=0 ) {
3586 mp_print_int(mp, mp_fm_font_extend(mp,f));
3587 mp_ps_print(mp, " ExtendFont ");
3589 if ( mp_xstrcmp(mp->font_name[f],"psyrgo")==0 ) {
3590 mp_ps_print(mp, " 890 ScaleFont ");
3591 mp_ps_print(mp, " 277 SlantFont ");
3593 if ( mp_xstrcmp(mp->font_name[f],"zpzdr-reversed")==0 ) {
3594 mp_ps_print(mp, " FontMatrix [-1 0 0 1 0 0] matrix concatmatrix /FontMatrix exch def ");
3595 mp_ps_print(mp, "/Metrics 2 dict dup begin ");
3596 mp_ps_print(mp, "/space[0 -278]def ");
3597 mp_ps_print(mp, "/a12[-904 -939]def ");
3598 mp_ps_print(mp, "end def ");
3600 mp_ps_print(mp, "currentdict end");
3602 mp_ps_print_defined_name(mp,f,prologues);
3603 mp_ps_print(mp, " exch definefont pop");
3609 void mp_ps_print_defined_name (MP mp, font_number f, int prologues);
3612 @c void mp_ps_print_defined_name(MP mp, font_number A, int prologues) {
3613 mp_ps_print(mp, " /");
3614 if ((mp_font_is_subsetted(mp,(A)))&&
3615 (mp_font_is_included(mp,(A)))&&(prologues==3))
3616 mp_print(mp, mp_fm_font_subset_name(mp,(A)));
3618 mp_print(mp, mp->font_ps_name[(A)]);
3619 if ( mp_xstrcmp(mp->font_name[(A)],"psyrgo")==0 )
3620 mp_ps_print(mp, "-Slanted");
3621 if ( mp_xstrcmp(mp->font_name[(A)],"zpzdr-reversed")==0 )
3622 mp_ps_print(mp, "-Reverse");
3623 if ( applied_reencoding((A)) ) {
3624 mp_ps_print(mp, "-");
3625 mp_ps_print(mp, mp->font_enc_name[(A)]);
3627 if ( mp_fm_font_slant(mp,(A))!=0 ) {
3628 mp_ps_print(mp, "-Slant_"); mp_print_int(mp, mp_fm_font_slant(mp,(A))) ;
3630 if ( mp_fm_font_extend(mp,(A))!=0 ) {
3631 mp_ps_print(mp, "-Extend_"); mp_print_int(mp, mp_fm_font_extend(mp,(A)));
3635 @ @<Include encodings and fonts for edge structure~|h|@>=
3636 mp_font_encodings(mp,mp->last_fnum,prologues==2);
3637 @<Embed fonts that are available@>
3639 @ @<Embed fonts that are available@>=
3642 @<Make |cur_fsize| a copy of the |font_sizes| array@>;
3645 for (f=null_font+1;f<=mp->last_fnum;f++) {
3646 if ( cur_fsize[f]!=null ) {
3647 if (prologues==3 ) {
3648 if ( ! mp_do_ps_font(mp,f) ) {
3649 if ( mp_has_fm_entry(mp,f, NULL) ) {
3650 print_err("Font embedding failed");
3655 cur_fsize[f]=link(cur_fsize[f]);
3656 if ( cur_fsize[f]!=null ) { mp_unmark_font(mp, f); done_fonts=false; }
3660 @<Increment |next_size| and apply |mark_string_chars| to all text nodes with
3662 } while (! done_fonts);
3665 @ @<Increment |next_size| and apply |mark_string_chars| to all text nodes...@>=
3668 mp_apply_mark_string_chars(mp, h, next_size);
3671 @ We also need to keep track of which characters are used in text nodes
3672 in the edge structure that is being shipped out. This is done by procedures
3673 that use the left-over |b3| field in the |char_info| words; i.e.,
3674 |char_info(f)(c).b3| gives the status of character |c| in font |f|.
3677 enum {unused=0, used};
3680 void mp_unmark_font (MP mp,font_number f) ;
3683 void mp_unmark_font (MP mp,font_number f) {
3684 int k; /* an index into |font_info| */
3685 for (k= mp->char_base[f]+mp->font_bc[f];
3686 k<=mp->char_base[f]+mp->font_ec[f];
3688 mp->font_info[k].qqqq.b3=unused;
3693 void mp_print_improved_prologue (MP mp, int prologues, int procset,
3694 int groffmode, int null, pointer h) ;
3699 void mp_print_improved_prologue (MP mp, int prologues, int procset,
3700 int groffmode, int null, pointer h) {
3701 quarterword next_size; /* the size index for fonts being listed */
3702 pointer *cur_fsize; /* current positions in |font_sizes| */
3703 boolean done_fonts; /* have we finished listing the fonts in the header? */
3704 font_number f; /* a font number for loops */
3706 cur_fsize = mp_xmalloc((mp->font_max+1),sizeof(pointer));
3708 mp_list_used_resources(mp, prologues, procset);
3709 mp_list_supplied_resources(mp, prologues, procset);
3710 mp_list_needed_resources(mp, prologues);
3711 mp_print_nl(mp, "%%EndComments");
3712 mp_print_nl(mp, "%%BeginProlog");
3714 mp_print_nl(mp, "%%BeginResource: procset mpost");
3716 mp_print_nl(mp, "%%BeginResource: procset mpost-minimal");
3717 mp_print_nl(mp, "/bd{bind def}bind def"
3718 "/fshow {exch findfont exch scalefont setfont show}bd");
3719 if ( procset>0 ) @<Print the procset@>;
3720 mp_print_nl(mp, "/fcp{findfont dup length dict begin"
3721 "{1 index/FID ne{def}{pop pop}ifelse}forall}bd");
3722 mp_print_nl(mp, "/fmc{FontMatrix dup length array copy dup dup}bd"
3723 "/fmd{/FontMatrix exch def}bd");
3724 mp_print_nl(mp, "/Amul{4 -1 roll exch mul 1000 div}bd"
3725 "/ExtendFont{fmc 0 get Amul 0 exch put fmd}bd");
3726 if ( groffmode>0 ) {
3727 mp_print_nl(mp, "/ScaleFont{dup fmc 0 get"
3728 " Amul 0 exch put dup dup 3 get Amul 3 exch put fmd}bd");
3730 mp_print_nl(mp, "/SlantFont{fmc 2 get dup 0 eq{pop 1}if"
3731 " Amul FontMatrix 0 get mul 2 exch put fmd}bd");
3732 mp_print_nl(mp, "%%EndResource");
3733 @<Include encodings and fonts for edge structure~|h|@>;
3734 mp_print_nl(mp, "%%EndProlog");
3735 mp_print_nl(mp, "%%BeginSetup");
3737 for (f=null_font+1;f<=mp->last_fnum;f++) {
3738 if ( mp_has_font_size(mp,f) ) {
3739 if ( mp_has_fm_entry(mp,f,NULL) ) {
3740 mp_write_font_definition(mp,f,(mp->internal[prologues]>>16));
3741 mp_ps_name_out(mp, mp->font_name[f],true);
3742 mp_ps_print_defined_name(mp,f,(mp->internal[prologues]>>16));
3743 mp_ps_print(mp, " def");
3746 snprintf(s,256,"font %s cannot be found in any fontmapfile!", mp->font_name[f]);
3748 mp_ps_name_out(mp, mp->font_name[f],true);
3749 mp_ps_name_out(mp, mp->font_name[f],true);
3750 mp_ps_print(mp, " def");
3755 mp_print_nl(mp, "%%EndSetup");
3756 mp_print_nl(mp, "%%Page: 1 1");
3758 mp_xfree(cur_fsize);
3762 font_number mp_print_font_comments (MP mp , int prologues, int null, pointer h);
3767 font_number mp_print_font_comments (MP mp , int prologues, int null, pointer h) {
3768 quarterword next_size; /* the size index for fonts being listed */
3769 pointer *cur_fsize; /* current positions in |font_sizes| */
3770 int ff; /* a loop counter */
3771 boolean done_fonts; /* have we finished listing the fonts in the header? */
3772 font_number f; /* a font number for loops */
3773 scaled ds; /* design size and scale factor for a text node */
3774 font_number ldf=0; /* the last \.{DocumentFont} listed (otherwise |null_font|) */
3775 cur_fsize = mp_xmalloc((mp->font_max+1),sizeof(pointer));
3776 if ( prologues>0 ) {
3777 @<Give a \.{DocumentFonts} comment listing all fonts with non-null
3778 |font_sizes| and eliminate duplicates@>;
3781 @<Make |cur_fsize| a copy of the |font_sizes| array@>;
3782 do { done_fonts=true;
3783 for (f=null_font+1;f<=mp->last_fnum;f++) {
3784 if ( cur_fsize[f]!=null ) {
3785 @<Print the \.{\%*Font} comment for font |f| and advance |cur_fsize[f]|@>;
3787 if ( cur_fsize[f]!=null ) { mp_unmark_font(mp, f); done_fonts=false; };
3789 if ( ! done_fonts ) {
3790 @<Increment |next_size| and apply |mark_string_chars| to all text nodes with
3793 } while (! done_fonts);
3795 mp_xfree(cur_fsize);
3799 @ @<Make |cur_fsize| a copy of the |font_sizes| array@>=
3800 for (f=null_font+1;f<= mp->last_fnum;f++)
3801 cur_fsize[f]=mp->font_sizes[f]
3803 @ It's not a good idea to make any assumptions about the |font_ps_name| entries,
3804 so we carefully remove duplicates. There is no harm in using a slow, brute-force
3807 @<Give a \.{DocumentFonts} comment listing all fonts with non-null...@>=
3810 for (f=null_font+1;f<= mp->last_fnum;f++) {
3811 if ( mp->font_sizes[f]!=null ) {
3812 if ( ldf==null_font )
3813 mp_print_nl(mp, "%%DocumentFonts:");
3814 for (ff=ldf;ff>=null_font;ff--) {
3815 if ( mp->font_sizes[ff]!=null )
3816 if ( mp_xstrcmp(mp->font_ps_name[f],mp->font_ps_name[ff])==0 )
3819 if ( mp->ps_offset+1+strlen(mp->font_ps_name[f])>(unsigned)mp->max_print_line )
3820 mp_print_nl(mp, "%%+");
3821 mp_print_char(mp, ' ');
3822 mp_print(mp, mp->font_ps_name[f]);
3831 void mp_hex_digit_out (MP mp,small_number d) {
3832 if ( d<10 ) mp_print_char(mp, d+'0');
3833 else mp_print_char(mp, d+'a'-10);
3836 @ We output the marks as a hexadecimal bit string starting at |c| or
3837 |font_bc[f]|, whichever is greater. If the output has to be truncated
3838 to avoid exceeding |emergency_line_length| the return value says where to
3839 start scanning next time.
3842 halfword mp_ps_marks_out (MP mp,font_number f, eight_bits c);
3845 @d emergency_line_length 255
3846 /* \ps\ output lines can be this long in unusual circumstances */
3849 halfword mp_ps_marks_out (MP mp,font_number f, eight_bits c) {
3850 eight_bits bc,ec; /* only encode characters between these bounds */
3851 integer lim; /* the maximum number of marks to encode before truncating */
3852 int p; /* |font_info| index for the current character */
3853 int d,b; /* used to construct a hexadecimal digit */
3854 lim=4*(emergency_line_length-mp->ps_offset-4);
3858 @<Restrict the range |bc..ec| so that it contains no unused characters
3859 at either end and has length at most |lim|@>;
3860 @<Print the initial label indicating that the bitmap starts at |bc|@>;
3861 @<Print a hexadecimal encoding of the marks for characters |bc..ec|@>;
3862 while ( (ec<mp->font_ec[f])&&(mp->font_info[p].qqqq.b3==unused) ) {
3868 @ We could save time by setting the return value before the loop that
3869 decrements |ec|, but there is no point in being so tricky.
3871 @<Restrict the range |bc..ec| so that it contains no unused characters...@>=
3872 p=mp->char_base[f]+bc;
3873 while ( (mp->font_info[p].qqqq.b3==unused)&&(bc<ec) ) {
3876 if ( ec>=bc+lim ) ec=bc+lim-1;
3877 p=mp->char_base[f]+ec;
3878 while ( (mp->font_info[p].qqqq.b3==unused)&&(bc<ec) ) {
3882 @ @<Print the initial label indicating that the bitmap starts at |bc|@>=
3883 mp_print_char(mp, ' ');
3884 mp_hex_digit_out(mp, bc / 16);
3885 mp_hex_digit_out(mp, bc % 16);
3886 mp_print_char(mp, ':')
3890 @<Print a hexadecimal encoding of the marks for characters |bc..ec|@>=
3892 for (p=mp->char_base[f]+bc;p<=mp->char_base[f]+ec;p++) {
3894 mp_hex_digit_out(mp, d);
3897 if ( mp->font_info[p].qqqq.b3!=unused ) d=d+b;
3900 mp_hex_digit_out(mp, d)
3903 @ Here is a simple function that determines whether there are any marked
3904 characters in font~|f| with character code at least~|c|.
3907 boolean mp_check_ps_marks (MP mp,font_number f, integer c) ;
3910 boolean mp_check_ps_marks (MP mp,font_number f, integer c) {
3911 int p; /* |font_info| index for the current character */
3912 for (p=mp->char_base[f]+c;p<=mp->char_base[f]+mp->font_ec[f];p++) {
3913 if ( mp->font_info[p].qqqq.b3==used )
3920 @ If the file name is so long that it can't be printed without exceeding
3921 |emergency_line_length| then there will be missing items in the \.{\%*Font:}
3922 line. We might have to repeat line in order to get the character usage
3923 information to fit within |emergency_line_length|.
3925 TODO: these two defines are also defined in mp.w!
3927 @d link(A) mp->mem[(A)].hh.rh /* the |link| field of a memory word */
3928 @d sc_factor(A) mp->mem[(A)+1].cint /* the scale factor stored in a font size node */
3930 @<Print the \.{\%*Font} comment for font |f| and advance |cur_fsize[f]|@>=
3932 while ( mp_check_ps_marks(mp, f,t) ) {
3933 mp_print_nl(mp, "%*Font: ");
3934 if ( mp->ps_offset+strlen(mp->font_name[f])+12>emergency_line_length )
3936 mp_print(mp, mp->font_name[f]);
3937 mp_print_char(mp, ' ');
3938 ds=(mp->font_dsize[f] + 8) / 16;
3939 mp_print_scaled(mp, mp_take_scaled(mp, ds,sc_factor(cur_fsize[f])));
3940 if ( mp->ps_offset+12>emergency_line_length ) break;
3941 mp_print_char(mp, ' ');
3942 mp_print_scaled(mp, ds);
3943 if ( mp->ps_offset+5>emergency_line_length ) break;
3944 t=mp_ps_marks_out(mp, f,t);
3946 cur_fsize[f]=link(cur_fsize[f]);
3949 @ @<Print the procset@>=
3951 mp_print_nl(mp, "/hlw{0 dtransform exch truncate exch idtransform pop setlinewidth}bd");
3952 mp_print_nl(mp, "/vlw{0 exch dtransform truncate idtransform setlinewidth pop}bd");
3953 mp_print_nl(mp, "/l{lineto}bd/r{rlineto}bd/c{curveto}bd/m{moveto}bd"
3954 "/p{closepath}bd/n{newpath}bd");
3955 mp_print_nl(mp, "/C{setcmykcolor}bd/G{setgray}bd/R{setrgbcolor}bd"
3956 "/lj{setlinejoin}bd/ml{setmiterlimit}bd");
3957 mp_print_nl(mp, "/lc{setlinecap}bd/S{stroke}bd/F{fill}bd/q{gsave}bd"
3958 "/Q{grestore}bd/s{scale}bd/t{concat}bd");
3959 mp_print_nl(mp, "/sd{setdash}bd/rd{[] 0 setdash}bd/P{showpage}bd/B{q F Q}bd/W{clip}bd");
3963 @ The prologue defines \.{fshow} and corrects for the fact that \.{fshow}
3964 arguments use |font_name| instead of |font_ps_name|. Downloaded bitmap fonts
3965 might not have reasonable |font_ps_name| entries, but we just charge ahead
3966 anyway. The user should not make \&{prologues} positive if this will cause
3968 @:prologues_}{\&{prologues} primitive@>
3971 void mp_print_prologue (MP mp, int prologues, int procset, int ldf);
3974 void mp_print_prologue (MP mp, int prologues, int procset, int ldf) {
3976 mp_print(mp, "%%BeginProlog"); mp_print_ln(mp);
3977 if ( (prologues>0)||(procset>0) ) {
3978 if ( ldf!=null_font ) {
3979 if ( prologues>0 ) {
3980 for (f=null_font+1;f<=mp->last_fnum;f++) {
3981 if ( mp_has_font_size(mp,f) ) {
3982 mp_ps_name_out(mp, mp->font_name[f],true);
3983 mp_ps_name_out(mp, mp->font_ps_name[f],true);
3984 mp_ps_print(mp, " def");
3989 mp_print(mp, "/fshow {exch findfont exch scalefont setfont show}bind def");
3995 mp_print_nl(mp, "%%BeginResource: procset mpost");
3996 if ( (prologues>0)&&(ldf!=null_font) )
3998 "/bd{bind def}bind def/fshow {exch findfont exch scalefont setfont show}bd");
4000 mp_print_nl(mp, "/bd{bind def}bind def");
4001 @<Print the procset@>;
4002 mp_print_nl(mp, "%%EndResource");
4006 mp_print(mp, "%%EndProlog");