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