SmartPDF - lightweight pdf viewer app for rosapps
[reactos.git] / rosapps / smartpdf / poppler / poppler / CairoFontEngine.cc
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
26 static void fileWrite(void *stream, char *data, int len) {
27 fwrite(data, 1, len, (FILE *)stream);
28 }
29
30 //------------------------------------------------------------------------
31 // CairoFont
32 //------------------------------------------------------------------------
33
34 static void cairo_font_face_destroy (void *data)
35 {
36 CairoFont *font = (CairoFont *) data;
37
38 delete font;
39 }
40
41 CairoFont *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
266 CairoFont::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
271 CairoFont::~CairoFont() {
272 FT_Done_Face (face);
273 gfree(codeToGID);
274 }
275
276 GBool
277 CairoFont::matches(Ref &other) {
278 return (other.num == ref.num && other.gen == ref.gen);
279 }
280
281 cairo_font_face_t *
282 CairoFont::getFontFace(void) {
283 return cairo_font_face;
284 }
285
286 unsigned long
287 CairoFont::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
303 CairoFontEngine::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
318 CairoFontEngine::~CairoFontEngine() {
319 int i;
320
321 for (i = 0; i < cairoFontCacheSize; ++i) {
322 if (fontCache[i])
323 delete fontCache[i];
324 }
325 }
326
327 CairoFont *
328 CairoFontEngine::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