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/kyocera/kyofonts.c |
Initial commit
Diffstat (limited to 'dviware/kyocera/kyofonts.c')
-rw-r--r-- | dviware/kyocera/kyofonts.c | 668 |
1 files changed, 668 insertions, 0 deletions
diff --git a/dviware/kyocera/kyofonts.c b/dviware/kyocera/kyofonts.c new file mode 100644 index 0000000000..fb18b306aa --- /dev/null +++ b/dviware/kyocera/kyofonts.c @@ -0,0 +1,668 @@ +/* kyofonts.c: font module for dvi printing on Kyocera laser printers + * Adapted from the qmsfonts module from Massachusetts Institute of Technology + */ + +#include <stdio.h> +#include "util.h" +#include "fonts.h" +#include "findfile.h" +#include "kyo.h" +#include "preload.h" +#include <sys/stat.h> + +#define MAXDVIFONTS 256 /* Max number of fonts allowed in a DVI file*/ +#define MAXFNTDIR 16 /* Max number of dirs to look for fonts */ + +unsigned char *malloc(); +char *strcat(); +char *strcpy(); +char *strncpy(); +char *strncmp(); +char *strcmp(); + +long numerator,denominator,half_denominator,jobmag; + +long freewords = KYOMAXWORDS; /* free space on printer */ +FILE *kyo; /* output device */ +char *filter_name; /* the name of the calling prog */ +char *fntdirvec[MAXFNTDIR]; +int fntdirveclen; + +int nkyofonts; +struct kyofont *curfnt; /* ptr to current and last font */ +long timestamp; /* Timestamp for stamping kyo fonts */ +int nloaded; /* Number of fonts already loaded */ +char *loadfile = PRLOAD ; +char fontnums[MAXKYOFONTS]; + +#define PR_USED 0x0001 +#define PR_LOADED 0x0002 + +struct preload { + struct preload_info *pr_font; + short pr_info; +} loaded[MAXKYOFONTS]; + +/* The dvifont struct provides a (possible) many-to-one mapping + * because several DVI fonts can map to the same Kyocera font during font + * substitution. + */ +struct dvifont { + unsigned long df_num; /* DVI font number */ + struct kyofont *df_kyofont; /* Font which contains */ +} dvifonts[MAXDVIFONTS]; +int ndvifonts; + +long max(a,b) + long a,b; +{ + return((a>b)? a:b); +} + +long min(a,b) + long a,b; +{ + return((a<b)? a:b); +} + +/* called at the beginning of the driver program */ +f_init(printer,pgmnam,dirvec,dirveclen,num,den,mag,options) + FILE *printer; + char *pgmnam,*dirvec[]; + int dirveclen; + long num,den,mag; + unsigned long options; +{ + int i, n, loadf; + struct stat s; + struct preload_info *fnt; + + numerator = num; + denominator = den; + half_denominator = denominator / 2; + jobmag = mag; + fntdirveclen = min(MAXFNTDIR,dirveclen); + for (i = 0; i < fntdirveclen; i++) fntdirvec[i] = dirvec[i]; + ndvifonts = 0; + nkyofonts = 0; + timestamp = 0; + kyo = printer; + filter_name = pgmnam; + + /* Try to read the file with information about the + * fonts loaded in the Kyocera at this moment + * The preload file should exist and have a length + * that is a multiple of the length of a preload-record + * This to protect against corrupted preload information + * When no preload information is present or when it is corrupt + * dump an explicit DAF (delete all fonts) command + */ + if (((loadf = open(loadfile, 0)) >= 0) && + (stat(loadfile, &s) == 0) && + (s.st_size > 0) && + ((s.st_size % sizeof(struct preload_info)) == 0)) { + n = s.st_size / sizeof(struct preload_info); + debug("%d fonts were preloaded\n", n); + for (i=0; i<n; i++) { + if (!(loaded[nloaded].pr_font = fnt = + (struct preload_info *) malloc(sizeof(struct preload_info)))) + croak("malloc %d",sizeof(struct preload_info)); + loaded[nloaded++].pr_info = PR_LOADED; + if (read(loadf, fnt, sizeof(struct preload_info)) != + sizeof(struct preload_info)) { + nloaded--; + debug("Could read the info of only %d preloaded fonts\n", + nloaded); + break; + } + freewords -= fnt->pr_words_used; + fontnums[fnt->pr_kyonumber-KF_NUMBASE] = KF_USED; + debug("%s\n", fnt->pr_name); + } + close(loadf); + } else fprintf(kyo, "!R! DAF;EXIT;"); + debug("Free font memory %ld words\n",freewords); + /* Clear the preload file before going on + * So when the driver crashes, it will not leave the next jobs + * with incorrect preload information + */ + close(creat(loadfile, 0644)); +} + +/* Called at the end of the driver program. */ +f_term() +{ + int i, j, loadf; + struct kyofont *fnt; + struct kyochar *c; + struct preload_info font; + struct preload *pfnt; + + if ((loadf = creat(loadfile, 0644)) < 0) { + debug("Cannot create %s\n", loadfile); + return; + } + + /* Just copy back the information for fonts not used by this job */ + for (i=0; i<nloaded; i++) { + pfnt = &loaded[i]; + if (!(pfnt->pr_info & PR_USED) && + (pfnt->pr_info & PR_LOADED)) + write(loadf, pfnt->pr_font, sizeof(struct preload_info)); + } + + /* Write back the information about the fonts that are used by this job */ + for (i=0; i<nkyofonts; i++) { + fnt = kyofonts[i]; + if (fnt->kf_info & KF_LOADED) { + font.pr_kyonumber = fnt->kf_kyonumber; + strcpy(font.pr_name, fnt->kf_name); + font.pr_mag = fnt->kf_mag; + font.pr_words_used = fnt->kf_words_used; + font.pr_tfm_checksum = fnt->kf_tfm_checksum; + for (j=0; j<4; j++) font.pr_charvec[j] = 0; + for (j=0; j<MAXCHARS; j++) { + c = &(fnt->kf_char[j]); + if (c->kc_info & KC_LOADED) + font.pr_charvec[j/32] |= (1 << (j % 32)); + } + write(loadf, &font, sizeof(struct preload_info)); + } + } + debug( "Font memory left: %ld words\n", freewords); +} + +/* This routine provides for an independent numbering scheme + * for the fonts loaded into the Kyocera + * It returns the first free number + * Fonts are numbered starting at KF_NUMBASE + */ +short next_kyonumber() +{ + int i; + + for (i=0; i<MAXKYOFONTS; i++) + if (!fontnums[i]) { + fontnums[i] = KF_USED; + return(i+KF_NUMBASE); + } +} + +/* Look if font "name" is preloaded + * If it is return a pointer to the preload information + * Ohterwise return 0 + */ +struct preload * +preloaded(name, tfmchecksum, mag) +char *name; +long tfmchecksum; +{ + int i; + struct preload *pnt; + register struct preload_info *fnt; + + for (i=0; i<nloaded; i++) { + pnt = &loaded[i]; + fnt = pnt->pr_font; + /* The name, magnification and tfm-checksum should match */ + if ((pnt->pr_info & PR_LOADED) && + (strcmp(fnt->pr_name, name) == 0) && + (fnt->pr_mag == mag) && + (fnt->pr_tfm_checksum == tfmchecksum)) { + return(pnt); + } + } + return((struct preload *) 0); +} + +/* Try to locate the font "name" with the specified attributes + * in "area" + */ +struct kyofont * +find_kyofont(area,name,texmag,s,tfmchecksum) + char *area,*name; + long texmag,s,tfmchecksum; +{ + char fname[MAXNAMLEN],nname[128]; + int i,nmag; + int mag = (texmag * 3 + 1) / 2; + struct kyofont *fnt; + struct preload *pfnt; + struct preload_info *pnt; + + /* try to find a font file */ + if (!findfile(fntdirvec,fntdirveclen,area,name,mag,fname,nname,&nmag)) + croak("no font %s.%d",name,texmag); + + /* make a new kyocera font */ + if (nkyofonts >= MAXKYOFONTS) croak("too many kyo fonts"); + + if (!(kyofonts[nkyofonts++] = fnt = + (struct kyofont *) malloc(sizeof(struct kyofont)))) + croak("malloc %d",sizeof(struct kyofont)); + fnt->kf_mag = nmag; + fnt->kf_timestamp = 0; + fnt->kf_s = s; + fnt->kf_tfm_checksum = tfmchecksum; + strcpy(fnt->kf_name,nname); + strcpy(fnt->kf_filename,fname); + for (i=0; i<MAXCHARS; i++) + fnt->kf_char[i].kc_info = 0; + + if (pfnt = preloaded(nname, tfmchecksum,nmag)) { + pnt = pfnt->pr_font; + fnt->kf_kyonumber = pnt->pr_kyonumber; + fnt->kf_words_needed = 0; + fnt->kf_words_used = pnt->pr_words_used; + for (i=0; i<MAXCHARS; i++) + if (pnt->pr_charvec[i/32] & ( 1 << (i % 32))) + fnt->kf_char[i].kc_info = KC_LOADED; + fnt->kf_info = KF_FILE | KF_LOADED; + pfnt->pr_info |= PR_USED; + } else { + fnt->kf_kyonumber = next_kyonumber(); + fnt->kf_words_needed = KF_MIN; + fnt->kf_words_used = 0; + fnt->kf_info = KF_FILE; + } + return(fnt); +} + +/* Read the font information from the pxl file + * and remember that it is done + */ +getfontfromfile(fnt) + struct kyofont *fnt; +{ + char fname[MAXNAMLEN]; + FILE *f; + int i; + + readpxlfile(fnt,fnt->kf_filename); + fnt->kf_info &= ~KF_FILE; +} + +/* Calculate the number of words needed by symbol "c" + * for its pxl raster + */ +int char_words_needed(c) + struct kyochar *c; +{ + return(((c->kc_width + 15) / 16) * c->kc_height); +} + +/* Define a font. + * Can be called more than once for the same font. + */ +f_define_font(num,options,area,name,texmag,s,tfmchecksum) +char *area,*name; +unsigned long num,options,texmag,s,tfmchecksum; +{ + int i; + + /* check to see if font is already defined */ + for(i = 0; i < ndvifonts ; i++) if (dvifonts[i].df_num == num) return; + + /* Does this make too many fonts defined? */ + if (ndvifonts >= MAXDVIFONTS) croak("too many dvi fonts"); + dvifonts[ndvifonts].df_num = num; + dvifonts[ndvifonts++].df_kyofont = find_kyofont(area,name,texmag + ,s,tfmchecksum); +} + +/* Try to find DVI font with number "fontnum" + * in the dvi-fonttable + * Timestamp it to enable LRU font removal + */ +struct kyofont * +find_dvi_font(fontnum) + unsigned long fontnum; +{ + register int i; + + /* scan through the dvi font list. */ + for(i = 0; i < ndvifonts ; i++) + if (dvifonts[i].df_num == fontnum) { + dvifonts[i].df_kyofont->kf_timestamp = timestamp++; + return(dvifonts[i].df_kyofont); + } + croak("no dvi font %d defined",fontnum); +} + +/* Select a font as the current font */ +f_use_font(fontnum,font_space) +unsigned long fontnum; +long *font_space; +{ + curfnt = find_dvi_font(fontnum); + /* The font should be loaded already + * because loading fonts while printing a page + * could cause the Kyocera to emit the sheet + * that is printed on at this moment + */ + if (!(curfnt->kf_info & KF_LOADED)) + croak("cannot load font %d while printing page", fontnum); + /* Start using it */ + fprintf(kyo,"!R! FONT %1d;EXIT;",curfnt->kf_kyonumber); + *font_space = curfnt->kf_s / 6; +} + +/* Put symbol "ch" to the printer + * "xsize" is the horizontal width of the character in pixels + */ +f_setc(ch, xsize) +unsigned long ch; +int xsize; +{ + register struct kyochar *c = &(curfnt->kf_char[ch]); + + /* When the symbol is to high it must be sent in raster format + * and canoot be loaded into the Kyocera + * Symbols higher than MAXKYOHEIGHT pixels cannot be loaded + */ + if (c->kc_info & KC_RASTER) + dev_raster(c); + else + dev_setc(ch, xsize); +} + +/* Hints as to what fonts are to be used. + * This is called once per page to give fonts module instrucions as what fonts + * and characters in those fonts have to be loaded for this page. + * "fontvec" contains a list of fonts used for this page + * "veclen" is the number of fonts used on this page + * "charvec" contains the per font information about the symbols needed + */ +f_newpage(fontvec,charvec,veclen) + unsigned long fontvec[]; + unsigned long charvec[][4]; + int veclen; +{ + struct kyochar *c; + register int i,j; + struct kyofont *f; + + for (i = 0; i < veclen; i++) { + /* Lookup font in the dvi-fonttable + * and read the pxlfile if needed + */ + f = find_dvi_font(fontvec[i]); + if (f->kf_info & KF_FILE) getfontfromfile(f); + /* If not not loaded initialize space requirements */ + if (!(f->kf_info & KF_LOADED)) { + f->kf_words_used = 0; + f->kf_words_needed = KF_MIN; + + } + /* Determine which symbols should be loaded from this font */ + for (j = 0; j < MAXCHARS; j++) + if (charvec[i][j/32] & (1 << (j % 32))) { + c = &(f->kf_char[j]); + c->kc_info |= KC_NEEDED; + if (!(c->kc_info & KC_LOADED)) + f->kf_words_needed += char_words_needed(c); + } else f->kf_char[j].kc_info &= ~KC_NEEDED; + /* Load the symbols needed and not yet loaded */ + download_font(f); + } +} + + +/* Load a font into the Kyocera */ +download_font(fnt) + struct kyofont *fnt; +{ + register int i; + + /* Make free space if needed */ + if (fnt->kf_words_needed > freewords) + kyofree(fnt->kf_words_needed); + freewords -= fnt->kf_words_needed; + fnt->kf_words_used += fnt->kf_words_needed; + + /* Load needed symbols that are not yet loaded */ + for (i = 0; i < MAXCHARS; i++) + if ((fnt->kf_char[i].kc_info & KC_NEEDED) + && !(fnt->kf_char[i].kc_info & KC_LOADED)) + load_char(i,fnt); + + /* If font is loaded for the first time set its font attributes */ + if (!(fnt->kf_info & KF_LOADED)) + fprintf(kyo, "!R! FONT %1d; SFA 0,0,P,0;EXIT;",fnt->kf_kyonumber); + + debug("Loaded %d words for font %s, %d\n", + fnt->kf_words_needed, fnt->kf_name, fnt->kf_kyonumber); + fnt->kf_words_needed = 0; + fnt->kf_info |= KF_LOADED; +} + +/* Load symbol "ch" from font "fnt" */ +load_char(ch,fnt) + unsigned long ch; + struct kyofont *fnt; +{ + register unsigned short *bp; + register int w; + struct kyochar *c = &(fnt->kf_char[ch]); + int row,bw; + + /* If symbol is too high it cannot be loaded + * and should be send as a raster each time it is used + */ + if (c->kc_height > MAXKYOHEIGHT) { + c->kc_info |= KC_RASTER; + return; + } + + /* Does this symbol exist */ + if (!(c->kc_glyph.l)) + croak("Char %#x not in font %s\n",ch, fnt->kf_name); + + /* Load metrics information about the symbol */ + fprintf(kyo, "!R! LDFC %1d,%1d,%1d,%1d,%1d,%1d,%1d,%1d,0;" + ,fnt->kf_kyonumber, visual(ch), c->kc_height, c->kc_width + ,32*c->kc_yoffset,32*c->kc_xoffset + ,32*c->kc_kyowidth, 16*c->kc_kyowidth); + + /* Load the pixel raster */ + bp = c->kc_glyph.p; + bw = (c->kc_width + 15) / 16; + for (row = 0; row < c->kc_height; row++) { + for (w = 0; w < bw; w++) convert(*bp++); + } + fprintf(kyo, "; EXIT;"); fflush(kyo); + c->kc_info |= KC_LOADED; +} + +/* Convert pixel information into the format needed by the Kyocera */ +convert(w) + unsigned short w; +{ + char c; + + c = ((w >> 10) & 077) + 64; + if (c == 127) c = '/'; putc(c, kyo); + c = ((w >> 4) & 077) + 64; + if (c == 127) c = '/'; putc(c, kyo); + c = (w & 017) + 48; putc(c, kyo); +} + +/* Read the information for font "fnt" from file "fname" */ +int readpxlfile(fnt,fname) + struct kyofont *fnt; + char *fname; +{ + long pxl_id,pxl_dir_ptr; + long pxlchecksum; + FILE *f; + + if (!(f = fopen(fname,"r"))) croak("no pxl file %s",fname); + if ((pxl_id = sget4(f)) != 1001) + croak("%d bad initial pxl ID; %s doesn't look like a pxl file", + pxl_id, fnt->kf_filename); + + debug("OK This is a PXL file\n"); + /* Read the last 5 longs from the pxl file */ + (void) fseek(f, (long)(-5*4), 2); + pxlchecksum = sget4(f); + fnt->kf_pxl_mag_val = sget4(f); + fnt->kf_pxl_design_size = sget4(f); + pxl_dir_ptr = sget4(f); + if ((pxl_id = sget4(f)) != 1001) + croak("%d bad final pxl ID; %s doesn't look like a pxl file", + pxl_id, fnt->kf_filename); + if (pxl_dir_ptr != ftell(f) / 4 - 517) + croak("%s pxl dir ptr is %x, should be %x", + fnt->kf_filename, pxl_dir_ptr, ftell(f) / 4 - 517); + debug("pxl: checksum %d mag %d designsize %d dir %x\n", + pxlchecksum,fnt->kf_pxl_mag_val, + fnt->kf_pxl_design_size,pxl_dir_ptr); + + if (fnt->kf_tfm_checksum & (pxlchecksum != fnt->kf_tfm_checksum)) { + fprintf(stderr, "Checksum mismatch: %s\n",fnt->kf_filename); + fprintf(stderr, " pxl file: %ld, tfm_file: %ld\n", + pxlchecksum, fnt->kf_tfm_checksum); + } + + /* Read the directory */ + (void) fseek(f, pxl_dir_ptr * 4, 0); + getpxldir(fnt,f); + debug(" %s max_height=%d\n",fnt->kf_filename,fnt->kf_maxheight); + + /* Read in all the glyphs */ + getglyphs(fnt,f); + + (void) fclose(f); +} + +/* Read the pixel directory for font "fnt" from file "f" */ +getpxldir(fnt,f) + struct kyofont *fnt; + FILE *f; +{ + int i; + struct kyochar *c; + double ds = ((double) fnt->kf_s) / ((double) (1 << 20)); + + /* Each symbol has an entry of 16 bytes */ + fnt->kf_maxheight = 0; + for (i = 0; i < MAXCHARS; i++) { + c = &(fnt->kf_char[i]); + c->kc_width = sget2(f); + c->kc_height = sget2(f); + c->kc_xoffset = sget2(f); + c->kc_yoffset = sget2(f); + c->kc_glyph.l = get4(f); + c->kc_pxlwidth = sget4(f); + c->kc_texwidth = (long) (((double) c->kc_pxlwidth) * ds); + c->kc_kyowidth = + (c->kc_texwidth * numerator + half_denominator) / denominator; + /* Determine the maximum height of the font */ + fnt->kf_maxheight = max(fnt->kf_maxheight,c->kc_height); + } +} + +/* Read the raster information for font "fnt" from file "f" + * The information per symbol is a multiple of 4 bytes + * The information per symbol that will be loaded is a multiple of 2 bytes + */ +getglyphs(fnt,f) + struct kyofont *fnt; + FILE *f; +{ + register int j,row; + register unsigned short *p; + int i,fbw,bw; + struct kyochar *c; + + for (i = 0; i < MAXCHARS; i++) { + c = &(fnt->kf_char[i]); + if (c->kc_glyph.l) { + (void) fseek(f, c->kc_glyph.l * 4, 0); + fbw = ((c->kc_width + 31) / 32) * 2; + bw = (c->kc_width + 15) / 16; + if (!(p = (unsigned short *)malloc(2*bw * c->kc_height))) + croak("malloc %d",2*bw * c->kc_height); + c->kc_glyph.p = p; + for (row = 0; row < c->kc_height; row++) { + for (j = 0; j < bw; j++) *p++ = get2(f); + /* get rid of empty trailing bytes */ + for (j = bw; j < fbw; j++) (void) get2(f); + } + } + } +} + +/* This procedure is called for every character so it must be fast + * It returns the TeX width and the device width of symbol "ch" + */ +f_use_char(ch,texwidth,devwidth) +unsigned long ch; +long *texwidth,*devwidth; +{ + register struct kyochar *c = &(curfnt->kf_char[ch]); + + *texwidth = c->kc_texwidth; + *devwidth = c->kc_kyowidth; +} + + +/* free words by deleting font(s) using LRU strategy + * at least "words" words should be free + */ +int kyofree(words) + int words; +{ + int i,oldtime; + struct kyofont *oldfont; + struct preload *oldpr; + + while (words > freewords) { + oldpr = NULL; + /* First try preloaded fonts not yet used by this job */ + for (i=0; i<nloaded; i++) + if (loaded[i].pr_info & PR_LOADED) { + oldpr = &loaded[i]; + break; + } + /* Found one, delete it */ + if (oldpr) { + oldpr->pr_info &= ~PR_LOADED; + fprintf(kyo,"!R! DELF %1d;EXIT;",oldpr->pr_font->pr_kyonumber); + fflush(kyo); + debug("Left free %ld\n", freewords); + debug("PRELOADED FONT %s, %d deleted, size %ld\n", + oldpr->pr_font->pr_name, + oldpr->pr_font->pr_kyonumber, + oldpr->pr_font->pr_words_used ); + freewords += oldpr->pr_font->pr_words_used; + } else { + /* Try the other fonts now */ + oldfont = NULL; + oldtime = timestamp; + for (i = 0; i < nkyofonts; i++) + if ((kyofonts[i]->kf_info & KF_LOADED) + && (kyofonts[i]->kf_timestamp < oldtime)) { + oldfont = kyofonts[i]; + oldtime = oldfont->kf_timestamp; + } + if (!oldfont) croak("kyofree bug"); + oldfont->kf_info &= ~KF_LOADED; + oldfont->kf_words_needed = KF_MIN; + oldfont->kf_words_used = 0; + fprintf(kyo,"!R! DELF %1d;EXIT;",oldfont->kf_kyonumber); + fflush(kyo); + debug("Left free %ld\n", freewords); + debug("FONT %s, %d deleted, size %ld\n", + oldfont->kf_name, + oldfont->kf_kyonumber, + oldfont->kf_words_used); + freewords += oldfont->kf_words_used; + for (i = 0; i < MAXCHARS; i++) { + oldfont->kf_char[i].kc_info &= ~KC_LOADED; + if (oldfont->kf_char[i].kc_info & KC_NEEDED) + oldfont->kf_words_needed+=char_words_needed(&(oldfont->kf_char[i])); + } + } + } +} |