]> www.fi.muni.cz Git - evince.git/blob - backend/dvi/mdvi-lib/gf.c
Update FSF address everywhere.
[evince.git] / backend / dvi / mdvi-lib / gf.c
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 */
66 DviFontInfo gf_font_info = {
67         "GF",
68         0, /* scaling not supported natively */
69         gf_load_font,
70         gf_font_get_glyph,
71         mdvi_shrink_glyph,
72         mdvi_shrink_glyph_grey,
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 }