diff options
Diffstat (limited to 'Build/source/texk/web2c/luatexdir/lua/psout.w')
-rw-r--r-- | Build/source/texk/web2c/luatexdir/lua/psout.w | 5686 |
1 files changed, 0 insertions, 5686 deletions
diff --git a/Build/source/texk/web2c/luatexdir/lua/psout.w b/Build/source/texk/web2c/luatexdir/lua/psout.w deleted file mode 100644 index 90cf6923e01..00000000000 --- a/Build/source/texk/web2c/luatexdir/lua/psout.w +++ /dev/null @@ -1,5686 +0,0 @@ -% $Id: mp.web,v 1.8 2005/08/24 10:54:02 taco Exp $ -% MetaPost, by John Hobby. Public domain. - -% Much of this program was copied with permission from MF.web Version 1.9 -% It interprets a language very similar to D.E. Knuth's METAFONT, but with -% changes designed to make it more suitable for PostScript output. - -% TeX is a trademark of the American Mathematical Society. -% METAFONT is a trademark of Addison-Wesley Publishing Company. -% PostScript is a trademark of Adobe Systems Incorporated. - -% Here is TeX material that gets inserted after \input webmac -\def\hang{\hangindent 3em\noindent\ignorespaces} -\def\textindent#1{\hangindent2.5em\noindent\hbox to2.5em{\hss#1 }\ignorespaces} -\def\PASCAL{Pascal} -\def\ps{PostScript} -\def\ph{\hbox{Pascal-H}} -\def\psqrt#1{\sqrt{\mathstrut#1}} -\def\k{_{k+1}} -\def\pct!{{\char`\%}} % percent sign in ordinary text -\font\tenlogo=logo10 % font used for the METAFONT logo -\font\logos=logosl10 -\def\MF{{\tenlogo META}\-{\tenlogo FONT}} -\def\MP{{\tenlogo META}\-{\tenlogo POST}} -\def\<#1>{$\langle#1\rangle$} -\def\section{\mathhexbox278} -\let\swap=\leftrightarrow -\def\round{\mathop{\rm round}\nolimits} -\mathchardef\vb="026A % synonym for `\|' -\def\[#1]{} % from pascal web -\def\(#1){} % this is used to make section names sort themselves better -\def\9#1{} % this is used for sort keys in the index via @@:sort key}{entry@@> - -\let\?=\relax % we want to be able to \write a \? - -\def\title{MetaPost \ps\ output} -\def\topofcontents{\hsize 5.5in - \vglue -30pt plus 1fil minus 1.5in - \def\?##1]{\hbox to 1in{\hfil##1.\ }} - } -\def\botofcontents{\vskip 0pt plus 1fil minus 1.5in} -\pdfoutput=1 -\pageno=3 - -@ -@d true 1 -@d false 0 -@d null_font 0 -@d null 0 -@d unity 0200000 /* $2^{16}$, represents 1.00000 */ -@d el_gordo 017777777777 /* $2^{31}-1$, the largest value that \MP\ likes */ -@d incr(A) (A)=(A)+1 /* increase a variable by unity */ -@d decr(A) (A)=(A)-1 /* decrease a variable by unity */ -@d negate(A) (A)=-(A) /* change the sign of a variable */ -@d odd(A) ((A)%2==1) -@d half(A) ((A)/2) -@d print_err(A) mp_print_err(mp,(A)) -@d max_quarterword 0x3FFF /* largest allowable value in a |quarterword| */ - -@c -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdarg.h> -#include <assert.h> -#include "avl.h" -#include "mplib.h" -#include "mpmp.h" /* internal header */ -#include "mppsout.h" /* internal header */ -@h -@<Declarations@> -@<Static variables in the outer block@> - -@ There is a small bit of code from the backend that bleads through -to the frontend because I do not know how to set up the includes -properly. Those are the definitions of |struct libavl_allocator| -and |typedef struct psout_data_struct * psout_data|. - -The |libavl_allocator| is a trick that makes sure that frontends -do not need |avl.h|, and the |psout_data| is needed for the backend -data structure. - -@ @(mppsout.h@>= -@<Types...@> -typedef struct psout_data_struct { - @<Globals@> -} psout_data_struct ; -@<Exported function headers@> - -@ @<Exported function headers@>= -void mp_backend_initialize (MP mp) ; -void mp_backend_free (MP mp) ; - -@ -@c void mp_backend_initialize (MP mp) { - mp->ps = mp_xmalloc(mp,1,sizeof(psout_data_struct)); - @<Set initial values@>; -} -void mp_backend_free (MP mp) { - @<Dealloc variables@>; - enc_free(mp); - t1_free(mp); - fm_free(mp); - mp_xfree(mp->ps); - mp->ps = NULL; -} - -@ Writing to ps files - -@<Globals@>= -integer ps_offset; - /* the number of characters on the current \ps\ file line */ - -@ @<Set initial values@>= -mp->ps->ps_offset = 0; - -@ - -@d wps(A) (mp->write_ascii_file)(mp,mp->ps_file,(A)) -@d wps_chr(A) do { - char ss[2]; - ss[0]=(A); ss[1]=0; - (mp->write_ascii_file)(mp,mp->ps_file,(char *)ss); -} while (0) -@d wps_cr (mp->write_ascii_file)(mp,mp->ps_file,"\n") -@d wps_ln(A) { wterm_cr; (mp->write_ascii_file)(mp,mp->ps_file,(A)); } - -@c -void mp_ps_print_ln (MP mp) { /* prints an end-of-line */ - wps_cr; - mp->ps->ps_offset=0; -} - -@ @c -void mp_ps_print_char (MP mp, ASCII_code s) { /* prints a single character */ - if ( s==13 ) { - wps_cr; mp->ps->ps_offset=0; - } else { - wps_chr(s); incr(mp->ps->ps_offset); - } -} - -@ @c -void mp_ps_do_print (MP mp, const char *ss, unsigned int len) { /* prints string |s| */ - unsigned int j = 0; - while ( j<len ){ - mp_ps_print_char(mp, ss[j]); incr(j); - } -} - -@ Deciding where to break the ps output line. - -@d ps_room(A) if ( (mp->ps->ps_offset+(int)(A))>mp->max_print_line ) { - mp_ps_print_ln(mp); /* optional line break */ -} - -@c -void mp_ps_print (MP mp, const char *ss) { - ps_room(strlen(ss)); - mp_ps_do_print(mp, ss, strlen(ss)); -} - -@ The procedure |print_nl| is like |print|, but it makes sure that the -string appears at the beginning of a new line. - -@c -void mp_ps_print_nl (MP mp, const char *s) { /* prints string |s| at beginning of line */ - if ( mp->ps->ps_offset>0 ) mp_ps_print_ln(mp); - mp_ps_print(mp, s); -} - -@ An array of digits in the range |0..9| is printed by |print_the_digs|. - -@c -void mp_ps_print_the_digs (MP mp, eight_bits k) { - /* prints |dig[k-1]|$\,\ldots\,$|dig[0]| */ - while ( k-->0 ){ - mp_ps_print_char(mp, '0'+mp->dig[k]); - } -} - -@ The following procedure, which prints out the decimal representation of a -given integer |n|, has been written carefully so that it works properly -if |n=0| or if |(-n)| would cause overflow. It does not apply |mod| or |div| -to negative arguments, since such operations are not implemented consistently -by all \PASCAL\ compilers. - -@c -void mp_ps_print_int (MP mp,integer n) { /* prints an integer in decimal form */ - integer m; /* used to negate |n| in possibly dangerous cases */ - int k = 0; /* index to current digit; we assume that $|n|<10^{23}$ */ - if ( n<0 ) { - mp_ps_print_char(mp, '-'); - if ( n>-100000000 ) { - negate(n); - } else { - m=-1-n; n=m / 10; m=(m % 10)+1; k=1; - if ( m<10 ) { - mp->dig[0]=m; - } else { - mp->dig[0]=0; incr(n); - } - } - } - do { - mp->dig[k]=n % 10; n=n / 10; incr(k); - } while (n!=0); - mp_ps_print_the_digs(mp, k); -} - -@ @<Internal ...@>= -void mp_ps_print_int (MP mp,integer n); - -@ \MP\ also makes use of a trivial procedure to print two digits. The -following subroutine is usually called with a parameter in the range |0<=n<=99|. - -@c -void mp_ps_print_dd (MP mp,integer n) { /* prints two least significant digits */ - n=abs(n) % 100; - mp_ps_print_char(mp, '0'+(n / 10)); - mp_ps_print_char(mp, '0'+(n % 10)); -} - -@ Conversely, here is a procedure analogous to |print_int|. If the output -of this procedure is subsequently read by \MP\ and converted by the -|round_decimals| routine above, it turns out that the original value will -be reproduced exactly. A decimal point is printed only if the value is -not an integer. If there is more than one way to print the result with -the optimum number of digits following the decimal point, the closest -possible value is given. - -The invariant relation in the \&{repeat} loop is that a sequence of -decimal digits yet to be printed will yield the original number if and only if -they form a fraction~$f$ in the range $s-\delta\L10\cdot2^{16}f<s$. -We can stop if and only if $f=0$ satisfies this condition; the loop will -terminate before $s$ can possibly become zero. - -@c -void mp_ps_print_scaled (MP mp,scaled s) { - scaled delta; /* amount of allowable inaccuracy */ - if ( s<0 ) { - mp_ps_print_char(mp, '-'); - negate(s); /* print the sign, if negative */ - } - mp_ps_print_int(mp, s / unity); /* print the integer part */ - s=10*(s % unity)+5; - if ( s!=5 ) { - delta=10; - mp_ps_print_char(mp, '.'); - do { - if ( delta>unity ) - s=s+0100000-(delta / 2); /* round the final digit */ - mp_ps_print_char(mp, '0'+(s / unity)); - s=10*(s % unity); - delta=delta*10; - } while (s>delta); - } -} - - -@* \[44a] Dealing with font encodings. - -First, here are a few helpers for parsing files - -@d check_buf(size, buf_size) - if ((unsigned)(size) > (unsigned)(buf_size)) { - char S[128]; - snprintf(S,128,"buffer overflow: (%d,%d) at file %s, line %d", - size,buf_size, __FILE__, __LINE__ ); - mp_fatal_error(mp,S); - } - -@d append_char_to_buf(c, p, buf, buf_size) do { - if (c == 9) - c = 32; - if (c == 13 || c == EOF) - c = 10; - if (c != ' ' || (p > buf && p[-1] != 32)) { - check_buf(p - buf + 1, (buf_size)); - *p++ = c; - } -} while (0) - -@d append_eol(p, buf, buf_size) do { - check_buf(p - buf + 2, (buf_size)); - if (p - buf > 1 && p[-1] != 10) - *p++ = 10; - if (p - buf > 2 && p[-2] == 32) { - p[-2] = 10; - p--; - } - *p = 0; -} while (0) - -@d remove_eol(p, buf) do { - p = strend(buf) - 1; - if (*p == 10) - *p = 0; -} while (0) - -@d skip(p, c) if (*p == c) p++ -@d strend(s) strchr(s, 0) -@d str_prefix(s1, s2) (strncmp((s1), (s2), strlen(s2)) == 0) - - -@ @<Types...@>= -typedef struct { - boolean loaded; /* the encoding has been loaded? */ - char *file_name; /* encoding file name */ - char *enc_name; /* encoding true name */ - integer objnum; /* object number */ - char **glyph_names; - integer tounicode; /* object number of associated ToUnicode entry */ -} enc_entry; - - -@ - -@d ENC_STANDARD 0 -@d ENC_BUILTIN 1 - -@<Glob...@>= -#define ENC_BUF_SIZE 0x1000 -char enc_line[ENC_BUF_SIZE]; -void * enc_file; - -@ -@d enc_eof() (mp->eof_file)(mp,mp->ps->enc_file) -@d enc_close() (mp->close_file)(mp,mp->ps->enc_file) - -@c -int enc_getchar(MP mp) { - size_t len = 1; - unsigned char abyte=0; - void *byte_ptr = &abyte; - (mp->read_binary_file)(mp,mp->ps->enc_file,&byte_ptr,&len); - return abyte; -} - -@ @c -static boolean mp_enc_open (MP mp, char *n) { - mp->ps->enc_file=(mp->open_file)(mp,n, "r", mp_filetype_encoding); - if (mp->ps->enc_file!=NULL) - return true; - else - return false; -} -static void mp_enc_getline (MP mp) { - char *p; - int c; -RESTART: - if (enc_eof ()) { - print_err("unexpected end of file"); - mp_error(mp); - } - p = mp->ps->enc_line; - do { - c = enc_getchar (mp); - append_char_to_buf (c, p, mp->ps->enc_line, ENC_BUF_SIZE); - } while (c != 10); - append_eol (p, mp->ps->enc_line, ENC_BUF_SIZE); - if (p - mp->ps->enc_line < 2 || *mp->ps->enc_line == '%') - goto RESTART; -} -static void mp_load_enc (MP mp, char *enc_name, - char **enc_encname, char **glyph_names){ - char buf[ENC_BUF_SIZE], *p, *r; - int names_count; - char *myname; - int save_selector = mp->selector; - if (!mp_enc_open (mp,enc_name)) { - mp_print (mp,"cannot open encoding file for reading"); - return; - } - mp_normalize_selector(mp); - mp_print (mp,"{"); - mp_print (mp, enc_name); - mp_enc_getline (mp); - if (*mp->ps->enc_line != '/' || (r = strchr (mp->ps->enc_line, '[')) == NULL) { - remove_eol (r, mp->ps->enc_line); - print_err ("invalid encoding vector (a name or `[' missing): `"); - mp_print(mp,mp->ps->enc_line); - mp_print(mp,"'"); - mp_error(mp); - } - while (*(r-1)==' ') r--; /* strip trailing spaces from encoding name */ - myname = mp_xmalloc(mp,r-mp->ps->enc_line,1); - memcpy(myname,mp->ps->enc_line+1,(r-mp->ps->enc_line)-1); - *(myname+(r-mp->ps->enc_line-1))=0; - *enc_encname = myname; - while (*r!='[') r++; - r++; /* skip '[' */ - names_count = 0; - skip (r, ' '); - for (;;) { - while (*r == '/') { - for (p = buf, r++; - *r != ' ' && *r != 10 && *r != ']' && *r != '/'; *p++ = *r++); - *p = 0; - skip (r, ' '); - if (names_count > 256) { - print_err ("encoding vector contains more than 256 names"); - mp_error(mp); - } - if (mp_xstrcmp (buf, notdef) != 0) - glyph_names[names_count] = mp_xstrdup (mp,buf); - names_count++; - } - if (*r != 10 && *r != '%') { - if (str_prefix (r, "] def")) - goto DONE; - else { - remove_eol (r, mp->ps->enc_line); - print_err - ("invalid encoding vector: a name or `] def' expected: `"); - mp_print(mp,mp->ps->enc_line); - mp_print(mp,"'"); - mp_error(mp); - } - } - mp_enc_getline (mp); - r = mp->ps->enc_line; - } -DONE: - enc_close (); - mp_print (mp,"}"); - mp->selector = save_selector; -} -static void mp_read_enc (MP mp, enc_entry * e) { - if (e->loaded) - return; - e->enc_name = NULL; - mp_load_enc (mp,e->file_name, &e->enc_name, e->glyph_names); - e->loaded = true; -} - -@ |write_enc| is used to write either external encoding (given in map file) or - internal encoding (read from the font file); - the 2nd argument is a pointer to the encoding entry; - -@c -static void mp_write_enc (MP mp, enc_entry * e) { - int i; - int s; - int foffset; - char **g; - if (e->objnum != 0) /* the encoding has been written already */ - return; - e->objnum = 1; - g = e->glyph_names; - - mp_ps_print(mp,"\n%%%%BeginResource: encoding "); - mp_ps_print(mp, e->enc_name); - mp_ps_print_nl(mp, "/"); - mp_ps_print(mp, e->enc_name); - mp_ps_print(mp, " [ "); - foffset = strlen(e->file_name)+3; - for (i = 0; i < 256; i++) { - s = strlen(g[i]); - if (s+1+foffset>=80) { - mp_ps_print_ln (mp); - foffset = 0; - } - foffset += s+2; - mp_ps_print_char(mp,'/'); - mp_ps_print(mp, g[i]); - mp_ps_print_char(mp,' '); - } - if (foffset>75) - mp_ps_print_ln (mp); - mp_ps_print_nl (mp,"] def\n"); - mp_ps_print(mp,"%%%%EndResource"); -} - - -@ All encoding entries go into AVL tree for fast search by name. - -@<Glob...@>= -struct avl_table *enc_tree; - -@ Memory management functions for avl - -@<Static variables in the outer block@>= -static const char notdef[] = ".notdef"; - -@ @<Declarations@>= -static void *avl_xmalloc (struct libavl_allocator *allocator, size_t size); -static void avl_xfree (struct libavl_allocator *allocator, void *block); - -@ @c -static void *avl_xmalloc (struct libavl_allocator *allocator, size_t size) { - (void)allocator; - return malloc (size); -} -static void avl_xfree (struct libavl_allocator *allocator, void *block) { - (void)allocator; - free (block); -} - -@ @<Glob...@>= -struct libavl_allocator avl_xallocator; - -@ @<Set initial...@>= -mp->ps->avl_xallocator.libavl_malloc=avl_xmalloc; -mp->ps->avl_xallocator.libavl_free= avl_xfree; -mp->ps->enc_tree = NULL; - -@ @c -static int comp_enc_entry (const void *pa, const void *pb, void *p) { - (void)p; - return strcmp (((const enc_entry *) pa)->file_name, - ((const enc_entry *) pb)->file_name); -} -static enc_entry * mp_add_enc (MP mp, char *s) { - int i; - enc_entry tmp, *p; - void **aa; - if (mp->ps->enc_tree == NULL) { - mp->ps->enc_tree = avl_create (comp_enc_entry, NULL, &mp->ps->avl_xallocator); - } - tmp.file_name = s; - p = (enc_entry *) avl_find (mp->ps->enc_tree, &tmp); - if (p != NULL) /* encoding already registered */ - return p; - p = mp_xmalloc (mp,1,sizeof (enc_entry)); - p->loaded = false; - p->file_name = mp_xstrdup (mp,s); - p->objnum = 0; - p->tounicode = 0; - p->glyph_names = mp_xmalloc (mp,256,sizeof (char *)); - for (i = 0; i < 256; i++) - p->glyph_names[i] = (char *) notdef; - aa = avl_probe (mp->ps->enc_tree, p); - return p; -} - -@ cleaning up... - -@c -static void mp_destroy_enc_entry (void *pa, void *pb) { - enc_entry *p; - int i; - p = (enc_entry *) pa; - (void)pb; - mp_xfree (p->file_name); - if (p->glyph_names != NULL) - for (i = 0; i < 256; i++) - if (p->glyph_names[i] != notdef) - mp_xfree (p->glyph_names[i]); - mp_xfree (p->glyph_names); - mp_xfree (p); -} - -@ @<Declarations@>= -static void enc_free (MP mp); - -@ @c static void enc_free (MP mp) { - if (mp->ps->enc_tree != NULL) - avl_destroy (mp->ps->enc_tree, mp_destroy_enc_entry); -} - -@ @<Exported function headers@>= -void mp_reload_encodings (MP mp) ; - -@ @<Declarations@>= -static void mp_font_encodings (MP mp, int lastfnum, int encodings_only) ; - -@ @c void mp_reload_encodings (MP mp) { - int f; - enc_entry *e; - fm_entry *fm_cur; - int lastfnum = mp->last_fnum; - for (f=null_font+1;f<=lastfnum;f++) { - if (mp->font_enc_name[f]!=NULL ) { - mp_xfree(mp->font_enc_name[f]); - mp->font_enc_name[f]=NULL; - } - if (mp_has_fm_entry (mp,f,&fm_cur)) { - if (fm_cur != NULL && fm_cur->ps_name != NULL &&is_reencoded (fm_cur)) { - e = fm_cur->encoding; - mp_read_enc (mp,e); - } - } - } -} -static void mp_font_encodings (MP mp, int lastfnum, int encodings_only) { - int f; - enc_entry *e; - fm_entry *fm; - for (f=null_font+1;f<=lastfnum;f++) { - if (mp_has_font_size(mp,f) && mp_has_fm_entry (mp,f, &fm)) { - if (fm != NULL && (fm->ps_name != NULL)) { - if (is_reencoded (fm)) { - if (encodings_only || (!is_subsetted (fm))) { - e = fm->encoding; - mp_write_enc (mp, e); - /* clear for next run */ - e->objnum = 0; - } - } - } - } - } -} - -@* \[44b] Parsing font map files. - -@d FM_BUF_SIZE 1024 - -@<Glob...@>= -void * fm_file; - -@ -@d fm_close() (mp->close_file)(mp,mp->ps->fm_file) -@d fm_eof() (mp->eof_file)(mp,mp->ps->fm_file) - -@c -int fm_getchar(MP mp) { - size_t len = 1; - unsigned char abyte=0; - void *byte_ptr = &abyte; - (mp->read_binary_file)(mp,mp->ps->fm_file,&byte_ptr,&len); - if (len==0) - return EOF; - return abyte; -} - - -@ @<Types...@>= -enum _mode { FM_DUPIGNORE, FM_REPLACE, FM_DELETE }; -enum _ltype { MAPFILE, MAPLINE }; -enum _tfmavail { TFM_UNCHECKED, TFM_FOUND, TFM_NOTFOUND }; -typedef struct mitem { - int mode; /* |FM_DUPIGNORE| or |FM_REPLACE| or |FM_DELETE| */ - int type; /* map file or map line */ - char *map_line; /* pointer to map file name or map line */ - int lineno; /* line number in map file */ -} mapitem; - -@ @<Glob...@>= -mapitem *mitem; -fm_entry *fm_cur; -fm_entry *loaded_tfm_found; -fm_entry *avail_tfm_found; -fm_entry *non_tfm_found; -fm_entry *not_avail_tfm_found; - -@ @<Set initial...@>= -mp->ps->mitem = NULL; - -@ @<Declarations@>= -static const char nontfm[] = "<nontfm>"; - -@ -@d read_field(r, q, buf) do { - q = buf; - while (*r != ' ' && *r != '\0') - *q++ = *r++; - *q = '\0'; - skip (r, ' '); -} while (0) - -@d set_field(F) do { - if (q > buf) - fm->F = mp_xstrdup(mp,buf); - if (*r == '\0') - goto DONE; -} while (0) - -@d cmp_return(a, b) - if (a > b) - return 1; - if (a < b) - return -1 - -@c -static fm_entry *new_fm_entry (MP mp) { - fm_entry *fm; - fm = mp_xmalloc (mp,1,sizeof(fm_entry)); - fm->tfm_name = NULL; - fm->ps_name = NULL; - fm->flags = 4; - fm->ff_name = NULL; - fm->subset_tag = NULL; - fm->encoding = NULL; - fm->tfm_num = null_font; - fm->tfm_avail = TFM_UNCHECKED; - fm->type = 0; - fm->slant = 0; - fm->extend = 0; - fm->ff_objnum = 0; - fm->fn_objnum = 0; - fm->fd_objnum = 0; - fm->charset = NULL; - fm->all_glyphs = false; - fm->links = 0; - fm->pid = -1; - fm->eid = -1; - return fm; -} - -static void delete_fm_entry (fm_entry * fm) { - mp_xfree (fm->tfm_name); - mp_xfree (fm->ps_name); - mp_xfree (fm->ff_name); - mp_xfree (fm->subset_tag); - mp_xfree (fm->charset); - mp_xfree (fm); -} - -static ff_entry *new_ff_entry (MP mp) { - ff_entry *ff; - ff = mp_xmalloc (mp,1,sizeof(ff_entry)); - ff->ff_name = NULL; - ff->ff_path = NULL; - return ff; -} - -static void delete_ff_entry (ff_entry * ff) { - mp_xfree (ff->ff_name); - mp_xfree (ff->ff_path); - mp_xfree (ff); -} - -static char *mk_base_tfm (MP mp, char *tfmname, int *i) { - static char buf[SMALL_BUF_SIZE]; - char *p = tfmname, *r = strend (p) - 1, *q = r; - while (q > p && isdigit (*q)) - --q; - if (!(q > p) || q == r || (*q != '+' && *q != '-')) - return NULL; - check_buf (q - p + 1, SMALL_BUF_SIZE); - strncpy (buf, p, (size_t) (q - p)); - buf[q - p] = '\0'; - *i = atoi (q); - return buf; -} - -@ @<Exported function headers@>= -boolean mp_has_fm_entry (MP mp,font_number f, fm_entry **fm); - -@ @c -boolean mp_has_fm_entry (MP mp,font_number f, fm_entry **fm) { - fm_entry *res = NULL; - res = mp_fm_lookup (mp, f); - if (fm != NULL) { - *fm =res; - } - return (res != NULL); -} - -@ @<Glob...@>= -struct avl_table *tfm_tree; -struct avl_table *ps_tree; -struct avl_table *ff_tree; - -@ @<Set initial...@>= -mp->ps->tfm_tree = NULL; -mp->ps->ps_tree = NULL; -mp->ps->ff_tree = NULL; - -@ AVL sort |fm_entry| into |tfm_tree| by |tfm_name | - -@c -static int comp_fm_entry_tfm (const void *pa, const void *pb, void *p) { - (void)p; - return strcmp (((const fm_entry *) pa)->tfm_name, - ((const fm_entry *) pb)->tfm_name); -} - -@ AVL sort |fm_entry| into |ps_tree| by |ps_name|, |slant|, and |extend| - -@c static int comp_fm_entry_ps (const void *pa, const void *pb, void *p) { - int i; - const fm_entry *p1 = (const fm_entry *) pa; - const fm_entry *p2 = (const fm_entry *) pb; - (void)p; - assert (p1->ps_name != NULL && p2->ps_name != NULL); - if ((i = strcmp (p1->ps_name, p2->ps_name))) - return i; - cmp_return (p1->slant, p2->slant); - cmp_return (p1->extend, p2->extend); - if (p1->tfm_name != NULL && p2->tfm_name != NULL && - (i = strcmp (p1->tfm_name, p2->tfm_name))) - return i; - return 0; -} - -@ AVL sort |ff_entry| into |ff_tree| by |ff_name| - -@c static int comp_ff_entry (const void *pa, const void *pb, void *p) { - (void)p; - return strcmp (((const ff_entry *) pa)->ff_name, - ((const ff_entry *) pb)->ff_name); -} - -@ @c static void create_avl_trees (MP mp) { - if (mp->ps->tfm_tree == NULL) { - mp->ps->tfm_tree = avl_create (comp_fm_entry_tfm, NULL, &mp->ps->avl_xallocator); - assert (mp->ps->tfm_tree != NULL); - } - if (mp->ps->ps_tree == NULL) { - mp->ps->ps_tree = avl_create (comp_fm_entry_ps, NULL, &mp->ps->avl_xallocator); - assert (mp->ps->ps_tree != NULL); - } - if (mp->ps->ff_tree == NULL) { - mp->ps->ff_tree = avl_create (comp_ff_entry, NULL, &mp->ps->avl_xallocator); - assert (mp->ps->ff_tree != NULL); - } -} - -@ The function |avl_do_entry| is not completely symmetrical with regards -to |tfm_name| and |ps_name handling|, e. g. a duplicate |tfm_name| gives a -|goto exit|, and no |ps_name| link is tried. This is to keep it compatible -with the original version. - -@d LINK_TFM 0x01 -@d LINK_PS 0x02 -@d set_tfmlink(fm) ((fm)->links |= LINK_TFM) -@d set_pslink(fm) ((fm)->links |= LINK_PS) -@d unset_tfmlink(fm) ((fm)->links &= ~LINK_TFM) -@d unset_pslink(fm) ((fm)->links &= ~LINK_PS) -@d has_tfmlink(fm) ((fm)->links & LINK_TFM) -@d has_pslink(fm) ((fm)->links & LINK_PS) - -@c -static int avl_do_entry (MP mp, fm_entry * fp, int mode) { - fm_entry *p; - void *a; - void **aa; - char s[128]; - - /* handle |tfm_name| link */ - - if (strcmp (fp->tfm_name, nontfm)) { - p = (fm_entry *) avl_find (mp->ps->tfm_tree, fp); - if (p != NULL) { - if (mode == FM_DUPIGNORE) { - snprintf(s,128,"fontmap entry for `%s' already exists, duplicates ignored", - fp->tfm_name); - mp_warn(mp,s); - goto exit; - } else { /* mode == |FM_REPLACE| / |FM_DELETE| */ - if (mp_has_font_size(mp,p->tfm_num)) { - snprintf(s,128, - "fontmap entry for `%s' has been used, replace/delete not allowed", - fp->tfm_name); - mp_warn(mp,s); - goto exit; - } - a = avl_delete (mp->ps->tfm_tree, p); - assert (a != NULL); - unset_tfmlink (p); - if (!has_pslink (p)) - delete_fm_entry (p); - } - } - if (mode != FM_DELETE) { - aa = avl_probe (mp->ps->tfm_tree, fp); - assert (aa != NULL); - set_tfmlink (fp); - } - } - - /* handle |ps_name| link */ - - if (fp->ps_name != NULL) { - assert (fp->tfm_name != NULL); - p = (fm_entry *) avl_find (mp->ps->ps_tree, fp); - if (p != NULL) { - if (mode == FM_DUPIGNORE) { - snprintf(s,128, - "ps_name entry for `%s' already exists, duplicates ignored", - fp->ps_name); - mp_warn(mp,s); - goto exit; - } else { /* mode == |FM_REPLACE| / |FM_DELETE| */ - if (mp_has_font_size(mp,p->tfm_num)) { - /* REPLACE/DELETE not allowed */ - snprintf(s,128, - "fontmap entry for `%s' has been used, replace/delete not allowed", - p->tfm_name); - mp_warn(mp,s); - goto exit; - } - a = avl_delete (mp->ps->ps_tree, p); - assert (a != NULL); - unset_pslink (p); - if (!has_tfmlink (p)) - delete_fm_entry (p); - } - } - if (mode != FM_DELETE) { - aa = avl_probe (mp->ps->ps_tree, fp); - assert (aa != NULL); - set_pslink (fp); - } - } - exit: - if (!has_tfmlink (fp) && !has_pslink (fp)) /* e. g. after |FM_DELETE| */ - return 1; /* deallocation of |fm_entry| structure required */ - else - return 0; -} - -@ consistency check for map entry, with warn flag - -@c -static int check_fm_entry (MP mp, fm_entry * fm, boolean warn) { - int a = 0; - char s[128]; - assert (fm != NULL); - if (fm->ps_name != NULL) { - if (is_basefont (fm)) { - if (is_fontfile (fm) && !is_included (fm)) { - if (warn) { - snprintf(s,128, "invalid entry for `%s': " - "font file must be included or omitted for base fonts", - fm->tfm_name); - mp_warn(mp,s); - } - a += 1; - } - } else { /* not a base font */ - /* if no font file given, drop this entry */ - /* |if (!is_fontfile (fm)) { - if (warn) { - snprintf(s,128, - "invalid entry for `%s': font file missing", - fm->tfm_name); - mp_warn(mp,s); - } - a += 2; - }| - */ - } - } - if (is_truetype (fm) && is_reencoded (fm) && !is_subsetted (fm)) { - if (warn) { - snprintf(s,128, - "invalid entry for `%s': only subsetted TrueType font can be reencoded", - fm->tfm_name); - mp_warn(mp,s); - } - a += 4; - } - if ((fm->slant != 0 || fm->extend != 0) && - (is_truetype (fm))) { - if (warn) { - snprintf(s,128, - "invalid entry for `%s': " - "SlantFont/ExtendFont can be used only with embedded T1 fonts", - fm->tfm_name); - mp_warn(mp,s); - } - a += 8; - } - if (abs (fm->slant) > 1000) { - if (warn) { - snprintf(s,128, - "invalid entry for `%s': too big value of SlantFont (%g)", - fm->tfm_name, fm->slant / 1000.0); - mp_warn(mp,s); - } - a += 16; - } - if (abs (fm->extend) > 2000) { - if (warn) { - snprintf(s,128, - "invalid entry for `%s': too big value of ExtendFont (%g)", - fm->tfm_name, fm->extend / 1000.0); - mp_warn(mp,s); - } - a += 32; - } - if (fm->pid != -1 && - !(is_truetype (fm) && is_included (fm) && - is_subsetted (fm) && !is_reencoded (fm))) { - if (warn) { - snprintf(s,128, - "invalid entry for `%s': " - "PidEid can be used only with subsetted non-reencoded TrueType fonts", - fm->tfm_name); - mp_warn(mp,s); - } - a += 64; - } - return a; -} - -@ returns true if s is one of the 14 std. font names; speed-trimmed. - -@c static boolean check_basefont (char *s) { - static const char *basefont_names[] = { - "Courier", /* 0:7 */ - "Courier-Bold", /* 1:12 */ - "Courier-Oblique", /* 2:15 */ - "Courier-BoldOblique", /* 3:19 */ - "Helvetica", /* 4:9 */ - "Helvetica-Bold", /* 5:14 */ - "Helvetica-Oblique", /* 6:17 */ - "Helvetica-BoldOblique", /* 7:21 */ - "Symbol", /* 8:6 */ - "Times-Roman", /* 9:11 */ - "Times-Bold", /* 10:10 */ - "Times-Italic", /* 11:12 */ - "Times-BoldItalic", /* 12:16 */ - "ZapfDingbats" /* 13:12 */ - }; - static const int Index[] = - { -1, -1, -1, -1, -1, -1, 8, 0, -1, 4, 10, 9, -1, -1, 5, 2, 12, 6, - -1, 3, -1, 7 - }; - const size_t n = strlen (s); - int k = -1; - if (n > 21) - return false; - if (n == 12) { /* three names have length 12 */ - switch (*s) { - case 'C': - k = 1; /* Courier-Bold */ - break; - case 'T': - k = 11; /* Times-Italic */ - break; - case 'Z': - k = 13; /* ZapfDingbats */ - break; - default: - return false; - } - } else - k = Index[n]; - if (k > -1 && !strcmp (basefont_names[k], s)) - return true; - return false; -} - -@ -@d is_cfg_comment(c) (c == 10 || c == '*' || c == '#' || c == ';' || c == '%') - -@c static void fm_scan_line (MP mp) { - int a, b, c, j, u = 0, v = 0; - float d; - fm_entry *fm; - char fm_line[FM_BUF_SIZE], buf[FM_BUF_SIZE]; - char *p, *q, *r, *s; - char warn_s[128]; - switch (mp->ps->mitem->type) { - case MAPFILE: - p = fm_line; - do { - c = fm_getchar (mp); - append_char_to_buf (c, p, fm_line, FM_BUF_SIZE); - } while (c != 10); - *(--p) = '\0'; - r = fm_line; - break; - case MAPLINE: - r = mp->ps->mitem->map_line; - break; - default: - assert (0); - } - if (*r == '\0' || is_cfg_comment (*r)) - return; - fm = new_fm_entry (mp); - read_field (r, q, buf); - set_field (tfm_name); - p = r; - read_field (r, q, buf); - if (*buf != '<' && *buf != '"') - set_field (ps_name); - else - r = p; /* unget the field */ - if (isdigit (*r)) { /* font flags given */ - fm->flags = atoi (r); - while (isdigit (*r)) - r++; - } - while (1) { /* loop through "specials", encoding, font file */ - skip (r, ' '); - switch (*r) { - case '\0': - goto DONE; - case '"': /* opening quote */ - r++; - u = v = 0; - do { - skip (r, ' '); - if (sscanf (r, "%f %n", &d, &j) > 0) { - s = r + j; /* jump behind number, eat also blanks, if any */ - if (*(s - 1) == 'E' || *(s - 1) == 'e') - s--; /* e. g. 0.5ExtendFont: \%f = 0.5E */ - if (str_prefix (s, "SlantFont")) { - d *= 1000.0; /* correct rounding also for neg. numbers */ - fm->slant = (integer) (d > 0 ? d + 0.5 : d - 0.5); - r = s + strlen ("SlantFont"); - } else if (str_prefix (s, "ExtendFont")) { - d *= 1000.0; - fm->extend = (integer) (d > 0 ? d + 0.5 : d - 0.5); - if (fm->extend == 1000) - fm->extend = 0; - r = s + strlen ("ExtendFont"); - } else { /* unknown name */ - for (r = s; - *r != ' ' && *r != '"' && *r != '\0'; - r++); /* jump over name */ - c = *r; /* remember char for temporary end of string */ - *r = '\0'; - snprintf(warn_s,128, - "invalid entry for `%s': unknown name `%s' ignored", - fm->tfm_name, s); - mp_warn(mp,warn_s); - *r = c; - } - } else - for (; *r != ' ' && *r != '"' && *r != '\0'; r++); - } - while (*r == ' '); - if (*r == '"') /* closing quote */ - r++; - else { - snprintf(warn_s,128, - "invalid entry for `%s': closing quote missing", - fm->tfm_name); - mp_warn(mp,warn_s); - goto bad_line; - } - break; - case 'P': /* handle cases for subfonts like 'PidEid=3,1' */ - if (sscanf (r, "PidEid=%i, %i %n", &a, &b, &c) >= 2) { - fm->pid = a; - fm->eid = b; - r += c; - break; - } - default: /* encoding or font file specification */ - a = b = 0; - if (*r == '<') { - a = *r++; - if (*r == '<' || *r == '[') - b = *r++; - } - read_field (r, q, buf); - /* encoding, formats: '8r.enc' or '<8r.enc' or '<[8r.enc' */ - if (strlen (buf) > 4 && strcasecmp (strend (buf) - 4, ".enc") == 0) { - fm->encoding = mp_add_enc (mp, buf); - u = v = 0; /* u, v used if intervening blank: "<< foo" */ - } else if (strlen (buf) > 0) { /* file name given */ - /* font file, formats: - * subsetting: '<cmr10.pfa' - * no subsetting: '<<cmr10.pfa' - * no embedding: 'cmr10.pfa' - */ - if (a == '<' || u == '<') { - set_included (fm); - if ((a == '<' && b == 0) || (a == 0 && v == 0)) - set_subsetted (fm); - /* otherwise b == '<' (or '[') => no subsetting */ - } - set_field (ff_name); - u = v = 0; - } else { - u = a; - v = b; - } - } - } - DONE: - if (fm->ps_name != NULL && check_basefont (fm->ps_name)) - set_basefont (fm); - if (is_fontfile (fm) - && strcasecmp (strend (fm_fontfile (fm)) - 4, ".ttf") == 0) - set_truetype (fm); - if (check_fm_entry (mp,fm, true) != 0) - goto bad_line; - /* - Until here the map line has been completely scanned without errors; - fm points to a valid, freshly filled-out |fm_entry| structure. - Now follows the actual work of registering/deleting. - */ - if (avl_do_entry (mp, fm, mp->ps->mitem->mode) == 0) /* if success */ - return; - bad_line: - delete_fm_entry (fm); -} - -@ -@c static void fm_read_info (MP mp) { - char *n; - char s[256]; - if (mp->ps->tfm_tree == NULL) - create_avl_trees (mp); - if (mp->ps->mitem->map_line == NULL) /* nothing to do */ - return; - mp->ps->mitem->lineno = 1; - switch (mp->ps->mitem->type) { - case MAPFILE: - n = mp->ps->mitem->map_line; - mp->ps->fm_file = (mp->open_file)(mp, n, "r", mp_filetype_fontmap); - if (!mp->ps->fm_file) { - snprintf(s,256,"cannot open font map file %s",n); - mp_warn(mp,s); - } else { - int save_selector = mp->selector; - mp_normalize_selector(mp); - mp_print (mp, "{"); - mp_print (mp, n); - while (!fm_eof ()) { - fm_scan_line (mp); - mp->ps->mitem->lineno++; - } - fm_close (); - mp_print (mp,"}"); - mp->selector = save_selector; - mp->ps->fm_file = NULL; - } - mp_xfree(n); - break; - case MAPLINE: - fm_scan_line (mp); - break; - default: - assert (0); - } - mp->ps->mitem->map_line = NULL; /* done with this line */ - return; -} - -@ @c static void init_fm (fm_entry * fm, font_number f) { - if (fm->tfm_num == null_font ) { - fm->tfm_num = f; - fm->tfm_avail = TFM_FOUND; - } -} - -@ @<Declarations@>= -static fm_entry * mp_fm_lookup (MP mp, font_number f); - -@ @c -static fm_entry * mp_fm_lookup (MP mp, font_number f) { - char *tfm; - fm_entry *fm; - fm_entry tmp; - int e; - if (mp->ps->tfm_tree == NULL) - fm_read_info (mp); /* only to read default map file */ - tfm = mp->font_name[f]; - assert (strcmp (tfm, nontfm)); - /* Look up for full <tfmname>[+-]<expand> */ - tmp.tfm_name = tfm; - fm = (fm_entry *) avl_find (mp->ps->tfm_tree, &tmp); - if (fm != NULL) { - init_fm (fm, f); - return (fm_entry *) fm; - } - tfm = mk_base_tfm (mp, mp->font_name[f], &e); - if (tfm == NULL) /* not an expanded font, nothing to do */ - return NULL; - - tmp.tfm_name = tfm; - fm = (fm_entry *) avl_find (mp->ps->tfm_tree, &tmp); - if (fm != NULL) { /* found an entry with the base tfm name, e.g. cmr10 */ - return (fm_entry *) fm; /* font expansion uses the base font */ - } - return NULL; -} - -@ Early check whether a font file exists. Used e. g. for replacing fonts - of embedded PDF files: Without font file, the font within the embedded - PDF-file is used. Search tree |ff_tree| is used in 1st instance, as it - may be faster than the |kpse_find_file()|, and |kpse_find_file()| is called - only once per font file name + expansion parameter. This might help - keeping speed, if many PDF pages with same fonts are to be embedded. - - The |ff_tree| contains only font files, which are actually needed, - so this tree typically is much smaller than the |tfm_tree| or |ps_tree|. - -@c -static ff_entry *check_ff_exist (MP mp, fm_entry * fm) { - ff_entry *ff; - ff_entry tmp; - void **aa; - - assert (fm->ff_name != NULL); - tmp.ff_name = fm->ff_name; - ff = (ff_entry *) avl_find (mp->ps->ff_tree, &tmp); - if (ff == NULL) { /* not yet in database */ - ff = new_ff_entry (mp); - ff->ff_name = mp_xstrdup (mp,fm->ff_name); - ff->ff_path = mp_xstrdup (mp,fm->ff_name); - aa = avl_probe (mp->ps->ff_tree, ff); - assert (aa != NULL); - } - return ff; -} - -@ Process map file given by its name or map line contents. Items not -beginning with [+-=] flush default map file, if it has not yet been -read. Leading blanks and blanks immediately following [+-=] are ignored. - - -@c static void mp_process_map_item (MP mp, char *s, int type) { - char *p; - int mode; - if (*s == ' ') - s++; /* ignore leading blank */ - switch (*s) { - case '+': /* +mapfile.map, +mapline */ - mode = FM_DUPIGNORE; /* insert entry, if it is not duplicate */ - s++; - break; - case '=': /* =mapfile.map, =mapline */ - mode = FM_REPLACE; /* try to replace earlier entry */ - s++; - break; - case '-': /* -mapfile.map, -mapline */ - mode = FM_DELETE; /* try to delete entry */ - s++; - break; - default: - mode = FM_DUPIGNORE; /* like +, but also: */ - mp_xfree(mp->ps->mitem->map_line); - mp->ps->mitem->map_line = NULL; /* flush default map file name */ - } - if (*s == ' ') - s++; /* ignore blank after [+-=] */ - p = s; /* map item starts here */ - switch (type) { - case MAPFILE: /* remove blank at end */ - while (*p != '\0' && *p != ' ') - p++; - *p = '\0'; - break; - case MAPLINE: /* blank at end allowed */ - break; - default: - assert (0); - } - if (mp->ps->mitem->map_line != NULL) /* read default map file first */ - fm_read_info (mp); - if (*s != '\0') { /* only if real item to process */ - mp->ps->mitem->mode = mode; - mp->ps->mitem->type = type; - mp->ps->mitem->map_line = s; - fm_read_info (mp); - } -} - -@ @<Exported function headers@>= -void mp_map_file (MP mp, str_number t); -void mp_map_line (MP mp, str_number t); -void mp_init_map_file (MP mp, int is_troff); - -@ @c -void mp_map_file (MP mp, str_number t) { - char *s = mp_xstrdup(mp,mp_str (mp,t)); - mp_process_map_item (mp, s, MAPFILE); - mp_xfree (s); -} -void mp_map_line (MP mp, str_number t) { - char *s = mp_xstrdup(mp,mp_str (mp,t)); - mp_process_map_item (mp, s, MAPLINE); - mp_xfree (s); -} - -@ -@c void mp_init_map_file (MP mp, int is_troff) { - char *r; - mp->ps->mitem = mp_xmalloc (mp,1,sizeof(mapitem)); - mp->ps->mitem->mode = FM_DUPIGNORE; - mp->ps->mitem->type = MAPFILE; - mp->ps->mitem->map_line = NULL; - r = (mp->find_file)(mp,"mpost.map", "r", mp_filetype_fontmap); - if (r != NULL) { - mp_xfree(r); - mp->ps->mitem->map_line = mp_xstrdup (mp,"mpost.map"); - } else { - if (is_troff) { - mp->ps->mitem->map_line = mp_xstrdup (mp,"troff.map"); - } else { - mp->ps->mitem->map_line = mp_xstrdup (mp,"pdftex.map"); - } - } -} - -@ @<Dealloc variables@>= -if (mp->ps->mitem!=NULL) { - mp_xfree(mp->ps->mitem->map_line); - mp_xfree(mp->ps->mitem); -} - -@ cleaning up... - -@c -static void destroy_fm_entry_tfm (void *pa, void *pb) { - fm_entry *fm; - (void)pb; - fm = (fm_entry *) pa; - if (!has_pslink (fm)) - delete_fm_entry (fm); - else - unset_tfmlink (fm); -} -static void destroy_fm_entry_ps (void *pa, void *pb) { - fm_entry *fm; - (void)pb; - fm = (fm_entry *) pa; - if (!has_tfmlink (fm)) - delete_fm_entry (fm); - else - unset_pslink (fm); -} -static void destroy_ff_entry (void *pa, void *pb) { - ff_entry *ff; - (void)pb; - ff = (ff_entry *) pa; - delete_ff_entry (ff); -} - -@ @<Declarations@>= -static void fm_free (MP mp); - -@ @c -static void fm_free (MP mp) { - if (mp->ps->tfm_tree != NULL) - avl_destroy (mp->ps->tfm_tree, destroy_fm_entry_tfm); - if (mp->ps->ps_tree != NULL) - avl_destroy (mp->ps->ps_tree, destroy_fm_entry_ps); - if (mp->ps->ff_tree != NULL) - avl_destroy (mp->ps->ff_tree, destroy_ff_entry); -} - -@ The file |ps_tab_file| gives a table of \TeX\ font names and corresponding -PostScript names for fonts that do not have to be downloaded, i.e., fonts that -can be used when |internal[prologues]>0|. Each line consists of a \TeX\ name, -one or more spaces, a PostScript name, and possibly a space and some other junk. -This routine reads the table, updates |font_ps_name| entries starting after -|last_ps_fnum|, and sets |last_ps_fnum:=last_fnum|. - -@d ps_tab_name "psfonts.map" /* locates font name translation table */ - -@<Declarations@>= -static void mp_read_psname_table (MP mp) ; - -@ @c -static void mp_read_psname_table (MP mp) { - font_number k; - if (mp->ps->mitem == NULL) { - mp->ps->mitem = mp_xmalloc (mp,1,sizeof(mapitem)); - mp->ps->mitem->mode = FM_DUPIGNORE; - mp->ps->mitem->type = MAPFILE; - mp->ps->mitem->map_line = NULL; - } - mp->ps->mitem->map_line = mp_xstrdup (mp,ps_tab_name); - fm_read_info (mp); - for (k=mp->last_ps_fnum+1;k<=mp->last_fnum;k++) { - if (mp_has_fm_entry(mp, k, NULL)) { - mp->font_ps_name[k] = mp_fm_font_name(mp,k); - } - } - mp->last_ps_fnum=mp->last_fnum; -} - - -@ The traditional function is a lot shorter now. - - - -@* \[44c] Helper functions for Type1 fonts. - -@<Types...@>= -typedef char char_entry; -typedef unsigned char Byte; -typedef Byte Bytef; - -@ @<Glob...@>= -char_entry *char_ptr, *char_array; -size_t char_limit; -char *job_id_string; - -@ @<Set initial...@>= -mp->ps->char_array = NULL; -mp->ps->job_id_string = NULL; - -@ -@d SMALL_ARRAY_SIZE 256 -@d Z_NULL 0 - -@c -void mp_set_job_id (MP mp) { - char *name_string, *format_string, *s; - size_t slen; - int i; - if (mp->ps->job_id_string != NULL) - return; - if ( mp->job_name==NULL ) - mp->job_name = mp_xstrdup(mp,"mpout"); - name_string = mp_xstrdup (mp,mp->job_name); - format_string = mp_xstrdup (mp,mp->mem_ident); - slen = SMALL_BUF_SIZE + - strlen (name_string) + - strlen (format_string); - s = mp_xmalloc (mp,slen, sizeof (char)); - i = snprintf (s, slen, - "%.4d/%.2d/%.2d %.2d:%.2d %s %s", - (mp->internal[mp_year]>>16), - (mp->internal[mp_month]>>16), - (mp->internal[mp_day]>>16), - (mp->internal[mp_time]>>16) / 60, - (mp->internal[mp_time]>>16) % 60, - name_string, format_string); - mp->ps->job_id_string = mp_xstrdup (mp,s); - mp_xfree (s); - mp_xfree (name_string); - mp_xfree (format_string); -} -static void fnstr_append (MP mp, const char *s) { - size_t l = strlen (s) + 1; - alloc_array (char, l, SMALL_ARRAY_SIZE); - strcat (mp->ps->char_ptr, s); - mp->ps->char_ptr = strend (mp->ps->char_ptr); -} - -@ @<Exported function headers@>= -void mp_set_job_id (MP mp) ; - -@ @<Dealloc variables@>= -mp_xfree(mp->ps->job_id_string); - -@ this is not really a true crc32, but it should be just enough to keep - subsets prefixes somewhat disjunct - -@c -static unsigned long crc32 (int oldcrc, const Byte *buf, int len) { - unsigned long ret = 0; - int i; - if (oldcrc==0) - ret = (23<<24)+(45<<16)+(67<<8)+89; - else - for (i=0;i<len;i++) - ret = (ret<<2)+buf[i]; - return ret; -} -static boolean mp_char_marked (MP mp,font_number f, eight_bits c) { - integer b; /* |char_base[f]| */ - b=mp->char_base[f]; - if ( (c>=mp->font_bc[f])&&(c<=mp->font_ec[f])&&(mp->font_info[b+c].qqqq.b3!=0) ) - return true; - else - return false; -} - -static void make_subset_tag (MP mp, fm_entry * fm_cur, char **glyph_names, int tex_font) -{ - char tag[7]; - unsigned long crc; - int i; - size_t l ; - if (mp->ps->job_id_string ==NULL) - mp_fatal_error(mp, "no job id!"); - l = strlen (mp->ps->job_id_string) + 1; - - alloc_array (char, l, SMALL_ARRAY_SIZE); - strcpy (mp->ps->char_array, mp->ps->job_id_string); - mp->ps->char_ptr = strend (mp->ps->char_array); - if (fm_cur->tfm_name != NULL) { - fnstr_append (mp," TFM name: "); - fnstr_append (mp,fm_cur->tfm_name); - } - fnstr_append (mp," PS name: "); - if (fm_cur->ps_name != NULL) - fnstr_append (mp,fm_cur->ps_name); - fnstr_append (mp," Encoding: "); - if (fm_cur->encoding != NULL && (fm_cur->encoding)->file_name != NULL) - fnstr_append (mp,(fm_cur->encoding)->file_name); - else - fnstr_append (mp,"built-in"); - fnstr_append (mp," CharSet: "); - for (i = 0; i < 256; i++) - if (mp_char_marked (mp,tex_font, i) && glyph_names[i] != notdef) { - if (glyph_names[i]!=NULL) { - fnstr_append (mp,"/"); - fnstr_append (mp,glyph_names[i]); - } - } - if (fm_cur->charset != NULL) { - fnstr_append (mp," Extra CharSet: "); - fnstr_append (mp, fm_cur->charset); - } - crc = crc32 (0L, Z_NULL, 0); - crc = crc32 (crc, (Bytef *) mp->ps->char_array, strlen (mp->ps->char_array)); - /* we need to fit a 32-bit number into a string of 6 uppercase chars long; - * there are 26 uppercase chars ==> each char represents a number in range - * |0..25|. The maximal number that can be represented by the tag is - * $26^6 - 1$, which is a number between $2^28$ and $2^29$. Thus the bits |29..31| - * of the CRC must be dropped out. - */ - for (i = 0; i < 6; i++) { - tag[i] = 'A' + crc % 26; - crc /= 26; - } - tag[6] = 0; - fm_cur->subset_tag = mp_xstrdup (mp,tag); -} - - - -@ -@d external_enc() (fm_cur->encoding)->glyph_names -@d is_used_char(c) mp_char_marked (mp, tex_font, c) -@d end_last_eexec_line() - mp->ps->hexline_length = HEXLINE_WIDTH; - end_hexline(mp); - mp->ps->t1_eexec_encrypt = false -@d t1_log(s) mp_print(mp,(char *)s) -@d t1_putchar(c) wps_chr(c) -@d embed_all_glyphs(tex_font) false -@d t1_char(c) c -@d extra_charset() mp->ps->dvips_extra_charset -@d update_subset_tag() -@d fixedcontent true - -@<Glob...@>= -#define PRINTF_BUF_SIZE 1024 -char *dvips_extra_charset; -char *cur_enc_name; -unsigned char *grid; -char *ext_glyph_names[256]; -char print_buf[PRINTF_BUF_SIZE]; -int t1_byte_waiting; - -@ @<Set initial ...@>= -mp->ps->dvips_extra_charset=NULL; -mp->ps->t1_byte_waiting=0; - -@ -@d t1_ungetchar(A) mp->ps->t1_byte_waiting=A -@d t1_eof() (mp->eof_file)(mp,mp->ps->t1_file) -@d t1_close() (mp->close_file)(mp,mp->ps->t1_file) -@d valid_code(c) (c >= 0 && c < 256) - -@c -int t1_getchar (MP mp) { - size_t len = 1; - unsigned char abyte=0; - void *byte_ptr = &abyte; - if (mp->ps->t1_byte_waiting) { - abyte = mp->ps->t1_byte_waiting; - mp->ps->t1_byte_waiting = 0; - } else { - (mp->read_binary_file)(mp,mp->ps->t1_file,&byte_ptr,&len); - } - return abyte; -} - -@ @<Static variables in the outer block@>= -static const char *standard_glyph_names[256] = - { notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, - notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, - notdef, notdef, notdef, notdef, notdef, notdef, - notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, - "space", "exclam", "quotedbl", "numbersign", - "dollar", "percent", "ampersand", "quoteright", "parenleft", - "parenright", "asterisk", "plus", "comma", "hyphen", "period", - "slash", "zero", "one", "two", "three", "four", "five", "six", "seven", - "eight", "nine", "colon", "semicolon", "less", - "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", - "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", - "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", - "backslash", "bracketright", "asciicircum", "underscore", - "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", - "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", - "w", "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", - notdef, notdef, notdef, notdef, notdef, notdef, notdef, - notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, - notdef, notdef, notdef, notdef, notdef, notdef, - notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, - notdef, notdef, notdef, "exclamdown", "cent", - "sterling", "fraction", "yen", "florin", "section", "currency", - "quotesingle", "quotedblleft", "guillemotleft", - "guilsinglleft", "guilsinglright", "fi", "fl", notdef, "endash", - "dagger", "daggerdbl", "periodcentered", notdef, - "paragraph", "bullet", "quotesinglbase", "quotedblbase", - "quotedblright", "guillemotright", "ellipsis", "perthousand", - notdef, "questiondown", notdef, "grave", "acute", "circumflex", - "tilde", "macron", "breve", "dotaccent", "dieresis", notdef, - "ring", "cedilla", notdef, "hungarumlaut", "ogonek", "caron", "emdash", - notdef, notdef, notdef, notdef, notdef, notdef, - notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, notdef, - notdef, "AE", notdef, "ordfeminine", notdef, notdef, - notdef, notdef, "Lslash", "Oslash", "OE", "ordmasculine", notdef, - notdef, notdef, notdef, notdef, "ae", notdef, notdef, - notdef, "dotlessi", notdef, notdef, "lslash", "oslash", "oe", - "germandbls", notdef, notdef, notdef, notdef }; -static const char charstringname[] = "/CharStrings"; - -@ @<Glob...@>= -char **t1_glyph_names; -char *t1_builtin_glyph_names[256]; -char charsetstr[0x4000]; -boolean read_encoding_only; -int t1_encoding; - -@ @c -#define T1_BUF_SIZE 0x10 - -#define CS_HSTEM 1 -#define CS_VSTEM 3 -#define CS_VMOVETO 4 -#define CS_RLINETO 5 -#define CS_HLINETO 6 -#define CS_VLINETO 7 -#define CS_RRCURVETO 8 -#define CS_CLOSEPATH 9 -#define CS_CALLSUBR 10 -#define CS_RETURN 11 -#define CS_ESCAPE 12 -#define CS_HSBW 13 -#define CS_ENDCHAR 14 -#define CS_RMOVETO 21 -#define CS_HMOVETO 22 -#define CS_VHCURVETO 30 -#define CS_HVCURVETO 31 -#define CS_1BYTE_MAX (CS_HVCURVETO + 1) - -#define CS_DOTSECTION CS_1BYTE_MAX + 0 -#define CS_VSTEM3 CS_1BYTE_MAX + 1 -#define CS_HSTEM3 CS_1BYTE_MAX + 2 -#define CS_SEAC CS_1BYTE_MAX + 6 -#define CS_SBW CS_1BYTE_MAX + 7 -#define CS_DIV CS_1BYTE_MAX + 12 -#define CS_CALLOTHERSUBR CS_1BYTE_MAX + 16 -#define CS_POP CS_1BYTE_MAX + 17 -#define CS_SETCURRENTPOINT CS_1BYTE_MAX + 33 -#define CS_2BYTE_MAX (CS_SETCURRENTPOINT + 1) -#define CS_MAX CS_2BYTE_MAX - -@ @<Types...@>= -typedef unsigned char byte; -typedef struct { - byte nargs; /* number of arguments */ - boolean bottom; /* take arguments from bottom of stack? */ - boolean clear; /* clear stack? */ - boolean valid; -} cc_entry; /* CharString Command */ -typedef struct { - char *glyph_name; /* glyph name (or notdef for Subrs entry) */ - byte *data; - unsigned short len; /* length of the whole string */ - unsigned short cslen; /* length of the encoded part of the string */ - boolean is_used; - boolean valid; -} cs_entry; - -@ @<Glob...@>= -unsigned short t1_dr, t1_er; -unsigned short t1_c1, t1_c2; -unsigned short t1_cslen; -short t1_lenIV; - -@ @<Set initial...@>= -mp->ps->t1_c1 = 52845; -mp->ps->t1_c2 = 22719; - -@ @<Types...@>= -typedef char t1_line_entry; -typedef char t1_buf_entry; - -@ @<Glob...@>= -t1_line_entry *t1_line_ptr, *t1_line_array; -size_t t1_line_limit; -t1_buf_entry *t1_buf_ptr, *t1_buf_array; -size_t t1_buf_limit; -int cs_start; -cs_entry *cs_tab, *cs_ptr, *cs_notdef; -char *cs_dict_start, *cs_dict_end; -int cs_count, cs_size, cs_size_pos; -cs_entry *subr_tab; -char *subr_array_start, *subr_array_end; -int subr_max, subr_size, subr_size_pos; - -@ @<Set initial...@>= -mp->ps->t1_line_array = NULL; -mp->ps->t1_buf_array = NULL; - -@ - This list contains the begin/end tokens commonly used in the - /Subrs array of a Type 1 font. - -@<Static variables in the outer block@>= -static const char *cs_token_pairs_list[][2] = { - {" RD", "NP"}, - {" -|", "|"}, - {" RD", "noaccess put"}, - {" -|", "noaccess put"}, - {NULL, NULL} -}; - -@ @<Glob...@>= -const char **cs_token_pair; -boolean t1_pfa, t1_cs, t1_scan, t1_eexec_encrypt, t1_synthetic; -int t1_in_eexec; /* 0 before eexec-encrypted, 1 during, 2 after */ -long t1_block_length; -int last_hexbyte; -void *t1_file; -int hexline_length; - -@ -@d HEXLINE_WIDTH 64 - -@<Set initial ...@>= -mp->ps->hexline_length = 0; - -@ -@d t1_prefix(s) str_prefix(mp->ps->t1_line_array, s) -@d t1_buf_prefix(s) str_prefix(mp->ps->t1_buf_array, s) -@d t1_suffix(s) str_suffix(mp->ps->t1_line_array, mp->ps->t1_line_ptr, s) -@d t1_buf_suffix(s) str_suffix(mp->ps->t1_buf_array, mp->ps->t1_buf_ptr, s) -@d t1_charstrings() strstr(mp->ps->t1_line_array, charstringname) -@d t1_subrs() t1_prefix("/Subrs") -@d t1_end_eexec() t1_suffix("mark currentfile closefile") -@d t1_cleartomark() t1_prefix("cleartomark") - -@d isdigit(A) ((A)>='0'&&(A)<='9') - -@c -static void end_hexline (MP mp) { - if (mp->ps->hexline_length >= HEXLINE_WIDTH) { - wps_cr; - mp->ps->hexline_length = 0; - } -} -static void t1_check_pfa (MP mp) { - const int c = t1_getchar (mp); - mp->ps->t1_pfa = (c != 128) ? true : false; - t1_ungetchar (c); -} -static int t1_getbyte (MP mp) -{ - int c = t1_getchar (mp); - if (mp->ps->t1_pfa) - return c; - if (mp->ps->t1_block_length == 0) { - if (c != 128) - mp_fatal_error (mp, "invalid marker"); - c = t1_getchar (mp); - if (c == 3) { - while (!t1_eof ()) - t1_getchar (mp); - return EOF; - } - mp->ps->t1_block_length = t1_getchar (mp) & 0xff; - mp->ps->t1_block_length |= (t1_getchar (mp) & 0xff) << 8; - mp->ps->t1_block_length |= (t1_getchar (mp) & 0xff) << 16; - mp->ps->t1_block_length |= (t1_getchar (mp) & 0xff) << 24; - c = t1_getchar (mp); - } - mp->ps->t1_block_length--; - return c; -} -static int hexval (int c) { - if (c >= 'A' && c <= 'F') - return c - 'A' + 10; - else if (c >= 'a' && c <= 'f') - return c - 'a' + 10; - else if (c >= '0' && c <= '9') - return c - '0'; - else - return -1; -} -static byte edecrypt (MP mp, byte cipher) { - byte plain; - if (mp->ps->t1_pfa) { - while (cipher == 10 || cipher == 13) - cipher = t1_getbyte (mp); - mp->ps->last_hexbyte = cipher = (hexval (cipher) << 4) + hexval (t1_getbyte (mp)); - } - plain = (cipher ^ (mp->ps->t1_dr >> 8)); - mp->ps->t1_dr = (cipher + mp->ps->t1_dr) * mp->ps->t1_c1 + mp->ps->t1_c2; - return plain; -} -static byte cdecrypt (MP mp, byte cipher, unsigned short *cr) -{ - const byte plain = (cipher ^ (*cr >> 8)); - *cr = (cipher + *cr) * mp->ps->t1_c1 + mp->ps->t1_c2; - return plain; -} -static byte eencrypt (MP mp, byte plain) -{ - const byte cipher = (plain ^ (mp->ps->t1_er >> 8)); - mp->ps->t1_er = (cipher + mp->ps->t1_er) * mp->ps->t1_c1 + mp->ps->t1_c2; - return cipher; -} - -static byte cencrypt (MP mp, byte plain, unsigned short *cr) -{ - const byte cipher = (plain ^ (*cr >> 8)); - *cr = (cipher + *cr) * mp->ps->t1_c1 + mp->ps->t1_c2; - return cipher; -} - -static char *eol (char *s) { - char *p = strend (s); - if (p - s > 1 && p[-1] != 10) { - *p++ = 10; - *p = 0; - } - return p; -} -static float t1_scan_num (MP mp, char *p, char **r) -{ - float f; - char s[128]; - skip (p, ' '); - if (sscanf (p, "%g", &f) != 1) { - remove_eol (p, mp->ps->t1_line_array); - snprintf(s,128, "a number expected: `%s'", mp->ps->t1_line_array); - mp_fatal_error(mp,s); - } - if (r != NULL) { - for (; isdigit (*p) || *p == '.' || - *p == 'e' || *p == 'E' || *p == '+' || *p == '-'; p++); - *r = p; - } - return f; -} - -static boolean str_suffix (const char *begin_buf, const char *end_buf, - const char *s) -{ - const char *s1 = end_buf - 1, *s2 = strend (s) - 1; - if (*s1 == 10) - s1--; - while (s1 >= begin_buf && s2 >= s) { - if (*s1-- != *s2--) - return false; - } - return s2 < s; -} - -@ - -@d alloc_array(T, n, s) do { - if (mp->ps->T##_array == NULL) { - mp->ps->T##_limit = (s); - if ((unsigned)(n) > mp->ps->T##_limit) - mp->ps->T##_limit = (n); - mp->ps->T##_array = mp_xmalloc (mp,mp->ps->T##_limit,sizeof(T##_entry)); - mp->ps->T##_ptr = mp->ps->T##_array; - } - else if ((unsigned)(mp->ps->T##_ptr - mp->ps->T##_array + (n)) > mp->ps->T##_limit) { - size_t last_ptr_index; - last_ptr_index = mp->ps->T##_ptr - mp->ps->T##_array; - mp->ps->T##_limit *= 2; - if ((unsigned)(mp->ps->T##_ptr - mp->ps->T##_array + (n)) > mp->ps->T##_limit) - mp->ps->T##_limit = mp->ps->T##_ptr - mp->ps->T##_array + (n); - mp->ps->T##_array = mp_xrealloc(mp,mp->ps->T##_array,mp->ps->T##_limit, sizeof(T##_entry)); - mp->ps->T##_ptr = mp->ps->T##_array + last_ptr_index; - } -} while (0) - -@d out_eexec_char(A) t1_outhex(mp,(A)) - -@c -static void t1_outhex (MP mp, byte b) -{ - static const char *hexdigits = "0123456789ABCDEF"; - t1_putchar (hexdigits[b / 16]); - t1_putchar (hexdigits[b % 16]); - mp->ps->hexline_length += 2; - end_hexline (mp); -} -static void t1_getline (MP mp) { - int c, l, eexec_scan; - char *p; - static const char eexec_str[] = "currentfile eexec"; - static int eexec_len = 17; /* |strlen(eexec_str)| */ - RESTART: - if (t1_eof ()) - mp_fatal_error (mp,"unexpected end of file"); - mp->ps->t1_line_ptr = mp->ps->t1_line_array; - alloc_array (t1_line, 1, T1_BUF_SIZE); - mp->ps->t1_cslen = 0; - eexec_scan = 0; - c = t1_getbyte (mp); - if (c == EOF) - goto EXIT; - while (!t1_eof ()) { - if (mp->ps->t1_in_eexec == 1) - c = edecrypt (mp,c); - alloc_array (t1_line, 1, T1_BUF_SIZE); - append_char_to_buf (c, mp->ps->t1_line_ptr, mp->ps->t1_line_array, mp->ps->t1_line_limit); - if (mp->ps->t1_in_eexec == 0 && eexec_scan >= 0 && eexec_scan < eexec_len) { - if (mp->ps->t1_line_array[eexec_scan] == eexec_str[eexec_scan]) - eexec_scan++; - else - eexec_scan = -1; - } - if (c == 10 || (mp->ps->t1_pfa && eexec_scan == eexec_len && c == 32)) - break; - if (mp->ps->t1_cs && mp->ps->t1_cslen == 0 && - (mp->ps->t1_line_ptr - mp->ps->t1_line_array > 4) && - (t1_suffix (" RD ") || t1_suffix (" -| "))) { - p = mp->ps->t1_line_ptr - 5; - while (*p != ' ') - p--; - mp->ps->t1_cslen = l = t1_scan_num (mp, p + 1, 0); - mp->ps->cs_start = mp->ps->t1_line_ptr - mp->ps->t1_line_array; - /* |mp->ps->cs_start| is an index now */ - alloc_array (t1_line, l, T1_BUF_SIZE); - while (l-- > 0) - *mp->ps->t1_line_ptr++ = edecrypt (mp,t1_getbyte (mp)); - } - c = t1_getbyte (mp); - } - alloc_array (t1_line, 2, T1_BUF_SIZE); /* |append_eol| can append 2 chars */ - append_eol (mp->ps->t1_line_ptr, mp->ps->t1_line_array, mp->ps->t1_line_limit); - if (mp->ps->t1_line_ptr - mp->ps->t1_line_array < 2) - goto RESTART; - if (eexec_scan == eexec_len) - mp->ps->t1_in_eexec = 1; - EXIT: - /* ensure that |mp->ps->t1_buf_array| has as much room as |t1_line_array| */ - mp->ps->t1_buf_ptr = mp->ps->t1_buf_array; - alloc_array (t1_buf, mp->ps->t1_line_limit, mp->ps->t1_line_limit); -} - -static void t1_putline (MP mp) -{ - char *p = mp->ps->t1_line_array; - if (mp->ps->t1_line_ptr - mp->ps->t1_line_array <= 1) - return; - if (mp->ps->t1_eexec_encrypt) { - while (p < mp->ps->t1_line_ptr) - out_eexec_char (eencrypt (mp,*p++)); - } else { - while (p < mp->ps->t1_line_ptr) - t1_putchar (*p++); - } -} - -static void t1_puts (MP mp, const char *s) -{ - if (s != mp->ps->t1_line_array) - strcpy (mp->ps->t1_line_array, s); - mp->ps->t1_line_ptr = strend (mp->ps->t1_line_array); - t1_putline (mp); -} - -static void t1_printf (MP mp, const char *fmt, ...) -{ - va_list args; - va_start (args, fmt); - vsprintf (mp->ps->t1_line_array, fmt, args); - t1_puts (mp,mp->ps->t1_line_array); - va_end (args); -} - -static void t1_init_params (MP mp, char *open_name_prefix, - char *cur_file_name) { - if ((open_name_prefix != NULL) && strlen(open_name_prefix)) { - t1_log (open_name_prefix); - t1_log (cur_file_name); - } - mp->ps->t1_lenIV = 4; - mp->ps->t1_dr = 55665; - mp->ps->t1_er = 55665; - mp->ps->t1_in_eexec = 0; - mp->ps->t1_cs = false; - mp->ps->t1_scan = true; - mp->ps->t1_synthetic = false; - mp->ps->t1_eexec_encrypt = false; - mp->ps->t1_block_length = 0; - t1_check_pfa (mp); -} -static void t1_close_font_file (MP mp, const char *close_name_suffix) { - if ((close_name_suffix != NULL) && strlen(close_name_suffix)) { - t1_log (close_name_suffix); - } - t1_close (); -} - -static void t1_check_block_len (MP mp, boolean decrypt) { - int l, c; - char s[128]; - if (mp->ps->t1_block_length == 0) - return; - c = t1_getbyte (mp); - if (decrypt) - c = edecrypt (mp,c); - l = mp->ps->t1_block_length; - if (!(l == 0 && (c == 10 || c == 13))) { - snprintf(s,128,"%i bytes more than expected were ignored", l+ 1); - mp_warn(mp,s); - while (l-- > 0) - t1_getbyte (mp); - } -} -static void t1_start_eexec (MP mp, fm_entry *fm_cur) { - int i; - if (!mp->ps->t1_pfa) - t1_check_block_len (mp, false); - for (mp->ps->t1_line_ptr = mp->ps->t1_line_array, i = 0; i < 4; i++) { - edecrypt (mp, t1_getbyte (mp)); - *mp->ps->t1_line_ptr++ = 0; - } - mp->ps->t1_eexec_encrypt = true; - if (!mp->ps->read_encoding_only) - if (is_included (fm_cur)) - t1_putline (mp); /* to put the first four bytes */ -} -static void t1_stop_eexec (MP mp) { - int c; - end_last_eexec_line (); - if (!mp->ps->t1_pfa) - t1_check_block_len (mp,true); - else { - c = edecrypt (mp, t1_getbyte (mp)); - if (!(c == 10 || c == 13)) { - if (mp->ps->last_hexbyte == 0) - t1_puts (mp,"00"); - else - mp_warn (mp,"unexpected data after eexec"); - } - } - mp->ps->t1_cs = false; - mp->ps->t1_in_eexec = 2; -} -static void t1_modify_fm (MP mp) { - mp->ps->t1_line_ptr = eol (mp->ps->t1_line_array); -} - -static void t1_modify_italic (MP mp) { - mp->ps->t1_line_ptr = eol (mp->ps->t1_line_array); -} - -@ @<Types...@>= -typedef struct { - const char *pdfname; - const char *t1name; - float value; - boolean valid; -} key_entry; - -@ -@d FONT_KEYS_NUM 11 - -@<Declarations@>= -static key_entry font_keys[FONT_KEYS_NUM] = { - {"Ascent", "Ascender", 0, false}, - {"CapHeight", "CapHeight", 0, false}, - {"Descent", "Descender", 0, false}, - {"FontName", "FontName", 0, false}, - {"ItalicAngle", "ItalicAngle", 0, false}, - {"StemV", "StdVW", 0, false}, - {"XHeight", "XHeight", 0, false}, - {"FontBBox", "FontBBox", 0, false}, - {"", "", 0, false}, - {"", "", 0, false}, - {"", "", 0, false} -}; - - -@ -@d ASCENT_CODE 0 -@d CAPHEIGHT_CODE 1 -@d DESCENT_CODE 2 -@d FONTNAME_CODE 3 -@d ITALIC_ANGLE_CODE 4 -@d STEMV_CODE 5 -@d XHEIGHT_CODE 6 -@d FONTBBOX1_CODE 7 -@d FONTBBOX2_CODE 8 -@d FONTBBOX3_CODE 9 -@d FONTBBOX4_CODE 10 -@d MAX_KEY_CODE (FONTBBOX1_CODE + 1) - -@c -static void t1_scan_keys (MP mp, int tex_font,fm_entry *fm_cur) { - int i, k; - char *p, *r; - key_entry *key; - if (fm_extend (fm_cur) != 0 || fm_slant (fm_cur) != 0) { - if (t1_prefix ("/FontMatrix")) { - t1_modify_fm (mp); - return; - } - if (t1_prefix ("/ItalicAngle")) { - t1_modify_italic (mp); - return; - } - } - if (t1_prefix ("/FontType")) { - p = mp->ps->t1_line_array + strlen ("FontType") + 1; - if ((i = t1_scan_num (mp,p, 0)) != 1) { - char s[128]; - snprintf(s,125,"Type%d fonts unsupported by metapost", i); - mp_fatal_error(mp,s); - } - return; - } - for (key = font_keys; key - font_keys < MAX_KEY_CODE; key++) - if (str_prefix (mp->ps->t1_line_array + 1, key->t1name)) - break; - if (key - font_keys == MAX_KEY_CODE) - return; - key->valid = true; - p = mp->ps->t1_line_array + strlen (key->t1name) + 1; - skip (p, ' '); - if ((k = key - font_keys) == FONTNAME_CODE) { - if (*p != '/') { - char s[128]; - remove_eol (p, mp->ps->t1_line_array); - snprintf(s,128,"a name expected: `%s'", mp->ps->t1_line_array); - mp_fatal_error(mp,s); - } - r = ++p; /* skip the slash */ - if (is_included (fm_cur)) { - /* save the fontname */ - strncpy (mp->ps->fontname_buf, p, FONTNAME_BUF_SIZE); - for (i=0; mp->ps->fontname_buf[i] != 10; i++); - mp->ps->fontname_buf[i]=0; - - if(is_subsetted (fm_cur)) { - if (fm_cur->encoding!=NULL && fm_cur->encoding->glyph_names!=NULL) - make_subset_tag (mp,fm_cur, fm_cur->encoding->glyph_names, tex_font); - else - make_subset_tag (mp,fm_cur, mp->ps->t1_builtin_glyph_names, tex_font); - - alloc_array (t1_line, (r-mp->ps->t1_line_array+6+1+strlen(mp->ps->fontname_buf)+1), - T1_BUF_SIZE); - strncpy (r, fm_cur->subset_tag , 6); - *(r+6) = '-'; - strncpy (r+7, mp->ps->fontname_buf, strlen(mp->ps->fontname_buf)+1); - mp->ps->t1_line_ptr = eol (r); - } else { - /* |for (q = p; *q != ' ' && *q != 10; *q++);|*/ - /*|*q = 0;|*/ - mp->ps->t1_line_ptr = eol (r); - } - } - return; - } - if ((k == STEMV_CODE || k == FONTBBOX1_CODE) - && (*p == '[' || *p == '{')) - p++; - if (k == FONTBBOX1_CODE) { - for (i = 0; i < 4; i++) { - key[i].value = t1_scan_num (mp, p, &r); - p = r; - } - return; - } - key->value = t1_scan_num (mp, p, 0); -} -static void t1_scan_param (MP mp, int tex_font,fm_entry *fm_cur) -{ - static const char *lenIV = "/lenIV"; - if (!mp->ps->t1_scan || *mp->ps->t1_line_array != '/') - return; - if (t1_prefix (lenIV)) { - mp->ps->t1_lenIV = t1_scan_num (mp,mp->ps->t1_line_array + strlen (lenIV), 0); - return; - } - t1_scan_keys (mp, tex_font,fm_cur); -} -static void copy_glyph_names (MP mp, char **glyph_names, int a, int b) { - if (glyph_names[b] != notdef) { - mp_xfree (glyph_names[b]); - glyph_names[b] = (char *) notdef; - } - if (glyph_names[a] != notdef) { - glyph_names[b] = mp_xstrdup (mp,glyph_names[a]); - } -} -static void t1_builtin_enc (MP mp) { - int i, a, b, c, counter = 0; - char *r, *p; - /* - * At this moment "/Encoding" is the prefix of |mp->ps->t1_line_array| - */ - if (t1_suffix ("def")) { /* predefined encoding */ - sscanf (mp->ps->t1_line_array + strlen ("/Encoding"), "%256s", mp->ps->t1_buf_array); - if (strcmp (mp->ps->t1_buf_array, "StandardEncoding") == 0) { - for (i = 0; i < 256; i++) - if (standard_glyph_names[i] == notdef) - mp->ps->t1_builtin_glyph_names[i] = (char *) notdef; - else - mp->ps->t1_builtin_glyph_names[i] = - mp_xstrdup (mp,standard_glyph_names[i]); - mp->ps->t1_encoding = ENC_STANDARD; - } else { - char s[128]; - snprintf(s,128, "cannot subset font (unknown predefined encoding `%s')", - mp->ps->t1_buf_array); - mp_fatal_error(mp,s); - } - return; - } else - mp->ps->t1_encoding = ENC_BUILTIN; - /* - * At this moment "/Encoding" is the prefix of |mp->ps->t1_line_array|, and the encoding is - * not a predefined encoding - * - * We have two possible forms of Encoding vector. The first case is - * - * /Encoding [/a /b /c...] readonly def - * - * and the second case can look like - * - * /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for - * dup 0 /x put - * dup 1 /y put - * ... - * readonly def - */ - for (i = 0; i < 256; i++) - mp->ps->t1_builtin_glyph_names[i] = (char *) notdef; - if (t1_prefix ("/Encoding [") || t1_prefix ("/Encoding[")) { /* the first case */ - r = strchr (mp->ps->t1_line_array, '[') + 1; - skip (r, ' '); - for (;;) { - while (*r == '/') { - for (p = mp->ps->t1_buf_array, r++; - *r != 32 && *r != 10 && *r != ']' && *r != '/'; - *p++ = *r++); - *p = 0; - skip (r, ' '); - if (counter > 255) { - mp_fatal_error - (mp, "encoding vector contains more than 256 names"); - } - if (strcmp (mp->ps->t1_buf_array, notdef) != 0) - mp->ps->t1_builtin_glyph_names[counter] = mp_xstrdup (mp,mp->ps->t1_buf_array); - counter++; - } - if (*r != 10 && *r != '%') { - if (str_prefix (r, "] def") - || str_prefix (r, "] readonly def")) - break; - else { - char s[128]; - remove_eol (r, mp->ps->t1_line_array); - snprintf(s,128,"a name or `] def' or `] readonly def' expected: `%s'", - mp->ps->t1_line_array); - mp_fatal_error(mp,s); - } - } - t1_getline (mp); - r = mp->ps->t1_line_array; - } - } else { /* the second case */ - p = strchr (mp->ps->t1_line_array, 10); - for (;;) { - if (*p == 10) { - t1_getline (mp); - p = mp->ps->t1_line_array; - } - /* - check for `dup <index> <glyph> put' - */ - if (sscanf (p, "dup %i%256s put", &i, mp->ps->t1_buf_array) == 2 && - *mp->ps->t1_buf_array == '/' && valid_code (i)) { - if (strcmp (mp->ps->t1_buf_array + 1, notdef) != 0) - mp->ps->t1_builtin_glyph_names[i] = - mp_xstrdup (mp,mp->ps->t1_buf_array + 1); - p = strstr (p, " put") + strlen (" put"); - skip (p, ' '); - } - /* - check for `dup dup <to> exch <from> get put' - */ - else if (sscanf (p, "dup dup %i exch %i get put", &b, &a) == 2 - && valid_code (a) && valid_code (b)) { - copy_glyph_names (mp,mp->ps->t1_builtin_glyph_names, a, b); - p = strstr (p, " get put") + strlen (" get put"); - skip (p, ' '); - } - /* - check for `dup dup <from> <size> getinterval <to> exch putinterval' - */ - else if (sscanf - (p, "dup dup %i %i getinterval %i exch putinterval", - &a, &c, &b) == 3 && valid_code (a) && valid_code (b) - && valid_code (c)) { - for (i = 0; i < c; i++) - copy_glyph_names (mp,mp->ps->t1_builtin_glyph_names, a + i, b + i); - p = strstr (p, " putinterval") + strlen (" putinterval"); - skip (p, ' '); - } - /* - check for `def' or `readonly def' - */ - else if ((p == mp->ps->t1_line_array || (p > mp->ps->t1_line_array && p[-1] == ' ')) - && strcmp (p, "def\n") == 0) - return; - /* - skip an unrecognizable word - */ - else { - while (*p != ' ' && *p != 10) - p++; - skip (p, ' '); - } - } - } -} - -static void t1_check_end (MP mp) { - if (t1_eof ()) - return; - t1_getline (mp); - if (t1_prefix ("{restore}")) - t1_putline (mp); -} - -@ @<Types...@>= -typedef struct { - char *ff_name; /* base name of font file */ - char *ff_path; /* full path to font file */ -} ff_entry; - -@ @c -static boolean t1_open_fontfile (MP mp, fm_entry *fm_cur,const char *open_name_prefix) { - ff_entry *ff; - ff = check_ff_exist (mp, fm_cur); - if (ff->ff_path != NULL) { - mp->ps->t1_file = (mp->open_file)(mp,ff->ff_path, "r", mp_filetype_font); - } else { - mp_warn (mp, "cannot open Type 1 font file for reading"); - return false; - } - t1_init_params (mp,(char *)open_name_prefix,fm_cur->ff_name); - mp->ps->fontfile_found = true; - return true; -} - -static void t1_scan_only (MP mp, int tex_font, fm_entry *fm_cur) { - do { - t1_getline (mp); - t1_scan_param (mp,tex_font, fm_cur); - } - while (mp->ps->t1_in_eexec == 0); - t1_start_eexec (mp,fm_cur); - do { - t1_getline (mp); - t1_scan_param (mp,tex_font, fm_cur); - } - while (!(t1_charstrings () || t1_subrs ())); -} - -static void t1_include (MP mp, int tex_font, fm_entry *fm_cur) { - do { - t1_getline (mp); - t1_scan_param (mp,tex_font, fm_cur); - t1_putline (mp); - } - while (mp->ps->t1_in_eexec == 0); - t1_start_eexec (mp,fm_cur); - do { - t1_getline (mp); - t1_scan_param (mp,tex_font, fm_cur); - t1_putline (mp); - } - while (!(t1_charstrings () || t1_subrs ())); - mp->ps->t1_cs = true; - do { - t1_getline (mp); - t1_putline (mp); - } - while (!t1_end_eexec ()); - t1_stop_eexec (mp); - if (fixedcontent) { /* copy 512 zeros (not needed for PDF) */ - do { - t1_getline (mp); - t1_putline (mp); - } - while (!t1_cleartomark ()); - t1_check_end (mp); /* write "{restore}if" if found */ - } -} - -@ -@d check_subr(SUBR) if (SUBR >= mp->ps->subr_size || SUBR < 0) { - char s[128]; - snprintf(s,128,"Subrs array: entry index out of range (%i)",SUBR); - mp_fatal_error(mp,s); - } - -@c -static const char **check_cs_token_pair (MP mp) { - const char **p = (const char **) cs_token_pairs_list; - for (; p[0] != NULL; ++p) - if (t1_buf_prefix (p[0]) && t1_buf_suffix (p[1])) - return p; - return NULL; -} - -static void cs_store (MP mp, boolean is_subr) { - char *p; - cs_entry *ptr; - int subr; - for (p = mp->ps->t1_line_array, mp->ps->t1_buf_ptr = mp->ps->t1_buf_array; *p != ' '; - *mp->ps->t1_buf_ptr++ = *p++); - *mp->ps->t1_buf_ptr = 0; - if (is_subr) { - subr = t1_scan_num (mp, p + 1, 0); - check_subr (subr); - ptr = mp->ps->subr_tab + subr; - } else { - ptr = mp->ps->cs_ptr++; - if (mp->ps->cs_ptr - mp->ps->cs_tab > mp->ps->cs_size) { - char s[128]; - snprintf(s,128,"CharStrings dict: more entries than dict size (%i)",mp->ps->cs_size); - mp_fatal_error(mp,s); - } - if (strcmp (mp->ps->t1_buf_array + 1, notdef) == 0) /* skip the slash */ - ptr->glyph_name = (char *) notdef; - else - ptr->glyph_name = mp_xstrdup (mp,mp->ps->t1_buf_array + 1); - } - /* copy " RD " + cs data to |mp->ps->t1_buf_array| */ - memcpy (mp->ps->t1_buf_array, mp->ps->t1_line_array + mp->ps->cs_start - 4, - (unsigned) (mp->ps->t1_cslen + 4)); - /* copy the end of cs data to |mp->ps->t1_buf_array| */ - for (p = mp->ps->t1_line_array + mp->ps->cs_start + mp->ps->t1_cslen, mp->ps->t1_buf_ptr = - mp->ps->t1_buf_array + mp->ps->t1_cslen + 4; *p != 10; *mp->ps->t1_buf_ptr++ = *p++); - *mp->ps->t1_buf_ptr++ = 10; - if (is_subr && mp->ps->cs_token_pair == NULL) - mp->ps->cs_token_pair = check_cs_token_pair (mp); - ptr->len = mp->ps->t1_buf_ptr - mp->ps->t1_buf_array; - ptr->cslen = mp->ps->t1_cslen; - ptr->data = mp_xmalloc (mp,ptr->len , sizeof (byte)); - memcpy (ptr->data, mp->ps->t1_buf_array, ptr->len); - ptr->valid = true; -} - -#define store_subr(mp) cs_store(mp,true) -#define store_cs(mp) cs_store(mp,false) - -#define CC_STACK_SIZE 24 - -static integer cc_stack[CC_STACK_SIZE], *stack_ptr = cc_stack; -static cc_entry cc_tab[CS_MAX]; -static boolean is_cc_init = false; - - -#define cc_pop(N) \ - if (stack_ptr - cc_stack < (N)) \ - stack_error(N); \ - stack_ptr -= N - -#define stack_error(N) { \ - char s[256]; \ - snprintf(s,255,"CharString: invalid access (%i) to stack (%i entries)", \ - (int) N, (int)(stack_ptr - cc_stack)); \ - mp_warn(mp,s); \ - goto cs_error; \ -} - - -#define cc_get(N) ((N) < 0 ? *(stack_ptr + (N)) : *(cc_stack + (N))) - -#define cc_push(V) *stack_ptr++ = V -#define cc_clear() stack_ptr = cc_stack - -#define set_cc(N, B, A, C) \ - cc_tab[N].nargs = A; \ - cc_tab[N].bottom = B; \ - cc_tab[N].clear = C; \ - cc_tab[N].valid = true - -static void cc_init (void) { - int i; - if (is_cc_init) - return; - for (i = 0; i < CS_MAX; i++) - cc_tab[i].valid = false; - set_cc (CS_HSTEM, true, 2, true); - set_cc (CS_VSTEM, true, 2, true); - set_cc (CS_VMOVETO, true, 1, true); - set_cc (CS_RLINETO, true, 2, true); - set_cc (CS_HLINETO, true, 1, true); - set_cc (CS_VLINETO, true, 1, true); - set_cc (CS_RRCURVETO, true, 6, true); - set_cc (CS_CLOSEPATH, false, 0, true); - set_cc (CS_CALLSUBR, false, 1, false); - set_cc (CS_RETURN, false, 0, false); - /* - |set_cc(CS_ESCAPE, false, 0, false);| - */ - set_cc (CS_HSBW, true, 2, true); - set_cc (CS_ENDCHAR, false, 0, true); - set_cc (CS_RMOVETO, true, 2, true); - set_cc (CS_HMOVETO, true, 1, true); - set_cc (CS_VHCURVETO, true, 4, true); - set_cc (CS_HVCURVETO, true, 4, true); - set_cc (CS_DOTSECTION, false, 0, true); - set_cc (CS_VSTEM3, true, 6, true); - set_cc (CS_HSTEM3, true, 6, true); - set_cc (CS_SEAC, true, 5, true); - set_cc (CS_SBW, true, 4, true); - set_cc (CS_DIV, false, 2, false); - set_cc (CS_CALLOTHERSUBR, false, 0, false); - set_cc (CS_POP, false, 0, false); - set_cc (CS_SETCURRENTPOINT, true, 2, true); - is_cc_init = true; -} - -@ - -@d cs_getchar(mp) cdecrypt(mp,*data++, &cr) - -@d mark_subr(mp,n) cs_mark(mp,0, n) -@d mark_cs(mp,s) cs_mark(mp,s, 0) -@d SMALL_BUF_SIZE 256 - -@c -static void cs_warn (MP mp, const char *cs_name, int subr, const char *fmt, ...) { - char buf[SMALL_BUF_SIZE]; - char s[300]; - va_list args; - va_start (args, fmt); - vsprintf (buf, fmt, args); - va_end (args); - if (cs_name == NULL) { - snprintf(s,299,"Subr (%i): %s", (int) subr, buf); - } else { - snprintf(s,299,"CharString (/%s): %s", cs_name, buf); - } - mp_warn(mp,s); -} - -static void cs_mark (MP mp, const char *cs_name, int subr) -{ - byte *data; - int i, b, cs_len; - integer a, a1, a2; - unsigned short cr; - static integer lastargOtherSubr3 = 3; /* the argument of last call to - OtherSubrs[3] */ - cs_entry *ptr; - cc_entry *cc; - if (cs_name == NULL) { - check_subr (subr); - ptr = mp->ps->subr_tab + subr; - if (!ptr->valid) - return; - } else { - if (mp->ps->cs_notdef != NULL && - (cs_name == notdef || strcmp (cs_name, notdef) == 0)) - ptr = mp->ps->cs_notdef; - else { - for (ptr = mp->ps->cs_tab; ptr < mp->ps->cs_ptr; ptr++) - if (strcmp (ptr->glyph_name, cs_name) == 0) - break; - if (ptr == mp->ps->cs_ptr) { - char s[128]; - snprintf (s,128,"glyph `%s' undefined", cs_name); - mp_warn(mp,s); - return; - } - if (ptr->glyph_name == notdef) - mp->ps->cs_notdef = ptr; - } - } - /* only marked CharString entries and invalid entries can be skipped; - valid marked subrs must be parsed to keep the stack in sync */ - if (!ptr->valid || (ptr->is_used && cs_name != NULL)) - return; - ptr->is_used = true; - cr = 4330; - cs_len = ptr->cslen; - data = ptr->data + 4; - for (i = 0; i < mp->ps->t1_lenIV; i++, cs_len--) - cs_getchar (mp); - while (cs_len > 0) { - --cs_len; - b = cs_getchar (mp); - if (b >= 32) { - if (b <= 246) - a = b - 139; - else if (b <= 250) { - --cs_len; - a = ((b - 247) << 8) + 108 + cs_getchar (mp); - } else if (b <= 254) { - --cs_len; - a = -((b - 251) << 8) - 108 - cs_getchar (mp); - } else { - cs_len -= 4; - a = (cs_getchar (mp) & 0xff) << 24; - a |= (cs_getchar (mp) & 0xff) << 16; - a |= (cs_getchar (mp) & 0xff) << 8; - a |= (cs_getchar (mp) & 0xff) << 0; - if (sizeof (integer) > 4 && (a & 0x80000000)) - a |= ~0x7FFFFFFF; - } - cc_push (a); - } else { - if (b == CS_ESCAPE) { - b = cs_getchar (mp) + CS_1BYTE_MAX; - cs_len--; - } - if (b >= CS_MAX) { - cs_warn (mp,cs_name, subr, "command value out of range: %i", - (int) b); - goto cs_error; - } - cc = cc_tab + b; - if (!cc->valid) { - cs_warn (mp,cs_name, subr, "command not valid: %i", (int) b); - goto cs_error; - } - if (cc->bottom) { - if (stack_ptr - cc_stack < cc->nargs) - cs_warn (mp,cs_name, subr, - "less arguments on stack (%i) than required (%i)", - (int) (stack_ptr - cc_stack), (int) cc->nargs); - else if (stack_ptr - cc_stack > cc->nargs) - cs_warn (mp,cs_name, subr, - "more arguments on stack (%i) than required (%i)", - (int) (stack_ptr - cc_stack), (int) cc->nargs); - } - switch (cc - cc_tab) { - case CS_CALLSUBR: - a1 = cc_get (-1); - cc_pop (1); - mark_subr (mp,a1); - if (!mp->ps->subr_tab[a1].valid) { - cs_warn (mp,cs_name, subr, "cannot call subr (%i)", (int) a1); - goto cs_error; - } - break; - case CS_DIV: - cc_pop (2); - cc_push (0); - break; - case CS_CALLOTHERSUBR: - if (cc_get (-1) == 3) - lastargOtherSubr3 = cc_get (-3); - a1 = cc_get (-2) + 2; - cc_pop (a1); - break; - case CS_POP: - cc_push (lastargOtherSubr3); - /* the only case when we care about the value being pushed onto - stack is when POP follows CALLOTHERSUBR (changing hints by - OtherSubrs[3]) - */ - break; - case CS_SEAC: - a1 = cc_get (3); - a2 = cc_get (4); - cc_clear (); - mark_cs (mp,standard_glyph_names[a1]); - mark_cs (mp,standard_glyph_names[a2]); - break; - default: - if (cc->clear) - cc_clear (); - } - } - } - return; - cs_error: /* an error occured during parsing */ - cc_clear (); - ptr->valid = false; - ptr->is_used = false; -} - -static void t1_subset_ascii_part (MP mp, int tex_font, fm_entry *fm_cur) -{ - int i, j; - t1_getline (mp); - while (!t1_prefix ("/Encoding")) { - t1_scan_param (mp,tex_font, fm_cur); - t1_putline (mp); - t1_getline (mp); - } - t1_builtin_enc (mp); - if (is_reencoded (fm_cur)) - mp->ps->t1_glyph_names = external_enc (); - else - mp->ps->t1_glyph_names = mp->ps->t1_builtin_glyph_names; - /* - |if (is_included (fm_cur) && is_subsetted (fm_cur)) { - make_subset_tag (fm_cur, t1_glyph_names, tex_font); - update_subset_tag (); - }| - */ - if ((!is_subsetted (fm_cur)) && mp->ps->t1_encoding == ENC_STANDARD) - t1_puts (mp,"/Encoding StandardEncoding def\n"); - else { - t1_puts - (mp,"/Encoding 256 array\n0 1 255 {1 index exch /.notdef put} for\n"); - for (i = 0, j = 0; i < 256; i++) { - if (is_used_char (i) && mp->ps->t1_glyph_names[i] != notdef) { - j++; - t1_printf (mp,"dup %i /%s put\n", (int) t1_char (i), - mp->ps->t1_glyph_names[i]); - } - } - /* We didn't mark anything for the Encoding array. */ - /* We add "dup 0 /.notdef put" for compatibility */ - /* with Acrobat 5.0. */ - if (j == 0) - t1_puts (mp,"dup 0 /.notdef put\n"); - t1_puts (mp,"readonly def\n"); - } - do { - t1_getline (mp); - t1_scan_param (mp,tex_font, fm_cur); - if (!t1_prefix ("/UniqueID")) /* ignore UniqueID for subsetted fonts */ - t1_putline (mp); - } - while (mp->ps->t1_in_eexec == 0); -} - -#define t1_subr_flush(mp) t1_flush_cs(mp,true) -#define t1_cs_flush(mp) t1_flush_cs(mp,false) - -static void cs_init (MP mp) { - mp->ps->cs_ptr = mp->ps->cs_tab = NULL; - mp->ps->cs_dict_start = mp->ps->cs_dict_end = NULL; - mp->ps->cs_count = mp->ps->cs_size = mp->ps->cs_size_pos = 0; - mp->ps->cs_token_pair = NULL; - mp->ps->subr_tab = NULL; - mp->ps->subr_array_start = mp->ps->subr_array_end = NULL; - mp->ps->subr_max = mp->ps->subr_size = mp->ps->subr_size_pos = 0; -} - -static void init_cs_entry ( cs_entry * cs) { - cs->data = NULL; - cs->glyph_name = NULL; - cs->len = 0; - cs->cslen = 0; - cs->is_used = false; - cs->valid = false; -} - -static void t1_mark_glyphs (MP mp, int tex_font); - -static void t1_read_subrs (MP mp, int tex_font, fm_entry *fm_cur) -{ - int i, s; - cs_entry *ptr; - t1_getline (mp); - while (!(t1_charstrings () || t1_subrs ())) { - t1_scan_param (mp,tex_font, fm_cur); - t1_putline (mp); - t1_getline (mp); - } - FOUND: - mp->ps->t1_cs = true; - mp->ps->t1_scan = false; - if (!t1_subrs ()) - return; - mp->ps->subr_size_pos = strlen ("/Subrs") + 1; - /* |subr_size_pos| points to the number indicating dict size after "/Subrs" */ - mp->ps->subr_size = t1_scan_num (mp,mp->ps->t1_line_array + mp->ps->subr_size_pos, 0); - if (mp->ps->subr_size == 0) { - while (!t1_charstrings ()) - t1_getline (mp); - return; - } - /* |subr_tab = xtalloc (subr_size, cs_entry);| */ - mp->ps->subr_tab = (cs_entry *)mp_xmalloc (mp,mp->ps->subr_size, sizeof (cs_entry)); - for (ptr = mp->ps->subr_tab; ptr - mp->ps->subr_tab < mp->ps->subr_size; ptr++) - init_cs_entry (ptr); - mp->ps->subr_array_start = mp_xstrdup (mp,mp->ps->t1_line_array); - t1_getline (mp); - while (mp->ps->t1_cslen) { - store_subr (mp); - t1_getline (mp); - } - /* mark the first four entries without parsing */ - for (i = 0; i < mp->ps->subr_size && i < 4; i++) - mp->ps->subr_tab[i].is_used = true; - /* the end of the Subrs array might have more than one line so we need to - concatnate them to |subr_array_end|. Unfortunately some fonts don't have - the Subrs array followed by the CharStrings dict immediately (synthetic - fonts). If we cannot find CharStrings in next |POST_SUBRS_SCAN| lines then - we will treat the font as synthetic and ignore everything until next - Subrs is found - */ -#define POST_SUBRS_SCAN 5 - s = 0; - *mp->ps->t1_buf_array = 0; - for (i = 0; i < POST_SUBRS_SCAN; i++) { - if (t1_charstrings ()) - break; - s += mp->ps->t1_line_ptr - mp->ps->t1_line_array; - alloc_array (t1_buf, s, T1_BUF_SIZE); - strcat (mp->ps->t1_buf_array, mp->ps->t1_line_array); - t1_getline (mp); - } - mp->ps->subr_array_end = mp_xstrdup (mp,mp->ps->t1_buf_array); - if (i == POST_SUBRS_SCAN) { /* CharStrings not found; - suppose synthetic font */ - for (ptr = mp->ps->subr_tab; ptr - mp->ps->subr_tab < mp->ps->subr_size; ptr++) - if (ptr->valid) - mp_xfree (ptr->data); - mp_xfree (mp->ps->subr_tab); - mp_xfree (mp->ps->subr_array_start); - mp_xfree (mp->ps->subr_array_end); - cs_init (mp); - mp->ps->t1_cs = false; - mp->ps->t1_synthetic = true; - while (!(t1_charstrings () || t1_subrs ())) - t1_getline (mp); - goto FOUND; - } -} - -@ @c -static void t1_flush_cs (MP mp, boolean is_subr) -{ - char *p; - byte *r, *return_cs = NULL; - cs_entry *tab, *end_tab, *ptr; - char *start_line, *line_end; - int count, size_pos; - unsigned short cr, cs_len = 0; /* to avoid warning about uninitialized use of |cs_len| */ - if (is_subr) { - start_line = mp->ps->subr_array_start; - line_end = mp->ps->subr_array_end; - size_pos = mp->ps->subr_size_pos; - tab = mp->ps->subr_tab; - count = mp->ps->subr_max + 1; - end_tab = mp->ps->subr_tab + count; - } else { - start_line = mp->ps->cs_dict_start; - line_end = mp->ps->cs_dict_end; - size_pos = mp->ps->cs_size_pos; - tab = mp->ps->cs_tab; - end_tab = mp->ps->cs_ptr; - count = mp->ps->cs_count; - } - mp->ps->t1_line_ptr = mp->ps->t1_line_array; - for (p = start_line; p - start_line < size_pos;) - *mp->ps->t1_line_ptr++ = *p++; - while (isdigit (*p)) - p++; - sprintf (mp->ps->t1_line_ptr, "%u", count); - strcat (mp->ps->t1_line_ptr, p); - mp->ps->t1_line_ptr = eol (mp->ps->t1_line_array); - t1_putline (mp); - - /* create |return_cs| to replace unsused subr's */ - if (is_subr) { - cr = 4330; - cs_len = 0; - return_cs = mp_xmalloc (mp, (mp->ps->t1_lenIV + 1) , sizeof(byte)); - if ( mp->ps->t1_lenIV > 0) { - for (cs_len = 0, r = return_cs; cs_len < mp->ps->t1_lenIV; cs_len++, r++) - *r = cencrypt (mp,0x00, &cr); - *r = cencrypt (mp,CS_RETURN, &cr); - } else { - *return_cs = CS_RETURN; - } - cs_len++; - } - - for (ptr = tab; ptr < end_tab; ptr++) { - if (ptr->is_used) { - if (is_subr) - sprintf (mp->ps->t1_line_array, "dup %i %u", (int) (ptr - tab), - ptr->cslen); - else - sprintf (mp->ps->t1_line_array, "/%s %u", ptr->glyph_name, ptr->cslen); - p = strend (mp->ps->t1_line_array); - memcpy (p, ptr->data, ptr->len); - mp->ps->t1_line_ptr = p + ptr->len; - t1_putline (mp); - } else { - /* replace unsused subr's by |return_cs| */ - if (is_subr) { - sprintf (mp->ps->t1_line_array, "dup %i %u%s ", (int) (ptr - tab), - cs_len, mp->ps->cs_token_pair[0]); - p = strend (mp->ps->t1_line_array); - memcpy (p, return_cs, cs_len); - mp->ps->t1_line_ptr = p + cs_len; - t1_putline (mp); - sprintf (mp->ps->t1_line_array, " %s", mp->ps->cs_token_pair[1]); - mp->ps->t1_line_ptr = eol (mp->ps->t1_line_array); - t1_putline (mp); - } - } - mp_xfree (ptr->data); - if (ptr->glyph_name != notdef) - mp_xfree (ptr->glyph_name); - } - sprintf (mp->ps->t1_line_array, "%s", line_end); - mp->ps->t1_line_ptr = eol (mp->ps->t1_line_array); - t1_putline (mp); - if (is_subr) - mp_xfree (return_cs); - mp_xfree (tab); - mp_xfree (start_line); - mp_xfree (line_end); -} - -static void t1_mark_glyphs (MP mp, int tex_font) -{ - int i; - char *charset = extra_charset (); - char *g, *s, *r; - cs_entry *ptr; - if (mp->ps->t1_synthetic || embed_all_glyphs (tex_font)) { /* mark everything */ - if (mp->ps->cs_tab != NULL) - for (ptr = mp->ps->cs_tab; ptr < mp->ps->cs_ptr; ptr++) - if (ptr->valid) - ptr->is_used = true; - if (mp->ps->subr_tab != NULL) { - for (ptr = mp->ps->subr_tab; ptr - mp->ps->subr_tab < mp->ps->subr_size; ptr++) - if (ptr->valid) - ptr->is_used = true; - mp->ps->subr_max = mp->ps->subr_size - 1; - } - return; - } - mark_cs (mp,notdef); - for (i = 0; i < 256; i++) - if (is_used_char (i)) { - if (mp->ps->t1_glyph_names[i] == notdef) { - char S[128]; - snprintf(S,128, "character %i is mapped to %s", i, notdef); - mp_warn(mp,S); - } else - mark_cs (mp,mp->ps->t1_glyph_names[i]); - } - if (charset == NULL) - goto SET_SUBR_MAX; - g = s = charset + 1; /* skip the first '/' */ - r = strend (g); - while (g < r) { - while (*s != '/' && s < r) - s++; - *s = 0; /* terminate g by rewriting '/' to 0 */ - mark_cs (mp,g); - g = s + 1; - } - SET_SUBR_MAX: - if (mp->ps->subr_tab != NULL) - for (mp->ps->subr_max = -1, ptr = mp->ps->subr_tab; - ptr - mp->ps->subr_tab < mp->ps->subr_size; - ptr++) - if (ptr->is_used && ptr - mp->ps->subr_tab > mp->ps->subr_max) - mp->ps->subr_max = ptr - mp->ps->subr_tab; -} - -static void t1_subset_charstrings (MP mp, int tex_font) -{ - cs_entry *ptr; - mp->ps->cs_size_pos = - strstr (mp->ps->t1_line_array, charstringname) + strlen (charstringname) - - mp->ps->t1_line_array + 1; - /* |cs_size_pos| points to the number indicating - dict size after "/CharStrings" */ - mp->ps->cs_size = t1_scan_num (mp,mp->ps->t1_line_array + mp->ps->cs_size_pos, 0); - mp->ps->cs_ptr = mp->ps->cs_tab = mp_xmalloc (mp,mp->ps->cs_size, sizeof(cs_entry)); - for (ptr = mp->ps->cs_tab; ptr - mp->ps->cs_tab < mp->ps->cs_size; ptr++) - init_cs_entry (ptr); - mp->ps->cs_notdef = NULL; - mp->ps->cs_dict_start = mp_xstrdup (mp,mp->ps->t1_line_array); - t1_getline (mp); - while (mp->ps->t1_cslen) { - store_cs (mp); - t1_getline (mp); - } - mp->ps->cs_dict_end = mp_xstrdup (mp,mp->ps->t1_line_array); - t1_mark_glyphs (mp,tex_font); - if (mp->ps->subr_tab != NULL) { - if (mp->ps->cs_token_pair == NULL) - mp_fatal_error - (mp, "This Type 1 font uses mismatched subroutine begin/end token pairs."); - t1_subr_flush (mp); - } - for (mp->ps->cs_count = 0, ptr = mp->ps->cs_tab; ptr < mp->ps->cs_ptr; ptr++) - if (ptr->is_used) - mp->ps->cs_count++; - t1_cs_flush (mp); -} - -static void t1_subset_end (MP mp) -{ - if (mp->ps->t1_synthetic) { /* copy to "dup /FontName get exch definefont pop" */ - while (!strstr (mp->ps->t1_line_array, "definefont")) { - t1_getline (mp); - t1_putline (mp); - } - while (!t1_end_eexec ()) - t1_getline (mp); /* ignore the rest */ - t1_putline (mp); /* write "mark currentfile closefile" */ - } else - while (!t1_end_eexec ()) { /* copy to "mark currentfile closefile" */ - t1_getline (mp); - t1_putline (mp); - } - t1_stop_eexec (mp); - if (fixedcontent) { /* copy 512 zeros (not needed for PDF) */ - while (!t1_cleartomark ()) { - t1_getline (mp); - t1_putline (mp); - } - if (!mp->ps->t1_synthetic) /* don't check "{restore}if" for synthetic fonts */ - t1_check_end (mp); /* write "{restore}if" if found */ - } -} - -static int t1_updatefm (MP mp, int f, fm_entry *fm) -{ - char *s, *p; - mp->ps->read_encoding_only = true; - if (!t1_open_fontfile (mp,fm,NULL)) { - return 0; - } - t1_scan_only (mp,f, fm); - s = mp_xstrdup(mp,mp->ps->fontname_buf); - p = s; - while (*p != ' ' && *p != 0) - p++; - *p=0; - fm->ps_name = s; - t1_close_font_file (mp,""); - return 1; -} - - -static void writet1 (MP mp, int tex_font, fm_entry *fm_cur) { - int save_selector = mp->selector; - mp_normalize_selector(mp); - mp->ps->read_encoding_only = false; - if (!is_included (fm_cur)) { /* scan parameters from font file */ - if (!t1_open_fontfile (mp,fm_cur,"{")) - return; - t1_scan_only (mp,tex_font, fm_cur); - t1_close_font_file (mp,"}"); - return; - } - if (!is_subsetted (fm_cur)) { /* include entire font */ - if (!t1_open_fontfile (mp,fm_cur,"<<")) - return; - t1_include (mp,tex_font,fm_cur); - t1_close_font_file (mp,">>"); - return; - } - /* partial downloading */ - if (!t1_open_fontfile (mp,fm_cur,"<")) - return; - t1_subset_ascii_part (mp,tex_font,fm_cur); - t1_start_eexec (mp,fm_cur); - cc_init (); - cs_init (mp); - t1_read_subrs (mp,tex_font, fm_cur); - t1_subset_charstrings (mp,tex_font); - t1_subset_end (mp); - t1_close_font_file (mp,">"); - mp->selector = save_selector; -} - -@ @<Declarations@>= -static void t1_free (MP mp); - -@ @c -static void t1_free (MP mp) { - mp_xfree (mp->ps->t1_line_array); - mp_xfree (mp->ps->t1_buf_array); -} - - -@* \[44d] Embedding fonts. - -@ The |tfm_num| is officially of type |font_number|, but that -type does not exist yet at this point in the output order. - -@<Types...@>= -typedef struct { - char *tfm_name; /* TFM file name */ - char *ps_name; /* PostScript name */ - integer flags; /* font flags */ - char *ff_name; /* font file name */ - char *subset_tag; /* pseudoUniqueTag for subsetted font */ - enc_entry *encoding; /* pointer to corresponding encoding */ - unsigned int tfm_num; /* number of the TFM refering this entry */ - unsigned short type; /* font type (T1/TTF/...) */ - short slant; /* SlantFont */ - short extend; /* ExtendFont */ - integer ff_objnum; /* FontFile object number */ - integer fn_objnum; /* FontName/BaseName object number */ - integer fd_objnum; /* FontDescriptor object number */ - char *charset; /* string containing used glyphs */ - boolean all_glyphs; /* embed all glyphs? */ - unsigned short links; /* link flags from |tfm_tree| and |ps_tree| */ - short tfm_avail; /* flags whether a tfm is available */ - short pid; /* Pid for truetype fonts */ - short eid; /* Eid for truetype fonts */ -} fm_entry; - - -@ -@<Glob...@>= -#define FONTNAME_BUF_SIZE 128 -boolean fontfile_found; -boolean is_otf_font; -char fontname_buf[FONTNAME_BUF_SIZE]; - -@ -@d F_INCLUDED 0x01 -@d F_SUBSETTED 0x02 -@d F_TRUETYPE 0x04 -@d F_BASEFONT 0x08 - -@d set_included(fm) ((fm)->type |= F_INCLUDED) -@d set_subsetted(fm) ((fm)->type |= F_SUBSETTED) -@d set_truetype(fm) ((fm)->type |= F_TRUETYPE) -@d set_basefont(fm) ((fm)->type |= F_BASEFONT) - -@d is_included(fm) ((fm)->type & F_INCLUDED) -@d is_subsetted(fm) ((fm)->type & F_SUBSETTED) -@d is_truetype(fm) ((fm)->type & F_TRUETYPE) -@d is_basefont(fm) ((fm)->type & F_BASEFONT) -@d is_reencoded(fm) ((fm)->encoding != NULL) -@d is_fontfile(fm) (fm_fontfile(fm) != NULL) -@d is_t1fontfile(fm) (is_fontfile(fm) && !is_truetype(fm)) - -@d fm_slant(fm) (fm)->slant -@d fm_extend(fm) (fm)->extend -@d fm_fontfile(fm) (fm)->ff_name - -@<Declarations@>= -static boolean mp_font_is_reencoded (MP mp, int f); -static boolean mp_font_is_included (MP mp, int f); -static boolean mp_font_is_subsetted (MP mp, int f); - -@ @c -static boolean mp_font_is_reencoded (MP mp, int f) { - fm_entry *fm; - if (mp_has_font_size(mp,f) && mp_has_fm_entry (mp, f, &fm)) { - if (fm != NULL - && (fm->ps_name != NULL) - && is_reencoded (fm)) - return 1; - } - return 0; -} -static boolean mp_font_is_included (MP mp, int f) { - fm_entry *fm; - if (mp_has_font_size(mp,f) && mp_has_fm_entry (mp, f, &fm)) { - if (fm != NULL - && (fm->ps_name != NULL && fm->ff_name != NULL) - && is_included (fm)) - return 1; - } - return 0; -} -static boolean mp_font_is_subsetted (MP mp, int f) { - fm_entry *fm; - if (mp_has_font_size(mp,f) && mp_has_fm_entry (mp, f,&fm)) { - if (fm != NULL - && (fm->ps_name != NULL && fm->ff_name != NULL) - && is_included (fm) && is_subsetted (fm)) - return 1; - } - return 0; -} - -@ @<Exported function headers@>= -char * mp_fm_encoding_name (MP mp, int f); -char * mp_fm_font_name (MP mp, int f); - -@ @<Declarations@>= -static char * mp_fm_font_subset_name (MP mp, int f); - -@ -@c char * mp_fm_encoding_name (MP mp, int f) { - enc_entry *e; - fm_entry *fm; - if (mp_has_fm_entry (mp, f, &fm)) { - if (fm != NULL && (fm->ps_name != NULL)) { - if (is_reencoded (fm)) { - e = fm->encoding; - if (e->enc_name!=NULL) - return mp_xstrdup(mp,e->enc_name); - } else { - return NULL; - } - } - } - print_err ("fontmap encoding problems for font "); - mp_print(mp,mp->font_name[f]); - mp_error(mp); - return NULL; -} -char * mp_fm_font_name (MP mp, int f) { - fm_entry *fm; - if (mp_has_fm_entry (mp, f,&fm)) { - if (fm != NULL && (fm->ps_name != NULL)) { - if (mp_font_is_included(mp, f) && !mp->font_ps_name_fixed[f]) { - /* find the real fontname, and update |ps_name| and |subset_tag| if needed */ - if (t1_updatefm(mp,f,fm)) { - mp->font_ps_name_fixed[f] = true; - } else { - print_err ("font loading problems for font "); - mp_print(mp,mp->font_name[f]); - mp_error(mp); - } - } - return mp_xstrdup(mp,fm->ps_name); - } - } - print_err ("fontmap name problems for font "); - mp_print(mp,mp->font_name[f]); - mp_error(mp); - return NULL; -} - -static char * mp_fm_font_subset_name (MP mp, int f) { - fm_entry *fm; - if (mp_has_fm_entry (mp, f, &fm)) { - if (fm != NULL && (fm->ps_name != NULL)) { - if (is_subsetted(fm)) { - char *s = mp_xmalloc(mp,strlen(fm->ps_name)+8,1); - snprintf(s,strlen(fm->ps_name)+8,"%s-%s",fm->subset_tag,fm->ps_name); - return s; - } else { - return mp_xstrdup(mp,fm->ps_name); - } - } - } - print_err ("fontmap name problems for font "); - mp_print(mp,mp->font_name[f]); - mp_error(mp); - return NULL; -} - -@ @<Declarations@>= -static integer mp_fm_font_slant (MP mp, int f); -static integer mp_fm_font_extend (MP mp, int f); - -@ -@c static integer mp_fm_font_slant (MP mp, int f) { - fm_entry *fm; - if (mp_has_fm_entry (mp, f, &fm)) { - if (fm != NULL && (fm->ps_name != NULL)) { - return fm->slant; - } - } - return 0; -} -static integer mp_fm_font_extend (MP mp, int f) { - fm_entry *fm; - if (mp_has_fm_entry (mp, f, &fm)) { - if (fm != NULL && (fm->ps_name != NULL)) { - return fm->extend; - } - } - return 0; -} - -@ @<Declarations@>= -static boolean mp_do_ps_font (MP mp, font_number f); - -@ @c static boolean mp_do_ps_font (MP mp, font_number f) { - fm_entry *fm_cur; - (void)mp_has_fm_entry (mp, f, &fm_cur); /* for side effects */ - if (fm_cur == NULL) - return 1; - if (is_truetype(fm_cur) || - (fm_cur->ps_name == NULL && fm_cur->ff_name == NULL)) { - return 0; - } - if (is_included(fm_cur)) { - mp_ps_print_nl(mp,"%%BeginResource: font "); - if (is_subsetted(fm_cur)) { - mp_ps_print(mp, fm_cur->subset_tag); - mp_ps_print_char(mp,'-'); - } - mp_ps_print(mp, fm_cur->ps_name); - mp_ps_print_ln(mp); - writet1 (mp,f,fm_cur); - mp_ps_print_nl(mp,"%%EndResource"); - mp_ps_print_ln(mp); - } - return 1; -} - -@ Included subset fonts do not need and encoding vector, make -sure we skip that case. - -@<Declarations@>= -static void mp_list_used_resources (MP mp, int prologues, int procset); - -@ @c static void mp_list_used_resources (MP mp, int prologues, int procset) { - font_number f; /* fonts used in a text node or as loop counters */ - int ff; /* a loop counter */ - font_number ldf; /* the last \.{DocumentFont} listed (otherwise |null_font|) */ - boolean firstitem; - if ( procset>0 ) - mp_ps_print_nl(mp, "%%DocumentResources: procset mpost"); - else - mp_ps_print_nl(mp, "%%DocumentResources: procset mpost-minimal"); - ldf=null_font; - firstitem=true; - for (f=null_font+1;f<=mp->last_fnum;f++) { - if ( (mp_has_font_size(mp,f))&&(mp_font_is_reencoded(mp,f)) ) { - for (ff=ldf;ff>=null_font;ff--) { - if ( mp_has_font_size(mp,ff) ) - if ( mp_xstrcmp(mp->font_enc_name[f],mp->font_enc_name[ff])==0 ) - goto FOUND; - } - if ( mp_font_is_subsetted(mp,f) ) - goto FOUND; - if ( mp->ps->ps_offset+1+strlen(mp->font_enc_name[f])> - (unsigned)mp->max_print_line ) - mp_ps_print_nl(mp, "%%+ encoding"); - if ( firstitem ) { - firstitem=false; - mp_ps_print_nl(mp, "%%+ encoding"); - } - mp_ps_print_char(mp, ' '); - mp_ps_print(mp, mp->font_enc_name[f]); - ldf=f; - } - FOUND: - ; - } - ldf=null_font; - firstitem=true; - for (f=null_font+1;f<=mp->last_fnum;f++) { - if ( mp_has_font_size(mp,f) ) { - for (ff=ldf;ff>=null_font;ff--) { - if ( mp_has_font_size(mp,ff) ) - if ( mp_xstrcmp(mp->font_name[f],mp->font_name[ff])==0 ) - goto FOUND2; - } - if ( mp->ps->ps_offset+1+strlen(mp->font_ps_name[f])> - (unsigned)mp->max_print_line ) - mp_ps_print_nl(mp, "%%+ font"); - if ( firstitem ) { - firstitem=false; - mp_ps_print_nl(mp, "%%+ font"); - } - mp_ps_print_char(mp, ' '); - if ( (prologues==3)&& - (mp_font_is_subsetted(mp,f)) ) - mp_ps_print(mp, mp_fm_font_subset_name(mp,f)); - else - mp_ps_print(mp, mp->font_ps_name[f]); - ldf=f; - } - FOUND2: - ; - } - mp_ps_print_ln(mp); -} - -@ @<Declarations@>= -static void mp_list_supplied_resources (MP mp, int prologues, int procset); - -@ @c static void mp_list_supplied_resources (MP mp, int prologues, int procset) { - font_number f; /* fonts used in a text node or as loop counters */ - int ff; /* a loop counter */ - font_number ldf; /* the last \.{DocumentFont} listed (otherwise |null_font|) */ - boolean firstitem; - if ( procset>0 ) - mp_ps_print_nl(mp, "%%DocumentSuppliedResources: procset mpost"); - else - mp_ps_print_nl(mp, "%%DocumentSuppliedResources: procset mpost-minimal"); - ldf=null_font; - firstitem=true; - for (f=null_font+1;f<=mp->last_fnum;f++) { - if ( (mp_has_font_size(mp,f))&&(mp_font_is_reencoded(mp,f)) ) { - for (ff=ldf;ff>= null_font;ff++) { - if ( mp_has_font_size(mp,ff) ) - if ( mp_xstrcmp(mp->font_enc_name[f],mp->font_enc_name[ff])==0 ) - goto FOUND; - } - if ( (prologues==3)&&(mp_font_is_subsetted(mp,f))) - goto FOUND; - if ( mp->ps->ps_offset+1+strlen(mp->font_enc_name[f])>(unsigned)mp->max_print_line ) - mp_ps_print_nl(mp, "%%+ encoding"); - if ( firstitem ) { - firstitem=false; - mp_ps_print_nl(mp, "%%+ encoding"); - } - mp_ps_print_char(mp, ' '); - mp_ps_print(mp, mp->font_enc_name[f]); - ldf=f; - } - FOUND: - ; - } - ldf=null_font; - firstitem=true; - if (prologues==3) { - for (f=null_font+1;f<=mp->last_fnum;f++) { - if ( mp_has_font_size(mp,f) ) { - for (ff=ldf;ff>= null_font;ff--) { - if ( mp_has_font_size(mp,ff) ) - if ( mp_xstrcmp(mp->font_name[f],mp->font_name[ff])==0 ) - goto FOUND2; - } - if ( ! mp_font_is_included(mp,f) ) - goto FOUND2; - if ( mp->ps->ps_offset+1+strlen(mp->font_ps_name[f])>(unsigned)mp->max_print_line ) - mp_ps_print_nl(mp, "%%+ font"); - if ( firstitem ) { - firstitem=false; - mp_ps_print_nl(mp, "%%+ font"); - } - mp_ps_print_char(mp, ' '); - if ( mp_font_is_subsetted(mp,f) ) - mp_ps_print(mp, mp_fm_font_subset_name(mp,f)); - else - mp_ps_print(mp, mp->font_ps_name[f]); - ldf=f; - } - FOUND2: - ; - } - mp_ps_print_ln(mp); - } -} - -@ @<Declarations...@>= -static void mp_list_needed_resources (MP mp, int prologues); - -@ @c static void mp_list_needed_resources (MP mp, int prologues) { - font_number f; /* fonts used in a text node or as loop counters */ - int ff; /* a loop counter */ - font_number ldf; /* the last \.{DocumentFont} listed (otherwise |null_font|) */ - boolean firstitem; - ldf=null_font; - firstitem=true; - for (f=null_font+1;f<=mp->last_fnum;f++ ) { - if ( mp_has_font_size(mp,f)) { - for (ff=ldf;ff>=null_font;ff--) { - if ( mp_has_font_size(mp,ff) ) - if ( mp_xstrcmp(mp->font_name[f],mp->font_name[ff])==0 ) - goto FOUND; - }; - if ((prologues==3)&&(mp_font_is_included(mp,f)) ) - goto FOUND; - if ( mp->ps->ps_offset+1+strlen(mp->font_ps_name[f])>(unsigned)mp->max_print_line ) - mp_ps_print_nl(mp, "%%+ font"); - if ( firstitem ) { - firstitem=false; - mp_ps_print_nl(mp, "%%DocumentNeededResources: font"); - } - mp_ps_print_char(mp, ' '); - mp_ps_print(mp, mp->font_ps_name[f]); - ldf=f; - } - FOUND: - ; - } - if ( ! firstitem ) { - mp_ps_print_ln(mp); - ldf=null_font; - firstitem=true; - for (f=null_font+1;f<= mp->last_fnum;f++) { - if ( mp_has_font_size(mp,f) ) { - for (ff=ldf;ff>=null_font;ff-- ) { - if ( mp_has_font_size(mp,ff) ) - if ( mp_xstrcmp(mp->font_name[f],mp->font_name[ff])==0 ) - goto FOUND2; - } - if ((prologues==3)&&(mp_font_is_included(mp,f)) ) - goto FOUND2; - mp_ps_print(mp, "%%IncludeResource: font "); - mp_ps_print(mp, mp->font_ps_name[f]); - mp_ps_print_ln(mp); - ldf=f; - } - FOUND2: - ; - } - } -} - -@ @<Declarations@>= -static void mp_write_font_definition (MP mp, font_number f, int prologues); - -@ - -@d applied_reencoding(A) ((mp_font_is_reencoded(mp,(A)))&& - ((! mp_font_is_subsetted(mp,(A)))||(prologues==2))) - -@c static void mp_write_font_definition(MP mp, font_number f, int prologues) { - if ( (applied_reencoding(f))||(mp_fm_font_slant(mp,f)!=0)|| - (mp_fm_font_extend(mp,f)!=0)|| - (mp_xstrcmp(mp->font_name[f],"psyrgo")==0)|| - (mp_xstrcmp(mp->font_name[f],"zpzdr-reversed")==0) ) { - if ( (mp_font_is_subsetted(mp,f))&& - (mp_font_is_included(mp,f))&&(prologues==3)) - mp_ps_name_out(mp, mp_fm_font_subset_name(mp,f),true); - else - mp_ps_name_out(mp, mp->font_ps_name[f],true); - mp_ps_print(mp, " fcp"); - mp_ps_print_ln(mp); - if ( applied_reencoding(f) ) { - mp_ps_print(mp, "/Encoding "); - mp_ps_print(mp, mp->font_enc_name[f]); - mp_ps_print(mp, " def "); - }; - if ( mp_fm_font_slant(mp,f)!=0 ) { - mp_ps_print_int(mp, mp_fm_font_slant(mp,f)); - mp_ps_print(mp, " SlantFont "); - }; - if ( mp_fm_font_extend(mp,f)!=0 ) { - mp_ps_print_int(mp, mp_fm_font_extend(mp,f)); - mp_ps_print(mp, " ExtendFont "); - }; - if ( mp_xstrcmp(mp->font_name[f],"psyrgo")==0 ) { - mp_ps_print(mp, " 890 ScaleFont "); - mp_ps_print(mp, " 277 SlantFont "); - }; - if ( mp_xstrcmp(mp->font_name[f],"zpzdr-reversed")==0 ) { - mp_ps_print(mp, " FontMatrix [-1 0 0 1 0 0] matrix concatmatrix /FontMatrix exch def "); - mp_ps_print(mp, "/Metrics 2 dict dup begin "); - mp_ps_print(mp, "/space[0 -278]def "); - mp_ps_print(mp, "/a12[-904 -939]def "); - mp_ps_print(mp, "end def "); - }; - mp_ps_print(mp, "currentdict end"); - mp_ps_print_ln(mp); - mp_ps_print_defined_name(mp,f,prologues); - mp_ps_print(mp, " exch definefont pop"); - mp_ps_print_ln(mp); - } -} - -@ @<Declarations@>= -static void mp_ps_print_defined_name (MP mp, font_number f, int prologues); - -@ -@c static void mp_ps_print_defined_name(MP mp, font_number A, int prologues) { - mp_ps_print(mp, " /"); - if ((mp_font_is_subsetted(mp,(A)))&& - (mp_font_is_included(mp,(A)))&&(prologues==3)) - mp_ps_print(mp, mp_fm_font_subset_name(mp,(A))); - else - mp_ps_print(mp, mp->font_ps_name[(A)]); - if ( mp_xstrcmp(mp->font_name[(A)],"psyrgo")==0 ) - mp_ps_print(mp, "-Slanted"); - if ( mp_xstrcmp(mp->font_name[(A)],"zpzdr-reversed")==0 ) - mp_ps_print(mp, "-Reverse"); - if ( applied_reencoding((A)) ) { - mp_ps_print(mp, "-"); - mp_ps_print(mp, mp->font_enc_name[(A)]); - } - if ( mp_fm_font_slant(mp,(A))!=0 ) { - mp_ps_print(mp, "-Slant_"); mp_ps_print_int(mp, mp_fm_font_slant(mp,(A))) ; - } - if ( mp_fm_font_extend(mp,(A))!=0 ) { - mp_ps_print(mp, "-Extend_"); mp_ps_print_int(mp, mp_fm_font_extend(mp,(A))); - } -} - -@ @<Include encodings and fonts for edge structure~|h|@>= -mp_font_encodings(mp,mp->last_fnum,(prologues==2)); -@<Embed fonts that are available@> - -@ @<Embed fonts that are available@>= -{ -next_size=0; -@<Make |cur_fsize| a copy of the |font_sizes| array@>; -do { - done_fonts=true; - for (f=null_font+1;f<=mp->last_fnum;f++) { - if ( cur_fsize[f]!=null ) { - if (prologues==3 ) { - if ( ! mp_do_ps_font(mp,f) ) { - if ( mp_has_fm_entry(mp,f, NULL) ) { - print_err("Font embedding failed"); - mp_error(mp); - } - } - } - cur_fsize[f]=link(cur_fsize[f]); - if ( cur_fsize[f]!=null ) { mp_unmark_font(mp, f); done_fonts=false; } - } - } - if ( ! done_fonts ) - @<Increment |next_size| and apply |mark_string_chars| to all text nodes with - that size index@>; -} while (! done_fonts); -} - -@ @<Increment |next_size| and apply |mark_string_chars| to all text nodes...@>= -{ - next_size++; - mp_apply_mark_string_chars(mp, h, next_size); -} - -@ We also need to keep track of which characters are used in text nodes -in the edge structure that is being shipped out. This is done by procedures -that use the left-over |b3| field in the |char_info| words; i.e., -|char_info(f)(c).b3| gives the status of character |c| in font |f|. - -@<Types...@>= -enum mp_char_mark_state {mp_unused=0, mp_used}; - -@ @<Exported...@>= -void mp_mark_string_chars (MP mp,font_number f, char *s) ; - -@ @c -void mp_mark_string_chars (MP mp,font_number f, char *s) { - integer b; /* |char_base[f]| */ - ASCII_code bc,ec; /* only characters between these bounds are marked */ - char *k; /* an index into string |s| */ - b=mp->char_base[f]; - bc=mp->font_bc[f]; - ec=mp->font_ec[f]; - k=s; /* str_stop */ - while (*k){ - if ( (*k>=bc)&&(*k<=ec) ) - mp->font_info[b+*k].qqqq.b3=mp_used; - k++; - } -} - - -@ @<Exported ...@>= -void mp_unmark_font (MP mp,font_number f) ; - -@ @c -void mp_unmark_font (MP mp,font_number f) { - int k; /* an index into |font_info| */ - for (k= mp->char_base[f]+mp->font_bc[f]; - k<=mp->char_base[f]+mp->font_ec[f]; - k++) - mp->font_info[k].qqqq.b3=mp_unused; -} - - -@ @<Exported...@>= -void mp_print_improved_prologue (MP mp, mp_edge_object *h, int prologues, int procset) ; - -@ @c -void mp_print_improved_prologue (MP mp, mp_edge_object *h, int prologues, int procset) { - quarterword next_size; /* the size index for fonts being listed */ - pointer *cur_fsize; /* current positions in |font_sizes| */ - boolean done_fonts; /* have we finished listing the fonts in the header? */ - font_number f; /* a font number for loops */ - cur_fsize = mp_xmalloc(mp,(mp->font_max+1),sizeof(pointer)); - mp_list_used_resources(mp, prologues, procset); - mp_list_supplied_resources(mp, prologues, procset); - mp_list_needed_resources(mp, prologues); - mp_ps_print_nl(mp, "%%EndComments"); - mp_ps_print_nl(mp, "%%BeginProlog"); - if ( procset>0 ) - mp_ps_print_nl(mp, "%%BeginResource: procset mpost"); - else - mp_ps_print_nl(mp, "%%BeginResource: procset mpost-minimal"); - mp_ps_print_nl(mp, "/bd{bind def}bind def" - "/fshow {exch findfont exch scalefont setfont show}bd"); - if ( procset>0 ) @<Print the procset@>; - mp_ps_print_nl(mp, "/fcp{findfont dup length dict begin" - "{1 index/FID ne{def}{pop pop}ifelse}forall}bd"); - mp_ps_print_nl(mp, "/fmc{FontMatrix dup length array copy dup dup}bd" - "/fmd{/FontMatrix exch def}bd"); - mp_ps_print_nl(mp, "/Amul{4 -1 roll exch mul 1000 div}bd" - "/ExtendFont{fmc 0 get Amul 0 exch put fmd}bd"); - mp_ps_print_nl(mp, "/ScaleFont{dup fmc 0 get" - " Amul 0 exch put dup dup 3 get Amul 3 exch put fmd}bd"); - mp_ps_print_nl(mp, "/SlantFont{fmc 2 get dup 0 eq{pop 1}if" - " Amul FontMatrix 0 get mul 2 exch put fmd}bd"); - mp_ps_print_nl(mp, "%%EndResource"); - @<Include encodings and fonts for edge structure~|h|@>; - mp_ps_print_nl(mp, "%%EndProlog"); - mp_ps_print_nl(mp, "%%BeginSetup"); - mp_ps_print_ln(mp); - for (f=null_font+1;f<=mp->last_fnum;f++) { - if ( mp_has_font_size(mp,f) ) { - if ( mp_has_fm_entry(mp,f,NULL) ) { - mp_write_font_definition(mp,f, prologues); - mp_ps_name_out(mp, mp->font_name[f],true); - mp_ps_print_defined_name(mp,f, prologues); - mp_ps_print(mp, " def"); - } else { - char s[256]; - snprintf(s,256,"font %s cannot be found in any fontmapfile!", mp->font_name[f]); - mp_warn(mp,s); - mp_ps_name_out(mp, mp->font_name[f],true); - mp_ps_name_out(mp, mp->font_name[f],true); - mp_ps_print(mp, " def"); - } - mp_ps_print_ln(mp); - } - } - mp_ps_print_nl(mp, "%%EndSetup"); - mp_ps_print_nl(mp, "%%Page: 1 1"); - mp_ps_print_ln(mp); - mp_xfree(cur_fsize); -} - -@ @<Declarations@>= -static font_number mp_print_font_comments (MP mp , mp_edge_object *h, int prologues); - - -@ -@c -static font_number mp_print_font_comments (MP mp , mp_edge_object *h, int prologues) { - quarterword next_size; /* the size index for fonts being listed */ - pointer *cur_fsize; /* current positions in |font_sizes| */ - int ff; /* a loop counter */ - boolean done_fonts; /* have we finished listing the fonts in the header? */ - font_number f; /* a font number for loops */ - scaled ds; /* design size and scale factor for a text node */ - font_number ldf=0; /* the last \.{DocumentFont} listed (otherwise |null_font|) */ - cur_fsize = mp_xmalloc(mp,(mp->font_max+1),sizeof(pointer)); - if ( prologues>0 ) { - @<Give a \.{DocumentFonts} comment listing all fonts with non-null - |font_sizes| and eliminate duplicates@>; - } else { - next_size=0; - @<Make |cur_fsize| a copy of the |font_sizes| array@>; - do { done_fonts=true; - for (f=null_font+1;f<=mp->last_fnum;f++) { - if ( cur_fsize[f]!=null ) { - @<Print the \.{\%*Font} comment for font |f| and advance |cur_fsize[f]|@>; - } - if ( cur_fsize[f]!=null ) { mp_unmark_font(mp, f); done_fonts=false; }; - } - if ( ! done_fonts ) { - @<Increment |next_size| and apply |mark_string_chars| to all text nodes with - that size index@>; - } - } while (! done_fonts); - } - mp_xfree(cur_fsize); - return ldf; -} - -@ @<Make |cur_fsize| a copy of the |font_sizes| array@>= -for (f=null_font+1;f<= mp->last_fnum;f++) - cur_fsize[f]=mp->font_sizes[f] - -@ It's not a good idea to make any assumptions about the |font_ps_name| entries, -so we carefully remove duplicates. There is no harm in using a slow, brute-force -search. - -@<Give a \.{DocumentFonts} comment listing all fonts with non-null...@>= -{ - ldf=null_font; - for (f=null_font+1;f<= mp->last_fnum;f++) { - if ( mp->font_sizes[f]!=null ) { - if ( ldf==null_font ) - mp_ps_print_nl(mp, "%%DocumentFonts:"); - for (ff=ldf;ff>=null_font;ff--) { - if ( mp->font_sizes[ff]!=null ) - if ( mp_xstrcmp(mp->font_ps_name[f],mp->font_ps_name[ff])==0 ) - goto FOUND; - } - if ( mp->ps->ps_offset+1+strlen(mp->font_ps_name[f])>(unsigned)mp->max_print_line ) - mp_ps_print_nl(mp, "%%+"); - mp_ps_print_char(mp, ' '); - mp_ps_print(mp, mp->font_ps_name[f]); - ldf=f; - FOUND: - ; - } - } -} - -@ @c -static void mp_hex_digit_out (MP mp,small_number d) { - if ( d<10 ) mp_ps_print_char(mp, d+'0'); - else mp_ps_print_char(mp, d+'a'-10); -} - -@ We output the marks as a hexadecimal bit string starting at |c| or -|font_bc[f]|, whichever is greater. If the output has to be truncated -to avoid exceeding |emergency_line_length| the return value says where to -start scanning next time. - -@<Declarations@>= -static halfword mp_ps_marks_out (MP mp,font_number f, eight_bits c); - -@ -@d emergency_line_length 255 - /* \ps\ output lines can be this long in unusual circumstances */ - -@c -static halfword mp_ps_marks_out (MP mp,font_number f, eight_bits c) { - eight_bits bc,ec; /* only encode characters between these bounds */ - integer lim; /* the maximum number of marks to encode before truncating */ - int p; /* |font_info| index for the current character */ - int d,b; /* used to construct a hexadecimal digit */ - lim=4*(emergency_line_length-mp->ps->ps_offset-4); - bc=mp->font_bc[f]; - ec=mp->font_ec[f]; - if ( c>bc ) bc=c; - @<Restrict the range |bc..ec| so that it contains no unused characters - at either end and has length at most |lim|@>; - @<Print the initial label indicating that the bitmap starts at |bc|@>; - @<Print a hexadecimal encoding of the marks for characters |bc..ec|@>; - while ( (ec<mp->font_ec[f])&&(mp->font_info[p].qqqq.b3==mp_unused) ) { - p++; ec++; - } - return (ec+1); -} - -@ We could save time by setting the return value before the loop that -decrements |ec|, but there is no point in being so tricky. - -@<Restrict the range |bc..ec| so that it contains no unused characters...@>= -p=mp->char_base[f]+bc; -while ( (mp->font_info[p].qqqq.b3==mp_unused)&&(bc<ec) ) { - p++; bc++; -} -if ( ec>=bc+lim ) ec=bc+lim-1; -p=mp->char_base[f]+ec; -while ( (mp->font_info[p].qqqq.b3==mp_unused)&&(bc<ec) ) { - p--; ec--; -} - -@ @<Print the initial label indicating that the bitmap starts at |bc|@>= -mp_ps_print_char(mp, ' '); -mp_hex_digit_out(mp, bc / 16); -mp_hex_digit_out(mp, bc % 16); -mp_ps_print_char(mp, ':') - -@ - -@<Print a hexadecimal encoding of the marks for characters |bc..ec|@>= -b=8; d=0; -for (p=mp->char_base[f]+bc;p<=mp->char_base[f]+ec;p++) { - if ( b==0 ) { - mp_hex_digit_out(mp, d); - d=0; b=8; - } - if ( mp->font_info[p].qqqq.b3!=mp_unused ) d=d+b; - b=b>>1; -} -mp_hex_digit_out(mp, d) - - -@ Here is a simple function that determines whether there are any marked -characters in font~|f| with character code at least~|c|. - -@<Declarations@>= -static boolean mp_check_ps_marks (MP mp,font_number f, integer c) ; - -@ @c -static boolean mp_check_ps_marks (MP mp,font_number f, integer c) { - int p; /* |font_info| index for the current character */ - for (p=mp->char_base[f]+c;p<=mp->char_base[f]+mp->font_ec[f];p++) { - if ( mp->font_info[p].qqqq.b3==mp_used ) - return true; - } - return false; -} - - -@ If the file name is so long that it can't be printed without exceeding -|emergency_line_length| then there will be missing items in the \.{\%*Font:} -line. We might have to repeat line in order to get the character usage -information to fit within |emergency_line_length|. - -TODO: these two defines are also defined in mp.w! - -@d link(A) mp->mem[(A)].hh.rh /* the |link| field of a memory word */ -@d sc_factor(A) mp->mem[(A)+1].cint /* the scale factor stored in a font size node */ - -@<Print the \.{\%*Font} comment for font |f| and advance |cur_fsize[f]|@>= -{ integer t=0; - while ( mp_check_ps_marks(mp, f,t) ) { - mp_ps_print_nl(mp, "%*Font: "); - if ( mp->ps->ps_offset+strlen(mp->font_name[f])+12>emergency_line_length ) - break; - mp_ps_print(mp, mp->font_name[f]); - mp_ps_print_char(mp, ' '); - ds=(mp->font_dsize[f] + 8) / 16; - mp_ps_print_scaled(mp, mp_take_scaled(mp, ds,sc_factor(cur_fsize[f]))); - if ( mp->ps->ps_offset+12>emergency_line_length ) break; - mp_ps_print_char(mp, ' '); - mp_ps_print_scaled(mp, ds); - if ( mp->ps->ps_offset+5>emergency_line_length ) break; - t=mp_ps_marks_out(mp, f,t); - } - cur_fsize[f]=link(cur_fsize[f]); -} - -@ @<Print the procset@>= -{ - mp_ps_print_nl(mp, "/hlw{0 dtransform exch truncate exch idtransform pop setlinewidth}bd"); - mp_ps_print_nl(mp, "/vlw{0 exch dtransform truncate idtransform setlinewidth pop}bd"); - mp_ps_print_nl(mp, "/l{lineto}bd/r{rlineto}bd/c{curveto}bd/m{moveto}bd" - "/p{closepath}bd/n{newpath}bd"); - mp_ps_print_nl(mp, "/C{setcmykcolor}bd/G{setgray}bd/R{setrgbcolor}bd" - "/lj{setlinejoin}bd/ml{setmiterlimit}bd"); - mp_ps_print_nl(mp, "/lc{setlinecap}bd/S{stroke}bd/F{fill}bd/q{gsave}bd" - "/Q{grestore}bd/s{scale}bd/t{concat}bd"); - mp_ps_print_nl(mp, "/sd{setdash}bd/rd{[] 0 setdash}bd/P{showpage}bd/B{q F Q}bd/W{clip}bd"); -} - - -@ The prologue defines \.{fshow} and corrects for the fact that \.{fshow} -arguments use |font_name| instead of |font_ps_name|. Downloaded bitmap fonts -might not have reasonable |font_ps_name| entries, but we just charge ahead -anyway. The user should not make \&{prologues} positive if this will cause -trouble. -@:prologues_}{\&{prologues} primitive@> - -@<Exported...@>= -void mp_print_prologue (MP mp, mp_edge_object *h, int prologues, int procset); - -@ @c -void mp_print_prologue (MP mp, mp_edge_object *h, int prologues, int procset) { - font_number f; - font_number ldf ; - ldf = mp_print_font_comments (mp, h, prologues); - mp_ps_print_ln(mp); - if ( (prologues==1) && (mp->last_ps_fnum<mp->last_fnum) ) - mp_read_psname_table(mp); - mp_ps_print(mp, "%%BeginProlog"); mp_ps_print_ln(mp); - if ( (prologues>0)||(procset>0) ) { - if ( ldf!=null_font ) { - if ( prologues>0 ) { - for (f=null_font+1;f<=mp->last_fnum;f++) { - if ( mp_has_font_size(mp,f) ) { - mp_ps_name_out(mp, mp->font_name[f],true); - mp_ps_name_out(mp, mp->font_ps_name[f],true); - mp_ps_print(mp, " def"); - mp_ps_print_ln(mp); - } - } - if ( procset==0 ) { - mp_ps_print(mp, "/fshow {exch findfont exch scalefont setfont show}bind def"); - mp_ps_print_ln(mp); - } - } - } - if (procset>0 ) { - mp_ps_print_nl(mp, "%%BeginResource: procset mpost"); - if ( (prologues>0)&&(ldf!=null_font) ) - mp_ps_print_nl(mp, - "/bd{bind def}bind def/fshow {exch findfont exch scalefont setfont show}bd"); - else - mp_ps_print_nl(mp, "/bd{bind def}bind def"); - @<Print the procset@>; - mp_ps_print_nl(mp, "%%EndResource"); - mp_ps_print_ln(mp); - } - } - mp_ps_print(mp, "%%EndProlog"); - mp_ps_print_nl(mp, "%%Page: 1 1"); mp_ps_print_ln(mp); -} - -@ \MP\ used to have one single routine to print to both `write' files -and the PostScript output. Web2c redefines ``Character |k| cannot be -printed'', and that resulted in some bugs where 8-bit characters were -written to the PostScript file (reported by Wlodek Bzyl). - -Also, Hans Hagen requested spaces to be output as "\\040" instead of -a plain space, since that makes it easier to parse the result file -for postprocessing. - -@<Character |k| is not allowed in PostScript output@>= - (k<=' ')||(k>'~') - -@ We often need to print a pair of coordinates. - -@c -void mp_ps_pair_out (MP mp,scaled x, scaled y) { - ps_room(26); - mp_ps_print_scaled(mp, x); mp_ps_print_char(mp, ' '); - mp_ps_print_scaled(mp, y); mp_ps_print_char(mp, ' '); -} - -@ @<Exported...@>= -void mp_ps_pair_out (MP mp,scaled x, scaled y) ; - -@ @c -void mp_ps_print_cmd (MP mp, const char *l, const char *s) { - if ( mp->internal[mp_procset]>0 ) { ps_room(strlen(s)); mp_ps_print(mp,s); } - else { ps_room(strlen(l)); mp_ps_print(mp, l); }; -} - -@ @<Exported...@>= -void mp_ps_print_cmd (MP mp, const char *l, const char *s) ; - -@ @c -void mp_ps_string_out (MP mp, const char *s) { - ASCII_code k; /* bits to be converted to octal */ - mp_ps_print(mp, "("); - while ((k=*s++)) { - if ( mp->ps->ps_offset+5>mp->max_print_line ) { - mp_ps_print_char(mp, '\\'); - mp_ps_print_ln(mp); - } - if ( (@<Character |k| is not allowed in PostScript output@>) ) { - mp_ps_print_char(mp, '\\'); - mp_ps_print_char(mp, '0'+(k / 64)); - mp_ps_print_char(mp, '0'+((k / 8) % 8)); - mp_ps_print_char(mp, '0'+(k % 8)); - } else { - if ( (k=='(')||(k==')')||(k=='\\') ) - mp_ps_print_char(mp, '\\'); - mp_ps_print_char(mp, k); - } - } - mp_ps_print_char(mp, ')'); -} - -@ @<Exported...@>= -void mp_ps_string_out (MP mp, const char *s) ; - -@ This is a define because the function does not use its |mp| argument. - -@d mp_is_ps_name(M,A) mp_do_is_ps_name(A) - -@c -static boolean mp_do_is_ps_name (char *s) { - ASCII_code k; /* the character being checked */ - while ((k=*s++)) { - if ( (k<=' ')||(k>'~') ) return false; - if ( (k=='(')||(k==')')||(k=='<')||(k=='>')|| - (k=='{')||(k=='}')||(k=='/')||(k=='%') ) return false; - } - return true; -} - -@ @<Exported...@>= -void mp_ps_name_out (MP mp, char *s, boolean lit) ; - -@ @c -void mp_ps_name_out (MP mp, char *s, boolean lit) { - ps_room(strlen(s)+2); - mp_ps_print_char(mp, ' '); - if ( mp_is_ps_name(mp, s) ) { - if ( lit ) mp_ps_print_char(mp, '/'); - mp_ps_print(mp, s); - } else { - mp_ps_string_out(mp, s); - if ( ! lit ) mp_ps_print(mp, "cvx "); - mp_ps_print(mp, "cvn"); - } -} - - -@ These special comments described in the {\sl PostScript Language Reference -Manual}, 2nd.~edition are understood by some \ps-reading programs. -We can't normally output ``conforming'' \ps\ because -the structuring conventions don't allow us to say ``Please make sure the -following characters are downloaded and define the \.{fshow} macro to access -them.'' - -The exact bounding box is written out if |mp_prologues<0|, although this -is not standard \ps, since it allows \TeX\ to calculate the box dimensions -accurately. (Overfull boxes are avoided if an illustration is made to -match a given \.{\char`\\hsize}.) - -@<Exported...@>= -void mp_print_initial_comment(MP mp,mp_edge_object *hh, int prologues); - -@ @c -void mp_print_initial_comment(MP mp,mp_edge_object *hh, int prologues) { - scaled t; - mp_ps_print(mp, "%!PS"); - if ( prologues>0 ) - mp_ps_print(mp, "-Adobe-3.0 EPSF-3.0"); - mp_ps_print_nl(mp, "%%BoundingBox: "); - if ( hh->_minx>hh->_maxx) { - mp_ps_print(mp, "0 0 0 0"); - } else if ( prologues<0 ) { - mp_ps_pair_out(mp, hh->_minx,hh->_miny); - mp_ps_pair_out(mp, hh->_maxx,hh->_maxy); - } else { - mp_ps_pair_out(mp, mp_floor_scaled(mp, hh->_minx),mp_floor_scaled(mp, hh->_miny)); - mp_ps_pair_out(mp, -mp_floor_scaled(mp, -hh->_maxx),-mp_floor_scaled(mp, -hh->_maxy)); - } - mp_ps_print_nl(mp, "%%HiResBoundingBox: "); - if ( hh->_minx>hh->_maxx ) { - mp_ps_print(mp, "0 0 0 0"); - } else { - mp_ps_pair_out(mp, hh->_minx,hh->_miny); - mp_ps_pair_out(mp, hh->_maxx,hh->_maxy); - } - mp_ps_print_nl(mp, "%%Creator: MetaPost "); - mp_ps_print(mp, mp_metapost_version(mp)); - mp_ps_print_nl(mp, "%%CreationDate: "); - mp_ps_print_int(mp, mp_round_unscaled(mp, mp->internal[mp_year])); - mp_ps_print_char(mp, '.'); - mp_ps_print_dd(mp, mp_round_unscaled(mp, mp->internal[mp_month])); - mp_ps_print_char(mp, '.'); - mp_ps_print_dd(mp, mp_round_unscaled(mp, mp->internal[mp_day])); - mp_ps_print_char(mp, ':'); - t=mp_round_unscaled(mp, mp->internal[mp_time]); - mp_ps_print_dd(mp, t / 60); - mp_ps_print_dd(mp, t % 60); - mp_ps_print_nl(mp, "%%Pages: 1"); -} - -@ The most important output procedure is the one that gives the \ps\ version of -a \MP\ path. - -@<Types...@>= -#define gr_left_type(A) (A)->left_type_field -#define gr_right_type(A) (A)->right_type_field -#define gr_x_coord(A) (A)->x_coord_field -#define gr_y_coord(A) (A)->y_coord_field -#define gr_left_x(A) (A)->left_x_field -#define gr_left_y(A) (A)->left_y_field -#define gr_right_x(A) (A)->right_x_field -#define gr_right_y(A) (A)->right_y_field -#define gr_next_knot(A) (A)->next_field -#define gr_originator(A) (A)->originator_field -typedef struct mp_knot { - unsigned short left_type_field; - unsigned short right_type_field; - scaled x_coord_field; - scaled y_coord_field; - scaled left_x_field; - scaled left_y_field; - scaled right_x_field; - scaled right_y_field; - struct mp_knot * next_field; - quarterword originator_field; -} mp_knot; - -@ @c -mp_knot * mp_gr_insert_knot (MP mp, mp_knot *q, scaled x, scaled y) { - /* returns the inserted knot */ - mp_knot *r; /* the new knot */ - r= mp_xmalloc(mp, 1, sizeof (mp_knot)); - gr_next_knot(r)=gr_next_knot(q); gr_next_knot(q)=r; - gr_right_x(r)=gr_right_x(q); - gr_right_y(r)=gr_right_y(q); - gr_x_coord(r)=x; - gr_y_coord(r)=y; - gr_right_x(q)=gr_x_coord(q); - gr_right_y(q)=gr_y_coord(q); - gr_left_x(r)=gr_x_coord(r); - gr_left_y(r)=gr_y_coord(r); - gr_left_type(r)=mp_explicit; - gr_right_type(r)=mp_explicit; - gr_originator(r)=mp_program_code; - return r; -} - - -@ If we want to duplicate a knot node, we can say |copy_knot|: - -@c -mp_knot *mp_gr_copy_knot (MP mp, mp_knot *p) { - mp_knot *q; /* the copy */ - q = mp_xmalloc(mp, 1, sizeof (mp_knot)); - memcpy(q,p,sizeof (mp_knot)); - gr_next_knot(q)=NULL; - return q; -} - -@ The |copy_path| routine makes a clone of a given path. - -@c -mp_knot *mp_gr_copy_path (MP mp, mp_knot *p) { - mp_knot *q, *pp, *qq; /* for list manipulation */ - if (p==NULL) - return NULL; - q=mp_gr_copy_knot(mp, p); - qq=q; - pp=gr_next_knot(p); - while ( pp!=p ) { - gr_next_knot(qq)=mp_gr_copy_knot(mp, pp); - qq=gr_next_knot(qq); - pp=gr_next_knot(pp); - } - gr_next_knot(qq)=q; - return q; -} - -@ Similarly, there's a way to copy the {\sl reverse\/} of a path. This procedure -returns a pointer to the first node of the copy, if the path is a cycle, -but to the final node of a non-cyclic copy. The global -variable |path_tail| will point to the final node of the original path; -this trick makes it easier to implement `\&{doublepath}'. - -All node types are assumed to be |endpoint| or |explicit| only. - -This function is currenly unused. - -@c -mp_knot * mp_gr_htap_ypoc (MP mp, mp_knot *p) { - mp_knot *q, *pp, *qq, *rr; /* for list manipulation */ - q=mp_xmalloc(mp, 1, sizeof (mp_knot)); /* this will correspond to |p| */ - qq=q; pp=p; - while (1) { - gr_right_type(qq)=gr_left_type(pp); - gr_left_type(qq)=gr_right_type(pp); - gr_x_coord(qq)=gr_x_coord(pp); - gr_y_coord(qq)=gr_y_coord(pp); - gr_right_x(qq)=gr_left_x(pp); - gr_right_y(qq)=gr_left_y(pp); - gr_left_x(qq)=gr_right_x(pp); - gr_left_y(qq)=gr_right_y(pp); - gr_originator(qq)=gr_originator(pp); - if ( gr_next_knot(pp)==p ) { - gr_next_knot(q)=qq; - /* mp->path_tail=pp; */ /* ? */ - return q; - } - rr=mp_xmalloc(mp, 1, sizeof (mp_knot)); - gr_next_knot(rr)=qq; - qq=rr; - pp=gr_next_knot(pp); - } -} - -@ When a cyclic list of knot nodes is no longer needed, it can be recycled by -calling the following subroutine. - -@<Declarations@>= -void mp_do_gr_toss_knot_list (mp_knot *p) ; - -@ -@d mp_gr_toss_knot_list(B,A) mp_do_gr_toss_knot_list(A) - -@c -void mp_do_gr_toss_knot_list (mp_knot * p) { - mp_knot *q; /* the node being freed */ - mp_knot *r; /* the next node */ - if (p==NULL) - return; - q=p; - do { - r=gr_next_knot(q); - mp_xfree(q); q=r; - } while (q!=p); -} - - - -@ @c -void mp_gr_ps_path_out (MP mp, mp_knot *h) { - mp_knot *p, *q; /* for scanning the path */ - scaled d; /* a temporary value */ - boolean curved; /* |true| unless the cubic is almost straight */ - ps_room(40); - mp_ps_print_cmd(mp, "newpath ","n "); - mp_ps_pair_out(mp, gr_x_coord(h),gr_y_coord(h)); - mp_ps_print_cmd(mp, "moveto","m"); - p=h; - do { - if ( gr_right_type(p)==mp_endpoint ) { - if ( p==h ) mp_ps_print_cmd(mp, " 0 0 rlineto"," 0 0 r"); - return; - } - q=gr_next_knot(p); - @<Start a new line and print the \ps\ commands for the curve from - |p| to~|q|@>; - p=q; - } while (p!=h); - mp_ps_print_cmd(mp, " closepath"," p"); -} - -@ @<Start a new line and print the \ps\ commands for the curve from...@>= -curved=true; -@<Set |curved:=false| if the cubic from |p| to |q| is almost straight@>; -mp_ps_print_ln(mp); -if ( curved ){ - mp_ps_pair_out(mp, gr_right_x(p),gr_right_y(p)); - mp_ps_pair_out(mp, gr_left_x(q),gr_left_y(q)); - mp_ps_pair_out(mp, gr_x_coord(q),gr_y_coord(q)); - mp_ps_print_cmd(mp, "curveto","c"); -} else if ( q!=h ){ - mp_ps_pair_out(mp, gr_x_coord(q),gr_y_coord(q)); - mp_ps_print_cmd(mp, "lineto","l"); -} - -@ Two types of straight lines come up often in \MP\ paths: -cubics with zero initial and final velocity as created by |make_path| or -|make_envelope|, and cubics with control points uniformly spaced on a line -as created by |make_choices|. - -@d bend_tolerance 131 /* allow rounding error of $2\cdot10^{-3}$ */ - -@<Set |curved:=false| if the cubic from |p| to |q| is almost straight@>= -if ( gr_right_x(p)==gr_x_coord(p) ) - if ( gr_right_y(p)==gr_y_coord(p) ) - if ( gr_left_x(q)==gr_x_coord(q) ) - if ( gr_left_y(q)==gr_y_coord(q) ) curved=false; -d=gr_left_x(q)-gr_right_x(p); -if ( abs(gr_right_x(p)-gr_x_coord(p)-d)<=bend_tolerance ) - if ( abs(gr_x_coord(q)-gr_left_x(q)-d)<=bend_tolerance ) - { d=gr_left_y(q)-gr_right_y(p); - if ( abs(gr_right_y(p)-gr_y_coord(p)-d)<=bend_tolerance ) - if ( abs(gr_y_coord(q)-gr_left_y(q)-d)<=bend_tolerance ) curved=false; - } - -@ The colored objects use a struct with anonymous fields to express the color parts: - -@<Types...@>= -typedef struct { - scaled _a_val, _b_val, _c_val, _d_val; -} mp_color; - -@ The exported form of a dash pattern is simpler than the internal -format, it is closely modelled to the PostScript model. The array of -dashes is ended by a single negative value, because this is not -allowed in PostScript. - -@<Types...@>= -typedef struct { - scaled offset_field; - scaled *array_field; -} mp_dash_object ; - - -@ -@d mp_gr_toss_dashes(A,B) mp_do_gr_toss_dashes(B) - -@<Declarations@>= -void mp_do_gr_toss_dashes(mp_dash_object *dl); - -@ @c -void mp_do_gr_toss_dashes(mp_dash_object *dl) { - if (dl==NULL) - return; - mp_xfree(dl->array_field); - mp_xfree(dl); -} - - -@ @c -mp_dash_object *mp_gr_copy_dashes(MP mp, mp_dash_object *dl) { - mp_dash_object *q = NULL; - (void)mp; - if (dl==NULL) - return NULL; - q = mp_xmalloc(mp, 1, sizeof (mp_dash_object)); - memcpy (q,dl,sizeof(mp_dash_object)); - if (dl->array_field != NULL) { - int i = 0; - while (*(dl->array_field+i) != -1) i++; - q->array_field = mp_xmalloc(mp, i, sizeof (scaled)); - memcpy(q->array_field,dl->array_field, (i*sizeof(scaled))); - } - return q; -} - - -@ Now for outputting the actual graphic objects. First, set up some -structures and access macros. - -@d gr_has_color(A) (gr_type((A))<mp_start_clip_code) - -@<Types...@>= -#define gr_type(A) (A)->_type_field -#define gr_link(A) (A)->_link_field -#define gr_color_model(A) (A)->color_model_field -#define gr_red_val(A) (A)->color_field._a_val -#define gr_green_val(A) (A)->color_field._b_val -#define gr_blue_val(A) (A)->color_field._c_val -#define gr_cyan_val(A) (A)->color_field._a_val -#define gr_magenta_val(A) (A)->color_field._b_val -#define gr_yellow_val(A) (A)->color_field._c_val -#define gr_black_val(A) (A)->color_field._d_val -#define gr_grey_val(A) (A)->color_field._a_val -#define gr_path_p(A) (A)->path_p_field -#define gr_htap_p(A) ((mp_fill_object *)A)->htap_p_field -#define gr_pen_p(A) (A)->pen_p_field -#define gr_ljoin_val(A) (A)->ljoin_field -#define gr_lcap_val(A) ((mp_stroked_object *)A)->lcap_field -#define gr_miterlim_val(A) (A)->miterlim_field -#define gr_pre_script(A) (A)->pre_script_field -#define gr_post_script(A) (A)->post_script_field -#define gr_dash_p(A) ((mp_stroked_object *)A)->dash_p_field -#define gr_name_type(A) ((mp_text_object *)A)->name_type_field -#define gr_text_p(A) ((mp_text_object *)A)->text_p_field -#define gr_font_n(A) ((mp_text_object *)A)->font_n_field -#define gr_font_name(A) ((mp_text_object *)A)->font_name_field -#define gr_font_dsize(A) ((mp_text_object *)A)->font_dsize_field -#define gr_width_val(A) ((mp_text_object *)A)->width_field -#define gr_height_val(A) ((mp_text_object *)A)->height_field -#define gr_depth_val(A) ((mp_text_object *)A)->depth_field -#define gr_tx_val(A) ((mp_text_object *)A)->tx_field -#define gr_ty_val(A) ((mp_text_object *)A)->ty_field -#define gr_txx_val(A) ((mp_text_object *)A)->txx_field -#define gr_txy_val(A) ((mp_text_object *)A)->txy_field -#define gr_tyx_val(A) ((mp_text_object *)A)->tyx_field -#define gr_tyy_val(A) ((mp_text_object *)A)->tyy_field - -#define GRAPHIC_BODY \ - halfword _type_field; \ - struct mp_graphic_object * _link_field - -typedef struct mp_graphic_object { - GRAPHIC_BODY; -} mp_graphic_object; - -typedef struct mp_text_object { - GRAPHIC_BODY; - char *pre_script_field; - char *post_script_field; - mp_color color_field; - quarterword color_model_field; - quarterword name_type_field; - char *text_p_field; - char *font_name_field ; - scaled font_dsize_field ; - font_number font_n_field ; - scaled width_field ; - scaled height_field ; - scaled depth_field ; - scaled tx_field ; - scaled ty_field ; - scaled txx_field ; - scaled txy_field ; - scaled tyx_field ; - scaled tyy_field ; -} mp_text_object; - -typedef struct mp_fill_object { - GRAPHIC_BODY; - char *pre_script_field; - char *post_script_field; - mp_color color_field; - quarterword color_model_field; - quarterword ljoin_field ; - mp_knot * path_p_field; - mp_knot * htap_p_field; - mp_knot * pen_p_field; - scaled miterlim_field ; -} mp_fill_object; - -typedef struct mp_stroked_object { - GRAPHIC_BODY; - char *pre_script_field; - char *post_script_field; - mp_color color_field; - quarterword color_model_field; - quarterword ljoin_field ; - quarterword lcap_field ; - mp_knot * path_p_field; - mp_knot * pen_p_field; - scaled miterlim_field ; - mp_dash_object *dash_p_field; -} mp_stroked_object; - -typedef struct mp_clip_object { - GRAPHIC_BODY; - mp_knot * path_p_field; -} mp_clip_object; - -typedef struct mp_bounds_object { - GRAPHIC_BODY; - mp_knot * path_p_field; -} mp_bounds_object; - -typedef struct mp_special_object { - GRAPHIC_BODY; - char *pre_script_field; -} mp_special_object ; - -typedef struct mp_edge_object { - struct mp_graphic_object * body; - struct mp_edge_object * _next; - char * _filename; - MP _parent; - scaled _minx, _miny, _maxx, _maxy; -} mp_edge_object; - -@ @<Exported function headers@>= -mp_graphic_object *mp_new_graphic_object(MP mp, int type); - -@ @c -mp_graphic_object *mp_new_graphic_object (MP mp, int type) { - mp_graphic_object *p; - int size ; - switch (type) { - case mp_fill_code: size = sizeof(mp_fill_object); break; - case mp_stroked_code: size = sizeof(mp_stroked_object); break; - case mp_text_code: size = sizeof(mp_text_object); break; - case mp_start_clip_code: size = sizeof(mp_clip_object); break; - case mp_start_bounds_code: size = sizeof(mp_bounds_object); break; - case mp_special_code: size = sizeof(mp_special_object); break; - default: size = sizeof(mp_graphic_object); break; - } - p = (mp_graphic_object *)mp_xmalloc(mp,1,size); - memset(p,0,size); - gr_type(p) = type; - return p; -} - -@ We need to keep track of several parameters from the \ps\ graphics state. -@^graphics state@> -This allows us to be sure that \ps\ has the correct values when they are -needed without wasting time and space setting them unnecessarily. - -@d gs_red mp->ps->gs_state->red_field -@d gs_green mp->ps->gs_state->green_field -@d gs_blue mp->ps->gs_state->blue_field -@d gs_black mp->ps->gs_state->black_field -@d gs_colormodel mp->ps->gs_state->colormodel_field -@d gs_ljoin mp->ps->gs_state->ljoin_field -@d gs_lcap mp->ps->gs_state->lcap_field -@d gs_adj_wx mp->ps->gs_state->adj_wx_field -@d gs_miterlim mp->ps->gs_state->miterlim_field -@d gs_dash_p mp->ps->gs_state->dash_p_field -@d gs_dash_init_done mp->ps->gs_state->dash_done_field -@d gs_previous mp->ps->gs_state->previous_field -@d gs_width mp->ps->gs_state->width_field - -@<Types...@>= -typedef struct _gs_state { - scaled red_field ; - scaled green_field ; - scaled blue_field ; - scaled black_field ; - /* color from the last \&{setcmykcolor} or \&{setrgbcolor} or \&{setgray} command */ - quarterword colormodel_field ; - /* the current colormodel */ - quarterword ljoin_field ; - quarterword lcap_field ; - /* values from the last \&{setlinejoin} and \&{setlinecap} commands */ - quarterword adj_wx_field ; - /* what resolution-dependent adjustment applies to the width */ - scaled miterlim_field ; - /* the value from the last \&{setmiterlimit} command */ - mp_dash_object * dash_p_field ; - /* edge structure for last \&{setdash} command */ - boolean dash_done_field ; /* to test for initial \&{setdash} */ - struct _gs_state * previous_field ; - /* backlink to the previous |_gs_state| structure */ - scaled width_field ; - /* width setting or $-1$ if no \&{setlinewidth} command so far */ -} _gs_state; - - -@ @<Glob...@>= -struct _gs_state * gs_state; - -@ @<Set init...@>= -mp->ps->gs_state=NULL; - -@ @<Dealloc variables@>= -mp_xfree(mp->ps->gs_state); - -@ To avoid making undue assumptions about the initial graphics state, these -parameters are given special values that are guaranteed not to match anything -in the edge structure being shipped out. On the other hand, the initial color -should be black so that the translation of an all-black picture will have no -\&{setcolor} commands. (These would be undesirable in a font application.) -Hence we use |c=0| when initializing the graphics state and we use |c<0| -to recover from a situation where we have lost track of the graphics state. - -@c -void mp_gs_unknown_graphics_state (MP mp,scaled c) ; - -@ -@d mp_void (null+1) /* a null pointer different from |null| */ - -@c void mp_gs_unknown_graphics_state (MP mp,scaled c) { - struct _gs_state *p; /* to shift graphic states around */ - if ( (c==0)||(c==-1) ) { - if ( mp->ps->gs_state==NULL ) { - mp->ps->gs_state = mp_xmalloc(mp,1,sizeof(struct _gs_state)); - gs_previous=NULL; - } else { - while ( gs_previous!=NULL ) { - p = gs_previous; - mp_xfree(mp->ps->gs_state); - mp->ps->gs_state=p; - } - } - gs_red=c; gs_green=c; gs_blue=c; gs_black=c; - gs_colormodel=mp_uninitialized_model; - gs_ljoin=3; - gs_lcap=3; - gs_miterlim=0; - gs_dash_p=NULL; - gs_dash_init_done=false; - gs_width=-1; - } else if ( c==1 ) { - p= mp->ps->gs_state; - mp->ps->gs_state = mp_xmalloc(mp,1,sizeof(struct _gs_state)); - memcpy(mp->ps->gs_state,p,sizeof(struct _gs_state)); - gs_previous = p; - } else if ( c==2 ) { - p = gs_previous; - mp_xfree(mp->ps->gs_state); - mp->ps->gs_state=p; - } -} - - -@ When it is time to output a graphical object, |fix_graphics_state| ensures -that \ps's idea of the graphics state agrees with what is stored in the object. - -@<Declarations@>= -void mp_gr_fix_graphics_state (MP mp, mp_graphic_object *p) ; - -@ @c -void mp_gr_fix_graphics_state (MP mp, mp_graphic_object *p) { - /* get ready to output graphical object |p| */ - mp_knot *pp, *path_p; /* for list manipulation */ - mp_dash_object *hh; - scaled wx,wy,ww; /* dimensions of pen bounding box */ - boolean adj_wx; /* whether pixel rounding should be based on |wx| or |wy| */ - integer tx,ty; /* temporaries for computing |adj_wx| */ - if ( gr_has_color(p) ) - @<Make sure \ps\ will use the right color for object~|p|@>; - if ( (gr_type(p)==mp_fill_code)||(gr_type(p)==mp_stroked_code) ) { - if (gr_type(p)==mp_fill_code) { - pp = gr_pen_p((mp_fill_object *)p); - path_p = gr_path_p((mp_fill_object *)p); - } else { - pp = gr_pen_p((mp_stroked_object *)p); - path_p = gr_path_p((mp_stroked_object *)p); - } - if ( pp!=NULL ) - if ( pen_is_elliptical(pp) ) { - @<Generate \ps\ code that sets the stroke width to the - appropriate rounded value@>; - @<Make sure \ps\ will use the right dash pattern for |dash_p(p)|@>; - @<Decide whether the line cap parameter matters and set it if necessary@>; - @<Set the other numeric parameters as needed for object~|p|@>; - } - } - if ( mp->ps->ps_offset>0 ) mp_ps_print_ln(mp); -} - -@ @<Decide whether the line cap parameter matters and set it if necessary@>= -if ( gr_type(p)==mp_stroked_code ) { - mp_stroked_object *ts = (mp_stroked_object *)p; - if ( (gr_left_type(gr_path_p(ts))==mp_endpoint)||(gr_dash_p(ts)!=NULL) ) - if ( gs_lcap!=gr_lcap_val(ts) ) { - ps_room(13); - mp_ps_print_char(mp, ' '); - mp_ps_print_char(mp, '0'+gr_lcap_val(ts)); - mp_ps_print_cmd(mp, " setlinecap"," lc"); - gs_lcap=gr_lcap_val(ts); - } -} - -@ -@d set_ljoin_miterlim(p) - if ( gs_ljoin!=gr_ljoin_val(p) ) { - ps_room(14); - mp_ps_print_char(mp, ' '); - mp_ps_print_char(mp, '0'+gr_ljoin_val(p)); - mp_ps_print_cmd(mp, " setlinejoin"," lj"); - gs_ljoin=gr_ljoin_val(p); - } - if ( gs_miterlim!=gr_miterlim_val(p) ) { - ps_room(27); - mp_ps_print_char(mp, ' '); - mp_ps_print_scaled(mp, gr_miterlim_val(p)); - mp_ps_print_cmd(mp, " setmiterlimit"," ml"); - gs_miterlim=gr_miterlim_val(p); - } - -@<Set the other numeric parameters as needed for object~|p|@>= -if ( gr_type(p)==mp_stroked_code ) { - mp_stroked_object *ts = (mp_stroked_object *)p; - set_ljoin_miterlim(ts); -} else { - mp_fill_object *ts = (mp_fill_object *)p; - set_ljoin_miterlim(ts); -} - -@ -@d set_color_objects(pq) - object_color_model = pq->color_model_field; - object_color_a = pq->color_field._a_val; - object_color_b = pq->color_field._b_val; - object_color_c = pq->color_field._c_val; - object_color_d = pq->color_field._d_val; - -@<Make sure \ps\ will use the right color for object~|p|@>= -{ - int object_color_model; - int object_color_a, object_color_b, object_color_c, object_color_d ; - if (gr_type(p) == mp_fill_code) { - mp_fill_object *pq = (mp_fill_object *)p; - set_color_objects(pq); - } else if (gr_type(p) == mp_stroked_code) { - mp_stroked_object *pq = (mp_stroked_object *)p; - set_color_objects(pq); - } else { - mp_text_object *pq = (mp_text_object *)p; - set_color_objects(pq); - } - - if ( object_color_model==mp_rgb_model) { - if ( (gs_colormodel!=mp_rgb_model)||(gs_red!=object_color_a)|| - (gs_green!=object_color_b)||(gs_blue!=object_color_c) ) { - gs_red = object_color_a; - gs_green = object_color_b; - gs_blue = object_color_c; - gs_black = -1; - gs_colormodel=mp_rgb_model; - { ps_room(36); - mp_ps_print_char(mp, ' '); - mp_ps_print_scaled(mp, gs_red); mp_ps_print_char(mp, ' '); - mp_ps_print_scaled(mp, gs_green); mp_ps_print_char(mp, ' '); - mp_ps_print_scaled(mp, gs_blue); - mp_ps_print_cmd(mp, " setrgbcolor", " R"); - } - } - } else if ( object_color_model==mp_cmyk_model) { - if ( (gs_red!=object_color_a)||(gs_green!=object_color_b)|| - (gs_blue!=object_color_c)||(gs_black!=object_color_d)|| - (gs_colormodel!=mp_cmyk_model) ) { - gs_red = object_color_a; - gs_green = object_color_b; - gs_blue = object_color_c; - gs_black = object_color_d; - gs_colormodel=mp_cmyk_model; - { ps_room(45); - mp_ps_print_char(mp, ' '); - mp_ps_print_scaled(mp, gs_red); - mp_ps_print_char(mp, ' '); - mp_ps_print_scaled(mp, gs_green); - mp_ps_print_char(mp, ' '); - mp_ps_print_scaled(mp, gs_blue); - mp_ps_print_char(mp, ' '); - mp_ps_print_scaled(mp, gs_black); - mp_ps_print_cmd(mp, " setcmykcolor"," C"); - } - } - } else if ( object_color_model==mp_grey_model ) { - if ( (gs_red!=object_color_a)||(gs_colormodel!=mp_grey_model) ) { - gs_red = object_color_a; - gs_green = -1; - gs_blue = -1; - gs_black = -1; - gs_colormodel=mp_grey_model; - { ps_room(16); - mp_ps_print_char(mp, ' '); - mp_ps_print_scaled(mp, gs_red); - mp_ps_print_cmd(mp, " setgray"," G"); - } - } - } else if ( object_color_model==mp_no_model ) { - gs_colormodel=mp_no_model; - } -} - -@ In order to get consistent widths for horizontal and vertical pen strokes, we -want \ps\ to use an integer number of pixels for the \&{setwidth} parameter. -@:setwidth}{\&{setwidth}command@> -We set |gs_width| to the ideal horizontal or vertical stroke width and then -generate \ps\ code that computes the rounded value. For non-circular pens, the -pen shape will be rescaled so that horizontal or vertical parts of the stroke -have the computed width. - -Rounding the width to whole pixels is not likely to improve the appearance of -diagonal or curved strokes, but we do it anyway for consistency. The -\&{truncate} command generated here tends to make all the strokes a little -@:truncate}{\&{truncate} command@> -thinner, but this is appropriate for \ps's scan-conversion rules. Even with -truncation, an ideal with of $w$~pixels gets mapped into $\lfloor w\rfloor+1$. -It would be better to have $\lceil w\rceil$ but that is ridiculously expensive -to compute in \ps. - -@<Generate \ps\ code that sets the stroke width...@>= -@<Set |wx| and |wy| to the width and height of the bounding box for - |pen_p(p)|@>; -@<Use |pen_p(p)| and |path_p(p)| to decide whether |wx| or |wy| is more - important and set |adj_wx| and |ww| accordingly@>; -if ( (ww!=gs_width) || (adj_wx!=gs_adj_wx) ) { - if ( adj_wx ) { - ps_room(13); - mp_ps_print_char(mp, ' '); mp_ps_print_scaled(mp, ww); - mp_ps_print_cmd(mp, - " 0 dtransform exch truncate exch idtransform pop setlinewidth"," hlw"); - } else { - if ( mp->internal[mp_procset]>0 ) { - ps_room(13); - mp_ps_print_char(mp, ' '); - mp_ps_print_scaled(mp, ww); - mp_ps_print(mp, " vlw"); - } else { - ps_room(15); - mp_ps_print(mp, " 0 "); mp_ps_print_scaled(mp, ww); - mp_ps_print(mp, " dtransform truncate idtransform setlinewidth pop"); - } - } - gs_width = ww; - gs_adj_wx = adj_wx; -} - -@ @<Set |wx| and |wy| to the width and height of the bounding box for...@>= -if ( (gr_right_x(pp)==gr_x_coord(pp)) && (gr_left_y(pp)==gr_y_coord(pp)) ) { - wx = abs(gr_left_x(pp) - gr_x_coord(pp)); - wy = abs(gr_right_y(pp) - gr_y_coord(pp)); -} else { - wx = mp_pyth_add(mp, gr_left_x(pp)-gr_x_coord(pp), gr_right_x(pp)-gr_x_coord(pp)); - wy = mp_pyth_add(mp, gr_left_y(pp)-gr_y_coord(pp), gr_right_y(pp)-gr_y_coord(pp)); -} - -@ The path is considered ``essentially horizontal'' if its range of -$y$~coordinates is less than the $y$~range |wy| for the pen. ``Essentially -vertical'' paths are detected similarly. This code ensures that no component -of the pen transformation is more that |aspect_bound*(ww+1)|. - -@d aspect_bound 10 /* ``less important'' of |wx|, |wy| cannot exceed the other by - more than this factor */ - -@d do_x_loc 1 -@d do_y_loc 2 - -@<Use |pen_p(p)| and |path_p(p)| to decide whether |wx| or |wy| is more...@>= -tx=1; ty=1; -if ( mp_gr_coord_rangeOK(path_p, do_y_loc, wy) ) tx=aspect_bound; -else if ( mp_gr_coord_rangeOK(path_p, do_x_loc, wx) ) ty=aspect_bound; -if ( wy / ty>=wx / tx ) { ww=wy; adj_wx=false; } -else { ww=wx; adj_wx=true; } - -@ This routine quickly tests if path |h| is ``essentially horizontal'' or -``essentially vertical,'' where |zoff| is |x_loc(0)| or |y_loc(0)| and |dz| is -allowable range for $x$ or~$y$. We do not need and cannot afford a full -bounding-box computation. - -@<Declarations@>= -boolean mp_gr_coord_rangeOK (mp_knot *h, - small_number zoff, scaled dz); - -@ @c -boolean mp_gr_coord_rangeOK (mp_knot *h, - small_number zoff, scaled dz) { - mp_knot *p; /* for scanning the path form |h| */ - scaled zlo,zhi; /* coordinate range so far */ - scaled z; /* coordinate currently being tested */ - if (zoff==do_x_loc) { - zlo=gr_x_coord(h); - zhi=zlo; - p=h; - while ( gr_right_type(p)!=mp_endpoint ) { - z=gr_right_x(p); - @<Make |zlo..zhi| include |z| and |return false| if |zhi-zlo>dz|@>; - p=gr_next_knot(p); z=gr_left_x(p); - @<Make |zlo..zhi| include |z| and |return false| if |zhi-zlo>dz|@>; - z=gr_x_coord(p); - @<Make |zlo..zhi| include |z| and |return false| if |zhi-zlo>dz|@>; - if ( p==h ) break; - } - } else { - zlo=gr_y_coord(h); - zhi=zlo; - p=h; - while ( gr_right_type(p)!=mp_endpoint ) { - z=gr_right_y(p); - @<Make |zlo..zhi| include |z| and |return false| if |zhi-zlo>dz|@>; - p=gr_next_knot(p); z=gr_left_y(p); - @<Make |zlo..zhi| include |z| and |return false| if |zhi-zlo>dz|@>; - z=gr_y_coord(p); - @<Make |zlo..zhi| include |z| and |return false| if |zhi-zlo>dz|@>; - if ( p==h ) break; - } - } - return true; -} - -@ @<Make |zlo..zhi| include |z| and |return false| if |zhi-zlo>dz|@>= -if ( z<zlo ) zlo=z; -else if ( z>zhi ) zhi=z; -if ( zhi-zlo>dz ) return false - -@ Filling with an elliptical pen is implemented via a combination of \&{stroke} -and \&{fill} commands and a nontrivial dash pattern would interfere with this. -@:stroke}{\&{stroke} command@> -@:fill}{\&{fill} command@> -Note that we don't use |delete_edge_ref| because |gs_dash_p| is not counted as -a reference. - -@<Make sure \ps\ will use the right dash pattern for |dash_p(p)|@>= -if ( gr_type(p)==mp_fill_code || gr_dash_p(p) == NULL) { - hh=NULL; -} else { - hh=gr_dash_p(p); -} -if ( hh==NULL ) { - if ( gs_dash_p!=NULL || gs_dash_init_done == false) { - mp_ps_print_cmd(mp, " [] 0 setdash"," rd"); - gs_dash_p=NULL; - gs_dash_init_done=true; - } -} else if ( ! mp_gr_same_dashes(gs_dash_p,hh) ) { - @<Set the dash pattern from |dash_list(hh)| scaled by |scf|@>; -} - -@ @<Declarations@>= -scaled mp_gr_get_pen_scale (MP mp, mp_knot *p) ; - - -@ @c -scaled mp_gr_get_pen_scale (MP mp, mp_knot *p) { - return mp_sqrt_det(mp, - gr_left_x(p)-gr_x_coord(p), gr_right_x(p)-gr_x_coord(p), - gr_left_y(p)-gr_y_coord(p), gr_right_y(p)-gr_y_coord(p)); -} - - -@ The original code had a check here to ensure that the result from -|mp_take_scaled| did not go out of bounds. - -@<Set the dash pattern from |dash_list(hh)| scaled by |scf|@>= -{ gs_dash_p=hh; - if ( (gr_dash_p(p)==NULL) || (hh==NULL) || (hh->array_field==NULL)) { - mp_ps_print_cmd(mp, " [] 0 setdash"," rd"); - } else { - int i; - ps_room(28); - mp_ps_print(mp, " ["); - for (i=0; *(hh->array_field+i) != -1;i++) { - ps_room(13); - mp_ps_print_scaled(mp, *(hh->array_field+i)); - mp_ps_print_char(mp, ' ') ; - } - ps_room(22); - mp_ps_print(mp, "] "); - mp_ps_print_scaled(mp, hh->offset_field); - mp_ps_print_cmd(mp, " setdash"," sd"); - } -} - -@ @<Declarations@>= -boolean mp_gr_same_dashes (mp_dash_object *h, mp_dash_object *hh) ; - -@ This function test if |h| and |hh| represent the same dash pattern. - -@c -boolean mp_gr_same_dashes (mp_dash_object *h, mp_dash_object *hh) { - boolean ret=false; - int i = 0; - if ( h==hh ) ret=true; - else if ( (h==NULL)||(hh==NULL) ) ret=false; - else if ( h->offset_field!=hh->offset_field ) ret=false; - else if ( h->array_field == hh->array_field) ret=true; - else if ( h->array_field == NULL || hh->array_field == NULL) ret=false; - else { @<Compare |dash_list(h)| and |dash_list(hh)|@>; } - return ret; -} - -@ @<Compare |dash_list(h)| and |dash_list(hh)|@>= -{ - while (*(h->array_field+i)!=-1 && - *(hh->array_field+i)!=-1 && - *(h->array_field+i) == *(hh->array_field+i)) i++; - if (i>0) { - if (*(h->array_field+(i))==-1 && *(hh->array_field+(i)) == -1) - ret=true; - } -} - -@ When stroking a path with an elliptical pen, it is necessary to transform -the coordinate system so that a unit circular pen will have the desired shape. -To keep this transformation local, we enclose it in a -$$\&{gsave}\ldots\&{grestore}$$ -block. Any translation component must be applied to the path being stroked -while the rest of the transformation must apply only to the pen. -If |fill_also=true|, the path is to be filled as well as stroked so we must -insert commands to do this after giving the path. - -@<Declarations@>= -void mp_gr_stroke_ellipse (MP mp, mp_graphic_object *h, boolean fill_also) ; - -@ -@c void mp_gr_stroke_ellipse (MP mp, mp_graphic_object *h, boolean fill_also) { - /* generate an elliptical pen stroke from object |h| */ - scaled txx,txy,tyx,tyy; /* transformation parameters */ - mp_knot *p; /* the pen to stroke with */ - scaled d1,det; /* for tweaking transformation parameters */ - integer s; /* also for tweaking transformation paramters */ - boolean transformed; /* keeps track of whether gsave/grestore are needed */ - transformed=false; - @<Use |pen_p(h)| to set the transformation parameters and give the initial - translation@>; - @<Tweak the transformation parameters so the transformation is nonsingular@>; - if (gr_type(h)==mp_fill_code) { - mp_gr_ps_path_out(mp, gr_path_p((mp_fill_object *)h)); - } else { - mp_gr_ps_path_out(mp, gr_path_p((mp_stroked_object *)h)); - } - if ( mp->internal[mp_procset]==0 ) { - if ( fill_also ) mp_ps_print_nl(mp, "gsave fill grestore"); - @<Issue \ps\ commands to transform the coordinate system@>; - mp_ps_print(mp, " stroke"); - if ( transformed ) mp_ps_print(mp, " grestore"); - } else { - if ( fill_also ) mp_ps_print_nl(mp, "B"); else mp_ps_print_ln(mp); - if ( (txy!=0)||(tyx!=0) ) { - mp_ps_print(mp, " ["); - mp_ps_pair_out(mp, txx,tyx); - mp_ps_pair_out(mp, txy,tyy); - mp_ps_print(mp, "0 0] t"); - } else if ((txx!=unity)||(tyy!=unity) ) { - mp_ps_pair_out(mp,txx,tyy); - mp_ps_print(mp, " s"); - }; - mp_ps_print(mp, " S"); - if ( transformed ) mp_ps_print(mp, " Q"); - } - mp_ps_print_ln(mp); -} - -@ @<Use |pen_p(h)| to set the transformation parameters and give the...@>= -if (gr_type(h)==mp_fill_code) { - p=gr_pen_p((mp_fill_object *)h); -} else { - p=gr_pen_p((mp_stroked_object *)h); -} -txx=gr_left_x(p); -tyx=gr_left_y(p); -txy=gr_right_x(p); -tyy=gr_right_y(p); -if ( (gr_x_coord(p)!=0)||(gr_y_coord(p)!=0) ) { - mp_ps_print_nl(mp, ""); - mp_ps_print_cmd(mp, "gsave ","q "); - mp_ps_pair_out(mp, gr_x_coord(p), gr_y_coord(p)); - mp_ps_print(mp, "translate "); - txx-=gr_x_coord(p); - tyx-=gr_y_coord(p); - txy-=gr_x_coord(p); - tyy-=gr_y_coord(p); - transformed=true; -} else { - mp_ps_print_nl(mp, ""); -} -@<Adjust the transformation to account for |gs_width| and output the - initial \&{gsave} if |transformed| should be |true|@> - -@ @<Adjust the transformation to account for |gs_width| and output the...@>= -if ( gs_width!=unity ) { - if ( gs_width==0 ) { - txx=unity; tyy=unity; - } else { - txx=mp_make_scaled(mp, txx,gs_width); - txy=mp_make_scaled(mp, txy,gs_width); - tyx=mp_make_scaled(mp, tyx,gs_width); - tyy=mp_make_scaled(mp, tyy,gs_width); - }; -} -if ( (txy!=0)||(tyx!=0)||(txx!=unity)||(tyy!=unity) ) { - if ( (! transformed) ){ - mp_ps_print_cmd(mp, "gsave ","q "); - transformed=true; - } -} - -@ @<Issue \ps\ commands to transform the coordinate system@>= -if ( (txy!=0)||(tyx!=0) ){ - mp_ps_print_ln(mp); - mp_ps_print_char(mp, '['); - mp_ps_pair_out(mp, txx,tyx); - mp_ps_pair_out(mp, txy,tyy); - mp_ps_print(mp, "0 0] concat"); -} else if ( (txx!=unity)||(tyy!=unity) ){ - mp_ps_print_ln(mp); - mp_ps_pair_out(mp, txx,tyy); - mp_ps_print(mp, "scale"); -} - -@ The \ps\ interpreter will probably abort if it encounters a singular -transformation matrix. The determinant must be large enough to ensure that -the printed representation will be nonsingular. Since the printed -representation is always within $2^{-17}$ of the internal |scaled| value, the -total error is at most $4T_{\rm max}2^{-17}$, where $T_{\rm max}$ is a bound on -the magnitudes of |txx/65536|, |txy/65536|, etc. - -The |aspect_bound*(gs_width+1)| bound on the components of the pen -transformation allows $T_{\rm max}$ to be at most |2*aspect_bound|. - -@<Tweak the transformation parameters so the transformation is nonsingular@>= -det=mp_take_scaled(mp, txx,tyy) - mp_take_scaled(mp, txy,tyx); -d1=4*aspect_bound+1; -if ( abs(det)<d1 ) { - if ( det>=0 ) { d1=d1-det; s=1; } - else { d1=-d1-det; s=-1; }; - d1=d1*unity; - if ( abs(txx)+abs(tyy)>=abs(txy)+abs(tyy) ) { - if ( abs(txx)>abs(tyy) ) tyy=tyy+(d1+s*abs(txx)) / txx; - else txx=txx+(d1+s*abs(tyy)) / tyy; - } else { - if ( abs(txy)>abs(tyx) ) tyx=tyx+(d1+s*abs(txy)) / txy; - else txy=txy+(d1+s*abs(tyx)) / tyx; - } -} - -@ Here is a simple routine that just fills a cycle. - -@<Declarations@>= -void mp_gr_ps_fill_out (MP mp, mp_knot *p); - -@ @c -void mp_gr_ps_fill_out (MP mp, mp_knot *p) { /* fill cyclic path~|p| */ - mp_gr_ps_path_out(mp, p); - mp_ps_print_cmd(mp, " fill"," F"); - mp_ps_print_ln(mp); -} - -@ A text node may specify an arbitrary transformation but the usual case -involves only shifting, scaling, and occasionally rotation. The purpose -of |choose_scale| is to select a scale factor so that the remaining -transformation is as ``nice'' as possible. The definition of ``nice'' -is somewhat arbitrary but shifting and $90^\circ$ rotation are especially -nice because they work out well for bitmap fonts. The code here selects -a scale factor equal to $1/\sqrt2$ times the Frobenius norm of the -non-shifting part of the transformation matrix. It is careful to avoid -additions that might cause undetected overflow. - -@<Declarations@>= -scaled mp_gr_choose_scale (MP mp, mp_graphic_object *p) ; - -@ @c scaled mp_gr_choose_scale (MP mp, mp_graphic_object *p) { - /* |p| should point to a text node */ - scaled a,b,c,d,ad,bc; /* temporary values */ - a=gr_txx_val(p); - b=gr_txy_val(p); - c=gr_tyx_val(p); - d=gr_tyy_val(p); - if ( a<0 ) negate(a); - if ( b<0 ) negate(b); - if ( c<0 ) negate(c); - if ( d<0 ) negate(d); - ad=half(a-d); - bc=half(b-c); - return mp_pyth_add(mp, mp_pyth_add(mp, d+ad,ad), mp_pyth_add(mp, c+bc,bc)); -} - -@ The potential overflow here is caused by the fact the returned value -has to fit in a |name_type|, which is a quarterword. - -@d fscale_tolerance 65 /* that's $.001\times2^{16}$ */ - -@<Declarations@>= -quarterword mp_size_index (MP mp, font_number f, scaled s) ; - -@ @c -quarterword mp_size_index (MP mp, font_number f, scaled s) { - pointer p,q; /* the previous and current font size nodes */ - quarterword i; /* the size index for |q| */ - q=mp->font_sizes[f]; - i=0; - while ( q!=null ) { - if ( abs(s-sc_factor(q))<=fscale_tolerance ) - return i; - else - { p=q; q=link(q); incr(i); }; - if ( i==max_quarterword ) - mp_overflow(mp, "sizes per font",max_quarterword); -@:MetaPost capacity exceeded sizes per font}{\quad sizes per font@> - } - q=mp_get_node(mp, font_size_size); - sc_factor(q)=s; - if ( i==0 ) mp->font_sizes[f]=q; else link(p)=q; - return i; -} - -@ @<Declarations@>= -scaled mp_indexed_size (MP mp,font_number f, quarterword j); - -@ @c -scaled mp_indexed_size (MP mp,font_number f, quarterword j) { - pointer p; /* a font size node */ - quarterword i; /* the size index for |p| */ - p=mp->font_sizes[f]; - i=0; - if ( p==null ) mp_confusion(mp, "size"); - while ( (i!=j) ) { - incr(i); p=link(p); - if ( p==null ) mp_confusion(mp, "size"); - } - return sc_factor(p); -} - -@ @<Declarations@>= -void mp_clear_sizes (MP mp) ; - -@ @c void mp_clear_sizes (MP mp) { - font_number f; /* the font whose size list is being cleared */ - pointer p; /* current font size nodes */ - for (f=null_font+1;f<=mp->last_fnum;f++) { - while ( mp->font_sizes[f]!=null ) { - p=mp->font_sizes[f]; - mp->font_sizes[f]=link(p); - mp_free_node(mp, p,font_size_size); - } - } -} - -@ A text node may specify an arbitrary transformation but the usual case -involves only shifting, scaling, and occasionally rotation. The purpose -of |choose_scale| is to select a scale factor so that the remaining -transformation is as ``nice'' as possible. The definition of ``nice'' -is somewhat arbitrary but shifting and $90^\circ$ rotation are especially -nice because they work out well for bitmap fonts. The code here selects -a scale factor equal to $1/\sqrt2$ times the Frobenius norm of the -non-shifting part of the transformation matrix. It is careful to avoid -additions that might cause undetected overflow. - -@<Declare the \ps\ output procedures@>= -scaled mp_choose_scale (MP mp, mp_graphic_object *p) ; - -@ @c scaled mp_choose_scale (MP mp, mp_graphic_object *p) { - /* |p| should point to a text node */ - scaled a,b,c,d,ad,bc; /* temporary values */ - a=gr_txx_val(p); - b=gr_txy_val(p); - c=gr_tyx_val(p); - d=gr_tyy_val(p); - if ( (a<0) ) negate(a); - if ( (b<0) ) negate(b); - if ( (c<0) ) negate(c); - if ( (d<0) ) negate(d); - ad=half(a-d); - bc=half(b-c); - return mp_pyth_add(mp, mp_pyth_add(mp, d+ad,ad), mp_pyth_add(mp, c+bc,bc)); -} - -@ There may be many sizes of one font and we need to keep track of the -characters used for each size. This is done by keeping a linked list of -sizes for each font with a counter in each text node giving the appropriate -position in the size list for its font. - -@d font_size_size 2 /* size of a font size node */ - - -@ @<Declarations@>= -void mp_apply_mark_string_chars(MP mp, mp_edge_object *h, int next_size); - -@ @c -void mp_apply_mark_string_chars(MP mp, mp_edge_object *h, int next_size) { - mp_graphic_object * p; - p=h->body; - while ( p!= NULL ) { - if ( gr_type(p)==mp_text_code ) { - if ( gr_font_n(p)!=null_font ) { - if ( gr_name_type(p)==next_size ) - mp_mark_string_chars(mp, gr_font_n(p),gr_text_p(p)); - } - } - p=gr_link(p); - } -} - -@ @<Unmark all marked characters@>= -for (f=null_font+1;f<=mp->last_fnum;f++) { - if ( mp->font_sizes[f]!=null ) { - mp_unmark_font(mp, f); - mp->font_sizes[f]=null; - } -} - -@ @<Scan all the text nodes and mark the used ...@>= -p=hh->body; -while ( p!=null ) { - if ( gr_type(p)==mp_text_code ) { - f = gr_font_n(p); - if (f!=null_font ) { - switch (prologues) { - case 2: - case 3: - mp->font_sizes[f] = mp_void; - mp_mark_string_chars(mp, f, gr_text_p(p)); - if (mp_has_fm_entry(mp,f,NULL) ) { - if (mp->font_enc_name[f]==NULL ) - mp->font_enc_name[f] = mp_fm_encoding_name(mp,f); - mp->font_ps_name[f] = mp_fm_font_name(mp,f); - } - break; - case 1: - mp->font_sizes[f]=mp_void; - break; - default: - gr_name_type(p)=mp_size_index(mp, f,mp_choose_scale(mp, p)); - if ( gr_name_type(p)==0 ) - mp_mark_string_chars(mp, f, gr_text_p(p)); - } - } - } - p=gr_link(p); -} - - -@ -@d pen_is_elliptical(A) ((A)==gr_next_knot((A))) - -@<Exported function headers@>= -void mp_gr_ship_out (mp_edge_object *hh, int prologues, int procset) ; - -@ @c -void mp_gr_ship_out (mp_edge_object *hh, int prologues, int procset) { - mp_graphic_object *p; - scaled ds,scf; /* design size and scale factor for a text node */ - font_number f; /* for loops over fonts while (un)marking characters */ - boolean transformed; /* is the coordinate system being transformed? */ - MP mp = hh->_parent; - if (mp->history >= mp_fatal_error_stop ) return; - if (prologues<0) - prologues = (mp->internal[mp_prologues]>>16); - if (procset<0) - procset = (mp->internal[mp_procset]>>16); - mp_open_output_file(mp); - mp_print_initial_comment(mp, hh, prologues); - p = hh->body; - @<Unmark all marked characters@>; - if ( prologues==2 || prologues==3 ) { - mp_reload_encodings(mp); - } - @<Scan all the text nodes and mark the used characters@>; - if ( prologues==2 || prologues==3 ) { - mp_print_improved_prologue(mp, hh, prologues, procset); - } else { - mp_print_prologue(mp, hh, prologues, procset); - } - mp_gs_unknown_graphics_state(mp, 0); - p = hh->body; - while ( p!=NULL ) { - if ( gr_has_color(p) ) { - @<Write |pre_script| of |p|@>; - } - mp_gr_fix_graphics_state(mp, p); - switch (gr_type(p)) { - case mp_fill_code: - if ( gr_pen_p((mp_fill_object *)p)==NULL ) { - mp_gr_ps_fill_out(mp, gr_path_p((mp_fill_object *)p)); - } else if ( pen_is_elliptical(gr_pen_p((mp_fill_object *)p)) ) { - mp_gr_stroke_ellipse(mp, p,true); - } else { - mp_gr_ps_fill_out(mp, gr_path_p((mp_fill_object *)p)); - mp_gr_ps_fill_out(mp, gr_htap_p(p)); - } - if ( gr_post_script((mp_fill_object *)p)!=NULL ) { - mp_ps_print_nl (mp, gr_post_script((mp_fill_object *)p)); - mp_ps_print_ln(mp); - } - break; - case mp_stroked_code: - if ( pen_is_elliptical(gr_pen_p((mp_stroked_object *)p)) ) - mp_gr_stroke_ellipse(mp, p,false); - else { - mp_gr_ps_fill_out(mp, gr_path_p((mp_stroked_object *)p)); - } - if ( gr_post_script((mp_stroked_object *)p)!=NULL ) { - mp_ps_print_nl (mp, gr_post_script((mp_stroked_object *)p)); - mp_ps_print_ln(mp); - } - break; - case mp_text_code: - if ( (gr_font_n(p)!=null_font) && (strlen(gr_text_p(p))>0) ) { - if ( prologues>0 ) - scf=mp_gr_choose_scale(mp, p); - else - scf=mp_indexed_size(mp, gr_font_n(p), gr_name_type(p)); - @<Shift or transform as necessary before outputting text node~|p| at scale - factor~|scf|; set |transformed:=true| if the original transformation must - be restored@>; - mp_ps_string_out(mp, gr_text_p(p)); - mp_ps_name_out(mp, mp->font_name[gr_font_n(p)],false); - @<Print the size information and \ps\ commands for text node~|p|@>; - mp_ps_print_ln(mp); - } - if ( gr_post_script((mp_text_object *)p)!=NULL ) { - mp_ps_print_nl (mp, gr_post_script((mp_text_object *)p)); mp_ps_print_ln(mp); - } - break; - case mp_start_clip_code: - mp_ps_print_nl(mp, ""); mp_ps_print_cmd(mp, "gsave ","q "); - mp_gr_ps_path_out(mp, gr_path_p((mp_clip_object *)p)); - mp_ps_print_cmd(mp, " clip"," W"); - mp_ps_print_ln(mp); - if ( mp->internal[mp_restore_clip_color]>0 ) - mp_gs_unknown_graphics_state(mp, 1); - break; - case mp_stop_clip_code: - mp_ps_print_nl(mp, ""); mp_ps_print_cmd(mp, "grestore","Q"); - mp_ps_print_ln(mp); - if ( mp->internal[mp_restore_clip_color]>0 ) - mp_gs_unknown_graphics_state(mp, 2); - else - mp_gs_unknown_graphics_state(mp, -1); - break; - case mp_start_bounds_code: - case mp_stop_bounds_code: - break; - case mp_special_code: - { - mp_special_object *ps = (mp_special_object *)p; - mp_ps_print_nl (mp, gr_pre_script(ps)); - mp_ps_print_ln (mp); - } - break; - } /* all cases are enumerated */ - p=gr_link(p); - } - mp_ps_print_cmd(mp, "showpage","P"); mp_ps_print_ln(mp); - mp_ps_print(mp, "%%EOF"); mp_ps_print_ln(mp); - (mp->close_file)(mp,mp->ps_file); - if ( prologues<=0 ) - mp_clear_sizes(mp); -} - -@ -@d do_write_prescript(a,b) { - if ( (gr_pre_script((b *)a))!=NULL ) { - mp_ps_print_nl (mp, gr_pre_script((b *)a)); - mp_ps_print_ln(mp); - } -} - -@<Write |pre_script| of |p|@>= -{ - if (gr_type(p)==mp_fill_code) { do_write_prescript(p,mp_fill_object); } - else if (gr_type(p)==mp_stroked_code) { do_write_prescript(p,mp_stroked_object); } - else if (gr_type(p)==mp_text_code) { do_write_prescript(p,mp_text_object); } -} - -@ The envelope of a cyclic path~|q| could be computed by calling -|make_envelope| once for |q| and once for its reversal. We don't do this -because it would fail color regions that are covered by the pen regardless -of where it is placed on~|q|. - -@<Break the cycle and set |t:=1| if path |q| is cyclic@>= -if ( gr_left_type(q)!=mp_endpoint ) { - gr_left_type(mp_gr_insert_knot(mp, q,gr_x_coord(q),gr_y_coord(q)))=mp_endpoint; - gr_right_type(q)=mp_endpoint; - q=gr_next_knot(q); - t=1; -} - -@ @<Print the size information and \ps\ commands for text node~|p|@>= -ps_room(18); -mp_ps_print_char(mp, ' '); -ds=(mp->font_dsize[gr_font_n(p)]+8) / 16; -mp_ps_print_scaled(mp, mp_take_scaled(mp, ds,scf)); -mp_ps_print(mp, " fshow"); -if ( transformed ) - mp_ps_print_cmd(mp, " grestore"," Q") - - - -@ @<Shift or transform as necessary before outputting text node~|p| at...@>= -transformed=(gr_txx_val(p)!=scf)||(gr_tyy_val(p)!=scf)|| - (gr_txy_val(p)!=0)||(gr_tyx_val(p)!=0); -if ( transformed ) { - mp_ps_print_cmd(mp, "gsave [", "q ["); - mp_ps_pair_out(mp, mp_make_scaled(mp, gr_txx_val(p),scf), - mp_make_scaled(mp, gr_tyx_val(p),scf)); - mp_ps_pair_out(mp, mp_make_scaled(mp, gr_txy_val(p),scf), - mp_make_scaled(mp, gr_tyy_val(p),scf)); - mp_ps_pair_out(mp, gr_tx_val(p),gr_ty_val(p)); - mp_ps_print_cmd(mp, "] concat 0 0 moveto","] t 0 0 m"); -} else { - mp_ps_pair_out(mp, gr_tx_val(p),gr_ty_val(p)); - mp_ps_print_cmd(mp, "moveto","m"); -} -mp_ps_print_ln(mp) - - -@ @<Exported function headers@>= -void mp_gr_toss_objects ( mp_edge_object *hh) ; -void mp_gr_toss_object (mp_graphic_object *p) ; - -@ @c -void mp_gr_toss_object (mp_graphic_object *p) { - mp_fill_object *tf; - mp_stroked_object *ts; - mp_text_object *tt; - switch (gr_type(p)) { - case mp_fill_code: - tf = (mp_fill_object *)p; - mp_xfree(gr_pre_script(tf)); - mp_xfree(gr_post_script(tf)); - mp_gr_toss_knot_list(mp,gr_pen_p(tf)); - mp_gr_toss_knot_list(mp,gr_path_p(tf)); - mp_gr_toss_knot_list(mp,gr_htap_p(p)); - break; - case mp_stroked_code: - ts = (mp_stroked_object *)p; - mp_xfree(gr_pre_script(ts)); - mp_xfree(gr_post_script(ts)); - mp_gr_toss_knot_list(mp,gr_pen_p(ts)); - mp_gr_toss_knot_list(mp,gr_path_p(ts)); - if (gr_dash_p(p)!=NULL) - mp_gr_toss_dashes (mp,gr_dash_p(p)); - break; - case mp_text_code: - tt = (mp_text_object *)p; - mp_xfree(gr_pre_script(tt)); - mp_xfree(gr_post_script(tt)); - mp_xfree(gr_text_p(p)); - mp_xfree(gr_font_name(p)); - break; - case mp_start_clip_code: - mp_gr_toss_knot_list(mp,gr_path_p((mp_clip_object *)p)); - break; - case mp_start_bounds_code: - mp_gr_toss_knot_list(mp,gr_path_p((mp_bounds_object *)p)); - break; - case mp_stop_clip_code: - case mp_stop_bounds_code: - break; - case mp_special_code: - mp_xfree(gr_pre_script((mp_special_object *)p)); - break; - } /* all cases are enumerated */ - mp_xfree(p); -} - - -@ @c -void mp_gr_toss_objects (mp_edge_object *hh) { - mp_graphic_object *p, *q; - p = hh->body; - while ( p!=NULL ) { - q = gr_link(p); - mp_gr_toss_object(p); - p=q; - } - mp_xfree(hh); -} - -@ @<Exported function headers@>= -mp_graphic_object *mp_gr_copy_object (MP mp, mp_graphic_object *p) ; - -@ @c -mp_graphic_object * -mp_gr_copy_object (MP mp, mp_graphic_object *p) { - mp_fill_object *tf; - mp_stroked_object *ts; - mp_text_object *tt; - mp_clip_object *tc; - mp_bounds_object *tb; - mp_special_object *tp; - mp_graphic_object *q = NULL; - switch (gr_type(p)) { - case mp_fill_code: - tf = (mp_fill_object *)mp_new_graphic_object(mp, mp_fill_code); - gr_pre_script(tf) = mp_xstrdup(mp, gr_pre_script((mp_fill_object *)p)); - gr_post_script(tf) = mp_xstrdup(mp, gr_post_script((mp_fill_object *)p)); - gr_path_p(tf) = mp_gr_copy_path(mp,gr_path_p((mp_fill_object *)p)); - gr_htap_p(tf) = mp_gr_copy_path(mp,gr_htap_p(p)); - gr_pen_p(tf) = mp_gr_copy_path(mp,gr_pen_p((mp_fill_object *)p)); - q = (mp_graphic_object *)tf; - break; - case mp_stroked_code: - ts = (mp_stroked_object *)mp_new_graphic_object(mp, mp_stroked_code); - gr_pre_script(ts) = mp_xstrdup(mp, gr_pre_script((mp_stroked_object *)p)); - gr_post_script(ts) = mp_xstrdup(mp, gr_post_script((mp_stroked_object *)p)); - gr_path_p(ts) = mp_gr_copy_path(mp,gr_path_p((mp_stroked_object *)p)); - gr_pen_p(ts) = mp_gr_copy_path(mp,gr_pen_p((mp_stroked_object *)p)); - gr_dash_p(ts) = mp_gr_copy_dashes(mp,gr_dash_p(p)); - q = (mp_graphic_object *)ts; - break; - case mp_text_code: - tt = (mp_text_object *)mp_new_graphic_object(mp, mp_text_code); - gr_pre_script(tt) = mp_xstrdup(mp, gr_pre_script((mp_text_object *)p)); - gr_post_script(tt) = mp_xstrdup(mp, gr_post_script((mp_text_object *)p)); - gr_text_p(tt) = mp_xstrdup(mp, gr_text_p(p)); - gr_font_name(tt) = mp_xstrdup(mp, gr_font_name(p)); - q = (mp_graphic_object *)tt; - break; - case mp_start_clip_code: - tc = (mp_clip_object *)mp_new_graphic_object(mp, mp_start_clip_code); - gr_path_p(tc) = mp_gr_copy_path(mp,gr_path_p((mp_clip_object *)p)); - q = (mp_graphic_object *)tc; - break; - case mp_start_bounds_code: - tb = (mp_bounds_object *)mp_new_graphic_object(mp, mp_start_bounds_code); - gr_path_p(tb) = mp_gr_copy_path(mp,gr_path_p((mp_bounds_object *)p)); - q = (mp_graphic_object *)tb; - break; - case mp_special_code: - tp = (mp_special_object *)mp_new_graphic_object(mp, mp_special_code); - gr_pre_script(tp) = mp_xstrdup(mp, gr_pre_script((mp_special_object *)p)); - q = (mp_graphic_object *)tp; - break; - case mp_stop_clip_code: - q = mp_new_graphic_object(mp, mp_stop_clip_code); - break; - case mp_stop_bounds_code: - q = mp_new_graphic_object(mp, mp_stop_bounds_code); - break; - } /* all cases are enumerated */ - return q; -} - |