2 /* Copyright (C) 2000, Matias Atria
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 * - First working version
25 * - FIXED: entirely white/black rows were missed.
27 * - TESTED: Glyphs are rendered correctly in different byte orders.
28 * - Made bitmap code much more efficient and compact.
42 #define PK_CMD_START 240
52 #define PK_DYN_F(x) (((x) >> 4) & 0xf)
53 #define PK_PACKED(x) (PK_DYN_F(x) != 14)
55 static int pk_load_font __PROTO((DviParams *, DviFont *));
56 static int pk_font_get_glyph __PROTO((DviParams *, DviFont *, int));
58 static int pk_auto_generate = 1; /* this is ON by default */
66 static char *pk_lookup __PROTO((const char *, Ushort *, Ushort *));
67 static char *pk_lookupn __PROTO((const char *, Ushort *, Ushort *));
69 /* only symbols exported by this file */
70 DviFontInfo pk_font_info = {
72 0, /* scaling not supported natively */
76 mdvi_shrink_glyph_grey,
79 pk_lookup, /* lookup */
84 DviFontInfo pkn_font_info = {
86 0, /* scaling not supported natively */
90 mdvi_shrink_glyph_grey,
93 pk_lookupn, /* lookup */
98 static char *pk_lookup(const char *name, Ushort *hdpi, Ushort *vdpi)
100 kpse_glyph_file_type type;
103 if(pk_auto_generate == 0) {
104 kpse_set_program_enabled(kpse_pk_format, 1, kpse_src_cmdline);
105 pk_auto_generate = 1;
107 filename = kpse_find_glyph(name, Max(*hdpi, *vdpi),
108 kpse_pk_format, &type);
109 if(filename && type.source == kpse_glyph_source_fallback) {
112 } else if(filename) {
113 *hdpi = *vdpi = type.dpi;
118 static char *pk_lookupn(const char *name, Ushort *hdpi, Ushort *vdpi)
120 kpse_glyph_file_type type;
123 if(pk_auto_generate) {
124 kpse_set_program_enabled(kpse_pk_format, 0, kpse_src_cmdline);
125 pk_auto_generate = 0;
127 filename = kpse_find_glyph(name, Max(*hdpi, *vdpi),
128 kpse_pk_format, &type);
129 if(filename && type.source == kpse_glyph_source_fallback) {
132 } else if(filename) {
133 *hdpi = *vdpi = type.dpi;
138 static inline int pk_get_nyb(FILE *p, pkread *pk)
144 t = c = pk->currbyte;
149 c = pk->currbyte = fuget1(p);
161 * this is a bit cumbersome because we have to pass around
162 * the `pkread' data...
164 static int pk_packed_num(FILE *p, pkread *pkr, int *repeat)
167 int dyn_f = pkr->dyn_f;
169 i = pk_get_nyb(p, pkr);
172 j = pk_get_nyb(p, pkr);
176 j = (j << 4) + pk_get_nyb(p, pkr);
177 return (j - 15 + ((13 - dyn_f) << 4) +
179 } else if(i <= dyn_f)
182 return ((i - dyn_f - 1) << 4) +
183 pk_get_nyb(p, pkr) + dyn_f + 1;
187 *repeat = pk_packed_num(p, pkr, repeat);
188 return pk_packed_num(p, pkr, repeat);
192 #define ROUND(x,y) (((x) + (y) - 1) / (y))
194 static BITMAP *get_bitmap(FILE *p, int w, int h, int flags)
202 flags = 0; /* shut up that compiler */
204 if((bm = bitmap_alloc(w, h)) == NULL)
206 DEBUG((DBG_BITMAPS, "get_bitmap(%d,%d,%d): reading raw bitmap\n",
210 for(i = 0; i < h; i++) {
214 for(j = 0; j < w; j++) {
219 if(currch & (1 << bitpos))
222 if(mask == LASTMASK) {
228 ptr = bm_offset(ptr, bm->stride);
233 static BITMAP *get_packed(FILE *p, int w, int h, int flags)
244 pkr.dyn_f = PK_DYN_F(flags);
245 paint = !!(flags & 0x8);
250 if((bm = bitmap_alloc(w, h)) == NULL)
252 DEBUG((DBG_BITMAPS, "get_packed(%d,%d,%d): reading packed glyph\n",
257 count = pk_packed_num(p, &pkr, &i);
260 fprintf(stderr, "second repeat count for this row (had %d and got %d)\n",
269 /* first finish current row */
271 bitmap_set_row(bm, row, w - inrow, inrow, paint);
272 /* now copy it as many times as required */
273 r = (Uchar *)bm->data + row * bm->stride;
274 while(repeat_count-- > 0) {
276 /* copy entire lines */
277 memcpy(t, r, bm->stride);
282 /* count first row we drew */
284 /* update run count */
286 /* now r points to the beginning of the last row we finished */
292 a = (BmUnit *)(r + bm->stride);
293 /* deal with entirely with/black rows */
295 /* count number of atoms in a row */
296 i = ROUND(w, BITMAP_BITS);
305 bitmap_set_row(bm, row, w - inrow, count, paint);
309 if(row != h || inrow != w) {
310 mdvi_error(_("Bad PK file: More bits than required\n"));
317 static BITMAP *get_char(FILE *p, int w, int h, int flags)
319 /* check if dyn_f == 14 */
320 if(((flags >> 4) & 0xf) == 14)
321 return get_bitmap(p, w, h, flags);
323 return get_packed(p, w, h, flags);
326 /* supports any number of characters in a font */
327 static int pk_load_font(DviParams *unused, DviFont *font)
339 font->chars = xnalloc(DviFontChar, 256);
341 memzero(font->chars, 256 * sizeof(DviFontChar));
342 for(i = 0; i < 256; i++)
343 font->chars[i].offset = 0;
345 /* check the preamble */
346 loc = fuget1(p); hic = fuget1(p);
347 if(loc != PK_PRE || hic != PK_ID)
351 for(loc = 0; loc < i; loc++)
354 DEBUG((DBG_FONTS, "(pk) %s: %s\n", font->fontname, s));
356 fseek(in, (long)i, SEEK_CUR);
358 /* get the design size */
359 font->design = fuget4(p);
360 /* get the checksum */
361 checksum = fuget4(p);
362 if(checksum && font->checksum && font->checksum != checksum) {
363 mdvi_warning(_("%s: checksum mismatch (expected %u, got %u)\n"),
364 font->fontname, font->checksum, checksum);
365 } else if(!font->checksum)
366 font->checksum = checksum;
367 /* skip pixel per point ratios */
373 /* now start reading the font */
374 loc = 256; hic = -1; maxch = 256;
376 /* initialize alpha and beta for TFM width computation */
377 TFMPREPARE(font->scale, z, alpha, beta);
379 while((flag_byte = fuget1(p)) != PK_POST) {
382 if(flag_byte >= PK_CMD_START) {
392 i = fugetn(p, flag_byte - PK_X1 + 1);
396 t = mdvi_malloc(i + 1);
397 for(n = 0; n < i; n++)
400 DEBUG((DBG_SPECIAL, "(pk) %s: Special \"%s\"\n",
405 i = fugetn(p, flag_byte - PK_X1 + 1);
413 DEBUG((DBG_SPECIAL, "(pk) %s: MF special %u\n",
414 font->fontname, (unsigned)i));
420 mdvi_error(_("%s: unexpected preamble\n"), font->fontname);
431 switch(flag_byte & 0x7) {
435 offset = ftell(p) + pl;
437 fsget4(p); /* skip dx */
438 fsget4(p); /* skip dy */
447 pl = (flag_byte % 4) * 65536 + fuget2(p);
449 offset = ftell(p) + pl;
451 fsget2(p); /* skip dx */
459 pl = (flag_byte % 4) * 256 + fuget1(p);
461 offset = ftell(p) + pl;
463 fsget1(p); /* skip dx */
477 font->chars = xresize(font->chars,
478 DviFontChar, cc + 16);
479 for(i = maxch; i < cc + 16; i++)
480 font->chars[i].offset = 0;
483 font->chars[cc].code = cc;
484 font->chars[cc].flags = flag_byte;
485 font->chars[cc].offset = ftell(p);
486 font->chars[cc].width = w;
487 font->chars[cc].height = h;
488 font->chars[cc].glyph.data = NULL;
489 font->chars[cc].x = x;
490 font->chars[cc].y = y;
491 font->chars[cc].glyph.x = x;
492 font->chars[cc].glyph.y = y;
493 font->chars[cc].glyph.w = w;
494 font->chars[cc].glyph.h = h;
495 font->chars[cc].grey.data = NULL;
496 font->chars[cc].shrunk.data = NULL;
497 font->chars[cc].tfmwidth = TFMSCALE(z, tfm, alpha, beta);
498 font->chars[cc].loaded = 0;
499 fseek(p, (long)offset, SEEK_SET);
502 if(flag_byte != PK_POST) {
503 mdvi_error(_("%s: unexpected end of file (no postamble)\n"),
507 while((flag_byte = fuget1(p)) != EOF) {
508 if(flag_byte != PK_NOOP) {
509 mdvi_error(_("invalid PK file! (junk in postamble)\n"));
514 /* resize font char data */
515 if(loc > 0 || hic < maxch-1) {
516 memmove(font->chars, font->chars + loc,
517 (hic - loc + 1) * sizeof(DviFontChar));
518 font->chars = xresize(font->chars,
519 DviFontChar, hic - loc + 1);
526 mdvi_error(_("%s: File corrupted, or not a PK file\n"), font->fontname);
528 mdvi_free(font->chars);
530 font->loc = font->hic = 0;
534 static int pk_font_get_glyph(DviParams *params, DviFont *font, int code)
538 if((ch = FONTCHAR(font, code)) == NULL)
543 DEBUG((DBG_GLYPHS, "(pk) loading glyph for character %d (%dx%d) in font `%s'\n",
544 code, ch->width, ch->height, font->fontname));
545 if(font->in == NULL && font_reopen(font) < 0)
547 if(!ch->width || !ch->height) {
548 /* this happens for ` ' (ASCII 32) in some fonts */
551 ch->glyph.w = ch->width;
552 ch->glyph.h = ch->height;
553 ch->glyph.data = NULL;
556 if(fseek(font->in, ch->offset, SEEK_SET) == -1)
558 ch->glyph.data = get_char(font->in,
559 ch->width, ch->height, ch->flags);
561 /* restore original settings */
564 ch->glyph.w = ch->width;
565 ch->glyph.h = ch->height;