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}
50 @d incr(A) (A)=(A)+1 /* increase a variable by unity */
51 @d decr(A) (A)=(A)-1 /* decrease a variable by unity */
52 @d negate(A) (A)=-(A) /* change the sign of a variable */
54 @d print_err(A) mp_print_err(mp,(A))
64 #include "mpmp.h" /* internal header */
65 #include "mppsout.h" /* internal header */
68 @<Static variables in the outer block@>;
70 @ There is a small bit of code from the backend that bleads through
71 to the frontend because I do not know how to set up the includes
72 properly. Those are the definitions of |struct libavl_allocator|
73 and |typedef struct psout_data_struct * psout_data|.
75 The |libavl_allocator| is a trick that makes sure that frontends
76 do not need |avl.h|, and the |psout_data| is needed for the backend
81 typedef struct psout_data_struct {
84 @<Exported function headers@>
86 @ @<Exported function headers@>=
87 void mp_backend_initialize (MP mp) ;
88 void mp_backend_free (MP mp) ;
91 @c void mp_backend_initialize (MP mp) {
92 mp->ps = mp_xmalloc(mp,1,sizeof(psout_data_struct));
93 @<Set initial values@>;
95 void mp_backend_free (MP mp) {
96 @<Dealloc variables@>;
105 @* Traditional {psfonts.map} loading.
107 TODO: It is likely that this code can be removed after a few minor tweaks.
109 @ The file |ps_tab_file| gives a table of \TeX\ font names and corresponding
110 PostScript names for fonts that do not have to be downloaded, i.e., fonts that
111 can be used when |internal[prologues]>0|. Each line consists of a \TeX\ name,
112 one or more spaces, a PostScript name, and possibly a space and some other junk.
113 This routine reads the table, updates |font_ps_name| entries starting after
114 |last_ps_fnum|, and sets |last_ps_fnum:=last_fnum|. If the file |ps_tab_file|
115 is missing, we assume that the existing font names are OK and nothing needs to
118 @d ps_tab_name "psfonts.map" /* locates font name translation table */
121 static void mp_read_psname_table (MP mp) ;
123 @ @c static void mp_read_psname_table (MP mp) {
124 font_number k; /* font for possible name match */
125 unsigned int lmax; /* upper limit on length of name to match */
126 unsigned int j; /* characters left to read before string gets too long */
127 char *s; /* possible font name to match */
128 text_char c=0; /* character being read from |ps_tab_file| */
129 if ( (mp->ps->ps_tab_file = mp_open_file(mp, ps_tab_name, "r", mp_filetype_fontmap)) ) {
130 @<Set |lmax| to the maximum |font_name| length for fonts
131 |last_ps_fnum+1| through |last_fnum|@>;
132 while (! feof(mp->ps->ps_tab_file) ) {
133 @<Read at most |lmax| characters from |ps_tab_file| into string |s|
134 but |goto common_ending| if there is trouble@>;
135 for (k=mp->last_ps_fnum+1;k<=mp->last_fnum;k++) {
136 if ( mp_xstrcmp(s,mp->font_name[k])==0 ) {
137 @<|flush_string(s)|, read in |font_ps_name[k]|, and
138 |goto common_ending|@>;
143 c = fgetc(mp->ps->ps_tab_file);
145 c = fgetc(mp->ps->ps_tab_file);
147 ungetc(c,mp->ps->ps_tab_file);
150 mp->last_ps_fnum=mp->last_fnum;
151 fclose(mp->ps->ps_tab_file);
156 FILE * ps_tab_file; /* file for font name translation table */
158 @ @<Set |lmax| to the maximum |font_name| length for fonts...@>=
160 for (k=mp->last_ps_fnum+1;k<=mp->last_fnum;k++) {
161 if (strlen(mp->font_name[k])>lmax )
162 lmax=strlen(mp->font_name[k]);
165 @ If we encounter the end of line before we have started reading
166 characters from |ps_tab_file|, we have found an entirely blank
167 line and we skip over it. Otherwise, we abort if the line ends
168 prematurely. If we encounter a comment character, we also skip
169 over the line, since recent versions of \.{dvips} allow comments
170 in the font map file.
172 TODO: this is probably not safe in the case of a really
173 broken font map file.
175 @<Read at most |lmax| characters from |ps_tab_file| into string |s|...@>=
176 s=mp_xmalloc(mp,lmax+1,1);
179 if (c == '\n' || c == '\r' ) {
181 mp_xfree(s); s=NULL; goto COMMON_ENDING;
183 mp_fatal_error(mp, "The psfont map file is bad!");
186 c = fgetc(mp->ps->ps_tab_file);
187 if (c=='%' || c=='*' || c==';' || c=='#' ) {
188 mp_xfree(s); s=NULL; goto COMMON_ENDING;
190 if (c==' ' || c=='\t') break;
192 s[j++] = mp->xord[c];
194 mp_xfree(s); s=NULL; goto COMMON_ENDING;
199 @ PostScript font names should be at most 28 characters long but we allow 32
202 @<|flush_string(s)|, read in |font_ps_name[k]|, and...@>=
207 if (c=='\n' || c == '\r')
208 mp_fatal_error(mp, "The psfont map file is bad!");
209 c = fgetc(mp->ps->ps_tab_file);
210 } while (c==' ' || c=='\t');
211 ps_name = mp_xmalloc(mp,33,1);
215 mp_fatal_error(mp, "The psfont map file is bad!");
217 ps_name[j++] = mp->xord[c];
218 if (c=='\n' || c == '\r')
221 c = fgetc(mp->ps->ps_tab_file);
222 } while (c != ' ' && c != '\t');
224 mp_xfree(mp->font_ps_name[k]);
225 mp->font_ps_name[k]=ps_name;
231 @* \[44a] Dealing with font encodings.
233 First, here are a few helpers for parsing files
235 @d check_buf(size, buf_size)
236 if ((unsigned)(size) > (unsigned)(buf_size)) {
238 snprintf(s,128,"buffer overflow: (%d,%d) at file %s, line %d",
239 size,buf_size, __FILE__, __LINE__ );
240 mp_fatal_error(mp,s);
243 @d append_char_to_buf(c, p, buf, buf_size) do {
246 if (c == 13 || c == EOF)
248 if (c != ' ' || (p > buf && p[-1] != 32)) {
249 check_buf(p - buf + 1, (buf_size));
254 @d append_eol(p, buf, buf_size) do {
255 check_buf(p - buf + 2, (buf_size));
256 if (p - buf > 1 && p[-1] != 10)
258 if (p - buf > 2 && p[-2] == 32) {
265 @d remove_eol(p, buf) do {
271 @d skip(p, c) if (*p == c) p++
272 @d strend(s) strchr(s, 0)
273 @d str_prefix(s1, s2) (strncmp((s1), (s2), strlen(s2)) == 0)
278 boolean loaded; /* the encoding has been loaded? */
279 char *file_name; /* encoding file name */
280 char *enc_name; /* encoding true name */
281 integer objnum; /* object number */
283 integer tounicode; /* object number of associated ToUnicode entry */
293 #define ENC_BUF_SIZE 0x1000
294 char enc_line[ENC_BUF_SIZE];
298 @d enc_getchar() getc(mp->ps->enc_file)
299 @d enc_eof() feof(mp->ps->enc_file)
300 @d enc_close() fclose(mp->ps->enc_file)
303 static boolean mp_enc_open (MP mp, char *n) {
304 mp->ps->enc_file=mp_open_file(mp, n, "rb", mp_filetype_encoding);
305 if (mp->ps->enc_file!=NULL)
310 static void mp_enc_getline (MP mp) {
315 print_err("unexpected end of file");
318 p = mp->ps->enc_line;
321 append_char_to_buf (c, p, mp->ps->enc_line, ENC_BUF_SIZE);
323 append_eol (p, mp->ps->enc_line, ENC_BUF_SIZE);
324 if (p - mp->ps->enc_line < 2 || *mp->ps->enc_line == '%')
327 static void mp_load_enc (MP mp, char *enc_name,
328 char **enc_encname, char **glyph_names){
329 char buf[ENC_BUF_SIZE], *p, *r;
332 int save_selector = mp->selector;
333 if (!mp_enc_open (mp,enc_name)) {
334 mp_print (mp,"cannot open encoding file for reading");
337 mp_normalize_selector(mp);
339 mp_print (mp, enc_name);
341 if (*mp->ps->enc_line != '/' || (r = strchr (mp->ps->enc_line, '[')) == NULL) {
342 remove_eol (r, mp->ps->enc_line);
343 print_err ("invalid encoding vector (a name or `[' missing): `");
344 mp_print(mp,mp->ps->enc_line);
348 while (*(r-1)==' ') r--; /* strip trailing spaces from encoding name */
349 myname = mp_xmalloc(mp,r-mp->ps->enc_line,1);
350 memcpy(myname,mp->ps->enc_line+1,(r-mp->ps->enc_line)-1);
351 *(myname+(r-mp->ps->enc_line-1))=0;
352 *enc_encname = myname;
360 *r != ' ' && *r != 10 && *r != ']' && *r != '/'; *p++ = *r++);
363 if (names_count > 256) {
364 print_err ("encoding vector contains more than 256 names");
367 if (mp_xstrcmp (buf, notdef) != 0)
368 glyph_names[names_count] = mp_xstrdup (mp,buf);
371 if (*r != 10 && *r != '%') {
372 if (str_prefix (r, "] def"))
375 remove_eol (r, mp->ps->enc_line);
377 ("invalid encoding vector: a name or `] def' expected: `");
378 mp_print(mp,mp->ps->enc_line);
384 r = mp->ps->enc_line;
389 mp->selector = save_selector;
391 static void mp_read_enc (MP mp, enc_entry * e) {
395 mp_load_enc (mp,e->file_name, &e->enc_name, e->glyph_names);
399 @ |write_enc| is used to write either external encoding (given in map file) or
400 internal encoding (read from the font file); when |glyph_names| is NULL
401 the 2nd argument is a pointer to the encoding entry; otherwise the 3rd is
402 the object number of the Encoding object
405 static void mp_write_enc (MP mp, char **glyph_names, enc_entry * e) {
410 if (glyph_names == NULL) {
411 if (e->objnum != 0) /* the encoding has been written already */
419 mp_print(mp,"\n%%%%BeginResource: encoding ");
420 mp_print(mp, e->enc_name);
422 mp_print(mp, e->enc_name);
424 foffset = strlen(e->file_name)+3;
425 for (i = 0; i < 256; i++) {
427 if (s+1+foffset>=80) {
432 mp_print_char(mp,'/');
434 mp_print_char(mp,' ');
438 mp_print_nl (mp,"] def\n");
439 mp_print(mp,"%%%%EndResource");
443 @ All encoding entries go into AVL tree for fast search by name.
446 struct avl_table *enc_tree;
448 @ Memory management functions for avl
450 @<Static variables in the outer block@>=
451 static const char notdef[] = ".notdef";
454 static void *avl_xmalloc (struct libavl_allocator *allocator, size_t size);
455 static void avl_xfree (struct libavl_allocator *allocator, void *block);
458 static void *avl_xmalloc (struct libavl_allocator *allocator, size_t size) {
460 return malloc (size);
462 static void avl_xfree (struct libavl_allocator *allocator, void *block) {
468 struct libavl_allocator avl_xallocator;
470 @ @<Set initial...@>=
471 mp->ps->avl_xallocator.libavl_malloc=avl_xmalloc;
472 mp->ps->avl_xallocator.libavl_free= avl_xfree;
473 mp->ps->enc_tree = NULL;
476 static int comp_enc_entry (const void *pa, const void *pb, void *p) {
478 return strcmp (((const enc_entry *) pa)->file_name,
479 ((const enc_entry *) pb)->file_name);
481 static enc_entry * mp_add_enc (MP mp, char *s) {
485 if (mp->ps->enc_tree == NULL) {
486 mp->ps->enc_tree = avl_create (comp_enc_entry, NULL, &mp->ps->avl_xallocator);
489 p = (enc_entry *) avl_find (mp->ps->enc_tree, &tmp);
490 if (p != NULL) /* encoding already registered */
492 p = mp_xmalloc (mp,1,sizeof (enc_entry));
494 p->file_name = mp_xstrdup (mp,s);
497 p->glyph_names = mp_xmalloc (mp,256,sizeof (char *));
498 for (i = 0; i < 256; i++)
499 p->glyph_names[i] = (char *) notdef;
500 aa = avl_probe (mp->ps->enc_tree, p);
507 static void mp_destroy_enc_entry (void *pa, void *pb) {
511 p = (enc_entry *) pa;
513 mp_xfree (p->file_name);
514 if (p->glyph_names != NULL)
515 for (i = 0; i < 256; i++)
516 if (p->glyph_names[i] != notdef)
517 mp_xfree (p->glyph_names[i]);
518 mp_xfree (p->glyph_names);
523 static void enc_free (MP mp);
525 @ @c static void enc_free (MP mp) {
526 if (mp->ps->enc_tree != NULL)
527 avl_destroy (mp->ps->enc_tree, mp_destroy_enc_entry);
530 @ @<Exported function headers@>=
531 void mp_reload_encodings (MP mp) ;
534 static void mp_font_encodings (MP mp, int lastfnum, int encodings_only) ;
536 @ @c void mp_reload_encodings (MP mp) {
540 int lastfnum = mp->last_fnum;
541 for (f=null_font+1;f<=lastfnum;f++) {
542 if (mp->font_enc_name[f]!=NULL ) {
543 mp_xfree(mp->font_enc_name[f]);
544 mp->font_enc_name[f]=NULL;
546 if (mp_has_font_size(mp,f) && mp_has_fm_entry (mp,f,&fm_cur)) {
547 if (fm_cur != NULL && fm_cur->ps_name != NULL &&is_reencoded (fm_cur)) {
548 e = fm_cur->encoding;
554 static void mp_font_encodings (MP mp, int lastfnum, int encodings_only) {
558 for (f=null_font+1;f<=lastfnum;f++) {
559 if (mp_has_font_size(mp,f) && mp_has_fm_entry (mp,f, &fm)) {
560 if (fm != NULL && (fm->ps_name != NULL)) {
561 if (is_reencoded (fm)) {
562 if (encodings_only || (!is_subsetted (fm))) {
564 mp_write_enc (mp,NULL, e);
565 /* clear for next run */
574 @* \[44b] Parsing font map files.
582 @d fm_close() fclose(mp->ps->fm_file)
583 @d fm_getchar() fgetc(mp->ps->fm_file)
584 @d fm_eof() feof(mp->ps->fm_file)
587 enum _mode { FM_DUPIGNORE, FM_REPLACE, FM_DELETE };
588 enum _ltype { MAPFILE, MAPLINE };
589 enum _tfmavail { TFM_UNCHECKED, TFM_FOUND, TFM_NOTFOUND };
590 typedef struct mitem {
591 int mode; /* |FM_DUPIGNORE| or |FM_REPLACE| or |FM_DELETE| */
592 int type; /* map file or map line */
593 char *map_line; /* pointer to map file name or map line */
594 int lineno; /* line number in map file */
600 fm_entry *loaded_tfm_found;
601 fm_entry *avail_tfm_found;
602 fm_entry *non_tfm_found;
603 fm_entry *not_avail_tfm_found;
605 @ @<Set initial...@>=
606 mp->ps->mitem = NULL;
609 static const char nontfm[] = "<nontfm>";
612 @d read_field(r, q, buf) do {
614 while (*r != ' ' && *r != '\0')
622 fm->F = mp_xstrdup(mp,buf);
634 static fm_entry *new_fm_entry (MP mp) {
636 fm = mp_xmalloc (mp,1,sizeof(fm_entry));
641 fm->subset_tag = NULL;
643 fm->tfm_num = null_font;
644 fm->tfm_avail = TFM_UNCHECKED;
652 fm->all_glyphs = false;
659 static void delete_fm_entry (fm_entry * fm) {
660 mp_xfree (fm->tfm_name);
661 mp_xfree (fm->ps_name);
662 mp_xfree (fm->ff_name);
663 mp_xfree (fm->subset_tag);
664 mp_xfree (fm->charset);
668 static ff_entry *new_ff_entry (MP mp) {
670 ff = mp_xmalloc (mp,1,sizeof(ff_entry));
676 static void delete_ff_entry (ff_entry * ff) {
677 mp_xfree (ff->ff_name);
678 mp_xfree (ff->ff_path);
682 static char *mk_base_tfm (MP mp, char *tfmname, int *i) {
683 static char buf[SMALL_BUF_SIZE];
684 char *p = tfmname, *r = strend (p) - 1, *q = r;
685 while (q > p && isdigit (*q))
687 if (!(q > p) || q == r || (*q != '+' && *q != '-'))
689 check_buf (q - p + 1, SMALL_BUF_SIZE);
690 strncpy (buf, p, (size_t) (q - p));
696 @ @<Exported function headers@>=
697 boolean mp_has_fm_entry (MP mp,font_number f, fm_entry **fm);
700 boolean mp_has_fm_entry (MP mp,font_number f, fm_entry **fm) {
701 fm_entry *res = NULL;
702 res = mp_fm_lookup (mp, f);
706 return (res != NULL);
710 struct avl_table *tfm_tree;
711 struct avl_table *ps_tree;
712 struct avl_table *ff_tree;
714 @ @<Set initial...@>=
715 mp->ps->tfm_tree = NULL;
716 mp->ps->ps_tree = NULL;
717 mp->ps->ff_tree = NULL;
719 @ AVL sort |fm_entry| into |tfm_tree| by |tfm_name |
722 static int comp_fm_entry_tfm (const void *pa, const void *pb, void *p) {
724 return strcmp (((const fm_entry *) pa)->tfm_name,
725 ((const fm_entry *) pb)->tfm_name);
728 @ AVL sort |fm_entry| into |ps_tree| by |ps_name|, |slant|, and |extend|
730 @c static int comp_fm_entry_ps (const void *pa, const void *pb, void *p) {
732 const fm_entry *p1 = (const fm_entry *) pa, *p2 = (const fm_entry *) pb;
734 assert (p1->ps_name != NULL && p2->ps_name != NULL);
735 if ((i = strcmp (p1->ps_name, p2->ps_name)))
737 cmp_return (p1->slant, p2->slant);
738 cmp_return (p1->extend, p2->extend);
739 if (p1->tfm_name != NULL && p2->tfm_name != NULL &&
740 (i = strcmp (p1->tfm_name, p2->tfm_name)))
745 @ AVL sort |ff_entry| into |ff_tree| by |ff_name|
747 @c static int comp_ff_entry (const void *pa, const void *pb, void *p) {
749 return strcmp (((const ff_entry *) pa)->ff_name,
750 ((const ff_entry *) pb)->ff_name);
753 @ @c static void create_avl_trees (MP mp) {
754 if (mp->ps->tfm_tree == NULL) {
755 mp->ps->tfm_tree = avl_create (comp_fm_entry_tfm, NULL, &mp->ps->avl_xallocator);
756 assert (mp->ps->tfm_tree != NULL);
758 if (mp->ps->ps_tree == NULL) {
759 mp->ps->ps_tree = avl_create (comp_fm_entry_ps, NULL, &mp->ps->avl_xallocator);
760 assert (mp->ps->ps_tree != NULL);
762 if (mp->ps->ff_tree == NULL) {
763 mp->ps->ff_tree = avl_create (comp_ff_entry, NULL, &mp->ps->avl_xallocator);
764 assert (mp->ps->ff_tree != NULL);
768 @ The function |avl_do_entry| is not completely symmetrical with regards
769 to |tfm_name| and |ps_name handling|, e. g. a duplicate |tfm_name| gives a
770 |goto exit|, and no |ps_name| link is tried. This is to keep it compatible
771 with the original version.
775 @d set_tfmlink(fm) ((fm)->links |= LINK_TFM)
776 @d set_pslink(fm) ((fm)->links |= LINK_PS)
777 @d unset_tfmlink(fm) ((fm)->links &= ~LINK_TFM)
778 @d unset_pslink(fm) ((fm)->links &= ~LINK_PS)
779 @d has_tfmlink(fm) ((fm)->links & LINK_TFM)
780 @d has_pslink(fm) ((fm)->links & LINK_PS)
783 static int avl_do_entry (MP mp, fm_entry * fp, int mode) {
789 /* handle |tfm_name| link */
791 if (strcmp (fp->tfm_name, nontfm)) {
792 p = (fm_entry *) avl_find (mp->ps->tfm_tree, fp);
794 if (mode == FM_DUPIGNORE) {
795 snprintf(s,128,"fontmap entry for `%s' already exists, duplicates ignored",
799 } else { /* mode == |FM_REPLACE| / |FM_DELETE| */
800 if (mp_has_font_size(mp,p->tfm_num)) {
802 "fontmap entry for `%s' has been used, replace/delete not allowed",
807 a = avl_delete (mp->ps->tfm_tree, p);
814 if (mode != FM_DELETE) {
815 aa = avl_probe (mp->ps->tfm_tree, fp);
821 /* handle |ps_name| link */
823 if (fp->ps_name != NULL) {
824 assert (fp->tfm_name != NULL);
825 p = (fm_entry *) avl_find (mp->ps->ps_tree, fp);
827 if (mode == FM_DUPIGNORE) {
829 "ps_name entry for `%s' already exists, duplicates ignored",
833 } else { /* mode == |FM_REPLACE| / |FM_DELETE| */
834 if (mp_has_font_size(mp,p->tfm_num)) {
835 /* REPLACE/DELETE not allowed */
837 "fontmap entry for `%s' has been used, replace/delete not allowed",
842 a = avl_delete (mp->ps->ps_tree, p);
845 if (!has_tfmlink (p))
849 if (mode != FM_DELETE) {
850 aa = avl_probe (mp->ps->ps_tree, fp);
856 if (!has_tfmlink (fp) && !has_pslink (fp)) /* e. g. after |FM_DELETE| */
857 return 1; /* deallocation of |fm_entry| structure required */
862 @ consistency check for map entry, with warn flag
865 static int check_fm_entry (MP mp, fm_entry * fm, boolean warn) {
869 if (fm->ps_name != NULL) {
870 if (is_basefont (fm)) {
871 if (is_fontfile (fm) && !is_included (fm)) {
873 snprintf(s,128, "invalid entry for `%s': "
874 "font file must be included or omitted for base fonts",
880 } else { /* not a base font */
881 /* if no font file given, drop this entry */
882 /* |if (!is_fontfile (fm)) {
885 "invalid entry for `%s': font file missing",
894 if (is_truetype (fm) && is_reencoded (fm) && !is_subsetted (fm)) {
897 "invalid entry for `%s': only subsetted TrueType font can be reencoded",
903 if ((fm->slant != 0 || fm->extend != 0) &&
904 (is_truetype (fm))) {
907 "invalid entry for `%s': "
908 "SlantFont/ExtendFont can be used only with embedded T1 fonts",
914 if (abs (fm->slant) > 1000) {
917 "invalid entry for `%s': too big value of SlantFont (%g)",
918 fm->tfm_name, fm->slant / 1000.0);
923 if (abs (fm->extend) > 2000) {
926 "invalid entry for `%s': too big value of ExtendFont (%g)",
927 fm->tfm_name, fm->extend / 1000.0);
933 !(is_truetype (fm) && is_included (fm) &&
934 is_subsetted (fm) && !is_reencoded (fm))) {
937 "invalid entry for `%s': "
938 "PidEid can be used only with subsetted non-reencoded TrueType fonts",
947 @ returns true if s is one of the 14 std. font names; speed-trimmed.
949 @c static boolean check_basefont (char *s) {
950 static const char *basefont_names[] = {
952 "Courier-Bold", /* 1:12 */
953 "Courier-Oblique", /* 2:15 */
954 "Courier-BoldOblique", /* 3:19 */
955 "Helvetica", /* 4:9 */
956 "Helvetica-Bold", /* 5:14 */
957 "Helvetica-Oblique", /* 6:17 */
958 "Helvetica-BoldOblique", /* 7:21 */
960 "Times-Roman", /* 9:11 */
961 "Times-Bold", /* 10:10 */
962 "Times-Italic", /* 11:12 */
963 "Times-BoldItalic", /* 12:16 */
964 "ZapfDingbats" /* 13:12 */
966 static const int Index[] =
967 { -1, -1, -1, -1, -1, -1, 8, 0, -1, 4, 10, 9, -1, -1, 5, 2, 12, 6,
970 const size_t n = strlen (s);
974 if (n == 12) { /* three names have length 12 */
977 k = 1; /* Courier-Bold */
980 k = 11; /* Times-Italic */
983 k = 13; /* ZapfDingbats */
990 if (k > -1 && !strcmp (basefont_names[k], s))
996 @d is_cfg_comment(c) (c == 10 || c == '*' || c == '#' || c == ';' || c == '%')
998 @c static void fm_scan_line (MP mp) {
999 int a, b, c, j, u = 0, v = 0;
1002 char fm_line[FM_BUF_SIZE], buf[FM_BUF_SIZE];
1003 char *p, *q, *r, *s;
1005 switch (mp->ps->mitem->type) {
1010 append_char_to_buf (c, p, fm_line, FM_BUF_SIZE);
1017 r = mp->ps->mitem->map_line;
1022 if (*r == '\0' || is_cfg_comment (*r))
1024 fm = new_fm_entry (mp);
1025 read_field (r, q, buf);
1026 set_field (tfm_name);
1028 read_field (r, q, buf);
1029 if (*buf != '<' && *buf != '"')
1030 set_field (ps_name);
1032 r = p; /* unget the field */
1033 if (isdigit (*r)) { /* font flags given */
1034 fm->flags = atoi (r);
1035 while (isdigit (*r))
1038 while (1) { /* loop through "specials", encoding, font file */
1043 case '"': /* opening quote */
1048 if (sscanf (r, "%f %n", &d, &j) > 0) {
1049 s = r + j; /* jump behind number, eat also blanks, if any */
1050 if (*(s - 1) == 'E' || *(s - 1) == 'e')
1051 s--; /* e. g. 0.5ExtendFont: \%f = 0.5E */
1052 if (str_prefix (s, "SlantFont")) {
1053 d *= 1000.0; /* correct rounding also for neg. numbers */
1054 fm->slant = (integer) (d > 0 ? d + 0.5 : d - 0.5);
1055 r = s + strlen ("SlantFont");
1056 } else if (str_prefix (s, "ExtendFont")) {
1058 fm->extend = (integer) (d > 0 ? d + 0.5 : d - 0.5);
1059 if (fm->extend == 1000)
1061 r = s + strlen ("ExtendFont");
1062 } else { /* unknown name */
1064 *r != ' ' && *r != '"' && *r != '\0';
1065 r++); /* jump over name */
1066 c = *r; /* remember char for temporary end of string */
1068 snprintf(warn_s,128,
1069 "invalid entry for `%s': unknown name `%s' ignored",
1075 for (; *r != ' ' && *r != '"' && *r != '\0'; r++);
1078 if (*r == '"') /* closing quote */
1081 snprintf(warn_s,128,
1082 "invalid entry for `%s': closing quote missing",
1088 case 'P': /* handle cases for subfonts like 'PidEid=3,1' */
1089 if (sscanf (r, "PidEid=%i, %i %n", &a, &b, &c) >= 2) {
1095 default: /* encoding or font file specification */
1099 if (*r == '<' || *r == '[')
1102 read_field (r, q, buf);
1103 /* encoding, formats: '8r.enc' or '<8r.enc' or '<[8r.enc' */
1104 if (strlen (buf) > 4 && strcasecmp (strend (buf) - 4, ".enc") == 0) {
1105 fm->encoding = mp_add_enc (mp, buf);
1106 u = v = 0; /* u, v used if intervening blank: "<< foo" */
1107 } else if (strlen (buf) > 0) { /* file name given */
1108 /* font file, formats:
1109 * subsetting: '<cmr10.pfa'
1110 * no subsetting: '<<cmr10.pfa'
1111 * no embedding: 'cmr10.pfa'
1113 if (a == '<' || u == '<') {
1115 if ((a == '<' && b == 0) || (a == 0 && v == 0))
1117 /* otherwise b == '<' (or '[') => no subsetting */
1119 set_field (ff_name);
1128 if (fm->ps_name != NULL && check_basefont (fm->ps_name))
1130 if (is_fontfile (fm)
1131 && strcasecmp (strend (fm_fontfile (fm)) - 4, ".ttf") == 0)
1133 if (check_fm_entry (mp,fm, true) != 0)
1136 Until here the map line has been completely scanned without errors;
1137 fm points to a valid, freshly filled-out |fm_entry| structure.
1138 Now follows the actual work of registering/deleting.
1140 if (avl_do_entry (mp, fm, mp->ps->mitem->mode) == 0) /* if success */
1143 delete_fm_entry (fm);
1147 @c static void fm_read_info (MP mp) {
1150 if (mp->ps->tfm_tree == NULL)
1151 create_avl_trees (mp);
1152 if (mp->ps->mitem->map_line == NULL) /* nothing to do */
1154 mp->ps->mitem->lineno = 1;
1155 switch (mp->ps->mitem->type) {
1157 n = mp->ps->mitem->map_line;
1158 mp->ps->fm_file = mp_open_file(mp, n, "r", mp_filetype_fontmap);
1159 if (!mp->ps->fm_file) {
1160 snprintf(s,256,"cannot open font map file %s",n);
1163 int save_selector = mp->selector;
1164 mp_normalize_selector(mp);
1167 while (!fm_eof ()) {
1169 mp->ps->mitem->lineno++;
1173 mp->selector = save_selector;
1174 mp->ps->fm_file = NULL;
1183 mp->ps->mitem->map_line = NULL; /* done with this line */
1188 static scaled mp_round_xn_over_d (MP mp, scaled x, integer n, integer d) {
1189 boolean positive; /* was |x>=0|? */
1190 unsigned int t,u; /* intermediate quantities */
1191 integer v; /* intermediate quantities */
1195 negate(x); positive=false;
1198 u=(x / 0100000)*n+(t / 0100000);
1199 v=(u % d)*0100000 + (t % 0100000);
1200 if ( u / d>=0100000 ) mp->arith_error=true;
1201 else u=0100000*(u / d) + (v / d);
1205 return ( positive ? u : -u );
1207 static fm_entry *mk_ex_fm (MP mp, font_number f, fm_entry * basefm, int ex) {
1209 integer e = basefm->extend;
1212 fm = new_fm_entry (mp);
1213 fm->flags = basefm->flags;
1214 fm->encoding = basefm->encoding;
1215 fm->type = basefm->type;
1216 fm->slant = basefm->slant;
1217 fm->extend = mp_round_xn_over_d (mp, e, 1000 + ex, 1000);
1218 /* modify ExtentFont to simulate expansion */
1219 if (fm->extend == 1000)
1221 fm->tfm_name = mp_xstrdup (mp,mp->font_name[f]);
1222 if (basefm->ps_name != NULL)
1223 fm->ps_name = mp_xstrdup (mp,basefm->ps_name);
1224 fm->ff_name = mp_xstrdup (mp,basefm->ff_name);
1227 fm->tfm_avail = TFM_FOUND;
1228 assert (strcmp (fm->tfm_name, nontfm));
1232 @ @c static void init_fm (fm_entry * fm, font_number f) {
1233 if (fm->tfm_num == null_font ) {
1235 fm->tfm_avail = TFM_FOUND;
1240 static fm_entry * mp_fm_lookup (MP mp, font_number f);
1243 static fm_entry * mp_fm_lookup (MP mp, font_number f) {
1245 fm_entry *fm, *exfm;
1248 if (mp->ps->tfm_tree == NULL)
1249 fm_read_info (mp); /* only to read default map file */
1250 tfm = mp->font_name[f];
1251 assert (strcmp (tfm, nontfm));
1252 /* Look up for full <tfmname>[+-]<expand> */
1254 fm = (fm_entry *) avl_find (mp->ps->tfm_tree, &tmp);
1257 return (fm_entry *) fm;
1259 tfm = mk_base_tfm (mp, mp->font_name[f], &e);
1260 if (tfm == NULL) /* not an expanded font, nothing to do */
1264 fm = (fm_entry *) avl_find (mp->ps->tfm_tree, &tmp);
1265 if (fm != NULL) { /* found an entry with the base tfm name, e.g. cmr10 */
1266 return (fm_entry *) fm; /* font expansion uses the base font */
1267 /* the following code would be obsolete, as would be |mk_ex_fm| */
1268 if (!is_t1fontfile (fm) || !is_included (fm)) {
1271 "font %s cannot be expanded (not an included Type1 font)", tfm);
1275 exfm = mk_ex_fm (mp, f, fm, e); /* copies all fields from fm except tfm name */
1277 ai = avl_do_entry (mp, exfm, FM_DUPIGNORE);
1279 return (fm_entry *) exfm;
1284 @ Early check whether a font file exists. Used e. g. for replacing fonts
1285 of embedded PDF files: Without font file, the font within the embedded
1286 PDF-file is used. Search tree |ff_tree| is used in 1st instance, as it
1287 may be faster than the |kpse_find_file()|, and |kpse_find_file()| is called
1288 only once per font file name + expansion parameter. This might help
1289 keeping speed, if many PDF pages with same fonts are to be embedded.
1291 The |ff_tree| contains only font files, which are actually needed,
1292 so this tree typically is much smaller than the |tfm_tree| or |ps_tree|.
1295 static ff_entry *check_ff_exist (MP mp, fm_entry * fm) {
1300 assert (fm->ff_name != NULL);
1301 tmp.ff_name = fm->ff_name;
1302 ff = (ff_entry *) avl_find (mp->ps->ff_tree, &tmp);
1303 if (ff == NULL) { /* not yet in database */
1304 ff = new_ff_entry (mp);
1305 ff->ff_name = mp_xstrdup (mp,fm->ff_name);
1306 ff->ff_path = mp_xstrdup (mp,fm->ff_name);
1307 aa = avl_probe (mp->ps->ff_tree, ff);
1308 assert (aa != NULL);
1313 @ Process map file given by its name or map line contents. Items not
1314 beginning with [+-=] flush default map file, if it has not yet been
1315 read. Leading blanks and blanks immediately following [+-=] are ignored.
1318 @c static void mp_process_map_item (MP mp, char *s, int type) {
1322 s++; /* ignore leading blank */
1324 case '+': /* +mapfile.map, +mapline */
1325 mode = FM_DUPIGNORE; /* insert entry, if it is not duplicate */
1328 case '=': /* =mapfile.map, =mapline */
1329 mode = FM_REPLACE; /* try to replace earlier entry */
1332 case '-': /* -mapfile.map, -mapline */
1333 mode = FM_DELETE; /* try to delete entry */
1337 mode = FM_DUPIGNORE; /* like +, but also: */
1338 mp->ps->mitem->map_line = NULL; /* flush default map file name */
1341 s++; /* ignore blank after [+-=] */
1342 p = s; /* map item starts here */
1344 case MAPFILE: /* remove blank at end */
1345 while (*p != '\0' && *p != ' ')
1349 case MAPLINE: /* blank at end allowed */
1354 if (mp->ps->mitem->map_line != NULL) /* read default map file first */
1356 if (*s != '\0') { /* only if real item to process */
1357 mp->ps->mitem->mode = mode;
1358 mp->ps->mitem->type = type;
1359 mp->ps->mitem->map_line = s;
1364 @ @<Exported function headers@>=
1365 void mp_map_file (MP mp, str_number t);
1366 void mp_map_line (MP mp, str_number t);
1367 void mp_init_map_file (MP mp, int is_troff);
1370 void mp_map_file (MP mp, str_number t) {
1371 char *s = mp_xstrdup(mp,mp_str (mp,t));
1372 mp_process_map_item (mp, s, MAPFILE);
1375 void mp_map_line (MP mp, str_number t) {
1376 char *s = mp_xstrdup(mp,mp_str (mp,t));
1377 mp_process_map_item (mp, s, MAPLINE);
1382 @c void mp_init_map_file (MP mp, int is_troff) {
1384 mp->ps->mitem = mp_xmalloc (mp,1,sizeof(mapitem));
1385 mp->ps->mitem->mode = FM_DUPIGNORE;
1386 mp->ps->mitem->type = MAPFILE;
1387 mp->ps->mitem->map_line = NULL;
1388 r = (mp->find_file)("mpost.map", "rb", mp_filetype_fontmap);
1391 mp->ps->mitem->map_line = mp_xstrdup (mp,"mpost.map");
1394 mp->ps->mitem->map_line = mp_xstrdup (mp,"troff.map");
1396 mp->ps->mitem->map_line = mp_xstrdup (mp,"pdftex.map");
1401 @ @<Dealloc variables@>=
1402 if (mp->ps->mitem!=NULL) {
1403 mp_xfree(mp->ps->mitem->map_line);
1404 mp_xfree(mp->ps->mitem);
1410 static void destroy_fm_entry_tfm (void *pa, void *pb) {
1413 fm = (fm_entry *) pa;
1414 if (!has_pslink (fm))
1415 delete_fm_entry (fm);
1419 static void destroy_fm_entry_ps (void *pa, void *pb) {
1422 fm = (fm_entry *) pa;
1423 if (!has_tfmlink (fm))
1424 delete_fm_entry (fm);
1428 static void destroy_ff_entry (void *pa, void *pb) {
1431 ff = (ff_entry *) pa;
1432 delete_ff_entry (ff);
1436 static void fm_free (MP mp);
1439 static void fm_free (MP mp) {
1440 if (mp->ps->tfm_tree != NULL)
1441 avl_destroy (mp->ps->tfm_tree, destroy_fm_entry_tfm);
1442 if (mp->ps->ps_tree != NULL)
1443 avl_destroy (mp->ps->ps_tree, destroy_fm_entry_ps);
1444 if (mp->ps->ff_tree != NULL)
1445 avl_destroy (mp->ps->ff_tree, destroy_ff_entry);
1448 @* \[44c] Helper functions for Type1 fonts.
1451 typedef char char_entry;
1452 typedef unsigned char Byte;
1456 char_entry *char_ptr, *char_array;
1458 char *job_id_string;
1460 @ @<Set initial...@>=
1461 mp->ps->char_array = NULL;
1462 mp->ps->job_id_string = NULL;
1465 @d SMALL_ARRAY_SIZE 256
1469 void mp_set_job_id (MP mp) {
1470 char *name_string, *format_string, *s;
1473 if (mp->ps->job_id_string != NULL)
1475 if ( mp->job_name==NULL )
1476 mp->job_name = mp_xstrdup(mp,"mpout");
1477 name_string = mp_xstrdup (mp,mp->job_name);
1478 format_string = mp_xstrdup (mp,mp->mem_ident);
1479 slen = SMALL_BUF_SIZE +
1480 strlen (name_string) +
1481 strlen (format_string);
1482 s = mp_xmalloc (mp,slen, sizeof (char));
1483 i = snprintf (s, slen,
1484 "%.4d/%.2d/%.2d %.2d:%.2d %s %s",
1485 (mp->internal[mp_year]>>16),
1486 (mp->internal[mp_month]>>16),
1487 (mp->internal[mp_day]>>16),
1488 (mp->internal[mp_time]>>16) / 60,
1489 (mp->internal[mp_time]>>16) % 60,
1490 name_string, format_string);
1491 mp->ps->job_id_string = mp_xstrdup (mp,s);
1493 mp_xfree (name_string);
1494 mp_xfree (format_string);
1496 static void fnstr_append (MP mp, const char *s) {
1497 size_t l = strlen (s) + 1;
1498 alloc_array (char, l, SMALL_ARRAY_SIZE);
1499 strcat (mp->ps->char_ptr, s);
1500 mp->ps->char_ptr = strend (mp->ps->char_ptr);
1503 @ @<Exported function headers@>=
1504 void mp_set_job_id (MP mp) ;
1506 @ @<Dealloc variables@>=
1507 mp_xfree(mp->ps->job_id_string);
1509 @ this is not really a true crc32, but it should be just enough to keep
1510 subsets prefixes somewhat disjunct
1513 static unsigned long crc32 (int oldcrc, const Byte *buf, int len) {
1514 unsigned long ret = 0;
1517 ret = (23<<24)+(45<<16)+(67<<8)+89;
1520 ret = (ret<<2)+buf[i];
1523 static boolean mp_char_marked (MP mp,font_number f, eight_bits c) {
1524 integer b; /* |char_base[f]| */
1526 if ( (c>=mp->font_bc[f])&&(c<=mp->font_ec[f])&&(mp->font_info[b+c].qqqq.b3!=0) )
1532 static void make_subset_tag (MP mp, fm_entry * fm_cur, char **glyph_names, int tex_font)
1538 if (mp->ps->job_id_string ==NULL)
1539 mp_fatal_error(mp, "no job id!");
1540 l = strlen (mp->ps->job_id_string) + 1;
1542 alloc_array (char, l, SMALL_ARRAY_SIZE);
1543 strcpy (mp->ps->char_array, mp->ps->job_id_string);
1544 mp->ps->char_ptr = strend (mp->ps->char_array);
1545 if (fm_cur->tfm_name != NULL) {
1546 fnstr_append (mp," TFM name: ");
1547 fnstr_append (mp,fm_cur->tfm_name);
1549 fnstr_append (mp," PS name: ");
1550 if (fm_cur->ps_name != NULL)
1551 fnstr_append (mp,fm_cur->ps_name);
1552 fnstr_append (mp," Encoding: ");
1553 if (fm_cur->encoding != NULL && (fm_cur->encoding)->file_name != NULL)
1554 fnstr_append (mp,(fm_cur->encoding)->file_name);
1556 fnstr_append (mp,"built-in");
1557 fnstr_append (mp," CharSet: ");
1558 for (i = 0; i < 256; i++)
1559 if (mp_char_marked (mp,tex_font, i) && glyph_names[i] != notdef) {
1560 if (glyph_names[i]!=NULL) {
1561 fnstr_append (mp,"/");
1562 fnstr_append (mp,glyph_names[i]);
1565 if (fm_cur->charset != NULL) {
1566 fnstr_append (mp," Extra CharSet: ");
1567 fnstr_append (mp, fm_cur->charset);
1569 crc = crc32 (0L, Z_NULL, 0);
1570 crc = crc32 (crc, (Bytef *) mp->ps->char_array, strlen (mp->ps->char_array));
1571 /* we need to fit a 32-bit number into a string of 6 uppercase chars long;
1572 * there are 26 uppercase chars ==> each char represents a number in range
1573 * |0..25|. The maximal number that can be represented by the tag is
1574 * $26^6 - 1$, which is a number between $2^28$ and $2^29$. Thus the bits |29..31|
1575 * of the CRC must be dropped out.
1577 for (i = 0; i < 6; i++) {
1578 tag[i] = 'A' + crc % 26;
1582 fm_cur->subset_tag = mp_xstrdup (mp,tag);
1588 @d external_enc() (fm_cur->encoding)->glyph_names
1589 @d is_used_char(c) mp_char_marked (mp, tex_font, c)
1590 @d end_last_eexec_line()
1591 mp->ps->hexline_length = HEXLINE_WIDTH;
1593 mp->ps->t1_eexec_encrypt = false
1594 @d t1_log(s) mp_print(mp,(char *)s)
1595 @d t1_putchar(c) fputc(c, mp->ps_file)
1596 @d embed_all_glyphs(tex_font) false
1598 @d extra_charset() mp->ps->dvips_extra_charset
1599 @d update_subset_tag()
1600 @d fixedcontent true
1603 #define PRINTF_BUF_SIZE 1024
1604 char *dvips_extra_charset;
1606 unsigned char *grid;
1607 char *ext_glyph_names[256];
1608 char print_buf[PRINTF_BUF_SIZE];
1610 @ @<Set initial ...@>=
1611 mp->ps->dvips_extra_charset=NULL;
1614 @d t1_getchar() fgetc(mp->ps->t1_file)
1615 @d t1_ungetchar(c) ungetc(c, mp->ps->t1_file)
1616 @d t1_eof() feof(mp->ps->t1_file)
1617 @d t1_close() fclose(mp->ps->t1_file)
1618 @d valid_code(c) (c >= 0 && c < 256)
1620 @<Static variables in the outer block@>=
1621 static const char *standard_glyph_names[256] =
1622 { notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1623 notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1624 notdef, notdef, notdef, notdef, notdef, notdef,
1625 notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1626 "space", "exclam", "quotedbl", "numbersign",
1627 "dollar", "percent", "ampersand", "quoteright", "parenleft",
1628 "parenright", "asterisk", "plus", "comma", "hyphen", "period",
1629 "slash", "zero", "one", "two", "three", "four", "five", "six", "seven",
1630 "eight", "nine", "colon", "semicolon", "less",
1631 "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F",
1632 "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q",
1633 "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft",
1634 "backslash", "bracketright", "asciicircum", "underscore",
1635 "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k",
1636 "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v",
1637 "w", "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde",
1638 notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1639 notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1640 notdef, notdef, notdef, notdef, notdef, notdef,
1641 notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1642 notdef, notdef, notdef, "exclamdown", "cent",
1643 "sterling", "fraction", "yen", "florin", "section", "currency",
1644 "quotesingle", "quotedblleft", "guillemotleft",
1645 "guilsinglleft", "guilsinglright", "fi", "fl", notdef, "endash",
1646 "dagger", "daggerdbl", "periodcentered", notdef,
1647 "paragraph", "bullet", "quotesinglbase", "quotedblbase",
1648 "quotedblright", "guillemotright", "ellipsis", "perthousand",
1649 notdef, "questiondown", notdef, "grave", "acute", "circumflex",
1650 "tilde", "macron", "breve", "dotaccent", "dieresis", notdef,
1651 "ring", "cedilla", notdef, "hungarumlaut", "ogonek", "caron", "emdash",
1652 notdef, notdef, notdef, notdef, notdef, notdef,
1653 notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef,
1654 notdef, "AE", notdef, "ordfeminine", notdef, notdef,
1655 notdef, notdef, "Lslash", "Oslash", "OE", "ordmasculine", notdef,
1656 notdef, notdef, notdef, notdef, "ae", notdef, notdef,
1657 notdef, "dotlessi", notdef, notdef, "lslash", "oslash", "oe",
1658 "germandbls", notdef, notdef, notdef, notdef };
1659 static const char charstringname[] = "/CharStrings";
1662 char **t1_glyph_names;
1663 char *t1_builtin_glyph_names[256];
1664 char charsetstr[0x4000];
1665 boolean read_encoding_only;
1669 #define T1_BUF_SIZE 0x10
1673 #define CS_VMOVETO 4
1674 #define CS_RLINETO 5
1675 #define CS_HLINETO 6
1676 #define CS_VLINETO 7
1677 #define CS_RRCURVETO 8
1678 #define CS_CLOSEPATH 9
1679 #define CS_CALLSUBR 10
1680 #define CS_RETURN 11
1681 #define CS_ESCAPE 12
1683 #define CS_ENDCHAR 14
1684 #define CS_RMOVETO 21
1685 #define CS_HMOVETO 22
1686 #define CS_VHCURVETO 30
1687 #define CS_HVCURVETO 31
1688 #define CS_1BYTE_MAX (CS_HVCURVETO + 1)
1690 #define CS_DOTSECTION CS_1BYTE_MAX + 0
1691 #define CS_VSTEM3 CS_1BYTE_MAX + 1
1692 #define CS_HSTEM3 CS_1BYTE_MAX + 2
1693 #define CS_SEAC CS_1BYTE_MAX + 6
1694 #define CS_SBW CS_1BYTE_MAX + 7
1695 #define CS_DIV CS_1BYTE_MAX + 12
1696 #define CS_CALLOTHERSUBR CS_1BYTE_MAX + 16
1697 #define CS_POP CS_1BYTE_MAX + 17
1698 #define CS_SETCURRENTPOINT CS_1BYTE_MAX + 33
1699 #define CS_2BYTE_MAX (CS_SETCURRENTPOINT + 1)
1700 #define CS_MAX CS_2BYTE_MAX
1703 typedef unsigned char byte;
1705 byte nargs; /* number of arguments */
1706 boolean bottom; /* take arguments from bottom of stack? */
1707 boolean clear; /* clear stack? */
1709 } cc_entry; /* CharString Command */
1711 char *glyph_name; /* glyph name (or notdef for Subrs entry) */
1713 unsigned short len; /* length of the whole string */
1714 unsigned short cslen; /* length of the encoded part of the string */
1720 unsigned short t1_dr, t1_er;
1721 unsigned short t1_c1, t1_c2;
1722 unsigned short t1_cslen;
1725 @ @<Set initial...@>=
1726 mp->ps->t1_c1 = 52845;
1727 mp->ps->t1_c2 = 22719;
1730 typedef char t1_line_entry;
1731 typedef char t1_buf_entry;
1734 t1_line_entry *t1_line_ptr, *t1_line_array;
1735 size_t t1_line_limit;
1736 t1_buf_entry *t1_buf_ptr, *t1_buf_array;
1737 size_t t1_buf_limit;
1739 cs_entry *cs_tab, *cs_ptr, *cs_notdef;
1740 char *cs_dict_start, *cs_dict_end;
1741 int cs_count, cs_size, cs_size_pos;
1743 char *subr_array_start, *subr_array_end;
1744 int subr_max, subr_size, subr_size_pos;
1746 @ @<Set initial...@>=
1747 mp->ps->t1_line_array = NULL;
1748 mp->ps->t1_buf_array = NULL;
1751 This list contains the begin/end tokens commonly used in the
1752 /Subrs array of a Type 1 font.
1754 @<Static variables in the outer block@>=
1755 static const char *cs_token_pairs_list[][2] = {
1758 {" RD", "noaccess put"},
1759 {" -|", "noaccess put"},
1764 const char **cs_token_pair;
1765 boolean t1_pfa, t1_cs, t1_scan, t1_eexec_encrypt, t1_synthetic;
1766 int t1_in_eexec; /* 0 before eexec-encrypted, 1 during, 2 after */
1767 long t1_block_length;
1775 @<Set initial ...@>=
1776 mp->ps->hexline_length = HEXLINE_WIDTH;
1779 @d t1_prefix(s) str_prefix(mp->ps->t1_line_array, s)
1780 @d t1_buf_prefix(s) str_prefix(mp->ps->t1_buf_array, s)
1781 @d t1_suffix(s) str_suffix(mp->ps->t1_line_array, mp->ps->t1_line_ptr, s)
1782 @d t1_buf_suffix(s) str_suffix(mp->ps->t1_buf_array, mp->ps->t1_buf_ptr, s)
1783 @d t1_charstrings() strstr(mp->ps->t1_line_array, charstringname)
1784 @d t1_subrs() t1_prefix("/Subrs")
1785 @d t1_end_eexec() t1_suffix("mark currentfile closefile")
1786 @d t1_cleartomark() t1_prefix("cleartomark")
1788 @d isdigit(A) ((A)>='0'&&(A)<='9')
1791 static void end_hexline (MP mp) {
1792 if (mp->ps->hexline_length == HEXLINE_WIDTH) {
1793 fputs ("\n", mp->ps_file);
1794 mp->ps->hexline_length = 0;
1797 static void t1_check_pfa (MP mp) {
1798 const int c = t1_getchar ();
1799 mp->ps->t1_pfa = (c != 128) ? true : false;
1802 static int t1_getbyte (MP mp)
1804 int c = t1_getchar ();
1807 if (mp->ps->t1_block_length == 0) {
1809 mp_fatal_error (mp, "invalid marker");
1816 mp->ps->t1_block_length = t1_getchar () & 0xff;
1817 mp->ps->t1_block_length |= (t1_getchar () & 0xff) << 8;
1818 mp->ps->t1_block_length |= (t1_getchar () & 0xff) << 16;
1819 mp->ps->t1_block_length |= (t1_getchar () & 0xff) << 24;
1822 mp->ps->t1_block_length--;
1825 static int hexval (int c) {
1826 if (c >= 'A' && c <= 'F')
1827 return c - 'A' + 10;
1828 else if (c >= 'a' && c <= 'f')
1829 return c - 'a' + 10;
1830 else if (c >= '0' && c <= '9')
1835 static byte edecrypt (MP mp, byte cipher) {
1837 if (mp->ps->t1_pfa) {
1838 while (cipher == 10 || cipher == 13)
1839 cipher = t1_getbyte (mp);
1840 mp->ps->last_hexbyte = cipher = (hexval (cipher) << 4) + hexval (t1_getbyte (mp));
1842 plain = (cipher ^ (mp->ps->t1_dr >> 8));
1843 mp->ps->t1_dr = (cipher + mp->ps->t1_dr) * mp->ps->t1_c1 + mp->ps->t1_c2;
1846 static byte cdecrypt (MP mp, byte cipher, unsigned short *cr)
1848 const byte plain = (cipher ^ (*cr >> 8));
1849 *cr = (cipher + *cr) * mp->ps->t1_c1 + mp->ps->t1_c2;
1852 static byte eencrypt (MP mp, byte plain)
1854 const byte cipher = (plain ^ (mp->ps->t1_er >> 8));
1855 mp->ps->t1_er = (cipher + mp->ps->t1_er) * mp->ps->t1_c1 + mp->ps->t1_c2;
1859 static byte cencrypt (MP mp, byte plain, unsigned short *cr)
1861 const byte cipher = (plain ^ (*cr >> 8));
1862 *cr = (cipher + *cr) * mp->ps->t1_c1 + mp->ps->t1_c2;
1866 static char *eol (char *s) {
1867 char *p = strend (s);
1868 if (p - s > 1 && p[-1] != 10) {
1874 static float t1_scan_num (MP mp, char *p, char **r)
1879 if (sscanf (p, "%g", &f) != 1) {
1880 remove_eol (p, mp->ps->t1_line_array);
1881 snprintf(s,128, "a number expected: `%s'", mp->ps->t1_line_array);
1882 mp_fatal_error(mp,s);
1885 for (; isdigit (*p) || *p == '.' ||
1886 *p == 'e' || *p == 'E' || *p == '+' || *p == '-'; p++);
1892 static boolean str_suffix (const char *begin_buf, const char *end_buf,
1895 const char *s1 = end_buf - 1, *s2 = strend (s) - 1;
1898 while (s1 >= begin_buf && s2 >= s) {
1907 @d alloc_array(T, n, s) do {
1908 if (mp->ps->T##_array == NULL) {
1909 mp->ps->T##_limit = (s);
1910 if ((unsigned)(n) > mp->ps->T##_limit)
1911 mp->ps->T##_limit = (n);
1912 mp->ps->T##_array = mp_xmalloc (mp,mp->ps->T##_limit,sizeof(T##_entry));
1913 mp->ps->T##_ptr = mp->ps->T##_array;
1915 else if ((unsigned)(mp->ps->T##_ptr - mp->ps->T##_array + (n)) > mp->ps->T##_limit) {
1916 size_t last_ptr_index;
1917 last_ptr_index = mp->ps->T##_ptr - mp->ps->T##_array;
1918 mp->ps->T##_limit *= 2;
1919 if ((unsigned)(mp->ps->T##_ptr - mp->ps->T##_array + (n)) > mp->ps->T##_limit)
1920 mp->ps->T##_limit = mp->ps->T##_ptr - mp->ps->T##_array + (n);
1921 mp->ps->T##_array = mp_xrealloc(mp,mp->ps->T##_array,mp->ps->T##_limit, sizeof(T##_entry));
1922 mp->ps->T##_ptr = mp->ps->T##_array + last_ptr_index;
1926 @d out_eexec_char(A) t1_outhex(mp,(A))
1929 static void t1_outhex (MP mp, byte b)
1931 static char *hexdigits = "0123456789ABCDEF";
1932 t1_putchar (hexdigits[b / 16]);
1933 t1_putchar (hexdigits[b % 16]);
1934 mp->ps->hexline_length += 2;
1937 static void t1_getline (MP mp) {
1938 int c, l, eexec_scan;
1940 static const char eexec_str[] = "currentfile eexec";
1941 static int eexec_len = 17; /* |strlen(eexec_str)| */
1944 mp_fatal_error (mp,"unexpected end of file");
1945 mp->ps->t1_line_ptr = mp->ps->t1_line_array;
1946 alloc_array (t1_line, 1, T1_BUF_SIZE);
1947 mp->ps->t1_cslen = 0;
1949 c = t1_getbyte (mp);
1952 while (!t1_eof ()) {
1953 if (mp->ps->t1_in_eexec == 1)
1954 c = edecrypt (mp,c);
1955 alloc_array (t1_line, 1, T1_BUF_SIZE);
1956 append_char_to_buf (c, mp->ps->t1_line_ptr, mp->ps->t1_line_array, mp->ps->t1_line_limit);
1957 if (mp->ps->t1_in_eexec == 0 && eexec_scan >= 0 && eexec_scan < eexec_len) {
1958 if (mp->ps->t1_line_array[eexec_scan] == eexec_str[eexec_scan])
1963 if (c == 10 || (mp->ps->t1_pfa && eexec_scan == eexec_len && c == 32))
1965 if (mp->ps->t1_cs && mp->ps->t1_cslen == 0 &&
1966 (mp->ps->t1_line_ptr - mp->ps->t1_line_array > 4) &&
1967 (t1_suffix (" RD ") || t1_suffix (" -| "))) {
1968 p = mp->ps->t1_line_ptr - 5;
1971 mp->ps->t1_cslen = l = t1_scan_num (mp, p + 1, 0);
1972 mp->ps->cs_start = mp->ps->t1_line_ptr - mp->ps->t1_line_array;
1973 /* |mp->ps->cs_start| is an index now */
1974 alloc_array (t1_line, l, T1_BUF_SIZE);
1976 *mp->ps->t1_line_ptr++ = edecrypt (mp,t1_getbyte (mp));
1978 c = t1_getbyte (mp);
1980 alloc_array (t1_line, 2, T1_BUF_SIZE); /* |append_eol| can append 2 chars */
1981 append_eol (mp->ps->t1_line_ptr, mp->ps->t1_line_array, mp->ps->t1_line_limit);
1982 if (mp->ps->t1_line_ptr - mp->ps->t1_line_array < 2)
1984 if (eexec_scan == eexec_len)
1985 mp->ps->t1_in_eexec = 1;
1987 /* ensure that |mp->ps->t1_buf_array| has as much room as |t1_line_array| */
1988 mp->ps->t1_buf_ptr = mp->ps->t1_buf_array;
1989 alloc_array (t1_buf, mp->ps->t1_line_limit, mp->ps->t1_line_limit);
1992 static void t1_putline (MP mp)
1994 char *p = mp->ps->t1_line_array;
1995 if (mp->ps->t1_line_ptr - mp->ps->t1_line_array <= 1)
1997 if (mp->ps->t1_eexec_encrypt) {
1998 while (p < mp->ps->t1_line_ptr)
1999 out_eexec_char (eencrypt (mp,*p++));
2001 while (p < mp->ps->t1_line_ptr)
2006 static void t1_puts (MP mp, const char *s)
2008 if (s != mp->ps->t1_line_array)
2009 strcpy (mp->ps->t1_line_array, s);
2010 mp->ps->t1_line_ptr = strend (mp->ps->t1_line_array);
2014 static void t1_printf (MP mp, const char *fmt, ...)
2017 va_start (args, fmt);
2018 vsprintf (mp->ps->t1_line_array, fmt, args);
2019 t1_puts (mp,mp->ps->t1_line_array);
2023 static void t1_init_params (MP mp, char *open_name_prefix,
2024 char *cur_file_name) {
2025 if ((open_name_prefix != NULL) && strlen(open_name_prefix)) {
2026 t1_log (open_name_prefix);
2027 t1_log (cur_file_name);
2029 mp->ps->t1_lenIV = 4;
2030 mp->ps->t1_dr = 55665;
2031 mp->ps->t1_er = 55665;
2032 mp->ps->t1_in_eexec = 0;
2033 mp->ps->t1_cs = false;
2034 mp->ps->t1_scan = true;
2035 mp->ps->t1_synthetic = false;
2036 mp->ps->t1_eexec_encrypt = false;
2037 mp->ps->t1_block_length = 0;
2040 static void t1_close_font_file (MP mp, const char *close_name_suffix) {
2041 if ((close_name_suffix != NULL) && strlen(close_name_suffix)) {
2042 t1_log (close_name_suffix);
2047 static void t1_check_block_len (MP mp, boolean decrypt) {
2050 if (mp->ps->t1_block_length == 0)
2052 c = t1_getbyte (mp);
2054 c = edecrypt (mp,c);
2055 l = mp->ps->t1_block_length;
2056 if (!(l == 0 && (c == 10 || c == 13))) {
2057 snprintf(s,128,"%i bytes more than expected were ignored", l+ 1);
2063 static void t1_start_eexec (MP mp, fm_entry *fm_cur) {
2065 if (!mp->ps->t1_pfa)
2066 t1_check_block_len (mp, false);
2067 for (mp->ps->t1_line_ptr = mp->ps->t1_line_array, i = 0; i < 4; i++) {
2068 edecrypt (mp, t1_getbyte (mp));
2069 *mp->ps->t1_line_ptr++ = 0;
2071 mp->ps->t1_eexec_encrypt = true;
2072 if (!mp->ps->read_encoding_only)
2073 if (is_included (fm_cur))
2074 t1_putline (mp); /* to put the first four bytes */
2076 static void t1_stop_eexec (MP mp) {
2078 end_last_eexec_line ();
2079 if (!mp->ps->t1_pfa)
2080 t1_check_block_len (mp,true);
2082 c = edecrypt (mp, t1_getbyte (mp));
2083 if (!(c == 10 || c == 13)) {
2084 if (mp->ps->last_hexbyte == 0)
2087 mp_warn (mp,"unexpected data after eexec");
2090 mp->ps->t1_cs = false;
2091 mp->ps->t1_in_eexec = 2;
2093 static void t1_modify_fm (MP mp) {
2094 mp->ps->t1_line_ptr = eol (mp->ps->t1_line_array);
2097 static void t1_modify_italic (MP mp) {
2098 mp->ps->t1_line_ptr = eol (mp->ps->t1_line_array);
2103 const char *pdfname;
2113 static key_entry font_keys[FONT_KEYS_NUM] = {
2114 {"Ascent", "Ascender", 0, false},
2115 {"CapHeight", "CapHeight", 0, false},
2116 {"Descent", "Descender", 0, false},
2117 {"FontName", "FontName", 0, false},
2118 {"ItalicAngle", "ItalicAngle", 0, false},
2119 {"StemV", "StdVW", 0, false},
2120 {"XHeight", "XHeight", 0, false},
2121 {"FontBBox", "FontBBox", 0, false},
2133 @d ITALIC_ANGLE_CODE 4
2139 @d FONTBBOX4_CODE 10
2140 @d MAX_KEY_CODE (FONTBBOX1_CODE + 1)
2143 static void t1_scan_keys (MP mp, int tex_font,fm_entry *fm_cur) {
2147 if (fm_extend (fm_cur) != 0 || fm_slant (fm_cur) != 0) {
2148 if (t1_prefix ("/FontMatrix")) {
2152 if (t1_prefix ("/ItalicAngle")) {
2153 t1_modify_italic (mp);
2157 if (t1_prefix ("/FontType")) {
2158 p = mp->ps->t1_line_array + strlen ("FontType") + 1;
2159 if ((i = t1_scan_num (mp,p, 0)) != 1) {
2161 snprintf(s,125,"Type%d fonts unsupported by metapost", i);
2162 mp_fatal_error(mp,s);
2166 for (key = font_keys; key - font_keys < MAX_KEY_CODE; key++)
2167 if (str_prefix (mp->ps->t1_line_array + 1, key->t1name))
2169 if (key - font_keys == MAX_KEY_CODE)
2172 p = mp->ps->t1_line_array + strlen (key->t1name) + 1;
2174 if ((k = key - font_keys) == FONTNAME_CODE) {
2177 remove_eol (p, mp->ps->t1_line_array);
2178 snprintf(s,128,"a name expected: `%s'", mp->ps->t1_line_array);
2179 mp_fatal_error(mp,s);
2181 r = ++p; /* skip the slash */
2182 if (is_included (fm_cur)) {
2183 /* save the fontname */
2184 strncpy (mp->ps->fontname_buf, p, FONTNAME_BUF_SIZE);
2185 for (i=0; mp->ps->fontname_buf[i] != 10; i++);
2186 mp->ps->fontname_buf[i]=0;
2188 if(is_subsetted (fm_cur)) {
2189 if (fm_cur->encoding!=NULL && fm_cur->encoding->glyph_names!=NULL)
2190 make_subset_tag (mp,fm_cur, fm_cur->encoding->glyph_names, tex_font);
2192 make_subset_tag (mp,fm_cur, mp->ps->t1_builtin_glyph_names, tex_font);
2194 alloc_array (t1_line, (r-mp->ps->t1_line_array+6+1+strlen(mp->ps->fontname_buf)+1),
2196 strncpy (r, fm_cur->subset_tag , 6);
2198 strncpy (r+7, mp->ps->fontname_buf, strlen(mp->ps->fontname_buf)+1);
2199 mp->ps->t1_line_ptr = eol (r);
2201 /* |for (q = p; *q != ' ' && *q != 10; *q++);|*/
2203 mp->ps->t1_line_ptr = eol (r);
2208 if ((k == STEMV_CODE || k == FONTBBOX1_CODE)
2209 && (*p == '[' || *p == '{'))
2211 if (k == FONTBBOX1_CODE) {
2212 for (i = 0; i < 4; i++) {
2213 key[i].value = t1_scan_num (mp, p, &r);
2218 key->value = t1_scan_num (mp, p, 0);
2220 static void t1_scan_param (MP mp, int tex_font,fm_entry *fm_cur)
2222 static const char *lenIV = "/lenIV";
2223 if (!mp->ps->t1_scan || *mp->ps->t1_line_array != '/')
2225 if (t1_prefix (lenIV)) {
2226 mp->ps->t1_lenIV = t1_scan_num (mp,mp->ps->t1_line_array + strlen (lenIV), 0);
2229 t1_scan_keys (mp, tex_font,fm_cur);
2231 static void copy_glyph_names (MP mp, char **glyph_names, int a, int b) {
2232 if (glyph_names[b] != notdef) {
2233 mp_xfree (glyph_names[b]);
2234 glyph_names[b] = (char *) notdef;
2236 if (glyph_names[a] != notdef) {
2237 glyph_names[b] = mp_xstrdup (mp,glyph_names[a]);
2240 static void t1_builtin_enc (MP mp) {
2241 int i, a, b, c, counter = 0;
2244 * At this moment "/Encoding" is the prefix of |mp->ps->t1_line_array|
2246 if (t1_suffix ("def")) { /* predefined encoding */
2247 sscanf (mp->ps->t1_line_array + strlen ("/Encoding"), "%256s", mp->ps->t1_buf_array);
2248 if (strcmp (mp->ps->t1_buf_array, "StandardEncoding") == 0) {
2249 for (i = 0; i < 256; i++)
2250 if (standard_glyph_names[i] == notdef)
2251 mp->ps->t1_builtin_glyph_names[i] = (char *) notdef;
2253 mp->ps->t1_builtin_glyph_names[i] =
2254 mp_xstrdup (mp,standard_glyph_names[i]);
2255 mp->ps->t1_encoding = ENC_STANDARD;
2258 snprintf(s,128, "cannot subset font (unknown predefined encoding `%s')",
2259 mp->ps->t1_buf_array);
2260 mp_fatal_error(mp,s);
2264 mp->ps->t1_encoding = ENC_BUILTIN;
2266 * At this moment "/Encoding" is the prefix of |mp->ps->t1_line_array|, and the encoding is
2267 * not a predefined encoding
2269 * We have two possible forms of Encoding vector. The first case is
2271 * /Encoding [/a /b /c...] readonly def
2273 * and the second case can look like
2275 * /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for
2281 for (i = 0; i < 256; i++)
2282 mp->ps->t1_builtin_glyph_names[i] = (char *) notdef;
2283 if (t1_prefix ("/Encoding [") || t1_prefix ("/Encoding[")) { /* the first case */
2284 r = strchr (mp->ps->t1_line_array, '[') + 1;
2288 for (p = mp->ps->t1_buf_array, r++;
2289 *r != 32 && *r != 10 && *r != ']' && *r != '/';
2293 if (counter > 255) {
2295 (mp, "encoding vector contains more than 256 names");
2297 if (strcmp (mp->ps->t1_buf_array, notdef) != 0)
2298 mp->ps->t1_builtin_glyph_names[counter] = mp_xstrdup (mp,mp->ps->t1_buf_array);
2301 if (*r != 10 && *r != '%') {
2302 if (str_prefix (r, "] def")
2303 || str_prefix (r, "] readonly def"))
2307 remove_eol (r, mp->ps->t1_line_array);
2308 snprintf(s,128,"a name or `] def' or `] readonly def' expected: `%s'",
2309 mp->ps->t1_line_array);
2310 mp_fatal_error(mp,s);
2314 r = mp->ps->t1_line_array;
2316 } else { /* the second case */
2317 p = strchr (mp->ps->t1_line_array, 10);
2321 p = mp->ps->t1_line_array;
2324 check for `dup <index> <glyph> put'
2326 if (sscanf (p, "dup %i%256s put", &i, mp->ps->t1_buf_array) == 2 &&
2327 *mp->ps->t1_buf_array == '/' && valid_code (i)) {
2328 if (strcmp (mp->ps->t1_buf_array + 1, notdef) != 0)
2329 mp->ps->t1_builtin_glyph_names[i] =
2330 mp_xstrdup (mp,mp->ps->t1_buf_array + 1);
2331 p = strstr (p, " put") + strlen (" put");
2335 check for `dup dup <to> exch <from> get put'
2337 else if (sscanf (p, "dup dup %i exch %i get put", &b, &a) == 2
2338 && valid_code (a) && valid_code (b)) {
2339 copy_glyph_names (mp,mp->ps->t1_builtin_glyph_names, a, b);
2340 p = strstr (p, " get put") + strlen (" get put");
2344 check for `dup dup <from> <size> getinterval <to> exch putinterval'
2347 (p, "dup dup %i %i getinterval %i exch putinterval",
2348 &a, &c, &b) == 3 && valid_code (a) && valid_code (b)
2349 && valid_code (c)) {
2350 for (i = 0; i < c; i++)
2351 copy_glyph_names (mp,mp->ps->t1_builtin_glyph_names, a + i, b + i);
2352 p = strstr (p, " putinterval") + strlen (" putinterval");
2356 check for `def' or `readonly def'
2358 else if ((p == mp->ps->t1_line_array || (p > mp->ps->t1_line_array && p[-1] == ' '))
2359 && strcmp (p, "def\n") == 0)
2362 skip an unrecognizable word
2365 while (*p != ' ' && *p != 10)
2373 static void t1_check_end (MP mp) {
2377 if (t1_prefix ("{restore}"))
2383 char *ff_name; /* base name of font file */
2384 char *ff_path; /* full path to font file */
2388 static boolean t1_open_fontfile (MP mp, fm_entry *fm_cur,const char *open_name_prefix) {
2390 ff = check_ff_exist (mp, fm_cur);
2391 if (ff->ff_path != NULL) {
2392 mp->ps->t1_file = mp_open_file(mp,ff->ff_path, "rb", mp_filetype_font);
2394 mp_warn (mp, "cannot open Type 1 font file for reading");
2397 t1_init_params (mp,(char *)open_name_prefix,fm_cur->ff_name);
2398 mp->ps->fontfile_found = true;
2402 static void t1_scan_only (MP mp, int tex_font, fm_entry *fm_cur) {
2405 t1_scan_param (mp,tex_font, fm_cur);
2407 while (mp->ps->t1_in_eexec == 0);
2408 t1_start_eexec (mp,fm_cur);
2411 t1_scan_param (mp,tex_font, fm_cur);
2413 while (!(t1_charstrings () || t1_subrs ()));
2416 static void t1_include (MP mp, int tex_font, fm_entry *fm_cur) {
2419 t1_scan_param (mp,tex_font, fm_cur);
2422 while (mp->ps->t1_in_eexec == 0);
2423 t1_start_eexec (mp,fm_cur);
2426 t1_scan_param (mp,tex_font, fm_cur);
2429 while (!(t1_charstrings () || t1_subrs ()));
2430 mp->ps->t1_cs = true;
2435 while (!t1_end_eexec ());
2437 if (fixedcontent) { /* copy 512 zeros (not needed for PDF) */
2442 while (!t1_cleartomark ());
2443 t1_check_end (mp); /* write "{restore}if" if found */
2448 @d check_subr(SUBR) if (SUBR >= mp->ps->subr_size || SUBR < 0) {
2450 snprintf(s,128,"Subrs array: entry index out of range (%i)",SUBR);
2451 mp_fatal_error(mp,s);
2455 static const char **check_cs_token_pair (MP mp) {
2456 const char **p = (const char **) cs_token_pairs_list;
2457 for (; p[0] != NULL; ++p)
2458 if (t1_buf_prefix (p[0]) && t1_buf_suffix (p[1]))
2463 static void cs_store (MP mp, boolean is_subr) {
2467 for (p = mp->ps->t1_line_array, mp->ps->t1_buf_ptr = mp->ps->t1_buf_array; *p != ' ';
2468 *mp->ps->t1_buf_ptr++ = *p++);
2469 *mp->ps->t1_buf_ptr = 0;
2471 subr = t1_scan_num (mp, p + 1, 0);
2473 ptr = mp->ps->subr_tab + subr;
2475 ptr = mp->ps->cs_ptr++;
2476 if (mp->ps->cs_ptr - mp->ps->cs_tab > mp->ps->cs_size) {
2478 snprintf(s,128,"CharStrings dict: more entries than dict size (%i)",mp->ps->cs_size);
2479 mp_fatal_error(mp,s);
2481 if (strcmp (mp->ps->t1_buf_array + 1, notdef) == 0) /* skip the slash */
2482 ptr->glyph_name = (char *) notdef;
2484 ptr->glyph_name = mp_xstrdup (mp,mp->ps->t1_buf_array + 1);
2486 /* copy " RD " + cs data to |mp->ps->t1_buf_array| */
2487 memcpy (mp->ps->t1_buf_array, mp->ps->t1_line_array + mp->ps->cs_start - 4,
2488 (unsigned) (mp->ps->t1_cslen + 4));
2489 /* copy the end of cs data to |mp->ps->t1_buf_array| */
2490 for (p = mp->ps->t1_line_array + mp->ps->cs_start + mp->ps->t1_cslen, mp->ps->t1_buf_ptr =
2491 mp->ps->t1_buf_array + mp->ps->t1_cslen + 4; *p != 10; *mp->ps->t1_buf_ptr++ = *p++);
2492 *mp->ps->t1_buf_ptr++ = 10;
2493 if (is_subr && mp->ps->cs_token_pair == NULL)
2494 mp->ps->cs_token_pair = check_cs_token_pair (mp);
2495 ptr->len = mp->ps->t1_buf_ptr - mp->ps->t1_buf_array;
2496 ptr->cslen = mp->ps->t1_cslen;
2497 ptr->data = mp_xmalloc (mp,ptr->len , sizeof (byte));
2498 memcpy (ptr->data, mp->ps->t1_buf_array, ptr->len);
2502 #define store_subr(mp) cs_store(mp,true)
2503 #define store_cs(mp) cs_store(mp,false)
2505 #define CC_STACK_SIZE 24
2507 static integer cc_stack[CC_STACK_SIZE], *stack_ptr = cc_stack;
2508 static cc_entry cc_tab[CS_MAX];
2509 static boolean is_cc_init = false;
2513 if (stack_ptr - cc_stack < (N)) \
2517 #define stack_error(N) { \
2519 snprintf(s,255,"CharString: invalid access (%i) to stack (%i entries)", \
2520 (int) N, (int)(stack_ptr - cc_stack)); \
2526 #define cc_get(N) ((N) < 0 ? *(stack_ptr + (N)) : *(cc_stack + (N)))
2528 #define cc_push(V) *stack_ptr++ = V
2529 #define cc_clear() stack_ptr = cc_stack
2531 #define set_cc(N, B, A, C) \
2532 cc_tab[N].nargs = A; \
2533 cc_tab[N].bottom = B; \
2534 cc_tab[N].clear = C; \
2535 cc_tab[N].valid = true
2537 static void cc_init (void) {
2541 for (i = 0; i < CS_MAX; i++)
2542 cc_tab[i].valid = false;
2543 set_cc (CS_HSTEM, true, 2, true);
2544 set_cc (CS_VSTEM, true, 2, true);
2545 set_cc (CS_VMOVETO, true, 1, true);
2546 set_cc (CS_RLINETO, true, 2, true);
2547 set_cc (CS_HLINETO, true, 1, true);
2548 set_cc (CS_VLINETO, true, 1, true);
2549 set_cc (CS_RRCURVETO, true, 6, true);
2550 set_cc (CS_CLOSEPATH, false, 0, true);
2551 set_cc (CS_CALLSUBR, false, 1, false);
2552 set_cc (CS_RETURN, false, 0, false);
2554 |set_cc(CS_ESCAPE, false, 0, false);|
2556 set_cc (CS_HSBW, true, 2, true);
2557 set_cc (CS_ENDCHAR, false, 0, true);
2558 set_cc (CS_RMOVETO, true, 2, true);
2559 set_cc (CS_HMOVETO, true, 1, true);
2560 set_cc (CS_VHCURVETO, true, 4, true);
2561 set_cc (CS_HVCURVETO, true, 4, true);
2562 set_cc (CS_DOTSECTION, false, 0, true);
2563 set_cc (CS_VSTEM3, true, 6, true);
2564 set_cc (CS_HSTEM3, true, 6, true);
2565 set_cc (CS_SEAC, true, 5, true);
2566 set_cc (CS_SBW, true, 4, true);
2567 set_cc (CS_DIV, false, 2, false);
2568 set_cc (CS_CALLOTHERSUBR, false, 0, false);
2569 set_cc (CS_POP, false, 0, false);
2570 set_cc (CS_SETCURRENTPOINT, true, 2, true);
2576 @d cs_getchar(mp) cdecrypt(mp,*data++, &cr)
2578 @d mark_subr(mp,n) cs_mark(mp,0, n)
2579 @d mark_cs(mp,s) cs_mark(mp,s, 0)
2580 @d SMALL_BUF_SIZE 256
2583 static void cs_warn (MP mp, const char *cs_name, int subr, const char *fmt, ...) {
2584 char buf[SMALL_BUF_SIZE];
2587 va_start (args, fmt);
2588 vsprintf (buf, fmt, args);
2590 if (cs_name == NULL) {
2591 snprintf(s,299,"Subr (%i): %s", (int) subr, buf);
2593 snprintf(s,299,"CharString (/%s): %s", cs_name, buf);
2598 static void cs_mark (MP mp, const char *cs_name, int subr)
2604 static integer lastargOtherSubr3 = 3; /* the argument of last call to
2608 if (cs_name == NULL) {
2610 ptr = mp->ps->subr_tab + subr;
2614 if (mp->ps->cs_notdef != NULL &&
2615 (cs_name == notdef || strcmp (cs_name, notdef) == 0))
2616 ptr = mp->ps->cs_notdef;
2618 for (ptr = mp->ps->cs_tab; ptr < mp->ps->cs_ptr; ptr++)
2619 if (strcmp (ptr->glyph_name, cs_name) == 0)
2621 if (ptr == mp->ps->cs_ptr) {
2623 snprintf (s,128,"glyph `%s' undefined", cs_name);
2627 if (ptr->glyph_name == notdef)
2628 mp->ps->cs_notdef = ptr;
2631 /* only marked CharString entries and invalid entries can be skipped;
2632 valid marked subrs must be parsed to keep the stack in sync */
2633 if (!ptr->valid || (ptr->is_used && cs_name != NULL))
2635 ptr->is_used = true;
2637 cs_len = ptr->cslen;
2638 data = ptr->data + 4;
2639 for (i = 0; i < mp->ps->t1_lenIV; i++, cs_len--)
2641 while (cs_len > 0) {
2643 b = cs_getchar (mp);
2647 else if (b <= 250) {
2649 a = ((b - 247) << 8) + 108 + cs_getchar (mp);
2650 } else if (b <= 254) {
2652 a = -((b - 251) << 8) - 108 - cs_getchar (mp);
2655 a = (cs_getchar (mp) & 0xff) << 24;
2656 a |= (cs_getchar (mp) & 0xff) << 16;
2657 a |= (cs_getchar (mp) & 0xff) << 8;
2658 a |= (cs_getchar (mp) & 0xff) << 0;
2659 if (sizeof (integer) > 4 && (a & 0x80000000))
2664 if (b == CS_ESCAPE) {
2665 b = cs_getchar (mp) + CS_1BYTE_MAX;
2669 cs_warn (mp,cs_name, subr, "command value out of range: %i",
2675 cs_warn (mp,cs_name, subr, "command not valid: %i", (int) b);
2679 if (stack_ptr - cc_stack < cc->nargs)
2680 cs_warn (mp,cs_name, subr,
2681 "less arguments on stack (%i) than required (%i)",
2682 (int) (stack_ptr - cc_stack), (int) cc->nargs);
2683 else if (stack_ptr - cc_stack > cc->nargs)
2684 cs_warn (mp,cs_name, subr,
2685 "more arguments on stack (%i) than required (%i)",
2686 (int) (stack_ptr - cc_stack), (int) cc->nargs);
2688 switch (cc - cc_tab) {
2693 if (!mp->ps->subr_tab[a1].valid) {
2694 cs_warn (mp,cs_name, subr, "cannot call subr (%i)", (int) a1);
2702 case CS_CALLOTHERSUBR:
2703 if (cc_get (-1) == 3)
2704 lastargOtherSubr3 = cc_get (-3);
2705 a1 = cc_get (-2) + 2;
2709 cc_push (lastargOtherSubr3);
2710 /* the only case when we care about the value being pushed onto
2711 stack is when POP follows CALLOTHERSUBR (changing hints by
2719 mark_cs (mp,standard_glyph_names[a1]);
2720 mark_cs (mp,standard_glyph_names[a2]);
2729 cs_error: /* an error occured during parsing */
2732 ptr->is_used = false;
2735 static void t1_subset_ascii_part (MP mp, int tex_font, fm_entry *fm_cur)
2739 while (!t1_prefix ("/Encoding")) {
2740 t1_scan_param (mp,tex_font, fm_cur);
2744 t1_builtin_enc (mp);
2745 if (is_reencoded (fm_cur))
2746 mp->ps->t1_glyph_names = external_enc ();
2748 mp->ps->t1_glyph_names = mp->ps->t1_builtin_glyph_names;
2750 |if (is_included (fm_cur) && is_subsetted (fm_cur)) {
2751 make_subset_tag (fm_cur, t1_glyph_names, tex_font);
2752 update_subset_tag ();
2755 if ((!is_subsetted (fm_cur)) && mp->ps->t1_encoding == ENC_STANDARD)
2756 t1_puts (mp,"/Encoding StandardEncoding def\n");
2759 (mp,"/Encoding 256 array\n0 1 255 {1 index exch /.notdef put} for\n");
2760 for (i = 0, j = 0; i < 256; i++) {
2761 if (is_used_char (i) && mp->ps->t1_glyph_names[i] != notdef) {
2763 t1_printf (mp,"dup %i /%s put\n", (int) t1_char (i),
2764 mp->ps->t1_glyph_names[i]);
2767 /* We didn't mark anything for the Encoding array. */
2768 /* We add "dup 0 /.notdef put" for compatibility */
2769 /* with Acrobat 5.0. */
2771 t1_puts (mp,"dup 0 /.notdef put\n");
2772 t1_puts (mp,"readonly def\n");
2776 t1_scan_param (mp,tex_font, fm_cur);
2777 if (!t1_prefix ("/UniqueID")) /* ignore UniqueID for subsetted fonts */
2780 while (mp->ps->t1_in_eexec == 0);
2783 #define t1_subr_flush(mp) t1_flush_cs(mp,true)
2784 #define t1_cs_flush(mp) t1_flush_cs(mp,false)
2786 static void cs_init (MP mp) {
2787 mp->ps->cs_ptr = mp->ps->cs_tab = NULL;
2788 mp->ps->cs_dict_start = mp->ps->cs_dict_end = NULL;
2789 mp->ps->cs_count = mp->ps->cs_size = mp->ps->cs_size_pos = 0;
2790 mp->ps->cs_token_pair = NULL;
2791 mp->ps->subr_tab = NULL;
2792 mp->ps->subr_array_start = mp->ps->subr_array_end = NULL;
2793 mp->ps->subr_max = mp->ps->subr_size = mp->ps->subr_size_pos = 0;
2796 static void init_cs_entry ( cs_entry * cs) {
2798 cs->glyph_name = NULL;
2801 cs->is_used = false;
2805 static void t1_mark_glyphs (MP mp, int tex_font);
2807 static void t1_read_subrs (MP mp, int tex_font, fm_entry *fm_cur)
2812 while (!(t1_charstrings () || t1_subrs ())) {
2813 t1_scan_param (mp,tex_font, fm_cur);
2818 mp->ps->t1_cs = true;
2819 mp->ps->t1_scan = false;
2822 mp->ps->subr_size_pos = strlen ("/Subrs") + 1;
2823 /* |subr_size_pos| points to the number indicating dict size after "/Subrs" */
2824 mp->ps->subr_size = t1_scan_num (mp,mp->ps->t1_line_array + mp->ps->subr_size_pos, 0);
2825 if (mp->ps->subr_size == 0) {
2826 while (!t1_charstrings ())
2830 /* |subr_tab = xtalloc (subr_size, cs_entry);| */
2831 mp->ps->subr_tab = (cs_entry *)mp_xmalloc (mp,mp->ps->subr_size, sizeof (cs_entry));
2832 for (ptr = mp->ps->subr_tab; ptr - mp->ps->subr_tab < mp->ps->subr_size; ptr++)
2833 init_cs_entry (ptr);
2834 mp->ps->subr_array_start = mp_xstrdup (mp,mp->ps->t1_line_array);
2836 while (mp->ps->t1_cslen) {
2840 /* mark the first four entries without parsing */
2841 for (i = 0; i < mp->ps->subr_size && i < 4; i++)
2842 mp->ps->subr_tab[i].is_used = true;
2843 /* the end of the Subrs array might have more than one line so we need to
2844 concatnate them to |subr_array_end|. Unfortunately some fonts don't have
2845 the Subrs array followed by the CharStrings dict immediately (synthetic
2846 fonts). If we cannot find CharStrings in next |POST_SUBRS_SCAN| lines then
2847 we will treat the font as synthetic and ignore everything until next
2850 #define POST_SUBRS_SCAN 5
2852 *mp->ps->t1_buf_array = 0;
2853 for (i = 0; i < POST_SUBRS_SCAN; i++) {
2854 if (t1_charstrings ())
2856 s += mp->ps->t1_line_ptr - mp->ps->t1_line_array;
2857 alloc_array (t1_buf, s, T1_BUF_SIZE);
2858 strcat (mp->ps->t1_buf_array, mp->ps->t1_line_array);
2861 mp->ps->subr_array_end = mp_xstrdup (mp,mp->ps->t1_buf_array);
2862 if (i == POST_SUBRS_SCAN) { /* CharStrings not found;
2863 suppose synthetic font */
2864 for (ptr = mp->ps->subr_tab; ptr - mp->ps->subr_tab < mp->ps->subr_size; ptr++)
2866 mp_xfree (ptr->data);
2867 mp_xfree (mp->ps->subr_tab);
2868 mp_xfree (mp->ps->subr_array_start);
2869 mp_xfree (mp->ps->subr_array_end);
2871 mp->ps->t1_cs = false;
2872 mp->ps->t1_synthetic = true;
2873 while (!(t1_charstrings () || t1_subrs ()))
2880 static void t1_flush_cs (MP mp, boolean is_subr)
2883 byte *r, *return_cs = NULL;
2884 cs_entry *tab, *end_tab, *ptr;
2885 char *start_line, *line_end;
2886 int count, size_pos;
2887 unsigned short cr, cs_len = 0; /* to avoid warning about uninitialized use of |cs_len| */
2889 start_line = mp->ps->subr_array_start;
2890 line_end = mp->ps->subr_array_end;
2891 size_pos = mp->ps->subr_size_pos;
2892 tab = mp->ps->subr_tab;
2893 count = mp->ps->subr_max + 1;
2894 end_tab = mp->ps->subr_tab + count;
2896 start_line = mp->ps->cs_dict_start;
2897 line_end = mp->ps->cs_dict_end;
2898 size_pos = mp->ps->cs_size_pos;
2899 tab = mp->ps->cs_tab;
2900 end_tab = mp->ps->cs_ptr;
2901 count = mp->ps->cs_count;
2903 mp->ps->t1_line_ptr = mp->ps->t1_line_array;
2904 for (p = start_line; p - start_line < size_pos;)
2905 *mp->ps->t1_line_ptr++ = *p++;
2906 while (isdigit (*p))
2908 sprintf (mp->ps->t1_line_ptr, "%u", count);
2909 strcat (mp->ps->t1_line_ptr, p);
2910 mp->ps->t1_line_ptr = eol (mp->ps->t1_line_array);
2913 /* create |return_cs| to replace unsused subr's */
2917 return_cs = mp_xmalloc (mp, (mp->ps->t1_lenIV + 1) , sizeof(byte));
2918 if ( mp->ps->t1_lenIV > 0) {
2919 for (cs_len = 0, r = return_cs; cs_len < mp->ps->t1_lenIV; cs_len++, r++)
2920 *r = cencrypt (mp,0x00, &cr);
2921 *r = cencrypt (mp,CS_RETURN, &cr);
2923 *return_cs = CS_RETURN;
2928 for (ptr = tab; ptr < end_tab; ptr++) {
2931 sprintf (mp->ps->t1_line_array, "dup %i %u", (int) (ptr - tab),
2934 sprintf (mp->ps->t1_line_array, "/%s %u", ptr->glyph_name, ptr->cslen);
2935 p = strend (mp->ps->t1_line_array);
2936 memcpy (p, ptr->data, ptr->len);
2937 mp->ps->t1_line_ptr = p + ptr->len;
2940 /* replace unsused subr's by |return_cs| */
2942 sprintf (mp->ps->t1_line_array, "dup %i %u%s ", (int) (ptr - tab),
2943 cs_len, mp->ps->cs_token_pair[0]);
2944 p = strend (mp->ps->t1_line_array);
2945 memcpy (p, return_cs, cs_len);
2946 mp->ps->t1_line_ptr = p + cs_len;
2948 sprintf (mp->ps->t1_line_array, " %s", mp->ps->cs_token_pair[1]);
2949 mp->ps->t1_line_ptr = eol (mp->ps->t1_line_array);
2953 mp_xfree (ptr->data);
2954 if (ptr->glyph_name != notdef)
2955 mp_xfree (ptr->glyph_name);
2957 sprintf (mp->ps->t1_line_array, "%s", line_end);
2958 mp->ps->t1_line_ptr = eol (mp->ps->t1_line_array);
2961 mp_xfree (return_cs);
2963 mp_xfree (start_line);
2964 mp_xfree (line_end);
2967 static void t1_mark_glyphs (MP mp, int tex_font)
2970 char *charset = extra_charset ();
2973 if (mp->ps->t1_synthetic || embed_all_glyphs (tex_font)) { /* mark everything */
2974 if (mp->ps->cs_tab != NULL)
2975 for (ptr = mp->ps->cs_tab; ptr < mp->ps->cs_ptr; ptr++)
2977 ptr->is_used = true;
2978 if (mp->ps->subr_tab != NULL) {
2979 for (ptr = mp->ps->subr_tab; ptr - mp->ps->subr_tab < mp->ps->subr_size; ptr++)
2981 ptr->is_used = true;
2982 mp->ps->subr_max = mp->ps->subr_size - 1;
2986 mark_cs (mp,notdef);
2987 for (i = 0; i < 256; i++)
2988 if (is_used_char (i)) {
2989 if (mp->ps->t1_glyph_names[i] == notdef) {
2991 snprintf(s,128, "character %i is mapped to %s", i, notdef);
2994 mark_cs (mp,mp->ps->t1_glyph_names[i]);
2996 if (charset == NULL)
2998 g = s = charset + 1; /* skip the first '/' */
3001 while (*s != '/' && s < r)
3003 *s = 0; /* terminate g by rewriting '/' to 0 */
3008 if (mp->ps->subr_tab != NULL)
3009 for (mp->ps->subr_max = -1, ptr = mp->ps->subr_tab;
3010 ptr - mp->ps->subr_tab < mp->ps->subr_size;
3012 if (ptr->is_used && ptr - mp->ps->subr_tab > mp->ps->subr_max)
3013 mp->ps->subr_max = ptr - mp->ps->subr_tab;
3016 static void t1_subset_charstrings (MP mp, int tex_font)
3019 mp->ps->cs_size_pos =
3020 strstr (mp->ps->t1_line_array, charstringname) + strlen (charstringname)
3021 - mp->ps->t1_line_array + 1;
3022 /* |cs_size_pos| points to the number indicating
3023 dict size after "/CharStrings" */
3024 mp->ps->cs_size = t1_scan_num (mp,mp->ps->t1_line_array + mp->ps->cs_size_pos, 0);
3025 mp->ps->cs_ptr = mp->ps->cs_tab = mp_xmalloc (mp,mp->ps->cs_size, sizeof(cs_entry));
3026 for (ptr = mp->ps->cs_tab; ptr - mp->ps->cs_tab < mp->ps->cs_size; ptr++)
3027 init_cs_entry (ptr);
3028 mp->ps->cs_notdef = NULL;
3029 mp->ps->cs_dict_start = mp_xstrdup (mp,mp->ps->t1_line_array);
3031 while (mp->ps->t1_cslen) {
3035 mp->ps->cs_dict_end = mp_xstrdup (mp,mp->ps->t1_line_array);
3036 t1_mark_glyphs (mp,tex_font);
3037 if (mp->ps->subr_tab != NULL) {
3038 if (mp->ps->cs_token_pair == NULL)
3040 (mp, "This Type 1 font uses mismatched subroutine begin/end token pairs.");
3043 for (mp->ps->cs_count = 0, ptr = mp->ps->cs_tab; ptr < mp->ps->cs_ptr; ptr++)
3049 static void t1_subset_end (MP mp)
3051 if (mp->ps->t1_synthetic) { /* copy to "dup /FontName get exch definefont pop" */
3052 while (!strstr (mp->ps->t1_line_array, "definefont")) {
3056 while (!t1_end_eexec ())
3057 t1_getline (mp); /* ignore the rest */
3058 t1_putline (mp); /* write "mark currentfile closefile" */
3060 while (!t1_end_eexec ()) { /* copy to "mark currentfile closefile" */
3065 if (fixedcontent) { /* copy 512 zeros (not needed for PDF) */
3066 while (!t1_cleartomark ()) {
3070 if (!mp->ps->t1_synthetic) /* don't check "{restore}if" for synthetic fonts */
3071 t1_check_end (mp); /* write "{restore}if" if found */
3075 static int t1_updatefm (MP mp, int f, fm_entry *fm)
3078 mp->ps->read_encoding_only = true;
3079 if (!t1_open_fontfile (mp,fm,NULL)) {
3082 t1_scan_only (mp,f, fm);
3083 s = mp_xstrdup(mp,mp->ps->fontname_buf);
3085 while (*p != ' ' && *p != 0)
3089 t1_close_font_file (mp,"");
3094 static void writet1 (MP mp, int tex_font, fm_entry *fm_cur) {
3095 int save_selector = mp->selector;
3096 mp_normalize_selector(mp);
3097 mp->ps->read_encoding_only = false;
3098 if (!is_included (fm_cur)) { /* scan parameters from font file */
3099 if (!t1_open_fontfile (mp,fm_cur,"{"))
3101 t1_scan_only (mp,tex_font, fm_cur);
3102 t1_close_font_file (mp,"}");
3105 if (!is_subsetted (fm_cur)) { /* include entire font */
3106 if (!t1_open_fontfile (mp,fm_cur,"<<"))
3108 t1_include (mp,tex_font,fm_cur);
3109 t1_close_font_file (mp,">>");
3112 /* partial downloading */
3113 if (!t1_open_fontfile (mp,fm_cur,"<"))
3115 t1_subset_ascii_part (mp,tex_font,fm_cur);
3116 t1_start_eexec (mp,fm_cur);
3119 t1_read_subrs (mp,tex_font, fm_cur);
3120 t1_subset_charstrings (mp,tex_font);
3122 t1_close_font_file (mp,">");
3123 mp->selector = save_selector;
3127 static void t1_free (MP mp);
3130 static void t1_free (MP mp) {
3131 mp_xfree (mp->ps->t1_line_array);
3132 mp_xfree (mp->ps->t1_buf_array);
3136 @* \[44d] Embedding fonts.
3138 @ The |tfm_num| is officially of type |font_number|, but that
3139 type does not exist yet at this point in the output order.
3143 char *tfm_name; /* TFM file name */
3144 char *ps_name; /* PostScript name */
3145 integer flags; /* font flags */
3146 char *ff_name; /* font file name */
3147 char *subset_tag; /* pseudoUniqueTag for subsetted font */
3148 enc_entry *encoding; /* pointer to corresponding encoding */
3149 unsigned int tfm_num; /* number of the TFM refering this entry */
3150 unsigned short type; /* font type (T1/TTF/...) */
3151 short slant; /* SlantFont */
3152 short extend; /* ExtendFont */
3153 integer ff_objnum; /* FontFile object number */
3154 integer fn_objnum; /* FontName/BaseName object number */
3155 integer fd_objnum; /* FontDescriptor object number */
3156 char *charset; /* string containing used glyphs */
3157 boolean all_glyphs; /* embed all glyphs? */
3158 unsigned short links; /* link flags from |tfm_tree| and |ps_tree| */
3159 short tfm_avail; /* flags whether a tfm is available */
3160 short pid; /* Pid for truetype fonts */
3161 short eid; /* Eid for truetype fonts */
3167 #define FONTNAME_BUF_SIZE 128
3168 boolean fontfile_found;
3169 boolean is_otf_font;
3170 char fontname_buf[FONTNAME_BUF_SIZE];
3178 @d set_included(fm) ((fm)->type |= F_INCLUDED)
3179 @d set_subsetted(fm) ((fm)->type |= F_SUBSETTED)
3180 @d set_truetype(fm) ((fm)->type |= F_TRUETYPE)
3181 @d set_basefont(fm) ((fm)->type |= F_BASEFONT)
3183 @d is_included(fm) ((fm)->type & F_INCLUDED)
3184 @d is_subsetted(fm) ((fm)->type & F_SUBSETTED)
3185 @d is_truetype(fm) ((fm)->type & F_TRUETYPE)
3186 @d is_basefont(fm) ((fm)->type & F_BASEFONT)
3187 @d is_reencoded(fm) ((fm)->encoding != NULL)
3188 @d is_fontfile(fm) (fm_fontfile(fm) != NULL)
3189 @d is_t1fontfile(fm) (is_fontfile(fm) && !is_truetype(fm))
3191 @d fm_slant(fm) (fm)->slant
3192 @d fm_extend(fm) (fm)->extend
3193 @d fm_fontfile(fm) (fm)->ff_name
3196 static boolean mp_font_is_reencoded (MP mp, int f);
3197 static boolean mp_font_is_included (MP mp, int f);
3198 static boolean mp_font_is_subsetted (MP mp, int f);
3201 static boolean mp_font_is_reencoded (MP mp, int f) {
3203 if (mp_has_font_size(mp,f) && mp_has_fm_entry (mp, f, &fm)) {
3205 && (fm->ps_name != NULL)
3206 && is_reencoded (fm))
3211 static boolean mp_font_is_included (MP mp, int f) {
3213 if (mp_has_font_size(mp,f) && mp_has_fm_entry (mp, f, &fm)) {
3215 && (fm->ps_name != NULL && fm->ff_name != NULL)
3216 && is_included (fm))
3221 static boolean mp_font_is_subsetted (MP mp, int f) {
3223 if (mp_has_font_size(mp,f) && mp_has_fm_entry (mp, f,&fm)) {
3225 && (fm->ps_name != NULL && fm->ff_name != NULL)
3226 && is_included (fm) && is_subsetted (fm))
3232 @ @<Exported function headers@>=
3233 char * mp_fm_encoding_name (MP mp, int f);
3234 char * mp_fm_font_name (MP mp, int f);
3237 static char * mp_fm_font_subset_name (MP mp, int f);
3240 @c char * mp_fm_encoding_name (MP mp, int f) {
3243 if (mp_has_fm_entry (mp, f, &fm)) {
3244 if (fm != NULL && (fm->ps_name != NULL)) {
3245 if (is_reencoded (fm)) {
3247 if (e->enc_name!=NULL)
3248 return mp_xstrdup(mp,e->enc_name);
3254 print_err ("fontmap encoding problems for font ");
3255 mp_print(mp,mp->font_name[f]);
3259 char * mp_fm_font_name (MP mp, int f) {
3261 if (mp_has_fm_entry (mp, f,&fm)) {
3262 if (fm != NULL && (fm->ps_name != NULL)) {
3263 if (mp_font_is_included(mp, f) && !mp->font_ps_name_fixed[f]) {
3264 /* find the real fontname, and update |ps_name| and |subset_tag| if needed */
3265 if (t1_updatefm(mp,f,fm)) {
3266 mp->font_ps_name_fixed[f] = true;
3268 print_err ("font loading problems for font ");
3269 mp_print(mp,mp->font_name[f]);
3273 return mp_xstrdup(mp,fm->ps_name);
3276 print_err ("fontmap name problems for font ");
3277 mp_print(mp,mp->font_name[f]);
3282 static char * mp_fm_font_subset_name (MP mp, int f) {
3284 if (mp_has_fm_entry (mp, f, &fm)) {
3285 if (fm != NULL && (fm->ps_name != NULL)) {
3286 if (is_subsetted(fm)) {
3287 char *s = mp_xmalloc(mp,strlen(fm->ps_name)+8,1);
3288 snprintf(s,strlen(fm->ps_name)+8,"%s-%s",fm->subset_tag,fm->ps_name);
3291 return mp_xstrdup(mp,fm->ps_name);
3295 print_err ("fontmap name problems for font ");
3296 mp_print(mp,mp->font_name[f]);
3302 static integer mp_fm_font_slant (MP mp, int f);
3303 static integer mp_fm_font_extend (MP mp, int f);
3306 @c static integer mp_fm_font_slant (MP mp, int f) {
3308 if (mp_has_fm_entry (mp, f, &fm)) {
3309 if (fm != NULL && (fm->ps_name != NULL)) {
3315 static integer mp_fm_font_extend (MP mp, int f) {
3317 if (mp_has_fm_entry (mp, f, &fm)) {
3318 if (fm != NULL && (fm->ps_name != NULL)) {
3326 static boolean mp_do_ps_font (MP mp, font_number f);
3328 @ @c static boolean mp_do_ps_font (MP mp, font_number f) {
3330 (void)mp_has_fm_entry (mp, f, &fm_cur); /* for side effects */
3333 if (is_truetype(fm_cur) ||
3334 (fm_cur->ps_name == NULL && fm_cur->ff_name == NULL)) {
3337 if (is_included(fm_cur)) {
3338 mp_print_nl(mp,"%%BeginResource: font ");
3339 if (is_subsetted(fm_cur)) {
3340 mp_print(mp, fm_cur->subset_tag);
3341 mp_print_char(mp,'-');
3343 mp_print(mp, fm_cur->ps_name);
3345 writet1 (mp,f,fm_cur);
3346 mp_print_nl(mp,"%%EndResource");
3352 @ Included subset fonts do not need and encoding vector, make
3353 sure we skip that case.
3356 static void mp_list_used_resources (MP mp);
3358 @ @c static void mp_list_used_resources (MP mp) {
3359 font_number f; /* fonts used in a text node or as loop counters */
3360 int ff; /* a loop counter */
3361 font_number ldf; /* the last \.{DocumentFont} listed (otherwise |null_font|) */
3363 int prologues = (mp->internal[mp_prologues]>>16);
3364 int procset = (mp->internal[mp_procset]>>16);
3367 mp_print_nl(mp, "%%DocumentResources: procset mpost");
3369 mp_print_nl(mp, "%%DocumentResources: procset mpost-minimal");
3372 for (f=null_font+1;f<=mp->last_fnum;f++) {
3373 if ( (mp_has_font_size(mp,f))&&(mp_font_is_reencoded(mp,f)) ) {
3374 for (ff=ldf;ff>=null_font;ff--) {
3375 if ( mp_has_font_size(mp,ff) )
3376 if ( mp_xstrcmp(mp->font_enc_name[f],mp->font_enc_name[ff])==0 )
3379 if ( mp_font_is_subsetted(mp,f) )
3381 if ( mp->ps_offset+1+strlen(mp->font_enc_name[f])>
3382 (unsigned)mp->max_print_line )
3383 mp_print_nl(mp, "%%+ encoding");
3386 mp_print_nl(mp, "%%+ encoding");
3388 mp_print_char(mp, ' ');
3389 mp_print(mp, mp->font_enc_name[f]);
3397 for (f=null_font+1;f<=mp->last_fnum;f++) {
3398 if ( mp_has_font_size(mp,f) ) {
3399 for (ff=ldf;ff>=null_font;ff--) {
3400 if ( mp_has_font_size(mp,ff) )
3401 if ( mp_xstrcmp(mp->font_name[f],mp->font_name[ff])==0 )
3404 if ( mp->ps_offset+1+strlen(mp->font_ps_name[f])>
3405 (unsigned)mp->max_print_line )
3406 mp_print_nl(mp, "%%+ font");
3409 mp_print_nl(mp, "%%+ font");
3411 mp_print_char(mp, ' ');
3412 if ( (prologues==3)&&
3413 (mp_font_is_subsetted(mp,f)) )
3414 mp_print(mp, mp_fm_font_subset_name(mp,f));
3416 mp_print(mp, mp->font_ps_name[f]);
3426 static void mp_list_supplied_resources (MP mp);
3428 @ @c static void mp_list_supplied_resources (MP mp) {
3429 font_number f; /* fonts used in a text node or as loop counters */
3430 int ff; /* a loop counter */
3431 font_number ldf; /* the last \.{DocumentFont} listed (otherwise |null_font|) */
3433 int prologues = (mp->internal[mp_prologues]>>16);
3434 int procset = (mp->internal[mp_procset]>>16);
3436 mp_print_nl(mp, "%%DocumentSuppliedResources: procset mpost");
3438 mp_print_nl(mp, "%%DocumentSuppliedResources: procset mpost-minimal");
3441 for (f=null_font+1;f<=mp->last_fnum;f++) {
3442 if ( (mp_has_font_size(mp,f))&&(mp_font_is_reencoded(mp,f)) ) {
3443 for (ff=ldf;ff>= null_font;ff++) {
3444 if ( mp_has_font_size(mp,ff) )
3445 if ( mp_xstrcmp(mp->font_enc_name[f],mp->font_enc_name[ff])==0 )
3448 if ( (prologues==3)&&(mp_font_is_subsetted(mp,f)))
3450 if ( mp->ps_offset+1+strlen(mp->font_enc_name[f])>(unsigned)mp->max_print_line )
3451 mp_print_nl(mp, "%%+ encoding");
3454 mp_print_nl(mp, "%%+ encoding");
3456 mp_print_char(mp, ' ');
3457 mp_print(mp, mp->font_enc_name[f]);
3466 for (f=null_font+1;f<=mp->last_fnum;f++) {
3467 if ( mp_has_font_size(mp,f) ) {
3468 for (ff=ldf;ff>= null_font;ff--) {
3469 if ( mp_has_font_size(mp,ff) )
3470 if ( mp_xstrcmp(mp->font_name[f],mp->font_name[ff])==0 )
3473 if ( ! mp_font_is_included(mp,f) )
3475 if ( mp->ps_offset+1+strlen(mp->font_ps_name[f])>(unsigned)mp->max_print_line )
3476 mp_print_nl(mp, "%%+ font");
3479 mp_print_nl(mp, "%%+ font");
3481 mp_print_char(mp, ' ');
3482 if ( mp_font_is_subsetted(mp,f) )
3483 mp_print(mp, mp_fm_font_subset_name(mp,f));
3485 mp_print(mp, mp->font_ps_name[f]);
3495 @ @<Declarations...@>=
3496 static void mp_list_needed_resources (MP mp);
3498 @ @c static void mp_list_needed_resources (MP mp) {
3499 font_number f; /* fonts used in a text node or as loop counters */
3500 int ff; /* a loop counter */
3501 font_number ldf; /* the last \.{DocumentFont} listed (otherwise |null_font|) */
3503 int prologues = (mp->internal[mp_prologues]>>16);
3506 for (f=null_font+1;f<=mp->last_fnum;f++ ) {
3507 if ( mp_has_font_size(mp,f)) {
3508 for (ff=ldf;ff>=null_font;ff--) {
3509 if ( mp_has_font_size(mp,ff) )
3510 if ( mp_xstrcmp(mp->font_name[f],mp->font_name[ff])==0 )
3513 if ((prologues==3)&&(mp_font_is_included(mp,f)) )
3515 if ( mp->ps_offset+1+strlen(mp->font_ps_name[f])>(unsigned)mp->max_print_line )
3516 mp_print_nl(mp, "%%+ font");
3519 mp_print_nl(mp, "%%DocumentNeededResources: font");
3521 mp_print_char(mp, ' ');
3522 mp_print(mp, mp->font_ps_name[f]);
3528 if ( ! firstitem ) {
3532 for (f=null_font+1;f<= mp->last_fnum;f++) {
3533 if ( mp_has_font_size(mp,f) ) {
3534 for (ff=ldf;ff>=null_font;ff-- ) {
3535 if ( mp_has_font_size(mp,ff) )
3536 if ( mp_xstrcmp(mp->font_name[f],mp->font_name[ff])==0 )
3539 if ((prologues==3)&&(mp_font_is_included(mp,f)) )
3541 mp_print(mp, "%%IncludeResource: font ");
3542 mp_print(mp, mp->font_ps_name[f]);
3553 static void mp_write_font_definition (MP mp, font_number f);
3557 @d applied_reencoding(A) ((mp_font_is_reencoded(mp,(A)))&&
3558 ((! mp_font_is_subsetted(mp,(A)))||(prologues==2)))
3560 @c static void mp_write_font_definition(MP mp, font_number f) {
3561 int prologues = (mp->internal[mp_prologues]>>16);
3562 if ( (applied_reencoding(f))||(mp_fm_font_slant(mp,f)!=0)||
3563 (mp_fm_font_extend(mp,f)!=0)||
3564 (mp_xstrcmp(mp->font_name[f],"psyrgo")==0)||
3565 (mp_xstrcmp(mp->font_name[f],"zpzdr-reversed")==0) ) {
3566 if ( (mp_font_is_subsetted(mp,f))&&
3567 (mp_font_is_included(mp,f))&&(prologues==3))
3568 mp_ps_name_out(mp, mp_fm_font_subset_name(mp,f),true);
3570 mp_ps_name_out(mp, mp->font_ps_name[f],true);
3571 mp_ps_print(mp, " fcp");
3573 if ( applied_reencoding(f) ) {
3574 mp_ps_print(mp, "/Encoding ");
3575 mp_ps_print(mp, mp->font_enc_name[f]);
3576 mp_ps_print(mp, " def ");
3578 if ( mp_fm_font_slant(mp,f)!=0 ) {
3579 mp_print_int(mp, mp_fm_font_slant(mp,f));
3580 mp_ps_print(mp, " SlantFont ");
3582 if ( mp_fm_font_extend(mp,f)!=0 ) {
3583 mp_print_int(mp, mp_fm_font_extend(mp,f));
3584 mp_ps_print(mp, " ExtendFont ");
3586 if ( mp_xstrcmp(mp->font_name[f],"psyrgo")==0 ) {
3587 mp_ps_print(mp, " 890 ScaleFont ");
3588 mp_ps_print(mp, " 277 SlantFont ");
3590 if ( mp_xstrcmp(mp->font_name[f],"zpzdr-reversed")==0 ) {
3591 mp_ps_print(mp, " FontMatrix [-1 0 0 1 0 0] matrix concatmatrix /FontMatrix exch def ");
3592 mp_ps_print(mp, "/Metrics 2 dict dup begin ");
3593 mp_ps_print(mp, "/space[0 -278]def ");
3594 mp_ps_print(mp, "/a12[-904 -939]def ");
3595 mp_ps_print(mp, "end def ");
3597 mp_ps_print(mp, "currentdict end");
3599 mp_ps_print_defined_name(mp,f);
3600 mp_ps_print(mp, " exch definefont pop");
3606 static void mp_ps_print_defined_name (MP mp, font_number f);
3609 @c static void mp_ps_print_defined_name(MP mp, font_number A) {
3610 int prologues = (mp->internal[mp_prologues]>>16);
3611 mp_ps_print(mp, " /");
3612 if ((mp_font_is_subsetted(mp,(A)))&&
3613 (mp_font_is_included(mp,(A)))&&(prologues==3))
3614 mp_print(mp, mp_fm_font_subset_name(mp,(A)));
3616 mp_print(mp, mp->font_ps_name[(A)]);
3617 if ( mp_xstrcmp(mp->font_name[(A)],"psyrgo")==0 )
3618 mp_ps_print(mp, "-Slanted");
3619 if ( mp_xstrcmp(mp->font_name[(A)],"zpzdr-reversed")==0 )
3620 mp_ps_print(mp, "-Reverse");
3621 if ( applied_reencoding((A)) ) {
3622 mp_ps_print(mp, "-");
3623 mp_ps_print(mp, mp->font_enc_name[(A)]);
3625 if ( mp_fm_font_slant(mp,(A))!=0 ) {
3626 mp_ps_print(mp, "-Slant_"); mp_print_int(mp, mp_fm_font_slant(mp,(A))) ;
3628 if ( mp_fm_font_extend(mp,(A))!=0 ) {
3629 mp_ps_print(mp, "-Extend_"); mp_print_int(mp, mp_fm_font_extend(mp,(A)));
3633 @ @<Include encodings and fonts for edge structure~|h|@>=
3634 mp_font_encodings(mp,mp->last_fnum,prologues==2);
3635 @<Embed fonts that are available@>
3637 @ @<Embed fonts that are available@>=
3640 @<Make |cur_fsize| a copy of the |font_sizes| array@>;
3643 for (f=null_font+1;f<=mp->last_fnum;f++) {
3644 if ( cur_fsize[f]!=null ) {
3645 if (prologues==3 ) {
3646 if ( ! mp_do_ps_font(mp,f) ) {
3647 if ( mp_has_fm_entry(mp,f, NULL) ) {
3648 print_err("Font embedding failed");
3653 cur_fsize[f]=link(cur_fsize[f]);
3654 if ( cur_fsize[f]!=null ) { mp_unmark_font(mp, f); done_fonts=false; }
3658 @<Increment |next_size| and apply |mark_string_chars| to all text nodes with
3660 } while (! done_fonts);
3663 @ @<Increment |next_size| and apply |mark_string_chars| to all text nodes...@>=
3666 mp_apply_mark_string_chars(mp, h, next_size);
3669 @ We also need to keep track of which characters are used in text nodes
3670 in the edge structure that is being shipped out. This is done by procedures
3671 that use the left-over |b3| field in the |char_info| words; i.e.,
3672 |char_info(f)(c).b3| gives the status of character |c| in font |f|.
3675 enum mp_char_mark_state {mp_unused=0, mp_used};
3678 void mp_mark_string_chars (MP mp,font_number f, str_number s) ;
3681 void mp_mark_string_chars (MP mp,font_number f, str_number s) {
3682 integer b; /* |char_base[f]| */
3683 ASCII_code bc,ec; /* only characters between these bounds are marked */
3684 pool_pointer k; /* an index into string |s| */
3688 k=mp->str_start[mp->next_str[s]]; /* str_stop */
3689 while ( k>mp->str_start[s] ){
3691 if ( (mp->str_pool[k]>=bc)&&(mp->str_pool[k]<=ec) )
3692 mp->font_info[b+mp->str_pool[k]].qqqq.b3=mp_used;
3698 void mp_unmark_font (MP mp,font_number f) ;
3701 void mp_unmark_font (MP mp,font_number f) {
3702 int k; /* an index into |font_info| */
3703 for (k= mp->char_base[f]+mp->font_bc[f];
3704 k<=mp->char_base[f]+mp->font_ec[f];
3706 mp->font_info[k].qqqq.b3=mp_unused;
3711 void mp_print_improved_prologue (MP mp, pointer h) ;
3716 void mp_print_improved_prologue (MP mp, pointer h) {
3717 quarterword next_size; /* the size index for fonts being listed */
3718 pointer *cur_fsize; /* current positions in |font_sizes| */
3719 boolean done_fonts; /* have we finished listing the fonts in the header? */
3720 font_number f; /* a font number for loops */
3722 int prologues = (mp->internal[mp_prologues]>>16);
3723 int procset = (mp->internal[mp_procset]>>16);
3724 int groffmode = (mp->internal[mp_gtroffmode]>>16);
3726 cur_fsize = mp_xmalloc(mp,(mp->font_max+1),sizeof(pointer));
3728 mp_list_used_resources(mp);
3729 mp_list_supplied_resources(mp);
3730 mp_list_needed_resources(mp);
3731 mp_print_nl(mp, "%%EndComments");
3732 mp_print_nl(mp, "%%BeginProlog");
3734 mp_print_nl(mp, "%%BeginResource: procset mpost");
3736 mp_print_nl(mp, "%%BeginResource: procset mpost-minimal");
3737 mp_print_nl(mp, "/bd{bind def}bind def"
3738 "/fshow {exch findfont exch scalefont setfont show}bd");
3739 if ( procset>0 ) @<Print the procset@>;
3740 mp_print_nl(mp, "/fcp{findfont dup length dict begin"
3741 "{1 index/FID ne{def}{pop pop}ifelse}forall}bd");
3742 mp_print_nl(mp, "/fmc{FontMatrix dup length array copy dup dup}bd"
3743 "/fmd{/FontMatrix exch def}bd");
3744 mp_print_nl(mp, "/Amul{4 -1 roll exch mul 1000 div}bd"
3745 "/ExtendFont{fmc 0 get Amul 0 exch put fmd}bd");
3746 if ( groffmode>0 ) {
3747 mp_print_nl(mp, "/ScaleFont{dup fmc 0 get"
3748 " Amul 0 exch put dup dup 3 get Amul 3 exch put fmd}bd");
3750 mp_print_nl(mp, "/SlantFont{fmc 2 get dup 0 eq{pop 1}if"
3751 " Amul FontMatrix 0 get mul 2 exch put fmd}bd");
3752 mp_print_nl(mp, "%%EndResource");
3753 @<Include encodings and fonts for edge structure~|h|@>;
3754 mp_print_nl(mp, "%%EndProlog");
3755 mp_print_nl(mp, "%%BeginSetup");
3757 for (f=null_font+1;f<=mp->last_fnum;f++) {
3758 if ( mp_has_font_size(mp,f) ) {
3759 if ( mp_has_fm_entry(mp,f,NULL) ) {
3760 mp_write_font_definition(mp,f);
3761 mp_ps_name_out(mp, mp->font_name[f],true);
3762 mp_ps_print_defined_name(mp,f);
3763 mp_ps_print(mp, " def");
3766 snprintf(s,256,"font %s cannot be found in any fontmapfile!", mp->font_name[f]);
3768 mp_ps_name_out(mp, mp->font_name[f],true);
3769 mp_ps_name_out(mp, mp->font_name[f],true);
3770 mp_ps_print(mp, " def");
3775 mp_print_nl(mp, "%%EndSetup");
3776 mp_print_nl(mp, "%%Page: 1 1");
3778 mp_xfree(cur_fsize);
3782 static font_number mp_print_font_comments (MP mp , pointer h);
3787 static font_number mp_print_font_comments (MP mp , pointer h) {
3788 quarterword next_size; /* the size index for fonts being listed */
3789 pointer *cur_fsize; /* current positions in |font_sizes| */
3790 int ff; /* a loop counter */
3791 boolean done_fonts; /* have we finished listing the fonts in the header? */
3792 font_number f; /* a font number for loops */
3793 scaled ds; /* design size and scale factor for a text node */
3794 font_number ldf=0; /* the last \.{DocumentFont} listed (otherwise |null_font|) */
3795 int prologues = (mp->internal[mp_prologues]>>16);
3796 cur_fsize = mp_xmalloc(mp,(mp->font_max+1),sizeof(pointer));
3797 if ( prologues>0 ) {
3798 @<Give a \.{DocumentFonts} comment listing all fonts with non-null
3799 |font_sizes| and eliminate duplicates@>;
3802 @<Make |cur_fsize| a copy of the |font_sizes| array@>;
3803 do { done_fonts=true;
3804 for (f=null_font+1;f<=mp->last_fnum;f++) {
3805 if ( cur_fsize[f]!=null ) {
3806 @<Print the \.{\%*Font} comment for font |f| and advance |cur_fsize[f]|@>;
3808 if ( cur_fsize[f]!=null ) { mp_unmark_font(mp, f); done_fonts=false; };
3810 if ( ! done_fonts ) {
3811 @<Increment |next_size| and apply |mark_string_chars| to all text nodes with
3814 } while (! done_fonts);
3816 mp_xfree(cur_fsize);
3820 @ @<Make |cur_fsize| a copy of the |font_sizes| array@>=
3821 for (f=null_font+1;f<= mp->last_fnum;f++)
3822 cur_fsize[f]=mp->font_sizes[f]
3824 @ It's not a good idea to make any assumptions about the |font_ps_name| entries,
3825 so we carefully remove duplicates. There is no harm in using a slow, brute-force
3828 @<Give a \.{DocumentFonts} comment listing all fonts with non-null...@>=
3831 for (f=null_font+1;f<= mp->last_fnum;f++) {
3832 if ( mp->font_sizes[f]!=null ) {
3833 if ( ldf==null_font )
3834 mp_print_nl(mp, "%%DocumentFonts:");
3835 for (ff=ldf;ff>=null_font;ff--) {
3836 if ( mp->font_sizes[ff]!=null )
3837 if ( mp_xstrcmp(mp->font_ps_name[f],mp->font_ps_name[ff])==0 )
3840 if ( mp->ps_offset+1+strlen(mp->font_ps_name[f])>(unsigned)mp->max_print_line )
3841 mp_print_nl(mp, "%%+");
3842 mp_print_char(mp, ' ');
3843 mp_print(mp, mp->font_ps_name[f]);
3852 static void mp_hex_digit_out (MP mp,small_number d) {
3853 if ( d<10 ) mp_print_char(mp, d+'0');
3854 else mp_print_char(mp, d+'a'-10);
3857 @ We output the marks as a hexadecimal bit string starting at |c| or
3858 |font_bc[f]|, whichever is greater. If the output has to be truncated
3859 to avoid exceeding |emergency_line_length| the return value says where to
3860 start scanning next time.
3863 static halfword mp_ps_marks_out (MP mp,font_number f, eight_bits c);
3866 @d emergency_line_length 255
3867 /* \ps\ output lines can be this long in unusual circumstances */
3870 static halfword mp_ps_marks_out (MP mp,font_number f, eight_bits c) {
3871 eight_bits bc,ec; /* only encode characters between these bounds */
3872 integer lim; /* the maximum number of marks to encode before truncating */
3873 int p; /* |font_info| index for the current character */
3874 int d,b; /* used to construct a hexadecimal digit */
3875 lim=4*(emergency_line_length-mp->ps_offset-4);
3879 @<Restrict the range |bc..ec| so that it contains no unused characters
3880 at either end and has length at most |lim|@>;
3881 @<Print the initial label indicating that the bitmap starts at |bc|@>;
3882 @<Print a hexadecimal encoding of the marks for characters |bc..ec|@>;
3883 while ( (ec<mp->font_ec[f])&&(mp->font_info[p].qqqq.b3==mp_unused) ) {
3889 @ We could save time by setting the return value before the loop that
3890 decrements |ec|, but there is no point in being so tricky.
3892 @<Restrict the range |bc..ec| so that it contains no unused characters...@>=
3893 p=mp->char_base[f]+bc;
3894 while ( (mp->font_info[p].qqqq.b3==mp_unused)&&(bc<ec) ) {
3897 if ( ec>=bc+lim ) ec=bc+lim-1;
3898 p=mp->char_base[f]+ec;
3899 while ( (mp->font_info[p].qqqq.b3==mp_unused)&&(bc<ec) ) {
3903 @ @<Print the initial label indicating that the bitmap starts at |bc|@>=
3904 mp_print_char(mp, ' ');
3905 mp_hex_digit_out(mp, bc / 16);
3906 mp_hex_digit_out(mp, bc % 16);
3907 mp_print_char(mp, ':')
3911 @<Print a hexadecimal encoding of the marks for characters |bc..ec|@>=
3913 for (p=mp->char_base[f]+bc;p<=mp->char_base[f]+ec;p++) {
3915 mp_hex_digit_out(mp, d);
3918 if ( mp->font_info[p].qqqq.b3!=mp_unused ) d=d+b;
3921 mp_hex_digit_out(mp, d)
3924 @ Here is a simple function that determines whether there are any marked
3925 characters in font~|f| with character code at least~|c|.
3928 static boolean mp_check_ps_marks (MP mp,font_number f, integer c) ;
3931 static boolean mp_check_ps_marks (MP mp,font_number f, integer c) {
3932 int p; /* |font_info| index for the current character */
3933 for (p=mp->char_base[f]+c;p<=mp->char_base[f]+mp->font_ec[f];p++) {
3934 if ( mp->font_info[p].qqqq.b3==mp_used )
3941 @ If the file name is so long that it can't be printed without exceeding
3942 |emergency_line_length| then there will be missing items in the \.{\%*Font:}
3943 line. We might have to repeat line in order to get the character usage
3944 information to fit within |emergency_line_length|.
3946 TODO: these two defines are also defined in mp.w!
3948 @d link(A) mp->mem[(A)].hh.rh /* the |link| field of a memory word */
3949 @d sc_factor(A) mp->mem[(A)+1].cint /* the scale factor stored in a font size node */
3951 @<Print the \.{\%*Font} comment for font |f| and advance |cur_fsize[f]|@>=
3953 while ( mp_check_ps_marks(mp, f,t) ) {
3954 mp_print_nl(mp, "%*Font: ");
3955 if ( mp->ps_offset+strlen(mp->font_name[f])+12>emergency_line_length )
3957 mp_print(mp, mp->font_name[f]);
3958 mp_print_char(mp, ' ');
3959 ds=(mp->font_dsize[f] + 8) / 16;
3960 mp_print_scaled(mp, mp_take_scaled(mp, ds,sc_factor(cur_fsize[f])));
3961 if ( mp->ps_offset+12>emergency_line_length ) break;
3962 mp_print_char(mp, ' ');
3963 mp_print_scaled(mp, ds);
3964 if ( mp->ps_offset+5>emergency_line_length ) break;
3965 t=mp_ps_marks_out(mp, f,t);
3967 cur_fsize[f]=link(cur_fsize[f]);
3970 @ @<Print the procset@>=
3972 mp_print_nl(mp, "/hlw{0 dtransform exch truncate exch idtransform pop setlinewidth}bd");
3973 mp_print_nl(mp, "/vlw{0 exch dtransform truncate idtransform setlinewidth pop}bd");
3974 mp_print_nl(mp, "/l{lineto}bd/r{rlineto}bd/c{curveto}bd/m{moveto}bd"
3975 "/p{closepath}bd/n{newpath}bd");
3976 mp_print_nl(mp, "/C{setcmykcolor}bd/G{setgray}bd/R{setrgbcolor}bd"
3977 "/lj{setlinejoin}bd/ml{setmiterlimit}bd");
3978 mp_print_nl(mp, "/lc{setlinecap}bd/S{stroke}bd/F{fill}bd/q{gsave}bd"
3979 "/Q{grestore}bd/s{scale}bd/t{concat}bd");
3980 mp_print_nl(mp, "/sd{setdash}bd/rd{[] 0 setdash}bd/P{showpage}bd/B{q F Q}bd/W{clip}bd");
3984 @ The prologue defines \.{fshow} and corrects for the fact that \.{fshow}
3985 arguments use |font_name| instead of |font_ps_name|. Downloaded bitmap fonts
3986 might not have reasonable |font_ps_name| entries, but we just charge ahead
3987 anyway. The user should not make \&{prologues} positive if this will cause
3989 @:prologues_}{\&{prologues} primitive@>
3992 void mp_print_prologue (MP mp, pointer h);
3995 void mp_print_prologue (MP mp, pointer h) {
3998 int prologues = (mp->internal[mp_prologues]>>16);
3999 int procset = (mp->internal[mp_procset]>>16);
4000 ldf = mp_print_font_comments (mp, h);
4002 if ( (mp->internal[mp_prologues]>0) && (mp->last_ps_fnum<mp->last_fnum) )
4003 mp_read_psname_table(mp);
4004 mp_print(mp, "%%BeginProlog"); mp_print_ln(mp);
4005 if ( (prologues>0)||(procset>0) ) {
4006 if ( ldf!=null_font ) {
4007 if ( prologues>0 ) {
4008 for (f=null_font+1;f<=mp->last_fnum;f++) {
4009 if ( mp_has_font_size(mp,f) ) {
4010 mp_ps_name_out(mp, mp->font_name[f],true);
4011 mp_ps_name_out(mp, mp->font_ps_name[f],true);
4012 mp_ps_print(mp, " def");
4017 mp_print(mp, "/fshow {exch findfont exch scalefont setfont show}bind def");
4023 mp_print_nl(mp, "%%BeginResource: procset mpost");
4024 if ( (prologues>0)&&(ldf!=null_font) )
4026 "/bd{bind def}bind def/fshow {exch findfont exch scalefont setfont show}bd");
4028 mp_print_nl(mp, "/bd{bind def}bind def");
4029 @<Print the procset@>;
4030 mp_print_nl(mp, "%%EndResource");
4034 mp_print(mp, "%%EndProlog");
4035 mp_print_nl(mp, "%%Page: 1 1"); mp_print_ln(mp);
4038 @ Deciding where to break the ps output line. For the moment,
4039 it is necessary to create an exported function as well.
4041 @d ps_room(A) if ( (mp->ps_offset+(int)(A))>mp->max_print_line )
4042 mp_print_ln(mp) /* optional line break */
4045 void mp_ps_room (MP mp,int s) {
4050 void mp_ps_room (MP mp,int s) ;
4052 @ \MP\ used to have one single routine to print to both `write' files
4053 and the PostScript output. Web2c redefines ``Character |k| cannot be
4054 printed'', and that resulted in some bugs where 8-bit characters were
4055 written to the PostScript file (reported by Wlodek Bzyl).
4057 Also, Hans Hagen requested spaces to be output as "\\040" instead of
4058 a plain space, since that makes it easier to parse the result file
4061 @<Character |k| is not allowed in PostScript output@>=
4064 @ We often need to print a pair of coordinates.
4067 void mp_ps_pair_out (MP mp,scaled x, scaled y) {
4069 mp_print_scaled(mp, x); mp_print_char(mp, ' ');
4070 mp_print_scaled(mp, y); mp_print_char(mp, ' ');
4074 void mp_ps_pair_out (MP mp,scaled x, scaled y) ;
4077 void mp_ps_print (MP mp,char *s) {
4081 void mp_ps_print_cmd (MP mp, char *l, char *s) {
4082 if ( mp->internal[mp_procset]>0 ) { ps_room(strlen(s)); mp_print(mp,s); }
4083 else { ps_room(strlen(l)); mp_print(mp, l); };
4087 void mp_ps_print (MP mp,char *s) ;
4088 void mp_ps_print_cmd (MP mp, char *l, char *s) ;
4091 void mp_ps_string_out (MP mp, char *s) {
4092 ASCII_code k; /* bits to be converted to octal */
4095 if ( mp->ps_offset+5>mp->max_print_line ) {
4096 mp_print_char(mp, '\\');
4099 if ( (@<Character |k| is not allowed in PostScript output@>) ) {
4100 mp_print_char(mp, '\\');
4101 mp_print_char(mp, '0'+(k / 64));
4102 mp_print_char(mp, '0'+((k / 8) % 8));
4103 mp_print_char(mp, '0'+(k % 8));
4105 if ( (k=='(')||(k==')')||(k=='\\') ) mp_print_char(mp, '\\');
4106 mp_print_char(mp, k);
4109 mp_print_char(mp, ')');
4113 void mp_ps_string_out (MP mp, char *s) ;
4115 @ This is a define because the function does not use its |mp| argument.
4117 @d mp_is_ps_name(M,A) mp_do_is_ps_name(A)
4120 static boolean mp_do_is_ps_name (char *s) {
4121 ASCII_code k; /* the character being checked */
4123 if ( (k<=' ')||(k>'~') ) return false;
4124 if ( (k=='(')||(k==')')||(k=='<')||(k=='>')||
4125 (k=='{')||(k=='}')||(k=='/')||(k=='%') ) return false;
4131 void mp_ps_name_out (MP mp, char *s, boolean lit) ;
4134 void mp_ps_name_out (MP mp, char *s, boolean lit) {
4135 ps_room(strlen(s)+2);
4136 mp_print_char(mp, ' ');
4137 if ( mp_is_ps_name(mp, s) ) {
4138 if ( lit ) mp_print_char(mp, '/');
4141 mp_ps_string_out(mp, s);
4142 if ( ! lit ) mp_ps_print(mp, "cvx ");
4143 mp_ps_print(mp, "cvn");
4148 @ These special comments described in the {\sl PostScript Language Reference
4149 Manual}, 2nd.~edition are understood by some \ps-reading programs.
4150 We can't normally output ``conforming'' \ps\ because
4151 the structuring conventions don't allow us to say ``Please make sure the
4152 following characters are downloaded and define the \.{fshow} macro to access
4155 The exact bounding box is written out if |mp_prologues<0|, although this
4156 is not standard \ps, since it allows \TeX\ to calculate the box dimensions
4157 accurately. (Overfull boxes are avoided if an illustration is made to
4158 match a given \.{\char`\\hsize}.)
4161 void mp_print_initial_comment(MP mp, pointer h,
4162 scaled minx, scaled miny, scaled maxx, scaled maxy);
4165 void mp_print_initial_comment(MP mp, pointer h,
4166 scaled minx, scaled miny, scaled maxx, scaled maxy) {
4168 int prologues = (mp->internal[mp_prologues]>>16);
4169 mp_print(mp, "%!PS");
4171 mp_print(mp, "-Adobe-3.0 EPSF-3.0");
4172 mp_set_bbox(mp, h,true);
4173 mp_print_nl(mp, "%%BoundingBox: ");
4175 mp_print(mp, "0 0 0 0");
4176 } else if ( prologues<0 ) {
4177 mp_ps_pair_out(mp, minx,miny);
4178 mp_ps_pair_out(mp, maxx,maxy);
4180 mp_ps_pair_out(mp, mp_floor_scaled(mp, minx),mp_floor_scaled(mp, miny));
4181 mp_ps_pair_out(mp, -mp_floor_scaled(mp, -maxx),-mp_floor_scaled(mp, -maxy));
4183 mp_print_nl(mp, "%%HiResBoundingBox: ");
4185 mp_print(mp, "0 0 0 0");
4187 mp_ps_pair_out(mp, minx,miny);
4188 mp_ps_pair_out(mp, maxx,maxy);
4190 mp_print_nl(mp, "%%Creator: MetaPost ");
4191 mp_print(mp, mp_metapost_version(mp));
4192 mp_print_nl(mp, "%%CreationDate: ");
4193 mp_print_int(mp, mp_round_unscaled(mp, mp->internal[mp_year])); mp_print_char(mp, '.');
4194 mp_print_dd(mp, mp_round_unscaled(mp, mp->internal[mp_month])); mp_print_char(mp, '.');
4195 mp_print_dd(mp, mp_round_unscaled(mp, mp->internal[mp_day])); mp_print_char(mp, ':');
4196 t=mp_round_unscaled(mp, mp->internal[mp_time]);
4197 mp_print_dd(mp, t / 60); mp_print_dd(mp, t % 60);
4198 mp_print_nl(mp, "%%Pages: 1");