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: */