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

Last change on this file since 44 was 44, checked in by Eugene Romanenko, 15 years ago

poppler updated to version 0.5.3, related changes

File size: 9.3 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 cairo_font_face_destroy (void *data)
35{
36  CairoFont *font = (CairoFont *) data;
37
38  delete font;
39}
40
41CairoFont *CairoFont::create(GfxFont *gfxFont, XRef *xref, FT_Library lib, GBool useCIDs) {
42  Ref embRef;
43  Object refObj, strObj;
44  GooString *tmpFileName, *fileName, *substName,*tmpFileName2;
45  DisplayFontParam *dfp;
46  FILE *tmpFile;
47  int c, i, n, code, cmap;
48  GfxFontType fontType;
49  char **enc;
50  char *name;
51  FoFiTrueType *ff;
52  FoFiType1C *ff1c;
53  CharCodeToUnicode *ctu;
54  Unicode uBuf[8];
55  Ref ref;
56  static cairo_user_data_key_t cairo_font_face_key;
57  cairo_font_face_t *cairo_font_face;
58  FT_Face face;
59
60  Gushort *codeToGID;
61  int codeToGIDLen;
62 
63  dfp = NULL;
64  codeToGID = NULL;
65  codeToGIDLen = 0;
66  cairo_font_face = NULL;
67 
68  ref = *gfxFont->getID();
69  fontType = gfxFont->getType();
70
71  tmpFileName = NULL;
72
73  if (gfxFont->getEmbeddedFontID(&embRef)) {
74    if (!openTempFile(&tmpFileName, &tmpFile, "wb", NULL)) {
75      error(-1, "Couldn't create temporary font file");
76      goto err2;
77    }
78   
79    refObj.initRef(embRef.num, embRef.gen);
80    refObj.fetch(xref, &strObj);
81    refObj.free();
82    strObj.streamReset();
83    while ((c = strObj.streamGetChar()) != EOF) {
84      fputc(c, tmpFile);
85    }
86    strObj.streamClose();
87    strObj.free();
88    fclose(tmpFile);
89    fileName = tmpFileName;
90   
91  } else if (!(fileName = gfxFont->getExtFontFile())) {
92    // look for a display font mapping or a substitute font
93    dfp = NULL;
94    if (gfxFont->getName()) {
95      dfp = globalParams->getDisplayFont(gfxFont);
96    }
97    if (!dfp) {
98      error(-1, "Couldn't find a font for '%s'",
99            gfxFont->getName() ? gfxFont->getName()->getCString()
100            : "(unnamed)");
101      goto err2;
102    }
103    switch (dfp->kind) {
104    case displayFontT1:
105      fileName = dfp->t1.fileName;
106      fontType = gfxFont->isCIDFont() ? fontCIDType0 : fontType1;
107      break;
108    case displayFontTT:
109      fileName = dfp->tt.fileName;
110      fontType = gfxFont->isCIDFont() ? fontCIDType2 : fontTrueType;
111      break;
112    }
113  }
114
115  switch (fontType) {
116  case fontType1:
117  case fontType1C:
118    if (FT_New_Face(lib, fileName->getCString(), 0, &face)) {
119      error(-1, "could not create type1 face");
120      goto err2;
121    }
122   
123    enc = ((Gfx8BitFont *)gfxFont)->getEncoding();
124   
125    codeToGID = (Gushort *)gmallocn(256, sizeof(int));
126    codeToGIDLen = 256;
127    for (i = 0; i < 256; ++i) {
128      codeToGID[i] = 0;
129      if ((name = enc[i])) {
130        codeToGID[i] = (Gushort)FT_Get_Name_Index(face, name);
131      }
132    }
133    break;
134   
135  case fontCIDType2:
136    codeToGID = NULL;
137    n = 0;
138    if (dfp) {
139      // create a CID-to-GID mapping, via Unicode
140      if ((ctu = ((GfxCIDFont *)gfxFont)->getToUnicode())) {
141        if ((ff = FoFiTrueType::load(fileName->getCString()))) {
142          // look for a Unicode cmap
143          for (cmap = 0; cmap < ff->getNumCmaps(); ++cmap) {
144            if ((ff->getCmapPlatform(cmap) == 3 &&
145                 ff->getCmapEncoding(cmap) == 1) ||
146                 ff->getCmapPlatform(cmap) == 0) {
147              break;
148            }
149          }
150          if (cmap < ff->getNumCmaps()) {
151            // map CID -> Unicode -> GID
152            n = ctu->getLength();
153            codeToGID = (Gushort *)gmallocn(n, sizeof(Gushort));
154            for (code = 0; code < n; ++code) {
155              if (ctu->mapToUnicode(code, uBuf, 8) > 0) {
156                  codeToGID[code] = ff->mapCodeToGID(cmap, uBuf[0]);
157              } else {
158                codeToGID[code] = 0;
159              }
160            }
161          }
162          delete ff;
163        }
164        ctu->decRefCnt();
165      } else {
166        error(-1, "Couldn't find a mapping to Unicode for font '%s'",
167              gfxFont->getName() ? gfxFont->getName()->getCString()
168                        : "(unnamed)");
169        goto err2;
170      }
171    } else {
172      if (((GfxCIDFont *)gfxFont)->getCIDToGID()) {
173        n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen();
174        codeToGID = (Gushort *)gmallocn(n, sizeof(Gushort));
175        memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(),
176               n * sizeof(Gushort));
177      }
178    }
179    codeToGIDLen = n;
180    /* Fall through */
181  case fontTrueType:
182    if (!(ff = FoFiTrueType::load(fileName->getCString()))) {
183      error(-1, "failed to load truetype font\n");
184      goto err2;
185    }
186    /* This might be set already for the CIDType2 case */
187    if (fontType == fontTrueType) {
188      codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ff);
189      codeToGIDLen = 256;
190    }
191    if (!openTempFile(&tmpFileName2, &tmpFile, "wb", NULL)) {
192      delete ff;
193      error(-1, "failed to open truetype tempfile\n");
194      goto err2;
195    }
196    ff->writeTTF(&fileWrite, tmpFile);
197    fclose(tmpFile);
198    delete ff;
199
200    if (FT_New_Face(lib, tmpFileName2->getCString(), 0, &face)) {
201      error(-1, "could not create truetype face\n");
202      goto err2;
203    }
204    unlink (tmpFileName2->getCString());
205    delete tmpFileName2;
206    break;
207   
208  case fontCIDType0:
209  case fontCIDType0C:
210
211    codeToGID = NULL;
212    codeToGIDLen = 0;
213
214    if (!useCIDs)
215    {
216      if ((ff1c = FoFiType1C::load(fileName->getCString()))) {
217        codeToGID = ff1c->getCIDToGIDMap(&codeToGIDLen);
218        delete ff1c;
219      }
220    }
221
222    if (FT_New_Face(lib, fileName->getCString(), 0, &face)) {
223      gfree(codeToGID);
224      codeToGID = NULL;
225      error(-1, "could not create cid face\n");
226      goto err2;
227    }
228    break;
229   
230  default:
231    printf ("font type not handled\n");
232    goto err2;
233    break;
234  }
235
236  // delete the (temporary) font file -- with Unix hard link
237  // semantics, this will remove the last link; otherwise it will
238  // return an error, leaving the file to be deleted later
239  if (fileName == tmpFileName) {
240    unlink (fileName->getCString());
241    delete tmpFileName;
242  }
243
244  cairo_font_face = cairo_ft_font_face_create_for_ft_face (face,
245                                                           FT_LOAD_NO_HINTING |
246                                                           FT_LOAD_NO_BITMAP);
247  if (cairo_font_face == NULL) {
248    error(-1, "could not create cairo font\n");
249    goto err2; /* this doesn't do anything, but it looks like we're
250                * handling the error */
251  } {
252  CairoFont *ret = new CairoFont(ref, cairo_font_face, face, codeToGID, codeToGIDLen);
253  cairo_font_face_set_user_data (cairo_font_face, 
254                                 &cairo_font_face_key,
255                                 ret,
256                                 cairo_font_face_destroy);
257
258  return ret;
259  }
260 err2:
261  /* hmm? */
262  printf ("some font thing failed\n");
263  return NULL;
264}
265
266CairoFont::CairoFont(Ref ref, cairo_font_face_t *cairo_font_face, FT_Face face,
267    Gushort *codeToGID, int codeToGIDLen) : ref(ref), cairo_font_face(cairo_font_face),
268                                            face(face), codeToGID(codeToGID),
269                                            codeToGIDLen(codeToGIDLen) { }
270
271CairoFont::~CairoFont() {
272  FT_Done_Face (face);
273  gfree(codeToGID);
274}
275
276GBool
277CairoFont::matches(Ref &other) {
278  return (other.num == ref.num && other.gen == ref.gen);
279}
280
281cairo_font_face_t *
282CairoFont::getFontFace(void) {
283  return cairo_font_face;
284}
285
286unsigned long
287CairoFont::getGlyph(CharCode code,
288                    Unicode *u, int uLen) {
289  FT_UInt gid;
290
291  if (codeToGID && code < codeToGIDLen) {
292    gid = (FT_UInt)codeToGID[code];
293  } else {
294    gid = (FT_UInt)code;
295  }
296  return gid;
297}
298
299//------------------------------------------------------------------------
300// CairoFontEngine
301//------------------------------------------------------------------------
302
303CairoFontEngine::CairoFontEngine(FT_Library libA) {
304  int i;
305
306  lib = libA;
307  for (i = 0; i < cairoFontCacheSize; ++i) {
308    fontCache[i] = NULL;
309  }
310 
311  FT_Int major, minor, patch;
312  // as of FT 2.1.8, CID fonts are indexed by CID instead of GID
313  FT_Library_Version(lib, &major, &minor, &patch);
314  useCIDs = major > 2 ||
315            (major == 2 && (minor > 1 || (minor == 1 && patch > 7)));
316}
317
318CairoFontEngine::~CairoFontEngine() {
319  int i;
320 
321  for (i = 0; i < cairoFontCacheSize; ++i) {
322    if (fontCache[i])
323      delete fontCache[i];
324  }
325}
326
327CairoFont *
328CairoFontEngine::getFont(GfxFont *gfxFont, XRef *xref) {
329  int i, j;
330  Ref ref;
331  CairoFont *font;
332  GfxFontType fontType;
333 
334  fontType = gfxFont->getType();
335  if (fontType == fontType3) {
336    /* Need to figure this out later */
337    //    return NULL;
338  }
339
340  ref = *gfxFont->getID();
341
342  for (i = 0; i < cairoFontCacheSize; ++i) {
343    font = fontCache[i];
344    if (font && font->matches(ref)) {
345      for (j = i; j > 0; --j) {
346        fontCache[j] = fontCache[j-1];
347      }
348      fontCache[0] = font;
349      return font;
350    }
351  }
352 
353  font = CairoFont::create (gfxFont, xref, lib, useCIDs);
354  //XXX: if font is null should we still insert it into the cache?
355  if (fontCache[cairoFontCacheSize - 1]) {
356    delete fontCache[cairoFontCacheSize - 1];
357  }
358  for (j = cairoFontCacheSize - 1; j > 0; --j) {
359    fontCache[j] = fontCache[j-1];
360  }
361  fontCache[0] = font;
362  return font;
363}
364
Note: See TracBrowser for help on using the repository browser.