1 /* gf.c - GF font support */
3 * Copyright (C) 2000, Matias Atria
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.
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.
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.
20 /* functions to read GF fonts */
41 #define GF_NEW_ROW_0 74
42 #define GF_NEW_ROW_1 75
43 #define GF_NEW_ROW_MAX 238
54 #define GF_POST_POST 249
57 #define GF_TRAILER 223
62 static int gf_load_font __PROTO((DviParams *, DviFont *));
63 static int gf_font_get_glyph __PROTO((DviParams *, DviFont *, int));
65 /* only symbol exported by this file */
66 DviFontInfo gf_font_info = {
68 0, /* scaling not supported natively */
72 mdvi_shrink_glyph_grey,
80 static int gf_read_bitmap(FILE *p, DviFontChar *ch)
92 fseek(p, (long)ch->offset, SEEK_SET);
95 /* skip character code */
103 } else if(op == GF_BOC1) {
104 /* skip character code */
106 min_m = fuget1(p); /* this is max_m - min_m */
108 min_n = fuget1(p); /* this is max_n - min_n */
110 min_m = max_m - min_m;
111 min_n = max_n - min_n;
113 mdvi_error(_("GF: invalid opcode %d in character %d\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);
124 ch->glyph.data = map;
127 ch->glyph.w = ch->width;
128 ch->glyph.h = ch->height;
130 #define COLOR(x) ((x) ? "BLACK" : "WHITE")
132 paint_switch = WHITE;
136 DEBUG((DBG_BITMAPS, "(gf) reading character %d\n", ch->code));
137 while((op = fuget1(p)) != GF_EOC) {
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) {
150 par = fugetn(p, op - GF_PAINT1 + 1);
151 if(y >= ch->height || x + par >= ch->width)
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;
161 } else if(op >= GF_NEW_ROW_0 && op <= GF_NEW_ROW_MAX) {
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));
170 line = bm_offset(line, bpl);
172 paint_switch = WHITE;
173 DEBUG((DBG_BITMAPS, "(gf) skip_0\n"));
178 par = fugetn(p, op - GF_SKIP1 + 1);
180 line = bm_offset(line, (par + 1) * bpl);
182 paint_switch = WHITE;
183 DEBUG((DBG_BITMAPS, "(gf) skip_%d\n", op - GF_SKIP1));
192 s = read_string(p, op - GF_XXX1 + 1, NULL, 0);
193 DEBUG((DBG_SPECIAL, "(gf) Character %d: Special \"%s\"\n",
197 n = fugetn(p, op - GF_XXX1 + 1);
198 fseek(p, (long)n, SEEK_CUR);
204 DEBUG((DBG_SPECIAL, "(gf) Character %d: MF special %u\n",
208 DEBUG((DBG_BITMAPS, "(gf) no_op\n"));
211 mdvi_error(_("(gf) Character %d: invalid opcode %d\n"),
215 /* chech that we're still inside the bitmap */
216 if(x > ch->width || y > ch->height)
218 DEBUG((DBG_BITMAPS, "(gf) curr_loc @ (%d,%d)\n", x, y));
223 DEBUG((DBG_BITMAPS, "(gf) end of character %d\n", ch->code));
227 mdvi_error(_("(gf) character %d has an incorrect bounding box\n"),
231 ch->glyph.data = NULL;
235 static int gf_load_font(DviParams *unused, DviFont *font)
252 loc = fuget1(p); hic = fuget1(p);
253 if(loc != GF_PRE || hic != GF_ID)
257 for(i = 0; i < loc; i++)
260 DEBUG((DBG_FONTS, "(gf) %s: %s\n", font->fontname, s));
262 fseek(p, (long)loc, SEEK_CUR);
264 /* now read character locators in postamble */
265 if(fseek(p, (long)-1, SEEK_END) == -1)
269 while((op = fuget1(p)) == GF_TRAILER) {
270 if(fseek(p, (long)-2, SEEK_CUR) < 0)
274 if(op != GF_ID || n < 4)
276 /* get the pointer to the postamble */
277 fseek(p, (long)-5, SEEK_CUR);
280 fseek(p, (long)op, SEEK_SET);
281 if(fuget1(p) != GF_POST)
283 /* skip pointer to last EOC */
285 /* get the design size */
286 font->design = 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 */
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);
304 TFMPREPARE(font->scale, z, alpha, beta);
305 while((op = fuget1(p)) != GF_POST_POST) {
309 /* get the character code */
315 ch = &font->chars[cc];
318 fsget4(p); /* skip dx */
319 fsget4(p); /* skip dy */
322 fuget1(p); /* skip dx */
326 mdvi_error(_("%s: junk in postamble\n"), font->fontname);
330 ch->tfmwidth = fuget4(p);
331 ch->tfmwidth = TFMSCALE(ch->tfmwidth, z, alpha, beta);
332 ch->offset = fuget4(p);
335 /* initialize the rest of the glyph information */
340 ch->glyph.data = NULL;
341 ch->shrunk.data = NULL;
342 ch->grey.data = NULL;
347 if(op != GF_POST_POST)
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);
363 mdvi_error(_("%s: File corrupted, or not a GF file\n"), font->fontname);
366 mdvi_free(font->chars);
369 font->loc = font->hic = 0;
373 static int gf_font_get_glyph(DviParams *params, DviFont *font, int code)
377 if(code < font->loc || code > font->hic || !font->chars)
379 ch = &font->chars[code - font->loc];
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)
388 if(fseek(font->in, ch->offset, SEEK_SET) == -1)
390 if(gf_read_bitmap(font->in, ch) < 0)