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