]> www.fi.muni.cz Git - evince.git/blob - backend/dvi/mdvi-lib/font.c
fedb7e78a595a580d8257c77f56971ce9f541d5f
[evince.git] / backend / 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         mdvi_free(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                         mdvi_free(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                         mdvi_free(font->chars);
144                 mdvi_free(font->fontname);
145                 mdvi_free(font->filename);
146                 mdvi_free(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         DviFontRef *subfont_ref;
166         
167         /* see if there is a font with the same characteristics */
168         for(font = (DviFont *)fontlist.head; font; font = font->next) {
169                 if(strcmp(name, font->fontname) == 0
170                    && (!sum || !font->checksum || font->checksum == sum)
171                    && font->hdpi == hdpi
172                    && font->vdpi == vdpi
173                    && font->scale == scale)
174                         break;
175         }
176         /* try to load the font */
177         if(font == NULL) {
178                 font = mdvi_add_font(name, sum, hdpi, vdpi, scale);
179                 if(font == NULL)
180                         return NULL;
181                 listh_append(&fontlist, LIST(font));
182         }
183         if(!font->links && !font->chars && load_font_file(params, font) < 0) {
184                 DEBUG((DBG_FONTS, "font_reference(%s) -> Error\n", name));
185                 return NULL;
186         }
187         ref = xalloc(DviFontRef);
188         ref->ref = font;
189
190         font->links++;
191         for(subfont_ref = font->subfonts; subfont_ref; subfont_ref = subfont_ref->next) {
192                 /* just adjust the reference counts */
193                 subfont_ref->ref->links++;
194         }
195
196         ref->fontid = id;
197
198         if(LIST(font) != fontlist.head) {
199                 listh_remove(&fontlist, LIST(font));
200                 listh_prepend(&fontlist, LIST(font));
201         }
202
203         DEBUG((DBG_FONTS, "font_reference(%s) -> %d links\n",
204                 font->fontname, font->links));
205         return ref;
206 }
207
208 void    font_transform_glyph(DviOrientation orient, DviGlyph *g)
209 {
210         BITMAP  *map;
211         int     x, y;
212         
213         map = (BITMAP *)g->data;
214         if(MDVI_GLYPH_ISEMPTY(map))
215                 map = NULL;
216
217         /* put the glyph in the right orientation */
218         switch(orient) {
219         case MDVI_ORIENT_TBLR:
220                 break;
221         case MDVI_ORIENT_TBRL:
222                 g->x = g->w - g->x;
223                 if(map) bitmap_flip_horizontally(map);
224                 break;
225         case MDVI_ORIENT_BTLR:
226                 g->y = g->h - g->y;
227                 if(map) bitmap_flip_vertically(map);
228                 break;
229         case MDVI_ORIENT_BTRL:
230                 g->x = g->w - g->x;
231                 g->y = g->h - g->y;
232                 if(map) bitmap_flip_diagonally(map);
233                 break;
234         case MDVI_ORIENT_RP90:
235                 if(map) bitmap_rotate_counter_clockwise(map);
236                 y = g->y;
237                 x = g->w - g->x;
238                 g->x = y;
239                 g->y = x;
240                 SWAPINT(g->w, g->h);
241                 break;
242         case MDVI_ORIENT_RM90: 
243                 if(map) bitmap_rotate_clockwise(map);
244                 y = g->h - g->y;
245                 x = g->x;
246                 g->x = y;
247                 g->y = x;
248                 SWAPINT(g->w, g->h);
249                 break;
250         case MDVI_ORIENT_IRP90:
251                 if(map) bitmap_flip_rotate_counter_clockwise(map);
252                 y = g->y;
253                 x = g->x;
254                 g->x = y;
255                 g->y = x;
256                 SWAPINT(g->w, g->h);
257                 break;
258         case MDVI_ORIENT_IRM90:
259                 if(map) bitmap_flip_rotate_clockwise(map);
260                 y = g->h - g->y;
261                 x = g->w - g->x;
262                 g->x = y;
263                 g->y = x;
264                 SWAPINT(g->w, g->h);
265                 break;
266         }
267 }
268
269 static int load_one_glyph(DviContext *dvi, DviFont *font, int code)
270 {
271         BITMAP *map;
272         DviFontChar *ch;
273         int     status;
274
275 #ifndef NODEBUG
276         ch = FONTCHAR(font, code);
277         DEBUG((DBG_GLYPHS, "loading glyph code %d in %s (at %u)\n",
278                 code, font->fontname, ch->offset));
279 #endif
280         if(font->finfo->getglyph == NULL) {
281                 /* font type does not need to load glyphs (e.g. vf) */
282                 return 0;
283         }
284
285         status = font->finfo->getglyph(&dvi->params, font, code);
286         if(status < 0)
287                 return -1;
288         /* get the glyph again (font->chars may have changed) */
289         ch = FONTCHAR(font, code);
290 #ifndef NODEBUG
291         map = (BITMAP *)ch->glyph.data;
292         if(DEBUGGING(BITMAP_DATA)) {
293                 DEBUG((DBG_BITMAP_DATA,
294                         "%s: new %s bitmap for character %d:\n",
295                         font->fontname, TYPENAME(font), code));
296                 if(MDVI_GLYPH_ISEMPTY(map))
297                         DEBUG((DBG_BITMAP_DATA, "blank bitmap\n"));
298                 else
299                         bitmap_print(stderr, map);
300         }
301 #endif
302         /* check if we have to scale it */
303         if(!font->finfo->scalable && font->hdpi != font->vdpi) {
304                 int     hs, vs, d;
305                 
306                 /* we scale it ourselves */
307                 d = Max(font->hdpi, font->vdpi);
308                 hs = d / font->hdpi;
309                 vs = d / font->vdpi;
310                 if(ch->width && ch->height && (hs > 1 || vs > 1)) {
311                         int     h, v;
312                         DviGlyph glyph;
313                         
314                         DEBUG((DBG_FONTS, 
315                                 "%s: scaling glyph %d to resolution %dx%d\n",
316                                 font->fontname, code, font->hdpi, font->vdpi));
317                         h = dvi->params.hshrink;
318                         v = dvi->params.vshrink;
319                         d = dvi->params.density;
320                         dvi->params.hshrink = hs;
321                         dvi->params.vshrink = vs;
322                         dvi->params.density = 50;
323                         /* shrink it */
324                         font->finfo->shrink0(dvi, font, ch, &glyph);
325                         /* restore parameters */
326                         dvi->params.hshrink = h;
327                         dvi->params.vshrink = v;
328                         dvi->params.density = d;
329                         /* update glyph data */
330                         if(!MDVI_GLYPH_ISEMPTY(ch->glyph.data))
331                                 bitmap_destroy((BITMAP *)ch->glyph.data);
332                         ch->glyph.data = glyph.data;
333                         ch->glyph.x = glyph.x;
334                         ch->glyph.y = glyph.y;
335                         ch->glyph.w = glyph.w;
336                         ch->glyph.h = glyph.h;
337                 }
338                         
339         }
340         font_transform_glyph(dvi->params.orientation, &ch->glyph);
341                 
342         return 0;
343 }
344
345 DviFontChar *font_get_glyph(DviContext *dvi, DviFont *font, int code)
346 {
347         DviFontChar *ch;
348
349 again:
350         /* if we have not loaded the font yet, do so now */
351         if(!font->chars && load_font_file(&dvi->params, font) < 0)
352                 return NULL;
353         
354         /* get the unscaled glyph, maybe loading it from disk */
355         ch = FONTCHAR(font, code);
356         if(!ch || !glyph_present(ch))
357                 return NULL;
358         if(!ch->loaded && load_one_glyph(dvi, font, code) == -1) {
359                 if(font->chars == NULL) {
360                         /* we need to try another font class */
361                         goto again;
362                 }
363                 return NULL;
364         }
365         /* yes, we have to do this again */
366         ch = FONTCHAR(font, code);
367
368         /* Got the glyph. If we also have the right scaled glyph, do no more */
369         if(!ch->width || !ch->height ||
370            font->finfo->getglyph == NULL ||
371            (dvi->params.hshrink == 1 && dvi->params.vshrink == 1))
372                 return ch;
373         
374         /* If the glyph is empty, we just need to shrink the box */
375         if(ch->missing || MDVI_GLYPH_ISEMPTY(ch->glyph.data)) {
376                 if(MDVI_GLYPH_UNSET(ch->shrunk.data))
377                         mdvi_shrink_box(dvi, font, ch, &ch->shrunk);
378                 return ch;
379         } else if(MDVI_ENABLED(dvi, MDVI_PARAM_ANTIALIASED)) {
380                 if(ch->grey.data && 
381                    ch->fg == dvi->curr_fg && 
382                    ch->bg == dvi->curr_bg)
383                         return ch;
384                 if(ch->grey.data) {
385                         if(dvi->device.free_image)
386                                 dvi->device.free_image(ch->grey.data);
387                         ch->grey.data = NULL;
388                 }
389                 font->finfo->shrink1(dvi, font, ch, &ch->grey);
390         } else if(!ch->shrunk.data)
391                 font->finfo->shrink0(dvi, font, ch, &ch->shrunk);
392
393         return ch;
394 }
395
396 void    font_reset_one_glyph(DviDevice *dev, DviFontChar *ch, int what)
397 {
398         if(!glyph_present(ch))
399                 return;
400         if(what & MDVI_FONTSEL_BITMAP) {
401                 if(MDVI_GLYPH_NONEMPTY(ch->shrunk.data))
402                         bitmap_destroy((BITMAP *)ch->shrunk.data);
403                 ch->shrunk.data = NULL;
404         }
405         if(what & MDVI_FONTSEL_GREY) {
406                 if(MDVI_GLYPH_NONEMPTY(ch->grey.data)) {
407                         if(dev->free_image)
408                                 dev->free_image(ch->grey.data);
409                 }
410                 ch->grey.data = NULL;
411         }
412         if(what & MDVI_FONTSEL_GLYPH) {
413                 if(MDVI_GLYPH_NONEMPTY(ch->glyph.data))
414                         bitmap_destroy((BITMAP *)ch->glyph.data);
415                 ch->glyph.data = NULL;
416                 ch->loaded = 0;
417         }
418 }
419
420 void    font_reset_font_glyphs(DviDevice *dev, DviFont *font, int what)
421 {
422         int     i;
423         DviFontChar *ch;
424         
425         if(what & MDVI_FONTSEL_GLYPH)
426                 what |= MDVI_FONTSEL_BITMAP|MDVI_FONTSEL_GREY;  
427         if(font->subfonts) {
428                 DviFontRef *ref;
429                 
430                 for(ref = font->subfonts; ref; ref = ref->next)
431                         font_reset_font_glyphs(dev, ref->ref, what);
432         }
433         if(font->in) {
434                 DEBUG((DBG_FILES, "close(%s)\n", font->filename));
435                 fclose(font->in);
436                 font->in = NULL;
437         }
438         if(font->finfo->getglyph == NULL)
439                 return;
440         DEBUG((DBG_FONTS, "resetting glyphs in font `%s'\n", font->fontname));
441         for(ch = font->chars, i = font->loc; i <= font->hic; ch++, i++) {
442                 if(glyph_present(ch))
443                         font_reset_one_glyph(dev, ch, what);
444         }
445         if((what & MDVI_FONTSEL_GLYPH) && font->finfo->reset)
446                 font->finfo->reset(font);
447 }       
448
449 void    font_reset_chain_glyphs(DviDevice *dev, DviFontRef *head, int what)
450 {
451         DviFontRef *ref;
452         
453         for(ref = head; ref; ref = ref->next)
454                 font_reset_font_glyphs(dev, ref->ref, what);
455 }
456
457 static int compare_refs(const void *p1, const void *p2)
458 {
459         return ((*(DviFontRef **)p1)->fontid - (*(DviFontRef **)p2)->fontid);
460 }
461
462 void    font_finish_definitions(DviContext *dvi)
463 {
464         int     count;
465         DviFontRef **map, *ref;
466         
467         /* first get rid of unused fonts */
468         font_free_unused(&dvi->device);
469
470         if(dvi->fonts == NULL) {
471                 warning(_("%s: no fonts defined\n"), dvi->filename);
472                 return;
473         }
474         map = xnalloc(DviFontRef *, dvi->nfonts);
475         for(count = 0, ref = dvi->fonts; ref; ref = ref->next)
476                 map[count++] = ref;
477         /* sort the array by font id */
478         qsort(map, dvi->nfonts, sizeof(DviFontRef *), compare_refs);
479         dvi->fontmap = map;
480 }
481
482 DviFontRef *font_find_flat(DviContext *dvi, Int32 id)
483 {
484         DviFontRef *ref;
485         
486         for(ref = dvi->fonts; ref; ref = ref->next)
487                 if(ref->fontid == id)
488                         break;
489         return ref;
490 }
491
492 DviFontRef *font_find_mapped(DviContext *dvi, Int32 id)
493 {
494         int     lo, hi, n;
495         DviFontRef **map;
496         
497         /* do a binary search */
498         lo = 0; hi = dvi->nfonts;
499         map = dvi->fontmap;
500         while(lo < hi) {
501                 int     sign;
502                 
503                 n = (hi + lo) >> 1;
504                 sign = (map[n]->fontid - id);
505                 if(sign == 0)
506                         break;
507                 else if(sign < 0)
508                         lo = n;
509                 else
510                         hi = n;
511         }
512         if(lo >= hi)
513                 return NULL;
514         return map[n];
515 }
516