Evince
Evince is a document viewer capable of displaying multiple and single page document formats like PDF and Postscript.
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
font.c
Go to the documentation of this file.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18 
19 #include <config.h>
20 #include <stdlib.h>
21 
22 #include "mdvi.h"
23 #include "private.h"
24 
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, "rb")) == 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 
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 
105 {
106  DviFontRef *ptr;
107 
108  for(; (ptr = head); ) {
109  head = ptr->next;
110  font_drop_one(ptr);
111  }
112 }
113 
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 */
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 *
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 
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:
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)) {
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))
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  }
342 
343  return 0;
344 }
345 
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  !MDVI_GLYPH_ISEMPTY(ch->grey.data) &&
383  ch->fg == dvi->curr_fg &&
384  ch->bg == dvi->curr_bg)
385  return ch;
386  if(ch->grey.data &&
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;
391  }
392  font->finfo->shrink1(dvi, font, ch, &ch->grey);
393  } else if(!ch->shrunk.data)
394  font->finfo->shrink0(dvi, font, ch, &ch->shrunk);
395 
396  return ch;
397 }
398 
399 void font_reset_one_glyph(DviDevice *dev, DviFontChar *ch, int what)
400 {
401  if(!glyph_present(ch))
402  return;
403  if(what & MDVI_FONTSEL_BITMAP) {
406  ch->shrunk.data = NULL;
407  }
408  if(what & MDVI_FONTSEL_GREY) {
409  if(MDVI_GLYPH_NONEMPTY(ch->grey.data)) {
410  if(dev->free_image)
411  dev->free_image(ch->grey.data);
412  }
413  ch->grey.data = NULL;
414  }
415  if(what & MDVI_FONTSEL_GLYPH) {
418  ch->glyph.data = NULL;
419  ch->loaded = 0;
420  }
421 }
422 
423 void font_reset_font_glyphs(DviDevice *dev, DviFont *font, int what)
424 {
425  int i;
426  DviFontChar *ch;
427 
428  if(what & MDVI_FONTSEL_GLYPH)
430  if(font->subfonts) {
431  DviFontRef *ref;
432 
433  for(ref = font->subfonts; ref; ref = ref->next)
434  font_reset_font_glyphs(dev, ref->ref, what);
435  }
436  if(font->in) {
437  DEBUG((DBG_FILES, "close(%s)\n", font->filename));
438  fclose(font->in);
439  font->in = NULL;
440  }
441  if(font->finfo->getglyph == NULL)
442  return;
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);
447  }
448  if((what & MDVI_FONTSEL_GLYPH) && font->finfo->reset)
449  font->finfo->reset(font);
450 }
451 
452 void font_reset_chain_glyphs(DviDevice *dev, DviFontRef *head, int what)
453 {
454  DviFontRef *ref;
455 
456  for(ref = head; ref; ref = ref->next)
457  font_reset_font_glyphs(dev, ref->ref, what);
458 }
459 
460 static int compare_refs(const void *p1, const void *p2)
461 {
462  return ((*(DviFontRef **)p1)->fontid - (*(DviFontRef **)p2)->fontid);
463 }
464 
466 {
467  int count;
468  DviFontRef **map, *ref;
469 
470  /* first get rid of unused fonts */
471  font_free_unused(&dvi->device);
472 
473  if(dvi->fonts == NULL) {
474  mdvi_warning(_("%s: no fonts defined\n"), dvi->filename);
475  return;
476  }
477  map = xnalloc(DviFontRef *, dvi->nfonts);
478  for(count = 0, ref = dvi->fonts; ref; ref = ref->next)
479  map[count++] = ref;
480  /* sort the array by font id */
481  qsort(map, dvi->nfonts, sizeof(DviFontRef *), compare_refs);
482  dvi->fontmap = map;
483 }
484 
486 {
487  DviFontRef *ref;
488 
489  for(ref = dvi->fonts; ref; ref = ref->next)
490  if(ref->fontid == id)
491  break;
492  return ref;
493 }
494 
496 {
497  int lo, hi, n;
498  DviFontRef **map;
499 
500  /* do a binary search */
501  lo = 0; hi = dvi->nfonts;
502  map = dvi->fontmap;
503  while(lo < hi) {
504  int sign;
505 
506  n = (hi + lo) >> 1;
507  sign = (map[n]->fontid - id);
508  if(sign == 0)
509  break;
510  else if(sign < 0)
511  lo = n;
512  else
513  hi = n;
514  }
515  if(lo >= hi)
516  return NULL;
517  return map[n];
518 }
519