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
gf.c
Go to the documentation of this file.
1 /* gf.c - GF font support */
2 /*
3  * Copyright (C) 2000, Matias Atria
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19 
20 /* functions to read GF fonts */
21 
22 #include <config.h>
23 #include <string.h>
24 #include "common.h"
25 #include "mdvi.h"
26 #include "private.h"
27 
28 /* opcodes */
29 
30 #define GF_PAINT0 0
31 #define GF_PAINT1 64
32 #define GF_PAINT2 65
33 #define GF_PAINT3 66
34 #define GF_BOC 67
35 #define GF_BOC1 68
36 #define GF_EOC 69
37 #define GF_SKIP0 70
38 #define GF_SKIP1 71
39 #define GF_SKIP2 72
40 #define GF_SKIP3 73
41 #define GF_NEW_ROW_0 74
42 #define GF_NEW_ROW_1 75
43 #define GF_NEW_ROW_MAX 238
44 #define GF_XXX1 239
45 #define GF_XXX2 240
46 #define GF_XXX3 241
47 #define GF_XXX4 242
48 #define GF_YYY 243
49 #define GF_NOOP 244
50 #define GF_LOC 245
51 #define GF_LOC0 246
52 #define GF_PRE 247
53 #define GF_POST 248
54 #define GF_POST_POST 249
55 
56 #define GF_ID 131
57 #define GF_TRAILER 223
58 
59 #define BLACK 1
60 #define WHITE 0
61 
62 static int gf_load_font __PROTO((DviParams *, DviFont *));
63 static int gf_font_get_glyph __PROTO((DviParams *, DviFont *, int));
64 
65 /* only symbol exported by this file */
67  "GF",
68  0, /* scaling not supported natively */
73  NULL, /* free */
74  NULL, /* reset */
75  NULL, /* lookup */
76  kpse_gf_format,
77  NULL
78 };
79 
80 static int gf_read_bitmap(FILE *p, DviFontChar *ch)
81 {
82  int op;
83  int min_n, max_n;
84  int min_m, max_m;
85  int paint_switch;
86  int x, y;
87  int bpl;
88  Int32 par;
89  BmUnit *line;
90  BITMAP *map;
91 
92  fseek(p, (long)ch->offset, SEEK_SET);
93  op = fuget1(p);
94  if(op == GF_BOC) {
95  /* skip character code */
96  fuget4(p);
97  /* skip pointer */
98  fuget4(p);
99  min_m = fsget4(p);
100  max_m = fsget4(p);
101  min_n = fsget4(p);
102  max_n = fsget4(p);
103  } else if(op == GF_BOC1) {
104  /* skip character code */
105  fuget1(p);
106  min_m = fuget1(p); /* this is max_m - min_m */
107  max_m = fuget1(p);
108  min_n = fuget1(p); /* this is max_n - min_n */
109  max_n = fuget1(p);
110  min_m = max_m - min_m;
111  min_n = max_n - min_n;
112  } else {
113  mdvi_error(_("GF: invalid opcode %d in character %d\n"),
114  op, ch->code);
115  return -1;
116  }
117 
118  ch->x = -min_m;
119  ch->y = max_n;
120  ch->width = max_m - min_m + 1;
121  ch->height = max_n - min_n + 1;
122  map = bitmap_alloc(ch->width, ch->height);
123 
124  ch->glyph.data = map;
125  ch->glyph.x = ch->x;
126  ch->glyph.y = ch->y;
127  ch->glyph.w = ch->width;
128  ch->glyph.h = ch->height;
129 
130 #define COLOR(x) ((x) ? "BLACK" : "WHITE")
131 
132  paint_switch = WHITE;
133  x = y = 0;
134  line = map->data;
135  bpl = map->stride;
136  DEBUG((DBG_BITMAPS, "(gf) reading character %d\n", ch->code));
137  while((op = fuget1(p)) != GF_EOC) {
138  Int32 n;
139 
140  if(feof(p))
141  break;
142  if(op == GF_PAINT0) {
143  DEBUG((DBG_BITMAPS, "(gf) Paint0 %s -> %s\n",
144  COLOR(paint_switch), COLOR(!paint_switch)));
145  paint_switch = !paint_switch;
146  } else if(op <= GF_PAINT3) {
147  if(op < GF_PAINT1)
148  par = op;
149  else
150  par = fugetn(p, op - GF_PAINT1 + 1);
151  if(y >= ch->height || x + par >= ch->width)
152  goto toobig;
153  /* paint everything between columns x and x + par - 1 */
154  DEBUG((DBG_BITMAPS, "(gf) Paint %d %s from (%d,%d)\n",
155  par, COLOR(paint_switch), x, y));
156  if(paint_switch == BLACK)
157  bitmap_paint_bits(line + (x / BITMAP_BITS),
158  x % BITMAP_BITS, par);
159  paint_switch = !paint_switch;
160  x += par;
161  } else if(op >= GF_NEW_ROW_0 && op <= GF_NEW_ROW_MAX) {
162  y++;
163  line = bm_offset(line, bpl);
164  x = op - GF_NEW_ROW_0;
165  paint_switch = BLACK;
166  DEBUG((DBG_BITMAPS, "(gf) new_row_%d\n", x));
167  } else switch(op) {
168  case GF_SKIP0:
169  y++;
170  line = bm_offset(line, bpl);
171  x = 0;
172  paint_switch = WHITE;
173  DEBUG((DBG_BITMAPS, "(gf) skip_0\n"));
174  break;
175  case GF_SKIP1:
176  case GF_SKIP2:
177  case GF_SKIP3:
178  par = fugetn(p, op - GF_SKIP1 + 1);
179  y += par + 1;
180  line = bm_offset(line, (par + 1) * bpl);
181  x = 0;
182  paint_switch = WHITE;
183  DEBUG((DBG_BITMAPS, "(gf) skip_%d\n", op - GF_SKIP1));
184  break;
185  case GF_XXX1:
186  case GF_XXX2:
187  case GF_XXX3:
188  case GF_XXX4: {
189 #ifndef NODEBUG
190  char *s;
191 
192  s = read_string(p, op - GF_XXX1 + 1, NULL, 0);
193  DEBUG((DBG_SPECIAL, "(gf) Character %d: Special \"%s\"\n",
194  ch->code, s));
195  mdvi_free(s);
196 #else
197  n = fugetn(p, op - GF_XXX1 + 1);
198  fseek(p, (long)n, SEEK_CUR);
199 #endif
200  break;
201  }
202  case GF_YYY:
203  n = fuget4(p);
204  DEBUG((DBG_SPECIAL, "(gf) Character %d: MF special %u\n",
205  ch->code, n));
206  break;
207  case GF_NOOP:
208  DEBUG((DBG_BITMAPS, "(gf) no_op\n"));
209  break;
210  default:
211  mdvi_error(_("(gf) Character %d: invalid opcode %d\n"),
212  ch->code, op);
213  goto error;
214  }
215  /* chech that we're still inside the bitmap */
216  if(x > ch->width || y > ch->height)
217  goto toobig;
218  DEBUG((DBG_BITMAPS, "(gf) curr_loc @ (%d,%d)\n", x, y));
219  }
220 
221  if(op != GF_EOC)
222  goto error;
223  DEBUG((DBG_BITMAPS, "(gf) end of character %d\n", ch->code));
224  return 0;
225 
226 toobig:
227  mdvi_error(_("(gf) character %d has an incorrect bounding box\n"),
228  ch->code);
229 error:
230  bitmap_destroy(map);
231  ch->glyph.data = NULL;
232  return -1;
233 }
234 
235 static int gf_load_font(DviParams *unused, DviFont *font)
236 {
237  int i;
238  int n;
239  int loc;
240  int hic;
241  FILE *p;
242  Int32 word;
243  int op;
244  long alpha, beta, z;
245 #ifndef NODEBUG
246  char s[256];
247 #endif
248 
249  p = font->in;
250 
251  /* check preamble */
252  loc = fuget1(p); hic = fuget1(p);
253  if(loc != GF_PRE || hic != GF_ID)
254  goto badgf;
255  loc = fuget1(p);
256 #ifndef NODEBUG
257  for(i = 0; i < loc; i++)
258  s[i] = fuget1(p);
259  s[i] = 0;
260  DEBUG((DBG_FONTS, "(gf) %s: %s\n", font->fontname, s));
261 #else
262  fseek(p, (long)loc, SEEK_CUR);
263 #endif
264  /* now read character locators in postamble */
265  if(fseek(p, (long)-1, SEEK_END) == -1)
266  return -1;
267 
268  n = 0;
269  while((op = fuget1(p)) == GF_TRAILER) {
270  if(fseek(p, (long)-2, SEEK_CUR) < 0)
271  break;
272  n++;
273  }
274  if(op != GF_ID || n < 4)
275  goto badgf;
276  /* get the pointer to the postamble */
277  fseek(p, (long)-5, SEEK_CUR);
278  op = fuget4(p);
279  /* jump to it */
280  fseek(p, (long)op, SEEK_SET);
281  if(fuget1(p) != GF_POST)
282  goto badgf;
283  /* skip pointer to last EOC */
284  fuget4(p);
285  /* get the design size */
286  font->design = fuget4(p);
287  /* the checksum */
288  word = fuget4(p);
289  if(word && font->checksum && font->checksum != word) {
290  mdvi_warning(_("%s: bad checksum (expected %u, found %u)\n"),
291  font->fontname, font->checksum, word);
292  } else if(!font->checksum)
293  font->checksum = word;
294  /* skip pixels per point ratio */
295  fuget4(p);
296  fuget4(p);
297  font->chars = xnalloc(DviFontChar, 256);
298  for(loc = 0; loc < 256; loc++)
299  font->chars[loc].offset = 0;
300  /* skip glyph "bounding box" */
301  fseek(p, (long)16, SEEK_CUR);
302  loc = 256;
303  hic = -1;
304  TFMPREPARE(font->scale, z, alpha, beta);
305  while((op = fuget1(p)) != GF_POST_POST) {
306  DviFontChar *ch;
307  int cc;
308 
309  /* get the character code */
310  cc = fuget1(p);
311  if(cc < loc)
312  loc = cc;
313  if(cc > hic)
314  hic = cc;
315  ch = &font->chars[cc];
316  switch(op) {
317  case GF_LOC:
318  fsget4(p); /* skip dx */
319  fsget4(p); /* skip dy */
320  break;
321  case GF_LOC0:
322  fuget1(p); /* skip dx */
323  /* dy assumed 0 */
324  break;
325  default:
326  mdvi_error(_("%s: junk in postamble\n"), font->fontname);
327  goto error;
328  }
329  ch->code = cc;
330  ch->tfmwidth = fuget4(p);
331  ch->tfmwidth = TFMSCALE(ch->tfmwidth, z, alpha, beta);
332  ch->offset = fuget4(p);
333  if(ch->offset == -1)
334  ch->offset = 0;
335  /* initialize the rest of the glyph information */
336  ch->x = 0;
337  ch->y = 0;
338  ch->width = 0;
339  ch->height = 0;
340  ch->glyph.data = NULL;
341  ch->shrunk.data = NULL;
342  ch->grey.data = NULL;
343  ch->flags = 0;
344  ch->loaded = 0;
345  }
346 
347  if(op != GF_POST_POST)
348  goto badgf;
349 
350  if(loc > 0 || hic < 255) {
351  /* shrink to optimal size */
352  memmove(font->chars, font->chars + loc,
353  (hic - loc + 1) * sizeof(DviFontChar));
354  font->chars = xresize(font->chars,
355  DviFontChar, hic - loc + 1);
356  }
357  font->loc = loc;
358  font->hic = hic;
359 
360  return 0;
361 
362 badgf:
363  mdvi_error(_("%s: File corrupted, or not a GF file\n"), font->fontname);
364 error:
365  if(font->chars) {
366  mdvi_free(font->chars);
367  font->chars = NULL;
368  }
369  font->loc = font->hic = 0;
370  return -1;
371 }
372 
373 static int gf_font_get_glyph(DviParams *params, DviFont *font, int code)
374 {
375  DviFontChar *ch;
376 
377  if(code < font->loc || code > font->hic || !font->chars)
378  return -1;
379  ch = &font->chars[code - font->loc];
380 
381  if(!ch->loaded) {
382  if(ch->offset == 0)
383  return -1;
384  DEBUG((DBG_GLYPHS, "(gf) %s: loading GF glyph for character %d\n",
385  font->fontname, code));
386  if(font->in == NULL && font_reopen(font) < 0)
387  return -1;
388  if(fseek(font->in, ch->offset, SEEK_SET) == -1)
389  return -1;
390  if(gf_read_bitmap(font->in, ch) < 0)
391  return -1;
392  ch->loaded = 1;
393  }
394  return 0;
395 }