2 * Copyright (C) 2000, Matias Atria
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 static ListHead fontlist;
27 extern char *_mdvi_fallback_font;
29 extern void vf_free_macros(DviFont *);
31 #define finfo search.info
32 #define TYPENAME(font) \
33 ((font)->finfo ? (font)->finfo->name : "none")
35 int font_reopen(DviFont *font)
38 fseek(font->in, (long)0, SEEK_SET);
39 else if((font->in = fopen(font->filename, "rb")) == NULL) {
40 DEBUG((DBG_FILES, "reopen(%s) -> Error\n", font->filename));
43 DEBUG((DBG_FILES, "reopen(%s) -> Ok.\n", font->filename));
47 /* used from context: params and device */
48 static int load_font_file(DviParams *params, DviFont *font)
52 if(SEARCH_DONE(font->search))
54 if(font->in == NULL && font_reopen(font) < 0)
56 DEBUG((DBG_FONTS, "%s: loading %s font from `%s'\n",
58 font->finfo->name, font->filename));
60 status = font->finfo->load(params, font);
61 } while(status < 0 && mdvi_font_retry(params, font) == 0);
68 DEBUG((DBG_FONTS, "reload_font(%s) -> %s\n",
69 font->fontname, status < 0 ? "Error" : "Ok"));
73 void font_drop_one(DviFontRef *ref)
79 /* drop all children */
80 for(ref = font->subfonts; ref; ref = ref->next) {
81 /* just adjust the reference counts */
84 if(--font->links == 0) {
86 * this font doesn't have any more references, but
87 * we still keep it around in case a virtual font
94 if(LIST(font) != fontlist.tail) {
95 /* move it to the end of the list */
96 listh_remove(&fontlist, LIST(font));
97 listh_append(&fontlist, LIST(font));
100 DEBUG((DBG_FONTS, "%s: reference dropped, %d more left\n",
101 font->fontname, font->links));
104 void font_drop_chain(DviFontRef *head)
108 for(; (ptr = head); ) {
114 int font_free_unused(DviDevice *dev)
116 DviFont *font, *next;
119 DEBUG((DBG_FONTS, "destroying unused fonts\n"));
120 for(font = (DviFont *)fontlist.head; font; font = next) {
127 DEBUG((DBG_FONTS, "removing unused %s font `%s'\n",
128 TYPENAME(font), font->fontname));
129 listh_remove(&fontlist, LIST(font));
132 /* get rid of subfonts (but can't use `drop_chain' here) */
133 for(; (ref = font->subfonts); ) {
134 font->subfonts = ref->next;
137 /* remove this font */
138 font_reset_font_glyphs(dev, font, MDVI_FONTSEL_GLYPH);
139 /* let the font destroy its private data */
140 if(font->finfo->freedata)
141 font->finfo->freedata(font);
142 /* destroy characters */
144 mdvi_free(font->chars);
145 mdvi_free(font->fontname);
146 mdvi_free(font->filename);
149 DEBUG((DBG_FONTS, "%d unused fonts removed\n", count));
153 /* used from context: params and device */
156 DviParams *params, /* rendering parameters */
157 Int32 id, /* external id number */
158 const char *name, /* font name */
159 Int32 sum, /* checksum (from DVI of VF) */
160 int hdpi, /* resolution */
162 Int32 scale) /* scaling factor (from DVI or VF) */
166 DviFontRef *subfont_ref;
168 /* see if there is a font with the same characteristics */
169 for(font = (DviFont *)fontlist.head; font; font = font->next) {
170 if(strcmp(name, font->fontname) == 0
171 && (!sum || !font->checksum || font->checksum == sum)
172 && font->hdpi == hdpi
173 && font->vdpi == vdpi
174 && font->scale == scale)
177 /* try to load the font */
179 font = mdvi_add_font(name, sum, hdpi, vdpi, scale);
182 listh_append(&fontlist, LIST(font));
184 if(!font->links && !font->chars && load_font_file(params, font) < 0) {
185 DEBUG((DBG_FONTS, "font_reference(%s) -> Error\n", name));
188 ref = xalloc(DviFontRef);
192 for(subfont_ref = font->subfonts; subfont_ref; subfont_ref = subfont_ref->next) {
193 /* just adjust the reference counts */
194 subfont_ref->ref->links++;
199 if(LIST(font) != fontlist.head) {
200 listh_remove(&fontlist, LIST(font));
201 listh_prepend(&fontlist, LIST(font));
204 DEBUG((DBG_FONTS, "font_reference(%s) -> %d links\n",
205 font->fontname, font->links));
209 void font_transform_glyph(DviOrientation orient, DviGlyph *g)
214 map = (BITMAP *)g->data;
215 if(MDVI_GLYPH_ISEMPTY(map))
218 /* put the glyph in the right orientation */
220 case MDVI_ORIENT_TBLR:
222 case MDVI_ORIENT_TBRL:
224 if(map) bitmap_flip_horizontally(map);
226 case MDVI_ORIENT_BTLR:
228 if(map) bitmap_flip_vertically(map);
230 case MDVI_ORIENT_BTRL:
233 if(map) bitmap_flip_diagonally(map);
235 case MDVI_ORIENT_RP90:
236 if(map) bitmap_rotate_counter_clockwise(map);
243 case MDVI_ORIENT_RM90:
244 if(map) bitmap_rotate_clockwise(map);
251 case MDVI_ORIENT_IRP90:
252 if(map) bitmap_flip_rotate_counter_clockwise(map);
259 case MDVI_ORIENT_IRM90:
260 if(map) bitmap_flip_rotate_clockwise(map);
270 static int load_one_glyph(DviContext *dvi, DviFont *font, int code)
277 ch = FONTCHAR(font, code);
278 DEBUG((DBG_GLYPHS, "loading glyph code %d in %s (at %u)\n",
279 code, font->fontname, ch->offset));
281 if(font->finfo->getglyph == NULL) {
282 /* font type does not need to load glyphs (e.g. vf) */
286 status = font->finfo->getglyph(&dvi->params, font, code);
289 /* get the glyph again (font->chars may have changed) */
290 ch = FONTCHAR(font, code);
292 map = (BITMAP *)ch->glyph.data;
293 if(DEBUGGING(BITMAP_DATA)) {
294 DEBUG((DBG_BITMAP_DATA,
295 "%s: new %s bitmap for character %d:\n",
296 font->fontname, TYPENAME(font), code));
297 if(MDVI_GLYPH_ISEMPTY(map))
298 DEBUG((DBG_BITMAP_DATA, "blank bitmap\n"));
300 bitmap_print(stderr, map);
303 /* check if we have to scale it */
304 if(!font->finfo->scalable && font->hdpi != font->vdpi) {
307 /* we scale it ourselves */
308 d = Max(font->hdpi, font->vdpi);
311 if(ch->width && ch->height && (hs > 1 || vs > 1)) {
316 "%s: scaling glyph %d to resolution %dx%d\n",
317 font->fontname, code, font->hdpi, font->vdpi));
318 h = dvi->params.hshrink;
319 v = dvi->params.vshrink;
320 d = dvi->params.density;
321 dvi->params.hshrink = hs;
322 dvi->params.vshrink = vs;
323 dvi->params.density = 50;
325 font->finfo->shrink0(dvi, font, ch, &glyph);
326 /* restore parameters */
327 dvi->params.hshrink = h;
328 dvi->params.vshrink = v;
329 dvi->params.density = d;
330 /* update glyph data */
331 if(!MDVI_GLYPH_ISEMPTY(ch->glyph.data))
332 bitmap_destroy((BITMAP *)ch->glyph.data);
333 ch->glyph.data = glyph.data;
334 ch->glyph.x = glyph.x;
335 ch->glyph.y = glyph.y;
336 ch->glyph.w = glyph.w;
337 ch->glyph.h = glyph.h;
341 font_transform_glyph(dvi->params.orientation, &ch->glyph);
346 DviFontChar *font_get_glyph(DviContext *dvi, DviFont *font, int code)
351 /* if we have not loaded the font yet, do so now */
352 if(!font->chars && load_font_file(&dvi->params, font) < 0)
355 /* get the unscaled glyph, maybe loading it from disk */
356 ch = FONTCHAR(font, code);
357 if(!ch || !glyph_present(ch))
359 if(!ch->loaded && load_one_glyph(dvi, font, code) == -1) {
360 if(font->chars == NULL) {
361 /* we need to try another font class */
366 /* yes, we have to do this again */
367 ch = FONTCHAR(font, code);
369 /* Got the glyph. If we also have the right scaled glyph, do no more */
370 if(!ch->width || !ch->height ||
371 font->finfo->getglyph == NULL ||
372 (dvi->params.hshrink == 1 && dvi->params.vshrink == 1))
375 /* If the glyph is empty, we just need to shrink the box */
376 if(ch->missing || MDVI_GLYPH_ISEMPTY(ch->glyph.data)) {
377 if(MDVI_GLYPH_UNSET(ch->shrunk.data))
378 mdvi_shrink_box(dvi, font, ch, &ch->shrunk);
380 } else if(MDVI_ENABLED(dvi, MDVI_PARAM_ANTIALIASED)) {
382 !MDVI_GLYPH_ISEMPTY(ch->grey.data) &&
383 ch->fg == dvi->curr_fg &&
384 ch->bg == dvi->curr_bg)
387 !MDVI_GLYPH_ISEMPTY(ch->grey.data)) {
388 if(dvi->device.free_image)
389 dvi->device.free_image(ch->grey.data);
390 ch->grey.data = NULL;
392 font->finfo->shrink1(dvi, font, ch, &ch->grey);
393 } else if(!ch->shrunk.data)
394 font->finfo->shrink0(dvi, font, ch, &ch->shrunk);
399 void font_reset_one_glyph(DviDevice *dev, DviFontChar *ch, int what)
401 if(!glyph_present(ch))
403 if(what & MDVI_FONTSEL_BITMAP) {
404 if(MDVI_GLYPH_NONEMPTY(ch->shrunk.data))
405 bitmap_destroy((BITMAP *)ch->shrunk.data);
406 ch->shrunk.data = NULL;
408 if(what & MDVI_FONTSEL_GREY) {
409 if(MDVI_GLYPH_NONEMPTY(ch->grey.data)) {
411 dev->free_image(ch->grey.data);
413 ch->grey.data = NULL;
415 if(what & MDVI_FONTSEL_GLYPH) {
416 if(MDVI_GLYPH_NONEMPTY(ch->glyph.data))
417 bitmap_destroy((BITMAP *)ch->glyph.data);
418 ch->glyph.data = NULL;
423 void font_reset_font_glyphs(DviDevice *dev, DviFont *font, int what)
428 if(what & MDVI_FONTSEL_GLYPH)
429 what |= MDVI_FONTSEL_BITMAP|MDVI_FONTSEL_GREY;
433 for(ref = font->subfonts; ref; ref = ref->next)
434 font_reset_font_glyphs(dev, ref->ref, what);
437 DEBUG((DBG_FILES, "close(%s)\n", font->filename));
441 if(font->finfo->getglyph == NULL)
443 DEBUG((DBG_FONTS, "resetting glyphs in font `%s'\n", font->fontname));
444 for(ch = font->chars, i = font->loc; i <= font->hic; ch++, i++) {
445 if(glyph_present(ch))
446 font_reset_one_glyph(dev, ch, what);
448 if((what & MDVI_FONTSEL_GLYPH) && font->finfo->reset)
449 font->finfo->reset(font);
452 void font_reset_chain_glyphs(DviDevice *dev, DviFontRef *head, int what)
456 for(ref = head; ref; ref = ref->next)
457 font_reset_font_glyphs(dev, ref->ref, what);
460 static int compare_refs(const void *p1, const void *p2)
462 return ((*(DviFontRef **)p1)->fontid - (*(DviFontRef **)p2)->fontid);
465 void font_finish_definitions(DviContext *dvi)
468 DviFontRef **map, *ref;
470 /* first get rid of unused fonts */
471 font_free_unused(&dvi->device);
473 if(dvi->fonts == NULL) {
474 mdvi_warning(_("%s: no fonts defined\n"), dvi->filename);
477 map = xnalloc(DviFontRef *, dvi->nfonts);
478 for(count = 0, ref = dvi->fonts; ref; ref = ref->next)
480 /* sort the array by font id */
481 qsort(map, dvi->nfonts, sizeof(DviFontRef *), compare_refs);
485 DviFontRef *font_find_flat(DviContext *dvi, Int32 id)
489 for(ref = dvi->fonts; ref; ref = ref->next)
490 if(ref->fontid == id)
495 DviFontRef *font_find_mapped(DviContext *dvi, Int32 id)
500 /* do a binary search */
501 lo = 0; hi = dvi->nfonts;
507 sign = (map[n]->fontid - id);