diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /dviware/dvitops/font.c |
Initial commit
Diffstat (limited to 'dviware/dvitops/font.c')
-rw-r--r-- | dviware/dvitops/font.c | 629 |
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: +*/ |