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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 /* functions to read GF fonts */
40 #define GF_NEW_ROW_0 74
41 #define GF_NEW_ROW_1 75
42 #define GF_NEW_ROW_MAX 238
53 #define GF_POST_POST 249
56 #define GF_TRAILER 223
61 static int gf_load_font __PROTO((DviParams *, DviFont *));
62 static int gf_font_get_glyph __PROTO((DviParams *, DviFont *, int));
64 /* only symbol exported by this file */
65 DviFontInfo gf_font_info = {
67 0, /* scaling not supported natively */
71 mdvi_shrink_glyph_grey,
79 static int gf_read_bitmap(FILE *p, DviFontChar *ch)
91 fseek(p, (long)ch->offset, SEEK_SET);
94 /* skip character code */
102 } else if(op == GF_BOC1) {
103 /* skip character code */
105 min_m = fuget1(p); /* this is max_m - min_m */
107 min_n = fuget1(p); /* this is max_n - min_n */
109 min_m = max_m - min_m;
110 min_n = max_n - min_n;
112 error(_("GF: invalid opcode %d in character %d\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);
123 ch->glyph.data = map;
126 ch->glyph.w = ch->width;
127 ch->glyph.h = ch->height;
129 #define COLOR(x) ((x) ? "BLACK" : "WHITE")
131 paint_switch = WHITE;
135 DEBUG((DBG_BITMAPS, "(gf) reading character %d\n", ch->code));
136 while((op = fuget1(p)) != GF_EOC) {
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) {
149 par = fugetn(p, op - GF_PAINT1 + 1);
150 if(y >= ch->height || x + par >= ch->width)
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;
160 } else if(op >= GF_NEW_ROW_0 && op <= GF_NEW_ROW_MAX) {
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));
169 line = bm_offset(line, bpl);
171 paint_switch = WHITE;
172 DEBUG((DBG_BITMAPS, "(gf) skip_0\n"));
177 par = fugetn(p, op - GF_SKIP1 + 1);
179 line = bm_offset(line, (par + 1) * bpl);
181 paint_switch = WHITE;
182 DEBUG((DBG_BITMAPS, "(gf) skip_%d\n", op - GF_SKIP1));
191 s = read_string(p, op - GF_XXX1 + 1, NULL, 0);
192 DEBUG((DBG_SPECIAL, "(gf) Character %d: Special \"%s\"\n",
196 n = fugetn(p, op - GF_XXX1 + 1);
197 fseek(p, (long)n, SEEK_CUR);
203 DEBUG((DBG_SPECIAL, "(gf) Character %d: MF special %u\n",
207 DEBUG((DBG_BITMAPS, "(gf) no_op\n"));
210 error(_("(gf) Character %d: invalid opcode %d\n"),
214 /* chech that we're still inside the bitmap */
215 if(x > ch->width || y > ch->height)
217 DEBUG((DBG_BITMAPS, "(gf) curr_loc @ (%d,%d)\n", x, y));
222 DEBUG((DBG_BITMAPS, "(gf) end of character %d\n", ch->code));
226 error(_("(gf) character %d has an incorrect bounding box\n"),
230 ch->glyph.data = NULL;
234 static int gf_load_font(DviParams *unused, DviFont *font)
251 loc = fuget1(p); hic = fuget1(p);
252 if(loc != GF_PRE || hic != GF_ID)
256 for(i = 0; i < loc; i++)
259 DEBUG((DBG_FONTS, "(gf) %s: %s\n", font->fontname, s));
261 fseek(p, (long)loc, SEEK_CUR);
263 /* now read character locators in postamble */
264 if(fseek(p, (long)-1, SEEK_END) == -1)
268 while((op = fuget1(p)) == GF_TRAILER) {
269 if(fseek(p, (long)-2, SEEK_CUR) < 0)
273 if(op != GF_ID || n < 4)
275 /* get the pointer to the postamble */
276 fseek(p, (long)-5, SEEK_CUR);
279 fseek(p, (long)op, SEEK_SET);
280 if(fuget1(p) != GF_POST)
282 /* skip pointer to last EOC */
284 /* get the design size */
285 font->design = 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 */
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);
303 TFMPREPARE(font->scale, z, alpha, beta);
304 while((op = fuget1(p)) != GF_POST_POST) {
308 /* get the character code */
314 ch = &font->chars[cc];
317 fsget4(p); /* skip dx */
318 fsget4(p); /* skip dy */
321 fuget1(p); /* skip dx */
325 error(_("%s: junk in postamble\n"), font->fontname);
329 ch->tfmwidth = fuget4(p);
330 ch->tfmwidth = TFMSCALE(ch->tfmwidth, z, alpha, beta);
331 ch->offset = fuget4(p);
334 /* initialize the rest of the glyph information */
339 ch->glyph.data = NULL;
340 ch->shrunk.data = NULL;
341 ch->grey.data = NULL;
346 if(op != GF_POST_POST)
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);
362 error(_("%s: File corrupted, or not a GF file\n"), font->fontname);
365 mdvi_free(font->chars);
368 font->loc = font->hic = 0;
372 static int gf_font_get_glyph(DviParams *params, DviFont *font, int code)
376 if(code < font->loc || code > font->hic || !font->chars)
378 ch = &font->chars[code - font->loc];
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)
387 if(fseek(font->in, ch->offset, SEEK_SET) == -1)
389 if(gf_read_bitmap(font->in, ch) < 0)