source: trunk/poppler/mypoppler/poppler/CairoFontEngine.cc @ 250

Last change on this file since 250 was 250, checked in by Eugene Romanenko, 13 years ago

PDF plugin: poppler library updated to version 0.8.3

File size: 9.9 KB
Line 
1//========================================================================
2//
3// CairoFontEngine.cc
4//
5// Copyright 2003 Glyph & Cog, LLC
6// Copyright 2004 Red Hat, Inc
7//
8//========================================================================
9
10#include <config.h>
11
12#include "config.h"
13#include <string.h>
14#include "CairoFontEngine.h"
15#include "CharCodeToUnicode.h"
16#include "GlobalParams.h"
17#include <fofi/FoFiTrueType.h>
18#include <fofi/FoFiType1C.h>
19#include "goo/gfile.h"
20#include "Error.h"
21
22#ifdef USE_GCC_PRAGMAS
23#pragma implementation
24#endif
25
26static void fileWrite(void *stream, char *data, int len) {
27  fwrite(data, 1, len, (FILE *)stream);
28}
29
30//------------------------------------------------------------------------
31// CairoFont
32//------------------------------------------------------------------------
33
34static void _ft_done_face (void *data)
35{
36  FT_Face face = (FT_Face) data;
37  FT_Done_Face (face);
38}
39
40CairoFont *CairoFont::create(GfxFont *gfxFont, XRef *xref, FT_Library lib, GBool useCIDs) {
41  Ref embRef;
42  Object refObj, strObj;
43  GooString *tmpFileName, *fileName,*tmpFileName2;
44  DisplayFontParam *dfp;
45  FILE *tmpFile;
46  int c, i, n;
47  GfxFontType fontType;
48  char **enc;
49  char *name;
50  FoFiTrueType *ff;
51  FoFiType1C *ff1c;
52  Ref ref;
53  static cairo_user_data_key_t cairo_font_face_key;
54  cairo_font_face_t *cairo_font_face;
55  FT_Face face;
56
57  Gushort *codeToGID;
58  int codeToGIDLen;
59 
60  dfp = NULL;
61  codeToGID = NULL;
62  codeToGIDLen = 0;
63  cairo_font_face = NULL;
64
65  GBool substitute = gFalse;
66 
67  ref = *gfxFont->getID();
68  fontType = gfxFont->getType();
69
70  tmpFileName = NULL;
71
72  if (gfxFont->getEmbeddedFontID(&embRef)) {
73    if (!openTempFile(&tmpFileName, &tmpFile, "wb", NULL)) {
74      error(-1, "Couldn't create temporary font file");
75      goto err2;
76    }
77   
78    refObj.initRef(embRef.num, embRef.gen);
79    refObj.fetch(xref, &strObj);
80    refObj.free();
81    if (!strObj.isStream()) {
82      error(-1, "Embedded font object is wrong type");
83      strObj.free();
84      fclose(tmpFile);
85      goto err2;
86    }
87    strObj.streamReset();
88    while ((c = strObj.streamGetChar()) != EOF) {
89      fputc(c, tmpFile);
90    }
91    strObj.streamClose();
92    strObj.free();
93    fclose(tmpFile);
94    fileName = tmpFileName;
95   
96  } else if (!(fileName = gfxFont->getExtFontFile())) {
97    // look for a display font mapping or a substitute font
98    dfp = NULL;
99    if (gfxFont->getName()) {
100      dfp = globalParams->getDisplayFont(gfxFont);
101    }
102    if (!dfp) {
103      error(-1, "Couldn't find a font for '%s'",
104            gfxFont->getName() ? gfxFont->getName()->getCString()
105            : "(unnamed)");
106      goto err2;
107    }
108    switch (dfp->kind) {
109    case displayFontT1:
110      fileName = dfp->t1.fileName;
111      fontType = gfxFont->isCIDFont() ? fontCIDType0 : fontType1;
112      break;
113    case displayFontTT:
114      fileName = dfp->tt.fileName;
115      fontType = gfxFont->isCIDFont() ? fontCIDType2 : fontTrueType;
116      break;
117    }
118    substitute = gTrue;
119  }
120
121  switch (fontType) {
122  case fontType1:
123  case fontType1C:
124    if (FT_New_Face(lib, fileName->getCString(), 0, &face)) {
125      error(-1, "could not create type1 face");
126      goto err2;
127    }
128   
129    enc = ((Gfx8BitFont *)gfxFont)->getEncoding();
130   
131    codeToGID = (Gushort *)gmallocn(256, sizeof(int));
132    codeToGIDLen = 256;
133    for (i = 0; i < 256; ++i) {
134      codeToGID[i] = 0;
135      if ((name = enc[i])) {
136        codeToGID[i] = (Gushort)FT_Get_Name_Index(face, name);
137      }
138    }
139    break;
140   
141  case fontCIDType2:
142    codeToGID = NULL;
143    n = 0;
144    if (((GfxCIDFont *)gfxFont)->getCIDToGID()) {
145      n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen();
146      if (n) {
147        codeToGID = (Gushort *)gmallocn(n, sizeof(Gushort));
148        memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(),
149                n * sizeof(Gushort));
150      }
151    } else {
152      ff = FoFiTrueType::load(fileName->getCString());
153      if (! ff)
154        goto err2;
155      codeToGID = ((GfxCIDFont *)gfxFont)->getCodeToGIDMap(ff, &n);
156      delete ff;
157    }
158    codeToGIDLen = n;
159    /* Fall through */
160  case fontTrueType:
161    if (!(ff = FoFiTrueType::load(fileName->getCString()))) {
162      error(-1, "failed to load truetype font\n");
163      goto err2;
164    }
165    /* This might be set already for the CIDType2 case */
166    if (fontType == fontTrueType) {
167      codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ff);
168      codeToGIDLen = 256;
169    }
170    if (!openTempFile(&tmpFileName2, &tmpFile, "wb", NULL)) {
171      delete ff;
172      error(-1, "failed to open truetype tempfile\n");
173      goto err2;
174    }
175    ff->writeTTF(&fileWrite, tmpFile);
176    fclose(tmpFile);
177    delete ff;
178
179    if (FT_New_Face(lib, tmpFileName2->getCString(), 0, &face)) {
180      error(-1, "could not create truetype face\n");
181      goto err2;
182    }
183    unlink (tmpFileName2->getCString());
184    delete tmpFileName2;
185    break;
186   
187  case fontCIDType0:
188  case fontCIDType0C:
189
190    codeToGID = NULL;
191    codeToGIDLen = 0;
192
193    if (!useCIDs)
194    {
195      if ((ff1c = FoFiType1C::load(fileName->getCString()))) {
196        codeToGID = ff1c->getCIDToGIDMap(&codeToGIDLen);
197        delete ff1c;
198      }
199    }
200
201    if (FT_New_Face(lib, fileName->getCString(), 0, &face)) {
202      gfree(codeToGID);
203      codeToGID = NULL;
204      error(-1, "could not create cid face\n");
205      goto err2;
206    }
207    break;
208   
209  default:
210    printf ("font type not handled\n");
211    goto err2;
212    break;
213  }
214
215  // delete the (temporary) font file -- with Unix hard link
216  // semantics, this will remove the last link; otherwise it will
217  // return an error, leaving the file to be deleted later
218  if (fileName == tmpFileName) {
219    unlink (fileName->getCString());
220    delete tmpFileName;
221  }
222
223  cairo_font_face = cairo_ft_font_face_create_for_ft_face (face,
224                                                           FT_LOAD_NO_HINTING |
225                                                           FT_LOAD_NO_BITMAP);
226  if (cairo_font_face_status (cairo_font_face)) {
227    error(-1, "could not create cairo font: %s\n", cairo_status_to_string (cairo_font_face_status (cairo_font_face)));
228    goto err2; /* this doesn't do anything, but it looks like we're
229                * handling the error */
230  } {
231  CairoFont *ret = new CairoFont(ref, cairo_font_face, face, codeToGID, codeToGIDLen, substitute);
232  cairo_font_face_set_user_data (cairo_font_face,
233                                 &cairo_font_face_key,
234                                 face,
235                                 _ft_done_face);
236
237  return ret;
238  }
239 err2:
240  /* hmm? */
241  printf ("some font thing failed\n");
242  return NULL;
243}
244
245CairoFont::CairoFont(Ref ref, cairo_font_face_t *cairo_font_face, FT_Face face,
246    Gushort *codeToGID, int codeToGIDLen, GBool substitute) : ref(ref), cairo_font_face(cairo_font_face),
247                                            face(face), codeToGID(codeToGID),
248                                            codeToGIDLen(codeToGIDLen), substitute(substitute) { }
249
250CairoFont::~CairoFont() {
251  cairo_font_face_destroy (cairo_font_face);
252  gfree(codeToGID);
253}
254
255GBool
256CairoFont::matches(Ref &other) {
257  return (other.num == ref.num && other.gen == ref.gen);
258}
259
260cairo_font_face_t *
261CairoFont::getFontFace(void) {
262  return cairo_font_face;
263}
264
265unsigned long
266CairoFont::getGlyph(CharCode code,
267                    Unicode *u, int uLen) {
268  FT_UInt gid;
269
270  if (codeToGID && code < codeToGIDLen) {
271    gid = (FT_UInt)codeToGID[code];
272  } else {
273    gid = (FT_UInt)code;
274  }
275  return gid;
276}
277
278double
279CairoFont::getSubstitutionCorrection(GfxFont *gfxFont)
280{
281  double w1, w2,w3;
282  CharCode code;
283  char *name;
284
285  // for substituted fonts: adjust the font matrix -- compare the
286  // width of 'm' in the original font and the substituted font
287  if (isSubstitute() && !gfxFont->isCIDFont()) {
288    for (code = 0; code < 256; ++code) {
289      if ((name = ((Gfx8BitFont *)gfxFont)->getCharName(code)) &&
290          name[0] == 'm' && name[1] == '\0') {
291        break;
292      }
293    }
294    if (code < 256) {
295      w1 = ((Gfx8BitFont *)gfxFont)->getWidth(code);
296      {
297        cairo_matrix_t m;
298        cairo_matrix_init_identity(&m);
299        cairo_font_options_t *options = cairo_font_options_create();
300        cairo_font_options_set_hint_style(options, CAIRO_HINT_STYLE_NONE);
301        cairo_font_options_set_hint_metrics(options, CAIRO_HINT_METRICS_OFF);
302        cairo_scaled_font_t *scaled_font = cairo_scaled_font_create(cairo_font_face, &m, &m, options);
303
304        cairo_text_extents_t extents;
305        cairo_scaled_font_text_extents(scaled_font, "m", &extents);
306
307        cairo_scaled_font_destroy(scaled_font);
308        cairo_font_options_destroy(options);
309        w3 = extents.width;
310        w2 = extents.x_advance;
311      }
312      if (!gfxFont->isSymbolic()) {
313        // if real font is substantially narrower than substituted
314        // font, reduce the font size accordingly
315        if (w1 > 0.01 && w1 < 0.9 * w2) {
316          w1 /= w2;
317          return w1;
318        }
319      }
320    }
321  }
322  return 1.0;
323}
324
325//------------------------------------------------------------------------
326// CairoFontEngine
327//------------------------------------------------------------------------
328
329CairoFontEngine::CairoFontEngine(FT_Library libA) {
330  int i;
331
332  lib = libA;
333  for (i = 0; i < cairoFontCacheSize; ++i) {
334    fontCache[i] = NULL;
335  }
336 
337  FT_Int major, minor, patch;
338  // as of FT 2.1.8, CID fonts are indexed by CID instead of GID
339  FT_Library_Version(lib, &major, &minor, &patch);
340  useCIDs = major > 2 ||
341            (major == 2 && (minor > 1 || (minor == 1 && patch > 7)));
342}
343
344CairoFontEngine::~CairoFontEngine() {
345  int i;
346 
347  for (i = 0; i < cairoFontCacheSize; ++i) {
348    if (fontCache[i])
349      delete fontCache[i];
350  }
351}
352
353CairoFont *
354CairoFontEngine::getFont(GfxFont *gfxFont, XRef *xref) {
355  int i, j;
356  Ref ref;
357  CairoFont *font;
358  GfxFontType fontType;
359 
360  fontType = gfxFont->getType();
361  if (fontType == fontType3) {
362    /* Need to figure this out later */
363    //    return NULL;
364  }
365
366  ref = *gfxFont->getID();
367
368  for (i = 0; i < cairoFontCacheSize; ++i) {
369    font = fontCache[i];
370    if (font && font->matches(ref)) {
371      for (j = i; j > 0; --j) {
372        fontCache[j] = fontCache[j-1];
373      }
374      fontCache[0] = font;
375      return font;
376    }
377  }
378 
379  font = CairoFont::create (gfxFont, xref, lib, useCIDs);
380  //XXX: if font is null should we still insert it into the cache?
381  if (fontCache[cairoFontCacheSize - 1]) {
382    delete fontCache[cairoFontCacheSize - 1];
383  }
384  for (j = cairoFontCacheSize - 1; j > 0; --j) {
385    fontCache[j] = fontCache[j-1];
386  }
387  fontCache[0] = font;
388  return font;
389}
390
Note: See TracBrowser for help on using the repository browser.