Evince
Evince is a document viewer capable of displaying multiple and single page document formats like PDF and Postscript.
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
pk.c
Go to the documentation of this file.
1 
2 /* Copyright (C) 2000, Matias Atria
3  *
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.
8  *
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.
13  *
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.
17  */
18 
19 /*
20  * History:
21  *
22  * 11/3/2000:
23  * - First working version
24  * 11/4/2000:
25  * - FIXED: entirely white/black rows were missed.
26  * 11/8/2000:
27  * - TESTED: Glyphs are rendered correctly in different byte orders.
28  * - Made bitmap code much more efficient and compact.
29  */
30 
31 #include <config.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <string.h>
36 #include <math.h>
37 
38 #include "mdvi.h"
39 #include "private.h"
40 
41 #define PK_ID 89
42 #define PK_CMD_START 240
43 #define PK_X1 240
44 #define PK_X2 241
45 #define PK_X3 242
46 #define PK_X4 243
47 #define PK_Y 244
48 #define PK_POST 245
49 #define PK_NOOP 246
50 #define PK_PRE 247
51 
52 #define PK_DYN_F(x) (((x) >> 4) & 0xf)
53 #define PK_PACKED(x) (PK_DYN_F(x) != 14)
54 
55 static int pk_load_font __PROTO((DviParams *, DviFont *));
56 static int pk_font_get_glyph __PROTO((DviParams *, DviFont *, int));
57 
58 static int pk_auto_generate = 1; /* this is ON by default */
59 
60 typedef struct {
61  char currbyte;
62  char nybpos;
63  int dyn_f;
64 } pkread;
65 
66 static char *pk_lookup __PROTO((const char *, Ushort *, Ushort *));
67 static char *pk_lookupn __PROTO((const char *, Ushort *, Ushort *));
68 
69 /* only symbols exported by this file */
71  "PK",
72  0, /* scaling not supported natively */
77  NULL, /* free */
78  NULL, /* reset */
79  pk_lookup, /* lookup */
80  kpse_pk_format,
81  NULL
82 };
83 
85  "PKN",
86  0, /* scaling not supported natively */
91  NULL, /* free */
92  NULL, /* reset */
93  pk_lookupn, /* lookup */
94  kpse_pk_format,
95  NULL
96 };
97 
98 static char *pk_lookup(const char *name, Ushort *hdpi, Ushort *vdpi)
99 {
100  kpse_glyph_file_type type;
101  char *filename;
102 
103  if(pk_auto_generate == 0) {
104  kpse_set_program_enabled(kpse_pk_format, 1, kpse_src_cmdline);
105  pk_auto_generate = 1;
106  }
107  filename = kpse_find_glyph(name, Max(*hdpi, *vdpi),
108  kpse_pk_format, &type);
109  if(filename && type.source == kpse_glyph_source_fallback) {
110  mdvi_free(filename);
111  filename = NULL;
112  } else if(filename) {
113  *hdpi = *vdpi = type.dpi;
114  }
115  return filename;
116 }
117 
118 static char *pk_lookupn(const char *name, Ushort *hdpi, Ushort *vdpi)
119 {
120  kpse_glyph_file_type type;
121  char *filename;
122 
123  if(pk_auto_generate) {
124  kpse_set_program_enabled(kpse_pk_format, 0, kpse_src_cmdline);
125  pk_auto_generate = 0;
126  }
127  filename = kpse_find_glyph(name, Max(*hdpi, *vdpi),
128  kpse_pk_format, &type);
129  if(filename && type.source == kpse_glyph_source_fallback) {
130  mdvi_free(filename);
131  filename = NULL;
132  } else if(filename) {
133  *hdpi = *vdpi = type.dpi;
134  }
135  return filename;
136 }
137 
138 static inline int pk_get_nyb(FILE *p, pkread *pk)
139 {
140  unsigned t;
141  int nb;
142  char c;
143 
144  t = c = pk->currbyte;
145  nb = pk->nybpos;
146 
147  switch(nb) {
148  case 0:
149  c = pk->currbyte = fuget1(p);
150  t = (c >> 4);
151  break;
152  case 1:
153  t = c;
154  break;
155  }
156  pk->nybpos = !nb;
157  return (t & 0xf);
158 }
159 
160 /*
161  * this is a bit cumbersome because we have to pass around
162  * the `pkread' data...
163  */
164 static int pk_packed_num(FILE *p, pkread *pkr, int *repeat)
165 {
166  int i, j;
167  int dyn_f = pkr->dyn_f;
168 
169  i = pk_get_nyb(p, pkr);
170  if(i == 0) {
171  do {
172  j = pk_get_nyb(p, pkr);
173  i++;
174  } while(j == 0);
175  while(i-- > 0)
176  j = (j << 4) + pk_get_nyb(p, pkr);
177  return (j - 15 + ((13 - dyn_f) << 4) +
178  dyn_f);
179  } else if(i <= dyn_f)
180  return i;
181  else if(i < 14)
182  return ((i - dyn_f - 1) << 4) +
183  pk_get_nyb(p, pkr) + dyn_f + 1;
184  else {
185  *repeat = 1;
186  if(i == 14)
187  *repeat = pk_packed_num(p, pkr, repeat);
188  return pk_packed_num(p, pkr, repeat);
189  }
190 }
191 
192 #define ROUND(x,y) (((x) + (y) - 1) / (y))
193 
194 static BITMAP *get_bitmap(FILE *p, int w, int h, int flags)
195 {
196  int i, j;
197  BmUnit *ptr;
198  BITMAP *bm;
199  int bitpos;
200  int currch;
201 
202  flags = 0; /* shut up that compiler */
203  bitpos = -1;
204  if((bm = bitmap_alloc(w, h)) == NULL)
205  return NULL;
206  DEBUG((DBG_BITMAPS, "get_bitmap(%d,%d,%d): reading raw bitmap\n",
207  w, h, flags));
208  ptr = bm->data;
209  currch = 0;
210  for(i = 0; i < h; i++) {
211  BmUnit mask;
212 
213  mask = FIRSTMASK;
214  for(j = 0; j < w; j++) {
215  if(bitpos < 0) {
216  currch = fuget1(p);
217  bitpos = 7;
218  }
219  if(currch & (1 << bitpos))
220  *ptr |= mask;
221  bitpos--;
222  if(mask == LASTMASK) {
223  ptr++;
224  mask = FIRSTMASK;
225  } else
226  NEXTMASK(mask);
227  }
228  ptr = bm_offset(ptr, bm->stride);
229  }
230  return bm;
231 }
232 
233 static BITMAP *get_packed(FILE *p, int w, int h, int flags)
234 {
235  int inrow, count;
236  int row;
237  BITMAP *bm;
238  int repeat_count;
239  int paint;
240  pkread pkr;
241 
242  pkr.nybpos = 0;
243  pkr.currbyte = 0;
244  pkr.dyn_f = PK_DYN_F(flags);
245  paint = !!(flags & 0x8);
246 
247  repeat_count = 0;
248  row = 0;
249  inrow = w;
250  if((bm = bitmap_alloc(w, h)) == NULL)
251  return NULL;
252  DEBUG((DBG_BITMAPS, "get_packed(%d,%d,%d): reading packed glyph\n",
253  w, h, flags));
254  while(row < h) {
255  int i = 0;
256 
257  count = pk_packed_num(p, &pkr, &i);
258  if(i > 0) {
259  if(repeat_count)
260  fprintf(stderr, "second repeat count for this row (had %d and got %d)\n",
261  repeat_count, i);
262  repeat_count = i;
263  }
264 
265  if(count >= inrow) {
266  Uchar *r, *t;
267  BmUnit *a, mask;
268 
269  /* first finish current row */
270  if(paint)
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) {
275  t = r + bm->stride;
276  /* copy entire lines */
277  memcpy(t, r, bm->stride);
278  r = t;
279  row++;
280  }
281  repeat_count = 0;
282  /* count first row we drew */
283  row++;
284  /* update run count */
285  count -= inrow;
286  /* now r points to the beginning of the last row we finished */
287  if(paint)
288  mask = ~((BmUnit)0);
289  else
290  mask = 0;
291  /* goto next row */
292  a = (BmUnit *)(r + bm->stride);
293  /* deal with entirely with/black rows */
294  while(count >= w) {
295  /* count number of atoms in a row */
296  i = ROUND(w, BITMAP_BITS);
297  while(i-- > 0)
298  *a++ = mask;
299  count -= w;
300  row++;
301  }
302  inrow = w;
303  }
304  if(count > 0)
305  bitmap_set_row(bm, row, w - inrow, count, paint);
306  inrow -= count;
307  paint = !paint;
308  }
309  if(row != h || inrow != w) {
310  mdvi_error(_("Bad PK file: More bits than required\n"));
311  bitmap_destroy(bm);
312  return NULL;
313  }
314  return bm;
315 }
316 
317 static BITMAP *get_char(FILE *p, int w, int h, int flags)
318 {
319  /* check if dyn_f == 14 */
320  if(((flags >> 4) & 0xf) == 14)
321  return get_bitmap(p, w, h, flags);
322  else
323  return get_packed(p, w, h, flags);
324 }
325 
326 /* supports any number of characters in a font */
327 static int pk_load_font(DviParams *unused, DviFont *font)
328 {
329  int i;
330  int flag_byte;
331  int hic, maxch;
332  Int32 checksum;
333  FILE *p;
334 #ifndef NODEBUG
335  char s[256];
336 #endif
337  long alpha, beta, z;
338  unsigned int loc;
339 
340  font->chars = xnalloc(DviFontChar, 256);
341  p = font->in;
342  memzero(font->chars, 256 * sizeof(DviFontChar));
343  for(i = 0; i < 256; i++)
344  font->chars[i].offset = 0;
345 
346  /* check the preamble */
347  loc = fuget1(p); hic = fuget1(p);
348  if(loc != PK_PRE || hic != PK_ID)
349  goto badpk;
350  i = fuget1(p);
351 #ifndef NODEBUG
352  for(loc = 0; loc < i; loc++)
353  s[loc] = fuget1(p);
354  s[loc] = 0;
355  DEBUG((DBG_FONTS, "(pk) %s: %s\n", font->fontname, s));
356 #else
357  fseek(in, (long)i, SEEK_CUR);
358 #endif
359  /* get the design size */
360  font->design = fuget4(p);
361  /* get the checksum */
362  checksum = fuget4(p);
363  if(checksum && font->checksum && font->checksum != checksum) {
364  mdvi_warning(_("%s: checksum mismatch (expected %u, got %u)\n"),
365  font->fontname, font->checksum, checksum);
366  } else if(!font->checksum)
367  font->checksum = checksum;
368  /* skip pixel per point ratios */
369  fuget4(p);
370  fuget4(p);
371  if(feof(p))
372  goto badpk;
373 
374  /* now start reading the font */
375  loc = 256; hic = -1; maxch = 256;
376 
377  /* initialize alpha and beta for TFM width computation */
378  TFMPREPARE(font->scale, z, alpha, beta);
379 
380  while((flag_byte = fuget1(p)) != PK_POST) {
381  if(feof(p))
382  break;
383  if(flag_byte >= PK_CMD_START) {
384  switch(flag_byte) {
385  case PK_X1:
386  case PK_X2:
387  case PK_X3:
388  case PK_X4: {
389 #ifndef NODEBUG
390  char *t;
391  int n;
392 
393  i = fugetn(p, flag_byte - PK_X1 + 1);
394  if(i < 256)
395  t = &s[0];
396  else
397  t = mdvi_malloc(i + 1);
398  for(n = 0; n < i; n++)
399  t[n] = fuget1(p);
400  t[n] = 0;
401  DEBUG((DBG_SPECIAL, "(pk) %s: Special \"%s\"\n",
402  font->fontname, t));
403  if(t != &s[0])
404  mdvi_free(t);
405 #else
406  i = fugetn(p, flag_byte - PK_X1 + 1);
407  while(i-- > 0)
408  fuget1(p);
409 #endif
410  break;
411  }
412  case PK_Y:
413  i = fuget4(p);
414  DEBUG((DBG_SPECIAL, "(pk) %s: MF special %u\n",
415  font->fontname, (unsigned)i));
416  break;
417  case PK_POST:
418  case PK_NOOP:
419  break;
420  case PK_PRE:
421  mdvi_error(_("%s: unexpected preamble\n"), font->fontname);
422  goto error;
423  }
424  } else {
425  int pl;
426  int cc;
427  int w, h;
428  int x, y;
429  int offset;
430  long tfm;
431 
432  switch(flag_byte & 0x7) {
433  case 7:
434  pl = fuget4(p);
435  cc = fuget4(p);
436  offset = ftell(p) + pl;
437  tfm = fuget4(p);
438  fsget4(p); /* skip dx */
439  fsget4(p); /* skip dy */
440  w = fuget4(p);
441  h = fuget4(p);
442  x = fsget4(p);
443  y = fsget4(p);
444  break;
445  case 4:
446  case 5:
447  case 6:
448  pl = (flag_byte % 4) * 65536 + fuget2(p);
449  cc = fuget1(p);
450  offset = ftell(p) + pl;
451  tfm = fuget3(p);
452  fsget2(p); /* skip dx */
453  /* dy assumed 0 */
454  w = fuget2(p);
455  h = fuget2(p);
456  x = fsget2(p);
457  y = fsget2(p);
458  break;
459  default:
460  pl = (flag_byte % 4) * 256 + fuget1(p);
461  cc = fuget1(p);
462  offset = ftell(p) + pl;
463  tfm = fuget3(p);
464  fsget1(p); /* skip dx */
465  /* dy assumed 0 */
466  w = fuget1(p);
467  h = fuget1(p);
468  x = fsget1(p);
469  y = fsget1(p);
470  }
471  if(feof(p))
472  break;
473 
474  /* Although the PK format support bigger char codes,
475  * XeTeX and other extended TeX engines support charcodes up to
476  * 65536, while normal TeX engine supports only charcode up to 255.*/
477  if (cc < 0 || cc > 65536) {
478  mdvi_error (_("%s: unexpected charcode (%d)\n"),
479  font->fontname,cc);
480  goto error;
481  }
482  if(cc < loc)
483  loc = cc;
484  if(cc > hic)
485  hic = cc;
486  if(cc > maxch) {
487  font->chars = xresize(font->chars,
488  DviFontChar, cc + 16);
489  for(i = maxch; i < cc + 16; i++)
490  font->chars[i].offset = 0;
491  maxch = cc + 16;
492  }
493  font->chars[cc].code = cc;
494  font->chars[cc].flags = flag_byte;
495  font->chars[cc].offset = ftell(p);
496  font->chars[cc].width = w;
497  font->chars[cc].height = h;
498  font->chars[cc].glyph.data = NULL;
499  font->chars[cc].x = x;
500  font->chars[cc].y = y;
501  font->chars[cc].glyph.x = x;
502  font->chars[cc].glyph.y = y;
503  font->chars[cc].glyph.w = w;
504  font->chars[cc].glyph.h = h;
505  font->chars[cc].grey.data = NULL;
506  font->chars[cc].shrunk.data = NULL;
507  font->chars[cc].tfmwidth = TFMSCALE(z, tfm, alpha, beta);
508  font->chars[cc].loaded = 0;
509  fseek(p, (long)offset, SEEK_SET);
510  }
511  }
512  if(flag_byte != PK_POST) {
513  mdvi_error(_("%s: unexpected end of file (no postamble)\n"),
514  font->fontname);
515  goto error;
516  }
517  while((flag_byte = fuget1(p)) != EOF) {
518  if(flag_byte != PK_NOOP) {
519  mdvi_error(_("invalid PK file! (junk in postamble)\n"));
520  goto error;
521  }
522  }
523 
524  /* resize font char data */
525  if(loc > 0 || hic < maxch-1) {
526  memmove(font->chars, font->chars + loc,
527  (hic - loc + 1) * sizeof(DviFontChar));
528  font->chars = xresize(font->chars,
529  DviFontChar, hic - loc + 1);
530  }
531  font->loc = loc;
532  font->hic = hic;
533  return 0;
534 
535 badpk:
536  mdvi_error(_("%s: File corrupted, or not a PK file\n"), font->fontname);
537 error:
538  mdvi_free(font->chars);
539  font->chars = NULL;
540  font->loc = font->hic = 0;
541  return -1;
542 }
543 
544 static int pk_font_get_glyph(DviParams *params, DviFont *font, int code)
545 {
546  DviFontChar *ch;
547 
548  if((ch = FONTCHAR(font, code)) == NULL)
549  return -1;
550 
551  if(ch->offset == 0)
552  return -1;
553  DEBUG((DBG_GLYPHS, "(pk) loading glyph for character %d (%dx%d) in font `%s'\n",
554  code, ch->width, ch->height, font->fontname));
555  if(font->in == NULL && font_reopen(font) < 0)
556  return -1;
557  if(!ch->width || !ch->height) {
558  /* this happens for ` ' (ASCII 32) in some fonts */
559  ch->glyph.x = ch->x;
560  ch->glyph.y = ch->y;
561  ch->glyph.w = ch->width;
562  ch->glyph.h = ch->height;
563  ch->glyph.data = NULL;
564  return 0;
565  }
566  if(fseek(font->in, ch->offset, SEEK_SET) == -1)
567  return -1;
568  ch->glyph.data = get_char(font->in,
569  ch->width, ch->height, ch->flags);
570  if(ch->glyph.data) {
571  /* restore original settings */
572  ch->glyph.x = ch->x;
573  ch->glyph.y = ch->y;
574  ch->glyph.w = ch->width;
575  ch->glyph.h = ch->height;
576  } else
577  return -1;
578  ch->loaded = 1;
579  return 0;
580 }