summaryrefslogtreecommitdiff
path: root/dviware/dvitops/font.c
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /dviware/dvitops/font.c
Initial commit
Diffstat (limited to 'dviware/dvitops/font.c')
-rw-r--r--dviware/dvitops/font.c629
1 files changed, 629 insertions, 0 deletions
diff --git a/dviware/dvitops/font.c b/dviware/dvitops/font.c
new file mode 100644
index 0000000000..c0d9498cfc
--- /dev/null
+++ b/dviware/dvitops/font.c
@@ -0,0 +1,629 @@
+static char rcsid[] = "$Header: /usr/jjc/dvitops/RCS/font.c,v 1.6 90/03/12 18:47:02 jjc Exp $";
+
+#include "dvitops.h"
+
+#define MAXFONTSIZE (20*1024) /*maximum printer VM that a bitmap font can use*/
+
+#ifdef PROTO
+static void load_tfm_file(int f);
+static void scale_font(int i, FILE *fp);
+static void find_font(char *name, FILE *fp);
+#if 0
+static void choose_ps_prolog(void);
+#endif
+static void read_f_directory(void);
+static int compare(char *p1, char *p2);
+static void choose_mags(void);
+static int order_mag(char *p1, char *p2);
+static void emit_encodings(FILE *psfp);
+#else
+static void load_tfm_file();
+static void scale_font();
+static void find_font();
+#if 0
+static void choose_ps_prolog();
+#endif
+static void read_f_directory();
+static int compare();
+static void choose_mags();
+static int order_mag();
+static void emit_encodings();
+#endif
+
+
+/* int nprolog_fonts = 2; */
+#define MAGS_MAX 50
+
+static struct postscript_f_list *postscript_fonts = NULL;
+
+static struct f_info {
+ int no;
+ enum { BLANK, BITMAP, POSTSCRIPT, BITMAP_PROLOG } type;
+ int mag;
+ int same_font; /* index of next font that is the same */
+ long doc_chars; /* sum over each page of the number of distinct
+ characters from the font occurring on that page */
+ integer at_size;
+ integer checksum;
+ long usage_index; /* the higher this is, the better it is to download
+ it in the prologue rather than on each page */
+ int npages; /* how many pages is it used on */
+ char *texname;
+ char *psname; /* the postscript name */
+ char *encoding; /* name of the encoding vector */
+ struct postscript_f_list *ps;
+ char used[MAXCHARS]; /* which characters are used in the document */
+ integer width[MAXCHARS];
+ integer rounded_width[MAXCHARS];
+ char *filename;
+} *font[MAXFONTS];
+
+
+
+static int target_mag;
+
+/* returns -1, 0, or 1 according as *p1 is better, equally good,
+ or worse as a choice of magnification when the desired
+ magnification is target_mag
+*/
+
+static int order_mag(p1, p2)
+char *p1, *p2;
+{
+ int n1 = *(int *)p1;
+ int n2 = *(int *)p2;
+ int d1 = abs(target_mag - n1);
+ int d2 = abs(target_mag - n2);
+ if (d2 < d1 && d2 <= 2)
+ return 1;
+ if (d1 < d2 && d1 <= 2)
+ return -1;
+ if (d1 == d2)
+ return 0;
+ if (n1 > n2)
+ return -1;
+ return 1;
+}
+
+
+
+static void choose_mags()
+{
+ int i;
+ int nmags;
+ char *p;
+ static int mag[MAGS_MAX] = {TEXMAGS,0};
+ for (i = 0; i < MAGS_MAX && mag[i] != 0; i++)
+ ;
+ nmags = i;
+ if ((p = getenv("TEXMAGS")) != NULL) {
+ static char sep_string[] = { AREA_LIST_SEP, ',', ':', ' ', '\t', '\0' }; /* be tolerant */
+ for (i = 0,p = strtok(p, sep_string); p != NULL && i < MAGS_MAX; p = strtok((char *)NULL, sep_string))
+ if ((mag[i] = atoi(p)) > 0)
+ ++i;
+ nmags = i;
+ }
+ for (i = 0; i < MAXFONTS; i++)
+ if (font[i] != NULL && font[i]->type != POSTSCRIPT) {
+ int j;
+ target_mag = font[i]->mag;
+ qsort((char *)mag, nmags, sizeof(int), order_mag);
+ for (j = 0; j < nmags; j++) {
+ char *p = find_pk_file(font[i]->texname, mag[j]);
+ if (p != NULL) {
+ char buf[FILENAME_MAX + 20];
+ if (abs(mag[j] - font[i]->mag) > 2)
+ message(WARNING,
+ "no exact font for %s at %d dpi",
+ font[i]->texname, font[i]->mag);
+ font[i]->mag = mag[j];
+ font[i]->type = BITMAP;
+ sprintf(buf,"%s-%d", font[i]->texname, font[i]->mag);
+ font[i]->psname = strsave(buf);
+ font[i]->filename = strsave(p);
+ break;
+ }
+ }
+ }
+}
+
+
+static void read_f_directory()
+{
+ char buf[512];
+ FILE *fp;
+ int i, j;
+ if ((fp = xfopen("dvitops.fnt", FALSE, texinputs, (char *)NULL)) == NULL)
+ message(FATAL_ERROR, "can't find dvitops.fnt");
+ while (fgets(buf, 512, fp) != NULL) {
+ char *ptr, *name, *psname;
+ char *encoding = NULL;
+ if ((ptr = strchr(buf, '%')) != NULL)
+ *ptr = '\0';
+ ptr = buf;
+ while (isspace(*ptr))
+ ptr++;
+ if (*ptr == '\0')
+ continue;
+ if ((name = strtok(ptr, " \t\n\r")) == NULL)
+ continue;
+ if ((psname = strtok((char *)NULL, " \t\n\r")) == NULL)
+ psname = name;
+ else
+ encoding = strtok((char *)NULL, "\t\n\r");
+ for (i = 0; i < MAXFONTS; i++)
+ if (font[i] != NULL && strcmp(font[i]->texname, name) == 0) {
+ font[i]->psname = strsave(psname);
+ font[i]->ps = add_postscript_font(psname);
+ font[i]->encoding = strsave(encoding);
+ font[i]->type = POSTSCRIPT;
+ }
+ }
+ choose_mags();
+ for (i = 0; i < MAXFONTS; i++)
+ if (font[i] != NULL && font[i]->type == BLANK)
+ message(WARNING,
+ "no font directory entry for %s: using blank space instead\n",
+ font[i]->texname);
+ fclose(fp);
+ for (i = 0; i < MAXFONTS; i++)
+ if (font[i] != NULL && font[i]->type == POSTSCRIPT)
+ for (j = i + 1; j < MAXFONTS; j++)
+ if (font[j] != NULL && font[j]->type == POSTSCRIPT
+ && strcmp(font[i]->psname, font[j]->psname) == 0) {
+ font[i]->same_font = j;
+ break;
+ }
+}
+
+
+static int compare(p1, p2)
+char *p1;
+char *p2;
+{
+ return (int)((*(struct f_info **)p2)->usage_index
+ - (*(struct f_info **)p1)->usage_index);
+}
+
+void f_prologue(fp)
+FILE *fp;
+{
+ struct f_info *p[MAXFONTS];
+ int i, j;
+ integer n;
+ struct postscript_f_list *q = postscript_fonts;
+#if 0
+ choose_ps_prolog();
+#endif
+ emit_encodings(fp);
+ for (q = postscript_fonts; q != NULL; q = q->next)
+ if (q->file != NULL && q->in_prolog) {
+ emit_ps_font(q->s, fp);
+ find_font(q->s, fp);
+ }
+ /* determine the most used bitmapped fonts */
+ for (i = j = 0; i < MAXFONTS; i++) {
+ if (font[i] != NULL && font[i]->type == BITMAP)
+ p[j++] = font[i];
+ if (font[i] != NULL)
+ font[i]->no = (unsigned char)i;
+ }
+ for (i = 0; i < j; i++) {
+ char *ptr = p[i]->used;
+ int k;
+ int nused = 0;
+ for (k = 0; k < MAXCHARS; k++)
+ if (ptr[k])
+ ++nused;
+ p[i]->usage_index = p[i]->doc_chars - nused;
+ }
+
+ qsort((char *)p, j, sizeof(struct f_info *), compare);
+ n = 0;
+ /* download and scale the most used bitmapped fonts */
+ for (i = 0; i < j && p[i]->usage_index > 0
+ && n + MAXFONTSIZE < f_memory; i++) {
+ int k = p[i]->no;
+ if (p[i]->type != BITMAP)
+ continue;
+ if (!load_pk_font(k, p[i]->filename,p[i]->used,p[i]->at_size,
+ p[i]->checksum, p[i]->width, p[i]->rounded_width)) {
+ p[i]->type = BLANK;
+ continue;
+ }
+ n += emit_pk_font(k, p[i]->psname, p[i]->used, fp);
+ free_pk_font(k);
+ p[i]->type = BITMAP_PROLOG;
+ find_font(p[i]->psname, fp);
+ scale_font(k, fp);
+ }
+ /* Load the pk files for the bitmapped fonts
+ not downloaded in the prologue;
+ load the tfm files for the bitmapped fonts for which no pk file
+ could be found, and for the PostScript files */
+ for (i = 0; i < MAXFONTS; i++) {
+ if (font[i] == NULL)
+ continue;
+ if (font[i]->type == BITMAP) {
+ if (!load_pk_font(i, font[i]->filename,
+ font[i]->used, font[i]->at_size,
+ font[i]->checksum, font[i]->width, font[i]->rounded_width))
+ font[i]->type = BLANK;
+ }
+ if (font[i]->type == BLANK || font[i]->type == POSTSCRIPT) {
+ load_tfm_file(i);
+ memcpy((char *)font[i]->rounded_width, (char *)font[i]->width,
+ MAXCHARS*sizeof(integer));
+ }
+ }
+ for (i = 0; i < MAXFONTS; i++)
+ if (font[i] != NULL && font[i]->type == POSTSCRIPT
+ && font[i]->ps->in_prolog == TRUE)
+ scale_font(i, fp);
+}
+
+static void scale_font(i, fp)
+int i;
+FILE *fp;
+{
+ fprintf(fp, "/F%d _%s", i, font[i]->psname);
+ if (font[i]->encoding != NULL)
+ fprintf(fp, "_%s", font[i]->encoding);
+ putc(' ', fp);
+ put_dim((long)(font[i]->at_size), fp);
+ fputs(" SF\n", fp);
+}
+
+
+static void find_font(name, fp)
+char *name;
+FILE *fp;
+{
+ int i;
+ fprintf(fp, "/_%s /%s FF\n", name, name);
+ /* reencode all fonts based on it */
+ for (i = 0; i < MAXFONTS; i++)
+ if (font[i] != 0 && font[i]->encoding != 0
+ && strcmp(font[i]->psname, name) == 0) {
+ int j;
+ for (j = 0; j < i; j++)
+ if (font[j] != 0 && font[j]->encoding != 0
+ && strcmp(font[i]->encoding, font[j]->encoding) == 0
+ && strcmp(font[j]->psname, name) == 0)
+ break;
+ if (j == i)
+ /* newdictname newfontname encodingvector basefontdict */
+ fprintf(fp, "/_%s_%s /%s_%s %s_encoding _%s RE\n",
+ name, font[i]->encoding,
+ name, font[i]->encoding,
+ font[i]->encoding,
+ name);
+ }
+}
+
+
+/* we might use the area argument in the future */
+void f_def(fontno, name, area, checksum, at_size, design_size, magnification)
+integer fontno;
+char *name, *area;
+integer checksum, at_size, design_size;
+int magnification;
+{
+ int i;
+ if (fontno < 0 || fontno > MAXFONTS)
+ message(FATAL_ERROR, "too many fonts");
+ i = (int)fontno;
+ if (font[i] != NULL)
+ cant_happen();
+ if ((font[i] = (struct f_info *)
+ calloc(1, sizeof(struct f_info))) == NULL)
+ out_of_memory();
+ font[i]->texname = strsave(name);
+ font[i]->checksum = checksum;
+ font[i]->at_size = at_size;
+ font[i]->mag = (int)(.5 +
+ ((double)magnification*(double)at_size*(double)dpi)
+ /(design_size*1000.0));
+ font[i]->same_font = EOF;
+ font[i]->npages = 0;
+ if ((page_used[i] = (char *)calloc(MAXCHARS, 1)) == NULL)
+ out_of_memory();
+}
+
+void store_page_usage()
+{
+ int i, j;
+ for (i = 0; i < MAXFONTS; i++) {
+ char *ptr = page_used[i], *q = font[i]->used;
+ int used = FALSE;
+ if (ptr != NULL)
+ for (j = 0; j < MAXCHARS; j++)
+ if (ptr[j]) {
+ q[j] = TRUE;
+ font[i]->doc_chars++;
+ ptr[j] = FALSE;
+ used = TRUE;
+ }
+ if (used)
+ (font[i]->npages)++;
+ }
+}
+
+
+
+char *strsave(s)
+char *s;
+{
+ char *p;
+ if (s == NULL)
+ return NULL;
+ if ((p = (char *)malloc(strlen(s) + 1)) == NULL)
+ out_of_memory();
+ strcpy(p, s);
+ return p;
+}
+
+/* this code is borrowed from sections 571, 572 of TeX the Program */
+
+integer scale(x, z)
+integer x, z;
+{
+ integer sw;
+ integer a, b, c, d;
+ integer alpha, beta;
+ alpha = 16*z; beta = 16;
+ while (z >= 040000000L) {
+ z /= 2; beta /= 2;
+ }
+ d = x & 255;
+ c = (x >> 8) & 255;
+ b = (x >> 16) & 255;
+ a = (x >> 24) & 255;
+ sw = (((((d * z) / 0400) + (c * z)) / 0400) + (b * z)) / beta;
+ if ( a == 255)
+ sw -= alpha;
+ else if (a != 0)
+ cant_happen();
+ return sw;
+}
+
+static void load_tfm_file(f)
+int f;
+{
+ int i;
+ int lh, bc, ec, nw;
+ integer ds, cs;
+ FILE *tfmfp;
+ unsigned char width_index[MAXCHARS];
+ integer width_table[MAXCHARS];
+ if ((tfmfp = xfopen(font[f]->texname, TRUE, texfonts, ".tfm")) == NULL)
+ message(FATAL_ERROR, "couldn't find tfm file for %s",
+ font[f]->texname);
+ (void)sread2(tfmfp);
+ lh = sread2(tfmfp);
+ bc = sread2(tfmfp);
+ ec = sread2(tfmfp);
+ nw = sread2(tfmfp);
+ fseek(tfmfp, 14L, 1);
+ cs = sread4(tfmfp);
+ if (cs != font[f]->checksum)
+ message(WARNING, "font %s: checksum in tfm file doesn't match",
+ font[f]->texname);
+ ds = sread4(tfmfp); /* not used at the moment */
+ lh -= 2;
+ fseek(tfmfp, (long)lh*4, 1);
+ for (i = 0; i < ec + 1 - bc; ++i) {
+ width_index[i] = uread1(tfmfp);
+ fseek(tfmfp, 3L, 1);
+ }
+ for (i = 0; i < nw; ++i)
+ width_table[i] = scale(sread4(tfmfp), font[f]->at_size);
+ fclose(tfmfp);
+/* Microsoft C 5.0's optimizer messes up this loop */
+ for (i = bc; i <= ec; i++)
+ font[f]->width[i] = width_table[width_index[i - bc]];
+}
+
+struct postscript_f_list *add_postscript_font(font)
+char *font;
+{
+ struct postscript_f_list *p;
+ for (p = postscript_fonts;p != NULL; p = p->next)
+ if (strcmp(font, p->s) == 0)
+ return p;
+ if ((p = (struct postscript_f_list *)malloc(
+ sizeof(struct postscript_f_list)+strlen(font))
+ ) == NULL)
+ out_of_memory();
+ strcpy(p->s, font);
+ p->next = postscript_fonts;
+ p->file = NULL;
+ p->in_prolog = FALSE;
+ p->nuses = 0;
+ postscript_fonts = p;
+ return p;
+}
+
+void f_comment(psfp)
+FILE *psfp;
+{
+ int i;
+ int cols;
+ struct postscript_f_list *p;
+ read_f_directory();
+ cols = fprintf(psfp, "%%%%DocumentFonts:");
+ for (i = 0; i < MAXFONTS; i++)
+ if (font[i] != NULL && font[i]->doc_chars > 0
+ && (font[i]->type == BITMAP || font[i]->type == BITMAP_PROLOG)) {
+ if (cols + strlen(font[i]->psname) > 70)
+ cols = fprintf(psfp, "\n%%%%+ %s", font[i]->psname);
+ else
+ cols += fprintf(psfp, " %s", font[i]->psname);
+ }
+ for (p = postscript_fonts; p != NULL; p = p->next) {
+ if (cols + strlen(p->s) > 70)
+ cols = fprintf(psfp, "\n%%%%+ %s",p->s) - 1;
+ else
+ cols += fprintf(psfp, " %s", p->s);
+ }
+ putc('\n', psfp);
+ cols = fprintf(psfp, "%%%%DocumentSuppliedFonts:");
+ for (i = 0; i < MAXFONTS; i++)
+ if (font[i] != NULL && font[i]->doc_chars > 0
+ && (font[i]->type == BITMAP || font[i]->type == BITMAP_PROLOG)) {
+ if (cols + strlen(font[i]->psname) > 70)
+ cols = fprintf(psfp, "\n%%%%+ %s", font[i]->psname);
+ else
+ cols += fprintf(psfp, " %s", font[i]->psname);
+ }
+ putc('\n', psfp);
+ cols = fprintf(psfp, "%%%%DocumentNeededFonts:");
+ for (p = postscript_fonts; p != NULL; p = p->next) {
+ if (cols + strlen(p->s) > 70)
+ cols = fprintf(psfp, "\n%%%%+ %s",p->s) - 1;
+ else
+ cols += fprintf(psfp, " %s", p->s);
+ }
+ putc('\n', psfp);
+}
+
+void f_emit(i, fp)
+int i;
+FILE *fp;
+{
+ if (font[i]->type == BITMAP) {
+ emit_pk_font(i, font[i]->psname, page_used[i], fp);
+ find_font(font[i]->psname, fp);
+ }
+ else if (font[i]->type == POSTSCRIPT && !font[i]->ps->in_prolog) {
+ emit_ps_font(font[i]->psname, fp);
+ find_font(font[i]->psname, fp);
+ }
+}
+
+void f_set(i, fp)
+int i;
+FILE *fp;
+{
+ if (font[i]->type == BITMAP ||
+ (font[i]->type == POSTSCRIPT && !font[i]->ps->in_prolog))
+ scale_font(i, fp);
+ memset(page_used[i], '\0', MAXCHARS);
+ fprintf(fp, "F%d F\n", i);
+}
+
+void emit_ps_font(font, psfp)
+char *font;
+FILE *psfp;
+{
+ fprintf(psfp, "%%%%IncludeFont: %s\n", font);
+}
+
+
+int f_is_blank(f)
+int f;
+{
+ return (font[f]->type == BLANK);
+}
+
+integer f_space(f)
+int f;
+{
+ return (font[f]->at_size/6);
+}
+
+
+integer f_width(f, c)
+int f;
+unsigned char c;
+{
+ return font[f]->width[c];
+}
+
+integer f_rounded_width(f, c)
+int f;
+unsigned char c;
+{
+ return font[f]->rounded_width[c];
+}
+
+int same_font(f)
+int f;
+{
+ return font[f] == NULL ? EOF : font[f]->same_font;
+}
+
+#if 0
+static void choose_ps_prolog()
+{
+ int i;
+ struct postscript_f_list *p, *s;
+ for (i = 0; i < MAXFONTS; ++i)
+ if (font[i] != NULL && font[i]->type == POSTSCRIPT)
+ font[i]->ps->nuses += font[i]->npages;
+ /* do a list insertion sort */
+ s = NULL;
+ p = postscript_fonts;
+ while (p != NULL) {
+ struct postscript_f_list *ss = s, *ssp = NULL, *temp;
+ while (ss != NULL && p->nuses < ss->nuses) {
+ ssp = ss;
+ ss = ss->next;
+ }
+ temp = p->next;
+ if (ssp == NULL) {
+ p->next = s;
+ s = p;
+ }
+ else {
+ ssp->next = p;
+ p->next = ss;
+ }
+ p = temp;
+ }
+ postscript_fonts = s;
+ for (p = postscript_fonts, i = 0; p != NULL && i < nprolog_fonts;
+ p = p->next, i++)
+ p->in_prolog = TRUE;
+}
+#endif
+
+static void emit_encodings(psfp)
+FILE *psfp;
+{
+ int i;
+ for (i = 0; i < MAXFONTS; i++)
+ if (font[i] != 0 && font[i]->encoding != NULL) {
+ int j;
+ for (j = 0; j < i; j++)
+ if (font[j] != 0 && font[j]->encoding != 0
+ && strcmp(font[j]->encoding, font[i]->encoding) == 0)
+ break;
+ if (j == i) {
+ char name[256];
+ FILE *fp = xfopen(font[i]->encoding, FALSE, texfonts, ".enc");
+ if (fp == NULL) {
+ message(FATAL_ERROR, "%s: no encoding file",
+ font[i]->encoding);
+ }
+ fprintf(psfp, "/%s_encoding [\n",
+ font[i]->encoding);
+ for (j = 0; j < 256 && fscanf(fp, "%s", name) == 1; j++)
+ fprintf(psfp, "/%s\n", name);
+ for (; j < 256; j++)
+ fputs("/.notdef\n", psfp);
+ fputs("] def\n", psfp);
+ }
+ }
+}
+
+/*
+Local Variables:
+tab-width: 4
+c-indent-level: 4
+c-continued-statement-offset: 4
+c-brace-offset: -4
+c-argdecl-indent: 0
+c-label-offset: -4
+End:
+*/