diff options
Diffstat (limited to 'backend/dvi/mdvi-lib/pk.c')
-rw-r--r-- | backend/dvi/mdvi-lib/pk.c | 570 |
1 files changed, 570 insertions, 0 deletions
diff --git a/backend/dvi/mdvi-lib/pk.c b/backend/dvi/mdvi-lib/pk.c new file mode 100644 index 00000000..a5791869 --- /dev/null +++ b/backend/dvi/mdvi-lib/pk.c @@ -0,0 +1,570 @@ + +/* Copyright (C) 2000, Matias Atria + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/* + * History: + * + * 11/3/2000: + * - First working version + * 11/4/2000: + * - FIXED: entirely white/black rows were missed. + * 11/8/2000: + * - TESTED: Glyphs are rendered correctly in different byte orders. + * - Made bitmap code much more efficient and compact. + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <math.h> + +#include "mdvi.h" +#include "private.h" + +#define PK_ID 89 +#define PK_CMD_START 240 +#define PK_X1 240 +#define PK_X2 241 +#define PK_X3 242 +#define PK_X4 243 +#define PK_Y 244 +#define PK_POST 245 +#define PK_NOOP 246 +#define PK_PRE 247 + +#define PK_DYN_F(x) (((x) >> 4) & 0xf) +#define PK_PACKED(x) (PK_DYN_F(x) != 14) + +static int pk_load_font __PROTO((DviParams *, DviFont *)); +static int pk_font_get_glyph __PROTO((DviParams *, DviFont *, int)); + +static int pk_auto_generate = 1; /* this is ON by default */ + +typedef struct { + char currbyte; + char nybpos; + int dyn_f; +} pkread; + +static char *pk_lookup __PROTO((const char *, Ushort *, Ushort *)); +static char *pk_lookupn __PROTO((const char *, Ushort *, Ushort *)); + +/* only symbols exported by this file */ +DviFontInfo pk_font_info = { + "PK", + 0, /* scaling not supported natively */ + pk_load_font, + pk_font_get_glyph, + mdvi_shrink_glyph, + mdvi_shrink_glyph_grey, + NULL, /* free */ + NULL, /* reset */ + pk_lookup, /* lookup */ + kpse_pk_format, + NULL +}; + +DviFontInfo pkn_font_info = { + "PKN", + 0, /* scaling not supported natively */ + pk_load_font, + pk_font_get_glyph, + mdvi_shrink_glyph, + mdvi_shrink_glyph_grey, + NULL, /* free */ + NULL, /* reset */ + pk_lookupn, /* lookup */ + kpse_pk_format, + NULL +}; + +static char *pk_lookup(const char *name, Ushort *hdpi, Ushort *vdpi) +{ + kpse_glyph_file_type type; + char *filename; + + if(pk_auto_generate == 0) { + kpse_set_program_enabled(kpse_pk_format, 1, kpse_src_cmdline); + pk_auto_generate = 1; + } + filename = kpse_find_glyph(name, Max(*hdpi, *vdpi), + kpse_pk_format, &type); + if(filename && type.source == kpse_glyph_source_fallback) { + mdvi_free(filename); + filename = NULL; + } else if(filename) { + *hdpi = *vdpi = type.dpi; + } + return filename; +} + +static char *pk_lookupn(const char *name, Ushort *hdpi, Ushort *vdpi) +{ + kpse_glyph_file_type type; + char *filename; + + if(pk_auto_generate) { + kpse_set_program_enabled(kpse_pk_format, 0, kpse_src_cmdline); + pk_auto_generate = 0; + } + filename = kpse_find_glyph(name, Max(*hdpi, *vdpi), + kpse_pk_format, &type); + if(filename && type.source == kpse_glyph_source_fallback) { + mdvi_free(filename); + filename = NULL; + } else if(filename) { + *hdpi = *vdpi = type.dpi; + } + return filename; +} + +static inline int pk_get_nyb(FILE *p, pkread *pk) +{ + unsigned t; + int nb; + char c; + + t = c = pk->currbyte; + nb = pk->nybpos; + + switch(nb) { + case 0: + c = pk->currbyte = fuget1(p); + t = (c >> 4); + break; + case 1: + t = c; + break; + } + pk->nybpos = !nb; + return (t & 0xf); +} + +/* + * this is a bit cumbersome because we have to pass around + * the `pkread' data... + */ +static int pk_packed_num(FILE *p, pkread *pkr, int *repeat) +{ + int i, j; + int dyn_f = pkr->dyn_f; + + i = pk_get_nyb(p, pkr); + if(i == 0) { + do { + j = pk_get_nyb(p, pkr); + i++; + } while(j == 0); + while(i-- > 0) + j = (j << 4) + pk_get_nyb(p, pkr); + return (j - 15 + ((13 - dyn_f) << 4) + + dyn_f); + } else if(i <= dyn_f) + return i; + else if(i < 14) + return ((i - dyn_f - 1) << 4) + + pk_get_nyb(p, pkr) + dyn_f + 1; + else { + *repeat = 1; + if(i == 14) + *repeat = pk_packed_num(p, pkr, repeat); + return pk_packed_num(p, pkr, repeat); + } +} + +#define ROUND(x,y) (((x) + (y) - 1) / (y)) + +static BITMAP *get_bitmap(FILE *p, int w, int h, int flags) +{ + int i, j; + BmUnit *ptr; + BITMAP *bm; + int bitpos; + int currch; + + flags = 0; /* shut up that compiler */ + bitpos = -1; + if((bm = bitmap_alloc(w, h)) == NULL) + return NULL; + DEBUG((DBG_BITMAPS, "get_bitmap(%d,%d,%d): reading raw bitmap\n", + w, h, flags)); + ptr = bm->data; + currch = 0; + for(i = 0; i < h; i++) { + BmUnit mask; + + mask = FIRSTMASK; + for(j = 0; j < w; j++) { + if(bitpos < 0) { + currch = fuget1(p); + bitpos = 7; + } + if(currch & (1 << bitpos)) + *ptr |= mask; + bitpos--; + if(mask == LASTMASK) { + ptr++; + mask = FIRSTMASK; + } else + NEXTMASK(mask); + } + ptr = bm_offset(ptr, bm->stride); + } + return bm; +} + +static BITMAP *get_packed(FILE *p, int w, int h, int flags) +{ + int inrow, count; + int row; + BITMAP *bm; + int repeat_count; + int paint; + pkread pkr; + + pkr.nybpos = 0; + pkr.currbyte = 0; + pkr.dyn_f = PK_DYN_F(flags); + paint = !!(flags & 0x8); + + repeat_count = 0; + row = 0; + inrow = w; + if((bm = bitmap_alloc(w, h)) == NULL) + return NULL; + DEBUG((DBG_BITMAPS, "get_packed(%d,%d,%d): reading packed glyph\n", + w, h, flags)); + while(row < h) { + int i = 0; + + count = pk_packed_num(p, &pkr, &i); + if(i > 0) { + if(repeat_count) + fprintf(stderr, "second repeat count for this row (had %d and got %d)\n", + repeat_count, i); + repeat_count = i; + } + + if(count >= inrow) { + Uchar *r, *t; + BmUnit *a, mask; + + /* first finish current row */ + if(paint) + bitmap_set_row(bm, row, w - inrow, inrow, paint); + /* now copy it as many times as required */ + r = (Uchar *)bm->data + row * bm->stride; + while(repeat_count-- > 0) { + t = r + bm->stride; + /* copy entire lines */ + memcpy(t, r, bm->stride); + r = t; + row++; + } + repeat_count = 0; + /* count first row we drew */ + row++; + /* update run count */ + count -= inrow; + /* now r points to the beginning of the last row we finished */ + if(paint) + mask = ~((BmUnit)0); + else + mask = 0; + /* goto next row */ + a = (BmUnit *)(r + bm->stride); + /* deal with entirely with/black rows */ + while(count >= w) { + /* count number of atoms in a row */ + i = ROUND(w, BITMAP_BITS); + while(i-- > 0) + *a++ = mask; + count -= w; + row++; + } + inrow = w; + } + if(count > 0) + bitmap_set_row(bm, row, w - inrow, count, paint); + inrow -= count; + paint = !paint; + } + if(row != h || inrow != w) { + mdvi_error(_("Bad PK file: More bits than required\n")); + bitmap_destroy(bm); + return NULL; + } + return bm; +} + +static BITMAP *get_char(FILE *p, int w, int h, int flags) +{ + /* check if dyn_f == 14 */ + if(((flags >> 4) & 0xf) == 14) + return get_bitmap(p, w, h, flags); + else + return get_packed(p, w, h, flags); +} + +/* supports any number of characters in a font */ +static int pk_load_font(DviParams *unused, DviFont *font) +{ + int i; + int flag_byte; + int loc, hic, maxch; + Int32 checksum; + FILE *p; +#ifndef NODEBUG + char s[256]; +#endif + long alpha, beta, z; + + font->chars = xnalloc(DviFontChar, 256); + p = font->in; + memzero(font->chars, 256 * sizeof(DviFontChar)); + for(i = 0; i < 256; i++) + font->chars[i].offset = 0; + + /* check the preamble */ + loc = fuget1(p); hic = fuget1(p); + if(loc != PK_PRE || hic != PK_ID) + goto badpk; + i = fuget1(p); +#ifndef NODEBUG + for(loc = 0; loc < i; loc++) + s[loc] = fuget1(p); + s[loc] = 0; + DEBUG((DBG_FONTS, "(pk) %s: %s\n", font->fontname, s)); +#else + fseek(in, (long)i, SEEK_CUR); +#endif + /* get the design size */ + font->design = fuget4(p); + /* get the checksum */ + checksum = fuget4(p); + if(checksum && font->checksum && font->checksum != checksum) { + mdvi_warning(_("%s: checksum mismatch (expected %u, got %u)\n"), + font->fontname, font->checksum, checksum); + } else if(!font->checksum) + font->checksum = checksum; + /* skip pixel per point ratios */ + fuget4(p); + fuget4(p); + if(feof(p)) + goto badpk; + + /* now start reading the font */ + loc = 256; hic = -1; maxch = 256; + + /* initialize alpha and beta for TFM width computation */ + TFMPREPARE(font->scale, z, alpha, beta); + + while((flag_byte = fuget1(p)) != PK_POST) { + if(feof(p)) + break; + if(flag_byte >= PK_CMD_START) { + switch(flag_byte) { + case PK_X1: + case PK_X2: + case PK_X3: + case PK_X4: { +#ifndef NODEBUG + char *t; + int n; + + i = fugetn(p, flag_byte - PK_X1 + 1); + if(i < 256) + t = &s[0]; + else + t = mdvi_malloc(i + 1); + for(n = 0; n < i; n++) + t[n] = fuget1(p); + t[n] = 0; + DEBUG((DBG_SPECIAL, "(pk) %s: Special \"%s\"\n", + font->fontname, t)); + if(t != &s[0]) + mdvi_free(t); +#else + i = fugetn(p, flag_byte - PK_X1 + 1); + while(i-- > 0) + fuget1(p); +#endif + break; + } + case PK_Y: + i = fuget4(p); + DEBUG((DBG_SPECIAL, "(pk) %s: MF special %u\n", + font->fontname, (unsigned)i)); + break; + case PK_POST: + case PK_NOOP: + break; + case PK_PRE: + mdvi_error(_("%s: unexpected preamble\n"), font->fontname); + goto error; + } + } else { + int pl; + int cc; + int w, h; + int x, y; + int offset; + long tfm; + + switch(flag_byte & 0x7) { + case 7: + pl = fuget4(p); + cc = fuget4(p); + offset = ftell(p) + pl; + tfm = fuget4(p); + fsget4(p); /* skip dx */ + fsget4(p); /* skip dy */ + w = fuget4(p); + h = fuget4(p); + x = fsget4(p); + y = fsget4(p); + break; + case 4: + case 5: + case 6: + pl = (flag_byte % 4) * 65536 + fuget2(p); + cc = fuget1(p); + offset = ftell(p) + pl; + tfm = fuget3(p); + fsget2(p); /* skip dx */ + /* dy assumed 0 */ + w = fuget2(p); + h = fuget2(p); + x = fsget2(p); + y = fsget2(p); + break; + default: + pl = (flag_byte % 4) * 256 + fuget1(p); + cc = fuget1(p); + offset = ftell(p) + pl; + tfm = fuget3(p); + fsget1(p); /* skip dx */ + /* dy assumed 0 */ + w = fuget1(p); + h = fuget1(p); + x = fsget1(p); + y = fsget1(p); + } + if(feof(p)) + break; + if(cc < loc) + loc = cc; + if(cc > hic) + hic = cc; + if(cc > maxch) { + font->chars = xresize(font->chars, + DviFontChar, cc + 16); + for(i = maxch; i < cc + 16; i++) + font->chars[i].offset = 0; + maxch = cc + 16; + } + font->chars[cc].code = cc; + font->chars[cc].flags = flag_byte; + font->chars[cc].offset = ftell(p); + font->chars[cc].width = w; + font->chars[cc].height = h; + font->chars[cc].glyph.data = NULL; + font->chars[cc].x = x; + font->chars[cc].y = y; + font->chars[cc].glyph.x = x; + font->chars[cc].glyph.y = y; + font->chars[cc].glyph.w = w; + font->chars[cc].glyph.h = h; + font->chars[cc].grey.data = NULL; + font->chars[cc].shrunk.data = NULL; + font->chars[cc].tfmwidth = TFMSCALE(z, tfm, alpha, beta); + font->chars[cc].loaded = 0; + fseek(p, (long)offset, SEEK_SET); + } + } + if(flag_byte != PK_POST) { + mdvi_error(_("%s: unexpected end of file (no postamble)\n"), + font->fontname); + goto error; + } + while((flag_byte = fuget1(p)) != EOF) { + if(flag_byte != PK_NOOP) { + mdvi_error(_("invalid PK file! (junk in postamble)\n")); + goto error; + } + } + + /* resize font char data */ + if(loc > 0 || hic < maxch-1) { + memmove(font->chars, font->chars + loc, + (hic - loc + 1) * sizeof(DviFontChar)); + font->chars = xresize(font->chars, + DviFontChar, hic - loc + 1); + } + font->loc = loc; + font->hic = hic; + return 0; + +badpk: + mdvi_error(_("%s: File corrupted, or not a PK file\n"), font->fontname); +error: + mdvi_free(font->chars); + font->chars = NULL; + font->loc = font->hic = 0; + return -1; +} + +static int pk_font_get_glyph(DviParams *params, DviFont *font, int code) +{ + DviFontChar *ch; + + if((ch = FONTCHAR(font, code)) == NULL) + return -1; + + if(ch->offset == 0) + return -1; + DEBUG((DBG_GLYPHS, "(pk) loading glyph for character %d (%dx%d) in font `%s'\n", + code, ch->width, ch->height, font->fontname)); + if(font->in == NULL && font_reopen(font) < 0) + return -1; + if(!ch->width || !ch->height) { + /* this happens for ` ' (ASCII 32) in some fonts */ + ch->glyph.x = ch->x; + ch->glyph.y = ch->y; + ch->glyph.w = ch->width; + ch->glyph.h = ch->height; + ch->glyph.data = NULL; + return 0; + } + if(fseek(font->in, ch->offset, SEEK_SET) == -1) + return -1; + ch->glyph.data = get_char(font->in, + ch->width, ch->height, ch->flags); + if(ch->glyph.data) { + /* restore original settings */ + ch->glyph.x = ch->x; + ch->glyph.y = ch->y; + ch->glyph.w = ch->width; + ch->glyph.h = ch->height; + } else + return -1; + ch->loaded = 1; + return 0; +} |