]> www.fi.muni.cz Git - evince.git/blob - dvi/mdvi-lib/font.c
Recent files support.
[evince.git] / dvi / mdvi-lib / font.c
1 /*
2  * Copyright (C) 2000, Matias Atria
3  *
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.
8  *
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.
13  *
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18
19 #include <stdlib.h>
20
21 #include "mdvi.h"
22 #include "private.h"
23
24 static ListHead fontlist;
25
26 extern char *_mdvi_fallback_font;
27
28 extern void vf_free_macros(DviFont *);
29
30 #define finfo   search.info
31 #define TYPENAME(font)  \
32         ((font)->finfo ? (font)->finfo->name : "none")
33
34 int     font_reopen(DviFont *font)
35 {
36         if(font->in)
37                 fseek(font->in, (long)0, SEEK_SET);
38         else if((font->in = fopen(font->filename, "r")) == NULL) {
39                 DEBUG((DBG_FILES, "reopen(%s) -> Error\n", font->filename));
40                 return -1;
41         }
42         DEBUG((DBG_FILES, "reopen(%s) -> Ok.\n", font->filename));
43         return 0;
44 }
45
46 /* used from context: params and device */
47 static int load_font_file(DviParams *params, DviFont *font)
48 {
49         int     status;
50                         
51         if(SEARCH_DONE(font->search))
52                 return -1;
53         if(font->in == NULL && font_reopen(font) < 0)
54                 return -1;
55         DEBUG((DBG_FONTS, "%s: loading %s font from `%s'\n",
56                 font->fontname,
57                 font->finfo->name, font->filename));
58         do {
59                 status = font->finfo->load(params, font);
60         } while(status < 0 && mdvi_font_retry(params, font) == 0);
61         if(status < 0)
62                 return -1;
63         if(font->in) {
64                 fclose(font->in);
65                 font->in = NULL;
66         }
67         DEBUG((DBG_FONTS, "reload_font(%s) -> %s\n",
68                 font->fontname, status < 0 ? "Error" : "Ok"));
69         return 0;
70 }
71
72 void    font_drop_one(DviFontRef *ref)
73 {
74         DviFont *font;
75         
76         font = ref->ref;
77         xfree(ref);
78         /* drop all children */
79         for(ref = font->subfonts; ref; ref = ref->next) {
80                 /* just adjust the reference counts */
81                 ref->ref->links--;
82         }
83         if(--font->links == 0) {
84                 /* 
85                  * this font doesn't have any more references, but
86                  * we still keep it around in case a virtual font
87                  * requests it.
88                  */
89                 if(font->in) {
90                         fclose(font->in);
91                         font->in = NULL;
92                 }
93                 if(LIST(font) != fontlist.tail) {
94                         /* move it to the end of the list */
95                         listh_remove(&fontlist, LIST(font));
96                         listh_append(&fontlist, LIST(font));
97                 }
98         }
99         DEBUG((DBG_FONTS, "%s: reference dropped, %d more left\n",
100                 font->fontname, font->links));
101 }
102
103 void    font_drop_chain(DviFontRef *head)
104 {
105         DviFontRef *ptr;
106         
107         for(; (ptr = head); ) {
108                 head = ptr->next;
109                 font_drop_one(ptr);
110         }
111 }
112
113 int     font_free_unused(DviDevice *dev)
114 {
115         DviFont *font, *next;
116         int     count = 0;
117
118         DEBUG((DBG_FONTS, "destroying unused fonts\n"));        
119         for(font = (DviFont *)fontlist.head; font; font = next) {
120                 DviFontRef *ref;
121                 
122                 next = font->next;
123                 if(font->links)
124                         continue;
125                 count++;
126                 DEBUG((DBG_FONTS, "removing unused %s font `%s'\n", 
127                         TYPENAME(font), font->fontname));
128                 listh_remove(&fontlist, LIST(font));
129                 if(font->in)
130                         fclose(font->in);
131                 /* get rid of subfonts (but can't use `drop_chain' here) */
132                 for(; (ref = font->subfonts); ) {
133                         font->subfonts = ref->next;
134                         xfree(ref);
135                 }
136                 /* remove this font */
137                 font_reset_font_glyphs(dev, font, MDVI_FONTSEL_GLYPH);
138                 /* let the font destroy its private data */
139                 if(font->finfo->freedata)
140                         font->finfo->freedata(font);
141                 /* destroy characters */
142                 if(font->chars)
143                         xfree(font->chars);
144                 xfree(font->fontname);
145                 xfree(font->filename);
146                 xfree(font);
147         }
148         DEBUG((DBG_FONTS, "%d unused fonts removed\n", count));
149         return count;
150 }
151
152 /* used from context: params and device */
153 DviFontRef *
154 font_reference(
155         DviParams *params,      /* rendering parameters */
156         Int32 id,               /* external id number */
157         const char *name,       /* font name */
158         Int32 sum,              /* checksum (from DVI of VF) */
159         int hdpi,               /* resolution */
160         int vdpi,
161         Int32 scale)            /* scaling factor (from DVI or VF) */
162 {
163         DviFont *font;
164         DviFontRef *ref;
165         
166         /* see if there is a font with the same characteristics */
167         for(font = (DviFont *)fontlist.head; font; font = font->next) {
168                 if(strcmp(name, font->fontname) == 0
169                    && (!sum || !font->checksum || font->checksum == sum)
170                    && font->hdpi == hdpi
171                    && font->vdpi == vdpi
172                    && font->scale == scale)
173                         break;
174         }
175         /* try to load the font */
176         if(font == NULL) {
177                 font = mdvi_add_font(name, sum, hdpi, vdpi, scale);
178                 if(font == NULL)
179                         return NULL;
180                 listh_append(&fontlist, LIST(font));
181         }
182         if(!font->links && !font->chars && load_font_file(params, font) < 0) {
183                 DEBUG((DBG_FONTS, "font_reference(%s) -> Error\n", name));
184                 return NULL;
185         }
186         ref = xalloc(DviFontRef);
187         ref->ref = font;
188         font->links++;
189         ref->fontid = id;
190
191         if(LIST(font) != fontlist.head) {
192                 listh_remove(&fontlist, LIST(font));
193                 listh_prepend(&fontlist, LIST(font));
194         }
195
196         DEBUG((DBG_FONTS, "font_reference(%s) -> %d links\n",
197                 font->fontname, font->links));
198         return ref;
199 }
200
201 void    font_transform_glyph(DviOrientation orient, DviGlyph *g)
202 {
203         BITMAP  *map;
204         int     x, y;
205         
206         map = (BITMAP *)g->data;
207         if(MDVI_GLYPH_ISEMPTY(map))
208                 map = NULL;
209
210         /* put the glyph in the right orientation */
211         switch(orient) {
212         case MDVI_ORIENT_TBLR:
213                 break;
214         case MDVI_ORIENT_TBRL:
215                 g->x = g->w - g->x;
216                 if(map) bitmap_flip_horizontally(map);
217                 break;
218         case MDVI_ORIENT_BTLR:
219                 g->y = g->h - g->y;
220                 if(map) bitmap_flip_vertically(map);
221                 break;
222         case MDVI_ORIENT_BTRL:
223                 g->x = g->w - g->x;
224                 g->y = g->h - g->y;
225                 if(map) bitmap_flip_diagonally(map);
226                 break;
227         case MDVI_ORIENT_RP90:
228                 if(map) bitmap_rotate_counter_clockwise(map);
229                 y = g->y;
230                 x = g->w - g->x;
231                 g->x = y;
232                 g->y = x;
233                 SWAPINT(g->w, g->h);
234                 break;
235         case MDVI_ORIENT_RM90: 
236                 if(map) bitmap_rotate_clockwise(map);
237                 y = g->h - g->y;
238                 x = g->x;
239                 g->x = y;
240                 g->y = x;
241                 SWAPINT(g->w, g->h);
242                 break;
243         case MDVI_ORIENT_IRP90:
244                 if(map) bitmap_flip_rotate_counter_clockwise(map);
245                 y = g->y;
246                 x = g->x;
247                 g->x = y;
248                 g->y = x;
249                 SWAPINT(g->w, g->h);
250                 break;
251         case MDVI_ORIENT_IRM90:
252                 if(map) bitmap_flip_rotate_clockwise(map);
253                 y = g->h - g->y;
254                 x = g->w - g->x;
255                 g->x = y;
256                 g->y = x;
257                 SWAPINT(g->w, g->h);
258                 break;
259         }
260 }
261
262 static int load_one_glyph(DviContext *dvi, DviFont *font, int code)
263 {
264         BITMAP *map;
265         DviFontChar *ch;
266         int     status;
267
268 #ifndef NODEBUG
269         ch = FONTCHAR(font, code);
270         DEBUG((DBG_GLYPHS, "loading glyph code %d in %s (at %u)\n",
271                 code, font->fontname, ch->offset));
272 #endif
273         if(font->finfo->getglyph == NULL) {
274                 /* font type does not need to load glyphs (e.g. vf) */
275                 return 0;
276         }
277
278         status = font->finfo->getglyph(&dvi->params, font, code);
279         if(status < 0)
280                 return -1;
281         /* get the glyph again (font->chars may have changed) */
282         ch = FONTCHAR(font, code);
283 #ifndef NODEBUG
284         map = (BITMAP *)ch->glyph.data;
285         if(DEBUGGING(BITMAP_DATA)) {
286                 DEBUG((DBG_BITMAP_DATA,
287                         "%s: new %s bitmap for character %d:\n",
288                         font->fontname, TYPENAME(font), code));
289                 if(MDVI_GLYPH_ISEMPTY(map))
290                         DEBUG((DBG_BITMAP_DATA, "blank bitmap\n"));
291                 else
292                         bitmap_print(stderr, map);
293         }
294 #endif
295         /* check if we have to scale it */
296         if(!font->finfo->scalable && font->hdpi != font->vdpi) {
297                 int     hs, vs, d;
298                 
299                 /* we scale it ourselves */
300                 d = Max(font->hdpi, font->vdpi);
301                 hs = d / font->hdpi;
302                 vs = d / font->vdpi;
303                 if(ch->width && ch->height && (hs > 1 || vs > 1)) {
304                         int     h, v;
305                         DviGlyph glyph;
306                         
307                         DEBUG((DBG_FONTS, 
308                                 "%s: scaling glyph %d to resolution %dx%d\n",
309                                 font->fontname, code, font->hdpi, font->vdpi));
310                         h = dvi->params.hshrink;
311                         v = dvi->params.vshrink;
312                         d = dvi->params.density;
313                         dvi->params.hshrink = hs;
314                         dvi->params.vshrink = vs;
315                         dvi->params.density = 50;
316                         /* shrink it */
317                         font->finfo->shrink0(dvi, font, ch, &glyph);
318                         /* restore parameters */
319                         dvi->params.hshrink = h;
320                         dvi->params.vshrink = v;
321                         dvi->params.density = d;
322                         /* update glyph data */
323                         if(!MDVI_GLYPH_ISEMPTY(ch->glyph.data))
324                                 bitmap_destroy((BITMAP *)ch->glyph.data);
325                         ch->glyph.data = glyph.data;
326                         ch->glyph.x = glyph.x;
327                         ch->glyph.y = glyph.y;
328                         ch->glyph.w = glyph.w;
329                         ch->glyph.h = glyph.h;
330                 }
331                         
332         }
333         font_transform_glyph(dvi->params.orientation, &ch->glyph);
334                 
335         return 0;
336 }
337
338 DviFontChar *font_get_glyph(DviContext *dvi, DviFont *font, int code)
339 {
340         DviFontChar *ch;
341
342 again:
343         /* if we have not loaded the font yet, do so now */
344         if(!font->chars && load_font_file(&dvi->params, font) < 0)
345                 return NULL;
346         
347         /* get the unscaled glyph, maybe loading it from disk */
348         ch = FONTCHAR(font, code);
349         if(!ch || !glyph_present(ch))
350                 return NULL;
351         if(!ch->loaded && load_one_glyph(dvi, font, code) == -1) {
352                 if(font->chars == NULL) {
353                         /* we need to try another font class */
354                         goto again;
355                 }
356                 return NULL;
357         }
358         /* yes, we have to do this again */
359         ch = FONTCHAR(font, code);
360
361         /* Got the glyph. If we also have the right scaled glyph, do no more */
362         if(!ch->width || !ch->height ||
363            font->finfo->getglyph == NULL ||
364            (dvi->params.hshrink == 1 && dvi->params.vshrink == 1))
365                 return ch;
366         
367         /* If the glyph is empty, we just need to shrink the box */
368         if(ch->missing || MDVI_GLYPH_ISEMPTY(ch->glyph.data)) {
369                 if(MDVI_GLYPH_UNSET(ch->shrunk.data))
370                         mdvi_shrink_box(dvi, font, ch, &ch->shrunk);
371                 return ch;
372         } else if(MDVI_ENABLED(dvi, MDVI_PARAM_ANTIALIASED)) {
373                 if(ch->grey.data && 
374                    ch->fg == dvi->curr_fg && 
375                    ch->bg == dvi->curr_bg)
376                         return ch;
377                 if(ch->grey.data) {
378                         if(dvi->device.free_image)
379                                 dvi->device.free_image(ch->grey.data);
380                         ch->grey.data = NULL;
381                 }
382                 font->finfo->shrink1(dvi, font, ch, &ch->grey);
383         } else if(!ch->shrunk.data)
384                 font->finfo->shrink0(dvi, font, ch, &ch->shrunk);
385
386         return ch;
387 }
388
389 void    font_reset_one_glyph(DviDevice *dev, DviFontChar *ch, int what)
390 {
391         if(!glyph_present(ch))
392                 return;
393         if(what & MDVI_FONTSEL_BITMAP) {
394                 if(MDVI_GLYPH_NONEMPTY(ch->shrunk.data))
395                         bitmap_destroy((BITMAP *)ch->shrunk.data);
396                 ch->shrunk.data = NULL;
397         }
398         if(what & MDVI_FONTSEL_GREY) {
399                 if(MDVI_GLYPH_NONEMPTY(ch->grey.data)) {
400                         if(dev->free_image)
401                                 dev->free_image(ch->grey.data);
402                 }
403                 ch->grey.data = NULL;
404         }
405         if(what & MDVI_FONTSEL_GLYPH) {
406                 if(MDVI_GLYPH_NONEMPTY(ch->glyph.data))
407                         bitmap_destroy((BITMAP *)ch->glyph.data);
408                 ch->glyph.data = NULL;
409                 ch->loaded = 0;
410         }
411 }
412
413 void    font_reset_font_glyphs(DviDevice *dev, DviFont *font, int what)
414 {
415         int     i;
416         DviFontChar *ch;
417         
418         if(what & MDVI_FONTSEL_GLYPH)
419                 what |= MDVI_FONTSEL_BITMAP|MDVI_FONTSEL_GREY;  
420         if(font->subfonts) {
421                 DviFontRef *ref;
422                 
423                 for(ref = font->subfonts; ref; ref = ref->next)
424                         font_reset_font_glyphs(dev, ref->ref, what);
425         }
426         if(font->in) {
427                 DEBUG((DBG_FILES, "close(%s)\n", font->filename));
428                 fclose(font->in);
429                 font->in = NULL;
430         }
431         if(font->finfo->getglyph == NULL)
432                 return;
433         DEBUG((DBG_FONTS, "resetting glyphs in font `%s'\n", font->fontname));
434         for(ch = font->chars, i = font->loc; i <= font->hic; ch++, i++) {
435                 if(glyph_present(ch))
436                         font_reset_one_glyph(dev, ch, what);
437         }
438         if((what & MDVI_FONTSEL_GLYPH) && font->finfo->reset)
439                 font->finfo->reset(font);
440 }       
441
442 void    font_reset_chain_glyphs(DviDevice *dev, DviFontRef *head, int what)
443 {
444         DviFontRef *ref;
445         
446         for(ref = head; ref; ref = ref->next)
447                 font_reset_font_glyphs(dev, ref->ref, what);
448 }
449
450 static int compare_refs(const void *p1, const void *p2)
451 {
452         return ((*(DviFontRef **)p1)->fontid - (*(DviFontRef **)p2)->fontid);
453 }
454
455 void    font_finish_definitions(DviContext *dvi)
456 {
457         int     count;
458         DviFontRef **map, *ref;
459         
460         /* first get rid of unused fonts */
461         font_free_unused(&dvi->device);
462
463         if(dvi->fonts == NULL) {
464                 warning(_("%s: no fonts defined\n"), dvi->filename);
465                 return;
466         }
467         map = xnalloc(DviFontRef *, dvi->nfonts);
468         for(count = 0, ref = dvi->fonts; ref; ref = ref->next)
469                 map[count++] = ref;
470         /* sort the array by font id */
471         qsort(map, dvi->nfonts, sizeof(DviFontRef *), compare_refs);
472         dvi->fontmap = map;
473 }
474
475 DviFontRef *font_find_flat(DviContext *dvi, Int32 id)
476 {
477         DviFontRef *ref;
478         
479         for(ref = dvi->fonts; ref; ref = ref->next)
480                 if(ref->fontid == id)
481                         break;
482         return ref;
483 }
484
485 DviFontRef *font_find_mapped(DviContext *dvi, Int32 id)
486 {
487         int     lo, hi, n;
488         DviFontRef **map;
489         
490         /* do a binary search */
491         lo = 0; hi = dvi->nfonts;
492         map = dvi->fontmap;
493         while(lo < hi) {
494                 int     sign;
495                 
496                 n = (hi + lo) >> 1;
497                 sign = (map[n]->fontid - id);
498                 if(sign == 0)
499                         break;
500                 else if(sign < 0)
501                         lo = n;
502                 else
503                         hi = n;
504         }
505         if(lo >= hi)
506                 return NULL;
507         return map[n];
508 }
509