/* * dvipage: DVI Previewer Program for Suns * * Neil Hunt (hunt@spar.slb.com) * * This program is based, in part, upon the program dvisun, * distributed by the UnixTeX group, extensively modified by * Neil Hunt at the Schlumberger Palo Alto Research Laboratories * of Schlumberger Technologies, Inc. * * Copyright (c) 1988 Schlumberger Technologies, Inc 1988. * Anyone can use this software in any manner they choose, * including modification and redistribution, provided they make * no charge for it, and these conditions remain unchanged. * * This program is distributed as is, with all faults (if any), and * without any warranty. No author or distributor accepts responsibility * to anyone for the consequences of using it, or for whether it serves any * particular purpose at all, or any other reason. * * $Log: fonts.c,v $ * Revision 1.1 88/11/28 18:40:54 hunt * Initial revision * * Stripped out of dvipage 1.4, * with additions from mitdrivers from TeX 1988 distribution tape. */ #include #include /* For MAXPATHLEN */ #include #include #include "dvipage.h" #include "dvi.h" forward FILE * open_font_file(); forward bool init_font_file(); forward bool read_font_char(); static int nopen = 0; /* number of open FNT files */ /* * get_font_def: * Read the font definitions as they are in the postamble of the DVI file. * Returns TRUE unless the document can not be processed further. */ bool get_font_def() { char *calloc (); unsigned char byte; while(((byte = get_unsigned(dvifp, 1)) >= FNT_DEF1) && (byte <= FNT_DEF4)) { switch (byte) { case FNT_DEF1: if(! read_font_def(get_unsigned(dvifp, 1))) return FALSE; break; case FNT_DEF2: if(! read_font_def(get_unsigned(dvifp, 2))) return FALSE; break; case FNT_DEF3: if(! read_font_def(get_unsigned(dvifp, 3))) return FALSE; break; case FNT_DEF4: if(! read_font_def(get_unsigned(dvifp, 4))) return FALSE; break; default: message( "%s: Bad dvi file: bad font specification.", filename); return FALSE; } } if(byte != POST_POST) { message( "%s: Bad dvi file: no postpostamble after fontdefs.", filename); return FALSE; } return TRUE; } /* * skip_font_def: * Ignore font definition when fonts have been read from the postamble. */ /* ARGSUSED */ void skip_font_def(k) int k; { int a, l; (void)get_unsigned(dvifp, 4); (void)get_unsigned(dvifp, 4); (void)get_unsigned(dvifp, 4); a = get_unsigned(dvifp, 1); l = get_unsigned(dvifp, 1); fseek(dvifp, (long)a+l, 1); } /* * read_font_def: * Reads font def, and attempts to open font file and read data. * Returns TRUE unless a fatal error has occurred so that * document processing cannot proceed. */ bool read_font_def(k) int k; { int i; struct char_entry *tcharptr; FILE *font_fp; /* * Allocate and link new font entry. */ if((fontptr = (struct font_entry *)calloc(1, sizeof(struct font_entry))) == NULL) { message( "Out of memory for font entries; try a larger machine."); return FALSE; } fontptr->next = hfontptr; hfontptr = fontptr; /* * Fill in new font entry. */ fontptr->font_file_fd = NULL; fontptr->k = k; fontptr->c = get_unsigned(dvifp, 4); /* checksum */ fontptr->s = get_unsigned(dvifp, 4); /* space size */ fontptr->d = get_unsigned(dvifp, 4); /* design size */ fontptr->a = get_unsigned(dvifp, 1); /* area length for font name */ fontptr->l = get_unsigned(dvifp, 1); /* device length */ fread(fontptr->n, 1, fontptr->a+fontptr->l, dvifp); fontptr->n[fontptr->a+fontptr->l] = '\0'; fontptr->font_space = fontptr->s/6; /* never used */ fontptr->font_gf_mag = (int)((actual_factor((int)(((float)fontptr->s/ (float)fontptr->d)*1000.0 + 0.5)) * #ifdef USEGLOBALMAG actual_factor(mag) * #endif (float)resolution) + 0.5); fontptr->font_pxl_mag = (int)((actual_factor((int)(((float)fontptr->s/ (float)fontptr->d)*1000.0 + 0.5)) * #ifdef USEGLOBALMAG actual_factor(mag) * #endif (float)resolution * 5.0) + 0.5); /* * Try to find the font file to match. */ if(! find_font_file(font_path, fontptr) || (font_fp = open_font_file(fontptr)) == NO_FILE) { message("Cant find or open font file \"%s\" .%dgf or .%dpxl", fontptr->n, fontptr->font_gf_mag, fontptr->font_pxl_mag); if(verbose & DEBUG_FONTS) fprintf(stderr, "Cant find font file %s %s .%dgf or .%dpxl\n", font_path, fontptr->n, fontptr->font_gf_mag, fontptr->font_pxl_mag); fontptr->font_file_fd = NO_FILE; fontptr->magnification = 0; fontptr->designsize = 0; for(i = 0; i < NFNTCHARS; i++) { tcharptr = &(fontptr->ch[i]); tcharptr->width = 0; tcharptr->height = 0; tcharptr->xOffset = 0; tcharptr->yOffset = 0; tcharptr->where.isloaded = FALSE; tcharptr->where.address.fileOffset = NONEXISTENT; tcharptr->tfmw = 0; } return TRUE; } else return init_font_file(font_fp, fontptr); } /* * open_font_file: * Called with fontptr; opens a file for this font. * May have to close another to do it. * Returns a FILE * pointer, or NO_FILE. */ FILE * open_font_file(fontptr) struct font_entry *fontptr; { register struct font_entry *tfontptr, *lufontptr; register int used; if(nopen >= MAXOPEN) { used = MAXINT; lufontptr = NULL; for(tfontptr = hfontptr; tfontptr; tfontptr = tfontptr->next) { if(tfontptr->font_file_fd == NO_FILE || tfontptr->font_file_fd == NULL || tfontptr == fontptr) continue; if(tfontptr->use_count < used) { used = tfontptr->use_count; lufontptr = tfontptr; } } if(lufontptr == NULL) { fprintf(stderr, "Cant have no least used font\n"); exit(1); } if(verbose & DEBUG_FONTS) fprintf(stderr, "Closing (%x) font '%s'\n", lufontptr->font_file_fd, lufontptr->name); fclose(lufontptr->font_file_fd); lufontptr->font_file_fd = NULL; --nopen; } /* * Open the file; close-on-exec. */ if((fontptr->font_file_fd = fopen(fontptr->name, "r")) == NULL) { message("Cant open font file %s", fontptr->name); fontptr->font_file_fd = NO_FILE; } else { if(verbose & DEBUG_FONTS) fprintf(stderr, "Opened (%x) font '%s'\n", fontptr->font_file_fd, fontptr->name); fcntl(fileno(fontptr->font_file_fd), F_SETFD, 1); nopen++; } return fontptr->font_file_fd; } /* * close_fonts: * Closes all the font files, and frees up all the memory. */ void close_fonts() { register struct font_entry *pf, *next; register struct pixrect *pr; register int i; for(pf = hfontptr; pf; pf = next) { if(verbose & DEBUG_FONTS) fprintf(stderr, "Freeing font %s\n", pf->name); /* * Close the file if still open. */ if(pf->font_file_fd != NO_FILE && pf->font_file_fd != NULL) { fclose(pf->font_file_fd); --nopen; } pf->font_file_fd = NULL; /* * Free the pixrects. */ for(i = 0; i < NFNTCHARS; i++) { if(pf->ch[i].where.isloaded == TRUE) { if(pr = pf->ch[i].where.address.pixrectptr) pr_destroy(pr); } } /* * Get the next. */ next = pf->next; free(pf); } hfontptr = NULL; fontptr = NULL; if(nopen != 0) { fprintf(stderr, "Mislaid some font files; cant happen\n"); exit(1); } } /* * load_char: * Reads in a character from the font file. * Returns TRUE unless document cannot be processed. */ bool load_char(fontptr, ptr) struct font_entry *fontptr; struct char_entry *ptr; { register FILE *font_fp; if(verbose & DEBUG_CHARS) fprintf(stderr, "Load char %d of font %s at offset %d\n", (ptr - &fontptr->ch[0]), fontptr->name, ptr->where.address.fileOffset); /* * If the font file is currently unopen, then open it. */ if((font_fp = fontptr->font_file_fd) == NULL) font_fp = open_font_file(fontptr); /* * If the font file is unavailable, forget it. */ if(font_fp == NO_FILE) { ptr->where.isloaded = TRUE; return TRUE; } /* * Read the font character. */ return read_font_char(font_fp, fontptr, ptr); } /* * Generic Font reading functions. * ============================== */ forward bool init_gf_font_file(); forward bool init_pxl_font_file(); forward bool init_pk_font_file(); forward bool read_gf_font_char(); forward bool read_pxl_font_char(); forward bool read_pk_font_char(); /* * init_font_file: * Reads general data from font file. * Returns TRUE unless processing cannot continue. */ bool init_font_file(font_fp, fontptr) FILE *font_fp; struct font_entry *fontptr; { switch(fontptr->type) { case TYPE_GF: return init_gf_font_file(font_fp, fontptr); case TYPE_PXL: return init_pxl_font_file(font_fp, fontptr); case TYPE_PK: return init_pk_font_file(font_fp, fontptr); default: fprintf(stderr, "Unknown type of font file; cant happen\n"); exit(1); } } /* * read_font_char: * Reads character from font file. * Returns TRUE unless document cannot be processed. */ bool read_font_char(font_fp, fontptr, ptr) FILE *font_fp; struct font_entry *fontptr; struct char_entry *ptr; { switch(fontptr->type) { case TYPE_GF: return read_gf_font_char(font_fp, fontptr, ptr); case TYPE_PXL: return read_pxl_font_char(font_fp, fontptr, ptr); case TYPE_PK: return read_pk_font_char(font_fp, fontptr, ptr); default: fprintf(stderr, "Unknown type of font file; cant happen\n"); exit(1); } } /* * GF font reading functions. * ========================== */ #define false 0 #define true 1 /* The following macros describe gf file format */ #define paint_0 0 #define last_paint 63 #define paint1 64 #define paint2 65 #define paint3 66 #define boc 67 #define boc1 68 #define eoc 69 #define skip0 70 #define skip1 71 #define skip2 72 #define skip3 73 #define new_row_0 74 #define last_new_row 238 #define xxx1 239 #define xxx2 240 #define xxx3 241 #define xxx4 242 #define yyy 243 #define no_op 244 #define char_loc 245 #define char_loc0 246 #define pre 247 #define post 248 #define postpost 249 #define undefined_cases 250: case 251: case 252: case 253: case 254: case 255 #define gf_version 131 /* * init_gf_font_file: * Reads font data from file. * If the file is unavailable, its fp is set to NO_FILE. * Returns TRUE unless processing cannot continue. */ bool init_gf_font_file(font_fp, fontptr) FILE *font_fp; struct font_entry *fontptr; { register int b, c; register struct char_entry *tcharptr; long checksum; /* should match TFM file and DVI file */ long hppp, vppp; /* horizontal and vertical pixels/point scaled * 1<<16 */ int font_min_m, font_max_m, font_min_n, font_max_n; int char_wd; /* character width in pixels, rounded if * necessary */ /* * Seek to the postamble part of the GF file. */ fseek(font_fp, -5L, 2); /* skip four 223's */ do { c = get_unsigned(font_fp, 1); fseek(font_fp, -2L, 1); } while(c == 223); if(c != gf_version) { message("Bad GF font version number (%d) in %s.", c, fontptr->name); fclose(fontptr->font_file_fd); fontptr->font_file_fd = NO_FILE; return TRUE; } fseek(font_fp, -3L, 1); /* back up to the pointer */ if(fseek(font_fp, (long)get_unsigned(font_fp, 4), 0) < 0 || get_unsigned(font_fp, 1) != post) { message("Bad GF font file format in %s.", fontptr->name); fclose(fontptr->font_file_fd); fontptr->font_file_fd = NO_FILE; return TRUE; } (void)get_unsigned(font_fp, 4); /* ignore back pointer to font-wide xxx * commands */ fontptr->designsize = get_unsigned(font_fp, 4); checksum = get_unsigned(font_fp, 4); hppp = get_unsigned(font_fp, 4); vppp = get_unsigned(font_fp, 4); font_min_m = get_unsigned(font_fp, 4); font_max_m = get_unsigned(font_fp, 4); font_min_n = get_unsigned(font_fp, 4); font_max_n = get_unsigned(font_fp, 4); if(verbose & DEBUG_FONTS) fprintf(stderr, "Initialising font %s\n", fontptr->name); for(tcharptr = &fontptr->ch[0]; tcharptr < &fontptr->ch[NFNTCHARS]; tcharptr++) { tcharptr->where.isloaded = FALSE; tcharptr->where.address.fileOffset = -1; tcharptr->tfmw = 0; } for(;;) { b = get_unsigned(font_fp, 1); c = get_unsigned(font_fp, 1); if(verbose & DEBUG_CHARS) fprintf(stderr, "Finding char %d type %d\n", c, b); if(b == char_loc0) char_wd = get_unsigned(font_fp, 1); else if(b == char_loc) { char_wd = (get_unsigned(font_fp, 4) + 0100000) >> 16; get_unsigned(font_fp, 4); /* skip dy */ } else break; tcharptr = &(fontptr->ch[c % NFNTCHARS]); tcharptr->tfmw = ((float)get_unsigned(font_fp, 4) * (float)fontptr->s) / (float)(1 << 20); tcharptr->where.address.fileOffset = get_unsigned(font_fp, 4); } if((fontptr->c != 0) && (checksum != 0) && (fontptr->c != checksum)) message("Bad font checksum %d != %d, font %s.", checksum, fontptr->c, fontptr->name); /* * Return leaving font file open for use. */ return TRUE; } /* * read_font_char: * Reads character from font file. * Returns TRUE unless document cannot be processed. */ bool read_gf_font_char(font_fp, fontptr, ptr) FILE *font_fp; struct font_entry *fontptr; register struct char_entry *ptr; { register int i, b, c; register int x, y; register struct pixrect *pr; int min_m, max_m, min_n, max_n; int bytes, lines, paint_switch; long backpointer; long charfam; if(verbose & DEBUG_CHARS) fprintf(stderr, "Reading char %d of font %s\n", (ptr - &fontptr->ch[0]), fontptr->name); /* * Seek to start of char. */ fseek(font_fp, (long)ptr->where.address.fileOffset, 0); /* * Sync with char */ do { switch(i = get_unsigned(font_fp, 1)) { case yyy: (void)get_unsigned(font_fp, 1); /* FALLTHROUGH */ case paint3: case skip3: (void)get_unsigned(font_fp, 1); /* FALLTHROUGH */ case paint2: case skip2: (void)get_unsigned(font_fp, 1); /* FALLTHROUGH */ case paint1: case skip1: (void)get_unsigned(font_fp, 1); break; case boc: case boc1: break; case pre: if((c = get_unsigned(font_fp, 1)) != gf_version) { message( "Bad GF font version number (%d); font %s.", c, fontptr->name); return TRUE; } fseek(font_fp, (long)get_unsigned(font_fp, 1), 1); break; case xxx1: fseek(font_fp, (long)get_unsigned(font_fp, 1), 1); break; case xxx2: fseek(font_fp, (long)get_unsigned(font_fp, 2), 1); break; case xxx3: fseek(font_fp, (long)get_unsigned(font_fp, 3), 1); break; case xxx4: fseek(font_fp, (long)get_unsigned(font_fp, 4), 1); break; case post: if(verbose & DEBUG_FONTS) fprintf(stderr, "gettochar: found POST\n"); return TRUE; case char_loc: case char_loc0: case postpost: case undefined_cases: message( "Bad GF font file format (%d); font %s.", i, fontptr->name); return TRUE; default: /* do nothing */ ; break; } if(i != boc && i != boc1 && verbose & DEBUG_FONTS) fprintf(stderr, "gettochar iterates with %d\n", i); } while(i != boc && i != boc1); /* * Read character code and raster sizes. */ switch(i) { case boc: c = get_unsigned(font_fp, 4); backpointer = get_unsigned(font_fp, 4); min_m = get_unsigned(font_fp, 4); max_m = get_unsigned(font_fp, 4); min_n = get_unsigned(font_fp, 4); max_n = get_unsigned(font_fp, 4); charfam = c < 0 ? -((-c) >> 8) : c >> 8; break; case boc1: c = get_unsigned(font_fp, 1); x = get_unsigned(font_fp, 1); /* del_m */ max_m = get_unsigned(font_fp, 1); min_m = max_m - x; x = get_unsigned(font_fp, 1); /* del_n */ max_n = get_unsigned(font_fp, 1); min_n = max_n - x; break; default: fprintf(stderr, "Font BOC code has corrupted in memory; cant happen.\n"); exit(1); } ptr->width = max_m - min_m + 1; ptr->height = max_n - min_n + 1; ptr->xOffset = -min_m; ptr->yOffset = max_n; /* * Create Pixrect for char. * Clear to zero. */ pr = mem_create(ptr->width, ptr->height, 1); ptr->where.address.pixrectptr = pr; pr_rop(pr, 0, 0, ptr->width, ptr->height, PIX_SRC | PIX_COLOR(0), NULL, 0, 0); #ifdef NEVER pr_rop(pr, 0, 0, ptr->width, ptr->height, PIX_SRC | PIX_COLOR(1), NULL, 0, 0); pr_rop(pr, 1, 1, ptr->width-2, ptr->height-2, PIX_SRC | PIX_COLOR(0), NULL, 0, 0); #endif NEVER x = 0; y = 0; paint_switch = 0; for(;;) { switch(b = get_unsigned(font_fp, 1)) { case paint1: bytes = get_unsigned(font_fp, 1); goto paint; case paint2: bytes = get_unsigned(font_fp, 2); goto paint; case paint3: bytes = get_unsigned(font_fp, 3); goto paint; case skip0: lines = 0; goto skip; case skip1: lines = get_unsigned(font_fp, 1); goto skip; case skip2: lines = get_unsigned(font_fp, 2); goto skip; case skip3: lines = get_unsigned(font_fp, 3); goto skip; case xxx1: fseek(font_fp, (long)get_unsigned(font_fp, 1), 1); continue; case xxx2: fseek(font_fp, (long)get_unsigned(font_fp, 2), 1); continue; case xxx3: fseek(font_fp, (long)get_unsigned(font_fp, 3), 1); continue; case xxx4: fseek(font_fp, (long)get_unsigned(font_fp, 4), 1); continue; case yyy: get_unsigned(font_fp, 4); continue; case no_op: continue; case eoc: ptr->where.isloaded = TRUE; return TRUE; default: if(b >= paint_0 && b <= last_paint) { bytes = b - paint_0; paint:; /* * Paint the specified number of bytes black * or white. * Toggle the paint colour. * Advance the current position. */ if(verbose & DEBUG_CHARS) fprintf(stderr, " Paint %d line %d, %d for %d\n", paint_switch, y, x, bytes); if(bytes > 0 && paint_switch) pr_rop(pr, x, y, bytes, 1, PIX_SRC | PIX_COLOR(1), NULL, 0, 0); paint_switch = ! paint_switch; x += bytes; continue; } else if(b >= new_row_0 && b <= last_new_row) { /* * Special shortcut; skip to new row, * and paint some white bytes. * Leave switch ready for next black bytes. */ y++; x = b - new_row_0; paint_switch = 1; if(verbose & DEBUG_CHARS) fprintf(stderr, " Jump to line %d, paint white to %d\n", y, x); continue; } else { message( "Bad GF file format code %d; char %d font %s.", b, (ptr - &fontptr->ch[0]), fontptr->name); return TRUE; } skip:; /* * Skip to the start of the line.th next line. * Start at beginnning of line, ready to paint white. */ y += lines + 1; x = 0; paint_switch = 0; if(verbose & DEBUG_CHARS) fprintf(stderr, " Jump to line %d at start\n", y); continue; } } } /* * PXL font reading functions. * ========================== */ #define NPXLCHARS 128 /* * init_pxl_font_file: * Reads font data from file. * If the file is unavailable, its fp is set to NO_FILE. * Returns TRUE unless processing cannot continue. */ bool init_pxl_font_file(font_fp, fontptr) FILE *font_fp; struct font_entry *fontptr; { int t, i; register struct char_entry *tcharptr; /* * Read the PXL file */ if((t = get_unsigned(font_fp, 4)) != PXLID) { message("Bad font file version %d; font %s.", t, fontptr->name); fclose(fontptr->font_file_fd); fontptr->font_file_fd = NO_FILE; return TRUE; } fseek(font_fp, -20L, 2); t = get_unsigned(font_fp, 4); if((fontptr->c != 0) && (t != 0) && (fontptr->c != t)) message("Bad font checksum %d != %d; font %s.", t, fontptr->c, fontptr->name); fontptr->magnification = get_unsigned(font_fp, 4); fontptr->designsize = get_unsigned(font_fp, 4); fseek(font_fp, (long)get_unsigned(font_fp, 4) * 4, 0); for(i = 0; i < NPXLCHARS; i++) { tcharptr = &(fontptr->ch[i]); tcharptr->width = get_unsigned(font_fp, 2); tcharptr->height = get_unsigned(font_fp, 2); tcharptr->xOffset= get_signed(font_fp, 2); tcharptr->yOffset = get_signed(font_fp, 2); tcharptr->where.isloaded = FALSE; tcharptr->where.address.fileOffset = get_unsigned(font_fp, 4) * 4; tcharptr->tfmw = ((float)get_unsigned(font_fp, 4)*(float)fontptr->s) / (float)(1<<20); } /* * Return leaving font file open for access. */ return TRUE; } static u_char bit_mask[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; /* * read_font_char: * Reads character from font file. * Returns TRUE unless document cannot be processed. */ /* ARGSUSED */ bool read_pxl_font_char(font_fp, fontptr, ptr) FILE *font_fp; struct font_entry *fontptr; register struct char_entry *ptr; { register struct pixrect *pr; register int i, j, nints, nbytes, bp; u_int buf; /* * Seek to start of char. */ fseek(font_fp, (long)ptr->where.address.fileOffset, 0); /* * Create a mem pixrect. * Read the char. */ pr = mem_create(ptr->width, ptr->height, 1); nints = (ptr->width + 31) >> 5; pr_rop(pr, 0, 0, ptr->width, ptr->height, PIX_CLR, NULL, 0, 0); bp = 0; for (i=0; i < ptr->height; i++) { nbytes = nints * 4; for (j=0; jwidth; j++) { if(!(bp & 7)) { buf = getc(font_fp); nbytes--; } pr_put(pr, j, i, (buf & bit_mask[bp&7])?1:0); bp++; } while (nbytes--) getc(font_fp); bp = 0; } ptr->where.address.pixrectptr = pr; ptr->where.isloaded = TRUE; return TRUE; } /* * PK font reading functions */ /* ID byte value at the beginning of PK files */ #define PK_ID 89 /* PK op codes */ #define PK_XXX1 240 #define PK_XXX2 241 #define PK_XXX3 242 #define PK_XXX4 243 #define PK_YYY 244 #define PK_POST 245 #define PK_NOP 246 #define PK_PRE 247 #define PK_REPEAT 0xe /* Repeat last row - repeat count in next nibble */ #define PK_AGAIN 0xf /* Repeat only once */ #define PK_LARGE 0x0 /* Long run vaule coming up */ /* * the macros that read pk values need these variables. */ static u_short _nyb_buf, _nyb_flag, _pk_repeat; /* * get the next nybble of the file. This macro requires * that 2 integers named _nyb_buf and _nyb_flag be allocated elsewhere in * the program. In addition, _nyb_flag must be initialized to 0. */ #define GET_NYB ((_nyb_flag ^= 1) ? \ ((_nyb_buf = (unsigned)getc(font_fp)) >> 4) : \ (_nyb_buf & 0xf)) /* * The quantity to be packed into nybbles may require an odd number of * nybbles which will cause the nybble fetching macro to get out of * sync. The following macro ``clears'' the state of the nybble fetching * routine and should be executed whenever transitioning from nybble to * byte (or other) quantities. */ #define CLEAR_NYB _nyb_flag = 0; /* * this macro gets a PK ``packed number'' from fp and puts it into x. * It is an adaption of an algorithm presented in Tugboat V. 6, No. 3. */ #define GET_PACKED(x) x = get_packed(font_fp, dyn_f) static u_int get_packed(font_fp, dyn_f) register FILE *font_fp; register u_int dyn_f; { register int i, j; i = GET_NYB; if (i == 0) { /* * we have an arbitrarily long number. scan to * find the first non-zero nybble which is the * count of the nybbles in this value. */ do { j = GET_NYB; i++; } while (j == 0); while (--i >= 0) j = (j << 4) + GET_NYB; return (j + 193 - 15 * dyn_f); } else if (i <= dyn_f) { /* this nybble is the number we want. */ return (i); } else if (i < 14) { return (i + 15 * (i - dyn_f - 1) + GET_NYB); } else if (i == 14) { _pk_repeat = get_packed (font_fp, dyn_f); } else { _pk_repeat = 1; } return (i); } bool init_pk_font_file (font_fp, fontptr) register FILE *font_fp; register struct font_entry *fontptr; { register unsigned c, cc; long pl, addr; register u_int i; u_int hppp, vppp; int checksum; u_int tfmw; double cscale; fseek (font_fp, 0L, 0); /* make sure at the beginning of pk file */ if (get_unsigned(font_fp, 1) != PK_PRE) { message("pk font file %s doesn't start with PRE\n", fontptr->name); fclose(fontptr->font_file_fd); fontptr->font_file_fd = NO_FILE; return TRUE; } if (get_unsigned(font_fp, 1) != PK_ID) { message("pk font file %s wrong version\n", fontptr->name); fclose(fontptr->font_file_fd); fontptr->font_file_fd = NO_FILE; return TRUE; } fseek (font_fp, (long) get_unsigned(font_fp, 1), 1); /* skip comment */ fontptr->designsize = get_unsigned(font_fp, 4); /* ds[4] */ checksum = get_unsigned(font_fp, 4); /* checksum[4] */ hppp = get_unsigned(font_fp, 4); /* hppp[4] */ vppp = get_unsigned(font_fp, 4); /* vppp[4] */ cscale = (double) fontptr->s / (double)(1 << 20); while ((c = get_unsigned(font_fp, 1)) != EOF) { if (c >= PK_XXX1) { /* commands are just skipped */ switch (c) { case PK_XXX1: /* pk_xxx1 k[1] x[k] */ fseek (font_fp, (long)get_unsigned(font_fp,1), 1); break; case PK_XXX2: /* pk_xxx2 k[2] x[k] */ fseek (font_fp, (long)get_unsigned(font_fp,2), 1); break; case PK_XXX3: /* pk_xxx3 k[3] x[k] */ fseek (font_fp, (long)get_unsigned(font_fp,3), 1); break; case PK_XXX4: /* pk_xxx4 k[4] x[4] */ fseek (font_fp, (long)get_signed(font_fp,4), 1); break; case PK_YYY: /* pk_yyy y[4] */ (void) get_unsigned(font_fp, 4); break; case PK_POST: return TRUE; case PK_PRE: message("pk font file %s has extra PRE\n", fontptr->name); fclose(fontptr->font_file_fd); fontptr->font_file_fd = NO_FILE; return TRUE; default: /* do nothing */ ; } } else { /* flag byte */ switch (c & 0x07) { /* check flag byte */ case 0:/* short form */ case 1: case 2: case 3: /* length */ pl = (long) get_unsigned(font_fp, 1) + (long) ((c & 0x03) << 8); cc = get_unsigned(font_fp,1); /* char. code */ tfmw = get_unsigned(font_fp,3); /* tfm width */ (void) get_unsigned(font_fp,1); /* x-escapement */ fontptr->ch[cc].width = get_unsigned(font_fp, 1); fontptr->ch[cc].height = get_unsigned(font_fp, 1); fontptr->ch[cc].xOffset = get_signed(font_fp, 1); fontptr->ch[cc].yOffset = get_signed(font_fp, 1); addr = ftell (font_fp); pl -= 8; break; case 4:/* extended short form */ case 5: case 6: pl = (long) get_unsigned(font_fp, 2) + (long) ((c & 0x03) << 16); cc = get_unsigned(font_fp,1); /* char. code */ tfmw = get_unsigned(font_fp,3); /* tfm width */ (void) get_unsigned(font_fp,2); /* x-escapement */ fontptr->ch[cc].width = get_unsigned(font_fp, 2); fontptr->ch[cc].height = get_unsigned(font_fp, 2); fontptr->ch[cc].xOffset = get_signed(font_fp, 2); fontptr->ch[cc].yOffset = get_signed(font_fp, 2); addr = ftell (font_fp); pl -= 13; break; case 7:/* long form */ pl = get_unsigned(font_fp,4); cc = get_unsigned(font_fp,4); /* char. code */ tfmw = get_unsigned(font_fp,4); (void) get_unsigned(font_fp,4); /* x-escapement */ fontptr->ch[cc].width = get_unsigned(font_fp, 4); fontptr->ch[cc].height = get_unsigned(font_fp, 4); fontptr->ch[cc].xOffset = get_signed(font_fp, 4); fontptr->ch[cc].yOffset = get_signed(font_fp, 4); addr = ftell (font_fp); pl -= 24; break; } fontptr->ch[cc].tfmw = (int)(((double)tfmw * cscale) + 0.5); fontptr->ch[cc].where.isloaded = 0; fontptr->ch[cc].where.flags = c; fontptr->ch[cc].where.address.fileOffset = addr;; fseek (font_fp, pl, 1); /* skip until next flag byte */ } } if((fontptr->c != 0) && (checksum != 0) && (fontptr->c != checksum)) message("Bad font checksum %d != %d; font %s.", checksum, fontptr->c, fontptr->name); return TRUE; } /* * load a PK character into memory. */ bool read_pk_font_char(font_fp, fontptr, ptr) register FILE *font_fp; register struct font_entry *fontptr; register struct char_entry *ptr; { register struct pixrect *pr; int cw; /* character width */ int ch; /* character height */ u_int dyn_f; /* dynamic factor, part of a PK word. */ register int i, j; register int black, bits, bp, rc; int rowp; if (ptr->width == 0 || ptr->height == 0) { ptr->where.address.pixrectptr = (struct pixrect *) 0; return; } fseek(font_fp, (long)ptr->where.address.fileOffset, 0); pr = mem_create(ptr->width, ptr->height, 1); ptr->where.address.pixrectptr = pr; cw = ptr->width; ch = ptr->height; pr_rop(pr, 0, 0, cw, ch, PIX_CLR, NULL, 0, 0); /* * what remains is the data for the image. It can be packaged * either as a run-encoding where successive values are the * number of adjacent pixels to paint in the opposite color of * the previous painting, or simply as a bitmap with no padding * except (possibly) for the very last nybble to round up to a * byte value. * * the data for the character is stored in successive bits with * each new horizontal row at a long boundary. See the PXL * file format. */ /* * grab the dyn_f out of the flag for this character. */ dyn_f = (ptr->where.flags >> 4) & 0xf; /* * the data returned by calloc is zeroed; we depend on that * because we only turn on bits that are supposed to be * black. */ if (dyn_f == 14) { /* * we have a bitmap rather than a run-encoding. */ u_int buf; bp = 0; for (i=0; i < ch; i++) { for (j=0; jwhere.flags & (1 << 3); bits = cw * ch; CLEAR_NYB; while (bp < bits) { GET_PACKED(j); if (_pk_repeat != 0) { rc = _pk_repeat; rowp = bp / cw; _pk_repeat = 0; continue; } /* * we have a run count in j. */ if (black) { register int k,l,m; l = bp / cw; /* starting row */ m = (bp + j) / cw; /* ending row */ k = bp % cw; /* start bit offset */ i = (bp + j) % cw; /* ending bit offset */ if (j <= cw && (k < i || i == 0)) { /* we're changing less than a row */ pr_rop(pr, k, l, j, 1, PIX_SET, NULL, 0, 0); } else { /* fill any fragment in the current row */ pr_rop(pr, k, l, cw-k, 1, PIX_SET, NULL, 0, 0); /* fill some number of full rows */ pr_rop(pr, 0, l+1, cw, (j-(cw-k))/cw, PIX_SET, NULL, 0, 0); /* fill any fragment in the last row */ if (i) pr_rop(pr, 0, m, i, 1, PIX_SET, NULL, 0, 0); } } bp += j; /* * if there's a repeat count and we hit the end of * a row, do the copy. */ if (rc && (bp - (rowp*cw)) >= cw) { i = rowp+1; j = rowp+1+rc; if ((i*cw) != bp) { pr_rop(pr, 0, j, cw, 1, PIX_SRC, pr, 0, i); } j = rc; while(j--) { pr_rop(pr, 0, i, cw, 1, PIX_SRC, pr, 0, rowp); i++; } bp += rc * cw; rc = 0; } black = !black; } } ptr->where.isloaded = TRUE; return TRUE; }