summaryrefslogtreecommitdiff
path: root/backend/dvi/mdvi-lib/pk.c
diff options
context:
space:
mode:
Diffstat (limited to 'backend/dvi/mdvi-lib/pk.c')
-rw-r--r--backend/dvi/mdvi-lib/pk.c570
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;
+}