/* -*-C-*- chargf.h */ /*-->chargf*/ /**********************************************************************/ /******************************* chargf *******************************/ /**********************************************************************/ int chargf(c,outfcn) /* return 0 on success, and EOF on failure */ BYTE c; /* current character value */ void (*outfcn)(); /* (possibly NULL) function to output current row */ { UNSIGN16 d; /* step in m index */ BOOLEAN do_output; /* FALSE if outfcn is NULL */ register UNSIGN16 k; /* loop step */ register INT16 m,n; /* column,row indices in image[n][m] */ long p; /* pointer into font file */ BYTE paint_switch; /* alternates between BLACK and WHITE */ struct char_entry *tcharptr;/* temporary char_entry pointer */ register BYTE the_byte; /* current command byte */ UNSIGN32 the_word; /* temporary result holder */ /* NB: We only test for equality with BLACK. WHITE is any non-zero bit pattern, so we cannot test for equality with it */ #define BLACK ((BYTE)0) #define WHITE ((BYTE)(!BLACK)) /******************************************************************* This function is called to process a single character description in the GF font file, and to set the character metrics hp, wp, xoffp, and yoffp for it. The character description may start either at a special (XXX) command, or at a beginning-of-character (BOC or BOC1) command. It processes the character description up to, and including, the end-of-character (EOC) command which terminates it. The GF raster description is encoded in a complex form, but is guaranteed to step across raster rows from left to right, and down from the top row to bottom row, such that in references to image[n][m], m never decreases in a row, and n never increases in a character. This means that we only require enough memory space to hold one row, provided that outfcn(c,yoff) is called each time a row is completed. This is an important economization for high-resolution output devices -- e.g. a 10pt character at 2400 dots/inch would require about 8Kb for the entire image, but fewer than 25 bytes for a single row. A 72pt character (such as in the aminch font) would need about 430Kb for the image, but only about 200 bytes for a row. Access to bit m in the current row is controlled through the macros SETBIT(m) and TESTBIT(m) so we need not be concerned about the details of bit masking. Too bad C does not have a bit data type! The row image is recorded in such a way that bits min_m .. max_m are mapped onto bits 0 .. (max_m - min_m) in img_row[], so that outfcn(c,yoff) should be relieved of any shifting operations. outfcn(c,yoff) is NEVER called if either of hp or wp is <= 0, or if if it is NULL. *******************************************************************/ if ((c < FIRSTPXLCHAR) || (LASTPXLCHAR < c)) { (void)warning( "chargf(): Character value out of range for GF font file"); return(EOF); } tcharptr = &(fontptr->ch[c]); p = (long)tcharptr->fontrp; /* font file raster pointer */ if (p < 0L) { (void)warning( "chargf(): Requested character not found in GF font file"); return(EOF); } if (FSEEK(fontfp,p,0)) { (void)warning( "chargf(): FSEEK() failure for GF font file character raster"); return(EOF); } do_output = (BOOLEAN)(outfcn != (void(*)())NULL); (void)skgfspec(); /* skip any GF special commands */ the_byte = (BYTE)nosignex(fontfp,(BYTE)1); if ((the_byte != GFBOC) && (the_byte != GFBOC1)) { (void)warning( "chargf(): GF font file not positioned at BOC or BOC1 command"); return(EOF); } for (;;) /* loop with exit at EOC, or at BOC or BOC1 if no rasters */ { switch (the_byte) { case GFPAINT0: paint_switch = (BYTE)(!paint_switch); break; case GFPAINT1: d = (UNSIGN16)nosignex(fontfp,(BYTE)1); if (do_output && (paint_switch == BLACK)) { for (k = 0; k < d; (++m, ++k)) SETBIT(m); } else m += (INT16)d; paint_switch = (BYTE)(!paint_switch); break; case GFPAINT2: d = (UNSIGN16)nosignex(fontfp,(BYTE)2); if (do_output && (paint_switch == BLACK)) { for (k = 0; k < d; (++m, ++k)) SETBIT(m); } else m += (INT16)d; paint_switch = (BYTE)(!paint_switch); break; case GFPAINT3: /* METAFONT never needs this */ d = (UNSIGN16)nosignex(fontfp,(BYTE)3); /* NOTE: truncation */ if (do_output && (paint_switch == BLACK)) { for (k = 0; k < d; (++m, ++k)) SETBIT(m); } else m += (INT16)d; paint_switch = (BYTE)(!paint_switch); break; case GFBOC: /* beginning-of-character -- long form */ the_word = (UNSIGN32)nosignex(fontfp,(BYTE)4); p = (long)signex(fontfp,(BYTE)4); if ((UNSIGN32)c != the_word) { if (p < 0L) { (void)warning( "chargf(): Requested character not found in back chain in GF font file"); return(EOF); } else (void)FSEEK(fontfp,p,0); /* must follow back chain */ break; } else { min_m = (INT16)signex(fontfp,(BYTE)4); max_m = (INT16)signex(fontfp,(BYTE)4); min_n = (INT16)signex(fontfp,(BYTE)4); max_n = (INT16)signex(fontfp,(BYTE)4); } if ((min_m < MIN_M) || (MAX_M < max_m) || (min_n < MIN_N) || (MAX_N < max_n)) { (void)warning( "chargf(): GF font file character box too large for me"); return(EOF); } m = min_m; n = max_n; paint_switch = WHITE; img_words = (UNSIGN16)((max_m - min_m + 1 + 31) >> 5); if (do_output) (void)clrrow(); tcharptr->hp = (COORDINATE)(max_n - min_n + 1); tcharptr->wp = (COORDINATE)(max_m - min_m + 1); tcharptr->xoffp = -(COORDINATE)(min_m); tcharptr->yoffp = (COORDINATE)(max_n); if (!VISIBLE(tcharptr)) return(0); /* empty character raster -- nothing to output */ break; case GFBOC1: /* beginning-of-character -- short form */ if (c != (BYTE)nosignex(fontfp,(BYTE)1)) { (void)warning( "chargf(): Requested character not found in GF font file"); return(EOF); } else { min_m = (INT16)nosignex(fontfp,(BYTE)1); max_m = (INT16)nosignex(fontfp,(BYTE)1); min_m = max_m - min_m; min_n = (INT16)nosignex(fontfp,(BYTE)1); max_n = (INT16)nosignex(fontfp,(BYTE)1); min_n = max_n - min_n; } if ((min_m < MIN_M) || (MAX_M < max_m) || (min_n < MIN_N) || (MAX_N < max_n)) { (void)warning( "chargf(): GF font file character box too large for me"); return(EOF); } m = min_m; n = max_n; paint_switch = WHITE; img_words = (UNSIGN16)((max_m - min_m + 1 + 31) >> 5); if (do_output) (void)clrrow(); tcharptr->hp = (COORDINATE)(max_n - min_n + 1); tcharptr->wp = (COORDINATE)(max_m - min_m + 1); tcharptr->xoffp = -(COORDINATE)(min_m); tcharptr->yoffp = (COORDINATE)(max_n); if (!VISIBLE(tcharptr)) return(0);/* empty character raster -- nothing to output */ break; case GFEOC: /* end-of-character */ if (do_output) { (void)(*outfcn)(c,max_n-n); /* output current row */ (void)clrrow(); /* clear next one */ --n; /* advance to next row below */ for ( ; n >= min_n ; --n) /* output any remaining rows */ (void)(*outfcn)(c,max_n-n); } return(0); /* exit outer loop */ case GFSKIP0: if (do_output) { (void)(*outfcn)(c,max_n-n); /* output current row */ (void)clrrow(); /* clear next one */ } --n; /* advance to next row below */ m = min_m; paint_switch = WHITE; break; case GFSKIP1: if (do_output) { (void)(*outfcn)(c,max_n-n); /* output current row */ (void)clrrow(); /* clear next one */ } --n; /* advance to next row below */ d = (UNSIGN16)nosignex(fontfp,(BYTE)1); if (do_output) { for (k = 0; k < d; (--n,++k)) /* output d white rows */ (void)(*outfcn)(c,max_n-n); } else n -= (INT16)d; m = min_m; paint_switch = WHITE; break; case GFSKIP2: if (do_output) { (void)(*outfcn)(c,max_n-n); /* output current row */ (void)clrrow(); /* clear next one */ } --n; /* advance to next row below */ d = (UNSIGN16)nosignex(fontfp,(BYTE)2); if (do_output) { for (k = 0; k < d; (--n,++k)) /* output d white rows */ (void)(*outfcn)(c,max_n-n); } else n -= (INT16)d; m = min_m; paint_switch = WHITE; break; case GFSKIP3: /* METAFONT never needs this */ if (do_output) { (void)(*outfcn)(c,max_n-n); /* output current row */ (void)clrrow(); /* clear next one */ } --n; /* advance to next row below */ d = (UNSIGN16)nosignex(fontfp,(BYTE)3); /* NOTE truncation */ if (do_output) { for (k = 0; k < d; (++k, --n)) /* output d white rows */ (void)(*outfcn)(c,max_n-n); } else n -= (INT16)d; m = min_m; paint_switch = WHITE; break; case GFXXX1: case GFXXX2: case GFXXX3: case GFXXX4: case GFYYY: case GFNOOP: (void)UNGETC((char)the_byte,fontfp); (void)skgfspec(); break; default: if (((BYTE)GFPAINT0 < the_byte) && (the_byte < GFPAINT1)) { d = (UNSIGN16)(the_byte - GFPAINT0); if (do_output && (paint_switch == BLACK)) { for (k = 0; k < d; (++m, ++k)) SETBIT(m); } else m += (INT16)d; paint_switch = (BYTE)(!paint_switch); } else if (((BYTE)GFNROW0 <= the_byte) && (the_byte <= GFNROWMAX)) { if (do_output) { (void)(*outfcn)(c,max_n-n); /* output current row */ (void)clrrow(); /* clear next one */ } n--; /* advance to next row below */ paint_switch = BLACK; m = min_m + (UNSIGN16)(the_byte - GFNROW0); } else { (void)sprintf(message, "chargf(): Unexpected byte %d (0x%02x) in GF font file \ at position %ld", the_byte,the_byte,(long)FTELL(fontfp)); (void)warning(message); return(EOF); } break; } /* end switch */ the_byte = (BYTE)nosignex(fontfp,(BYTE)1); } /* end for() */ }