1 //========================================================================
2 //
3 // SplashFTFontEngine.cc
4 //
5 // Copyright 2003-2013 Glyph & Cog, LLC
6 //
7 //========================================================================
8
9 #include <aconf.h>
10
11 #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
12
13 #ifdef USE_GCC_PRAGMAS
14 #pragma implementation
15 #endif
16
17 #include <stdio.h>
18 #ifndef _WIN32
19 # include <unistd.h>
20 #endif
21 #include "gmem.h"
22 #include "GString.h"
23 #include "gfile.h"
24 #include "FoFiTrueType.h"
25 #include "FoFiType1C.h"
26 #include "SplashFTFontFile.h"
27 #include "SplashFTFontEngine.h"
28 #include FT_MODULE_H
29 #ifdef FT_CFF_DRIVER_H
30 # include FT_CFF_DRIVER_H
31 #endif
32
33 #ifdef VMS
34 #if (__VMS_VER < 70000000)
35 extern "C" int unlink(char *filename);
36 #endif
37 #endif
38
39 //------------------------------------------------------------------------
40
fileWrite(void * stream,const char * data,int len)41 static void fileWrite(void *stream, const char *data, int len) {
42 fwrite(data, 1, len, (FILE *)stream);
43 }
44
45 #if LOAD_FONTS_FROM_MEM
gstringWrite(void * stream,const char * data,int len)46 static void gstringWrite(void *stream, const char *data, int len) {
47 ((GString *)stream)->append(data, len);
48 }
49 #endif
50
51 //------------------------------------------------------------------------
52 // SplashFTFontEngine
53 //------------------------------------------------------------------------
54
SplashFTFontEngine(GBool aaA,Guint flagsA,FT_Library libA)55 SplashFTFontEngine::SplashFTFontEngine(GBool aaA, Guint flagsA,
56 FT_Library libA) {
57 FT_Int major, minor, patch;
58
59 aa = aaA;
60 flags = flagsA;
61 lib = libA;
62
63 // as of FT 2.1.8, CID fonts are indexed by CID instead of GID
64 FT_Library_Version(lib, &major, &minor, &patch);
65 useCIDs = major > 2 ||
66 (major == 2 && (minor > 1 || (minor == 1 && patch > 7)));
67 }
68
init(GBool aaA,Guint flagsA)69 SplashFTFontEngine *SplashFTFontEngine::init(GBool aaA, Guint flagsA) {
70 FT_Library libA;
71
72 if (FT_Init_FreeType(&libA)) {
73 return NULL;
74 }
75 return new SplashFTFontEngine(aaA, flagsA, libA);
76 }
77
~SplashFTFontEngine()78 SplashFTFontEngine::~SplashFTFontEngine() {
79 FT_Done_FreeType(lib);
80 }
81
loadType1Font(SplashFontFileID * idA,GString * fontBuf,const char ** enc)82 SplashFontFile *SplashFTFontEngine::loadType1Font(SplashFontFileID *idA,
83 #if LOAD_FONTS_FROM_MEM
84 GString *fontBuf,
85 #else
86 char *fileName,
87 GBool deleteFile,
88 #endif
89 const char **enc) {
90 return SplashFTFontFile::loadType1Font(this, idA,
91 #if LOAD_FONTS_FROM_MEM
92 fontBuf,
93 #else
94 fileName, deleteFile,
95 #endif
96 enc, gTrue);
97 }
98
loadType1CFont(SplashFontFileID * idA,GString * fontBuf,const char ** enc)99 SplashFontFile *SplashFTFontEngine::loadType1CFont(SplashFontFileID *idA,
100 #if LOAD_FONTS_FROM_MEM
101 GString *fontBuf,
102 #else
103 char *fileName,
104 GBool deleteFile,
105 #endif
106 const char **enc) {
107 return SplashFTFontFile::loadType1Font(this, idA,
108 #if LOAD_FONTS_FROM_MEM
109 fontBuf,
110 #else
111 fileName, deleteFile,
112 #endif
113 enc, gFalse);
114 }
115
loadOpenTypeT1CFont(SplashFontFileID * idA,GString * fontBuf,const char ** enc)116 SplashFontFile *SplashFTFontEngine::loadOpenTypeT1CFont(SplashFontFileID *idA,
117 #if LOAD_FONTS_FROM_MEM
118 GString *fontBuf,
119 #else
120 char *fileName,
121 GBool deleteFile,
122 #endif
123 const char **enc) {
124 FoFiTrueType *ff;
125 #if LOAD_FONTS_FROM_MEM
126 GString *fontBuf2;
127 #else
128 GString *tmpFileName;
129 FILE *tmpFile;
130 #endif
131 SplashFontFile *ret;
132
133 #if LOAD_FONTS_FROM_MEM
134 if (!(ff = FoFiTrueType::make(fontBuf->getCString(), fontBuf->getLength(),
135 0, gTrue))) {
136 #else
137 if (!(ff = FoFiTrueType::load(fileName, 0, gTrue))) {
138 #endif
139 return NULL;
140 }
141 if (ff->isHeadlessCFF()) {
142 #if LOAD_FONTS_FROM_MEM
143 fontBuf2 = new GString();
144 ff->convertToType1(NULL, enc, gFalse, &gstringWrite, fontBuf2);
145 delete ff;
146 ret = SplashFTFontFile::loadType1Font(this, idA, fontBuf2, enc,
147 gFalse);
148 if (ret) {
149 delete fontBuf;
150 } else {
151 delete fontBuf2;
152 }
153 #else
154 tmpFileName = NULL;
155 if (!openTempFile(&tmpFileName, &tmpFile, "wb", NULL)) {
156 delete ff;
157 return NULL;
158 }
159 ff->convertToType1(NULL, enc, gFalse, &fileWrite, tmpFile);
160 delete ff;
161 fclose(tmpFile);
162 ret = SplashFTFontFile::loadType1Font(this, idA, tmpFileName->getCString(),
163 gTrue, enc, gFalse);
164 if (ret) {
165 if (deleteFile) {
166 unlink(fileName);
167 }
168 } else {
169 unlink(tmpFileName->getCString());
170 }
171 delete tmpFileName;
172 #endif
173 } else {
174 delete ff;
175 ret = SplashFTFontFile::loadType1Font(this, idA,
176 #if LOAD_FONTS_FROM_MEM
177 fontBuf,
178 #else
179 fileName, deleteFile,
180 #endif
181 enc, gFalse);
182 }
183 return ret;
184 }
185
186 SplashFontFile *SplashFTFontEngine::loadCIDFont(SplashFontFileID *idA,
187 #if LOAD_FONTS_FROM_MEM
188 GString *fontBuf
189 #else
190 char *fileName,
191 GBool deleteFile
192 #endif
193 ) {
194 FoFiType1C *ff;
195 int *cidToGIDMap;
196 int nCIDs;
197 SplashFontFile *ret;
198
199 // check for a CFF font
200 if (useCIDs) {
201 cidToGIDMap = NULL;
202 nCIDs = 0;
203 #if LOAD_FONTS_FROM_MEM
204 } else if ((ff = FoFiType1C::make(fontBuf->getCString(),
205 fontBuf->getLength()))) {
206 #else
207 } else if ((ff = FoFiType1C::load(fileName))) {
208 #endif
209 cidToGIDMap = ff->getCIDToGIDMap(&nCIDs);
210 delete ff;
211 } else {
212 cidToGIDMap = NULL;
213 nCIDs = 0;
214 }
215 ret = SplashFTFontFile::loadCIDFont(this, idA,
216 #if LOAD_FONTS_FROM_MEM
217 fontBuf,
218 #else
219 fileName, deleteFile,
220 #endif
221 cidToGIDMap, nCIDs);
222 if (!ret) {
223 gfree(cidToGIDMap);
224 }
225 return ret;
226 }
227
228 SplashFontFile *SplashFTFontEngine::loadOpenTypeCFFFont(SplashFontFileID *idA,
229 #if LOAD_FONTS_FROM_MEM
230 GString *fontBuf,
231 #else
232 char *fileName,
233 GBool deleteFile,
234 #endif
235 int *codeToGID,
236 int codeToGIDLen) {
237 FoFiTrueType *ff;
238 #if LOAD_FONTS_FROM_MEM
239 GString *fontBuf2;
240 #else
241 GString *tmpFileName;
242 FILE *tmpFile;
243 #endif
244 char *cffStart;
245 int cffLength;
246 int *cidToGIDMap;
247 int nCIDs;
248 SplashFontFile *ret;
249
250 #if LOAD_FONTS_FROM_MEM
251 if (!(ff = FoFiTrueType::make(fontBuf->getCString(), fontBuf->getLength(),
252 0, gTrue))) {
253 #else
254 if (!(ff = FoFiTrueType::load(fileName, 0, gTrue))) {
255 #endif
256 return NULL;
257 }
258 cidToGIDMap = NULL;
259 nCIDs = 0;
260 if (ff->isHeadlessCFF()) {
261 if (!ff->getCFFBlock(&cffStart, &cffLength)) {
262 return NULL;
263 }
264 #if LOAD_FONTS_FROM_MEM
265 fontBuf2 = new GString(cffStart, cffLength);
266 if (!useCIDs) {
267 cidToGIDMap = ff->getCIDToGIDMap(&nCIDs);
268 }
269 ret = SplashFTFontFile::loadCIDFont(this, idA, fontBuf2,
270 cidToGIDMap, nCIDs);
271 if (ret) {
272 delete fontBuf;
273 } else {
274 delete fontBuf2;
275 }
276 #else
277 tmpFileName = NULL;
278 if (!openTempFile(&tmpFileName, &tmpFile, "wb", NULL)) {
279 delete ff;
280 return NULL;
281 }
282 fwrite(cffStart, 1, cffLength, tmpFile);
283 fclose(tmpFile);
284 if (!useCIDs) {
285 cidToGIDMap = ff->getCIDToGIDMap(&nCIDs);
286 }
287 ret = SplashFTFontFile::loadCIDFont(this, idA,
288 tmpFileName->getCString(), gTrue,
289 cidToGIDMap, nCIDs);
290 if (ret) {
291 if (deleteFile) {
292 unlink(fileName);
293 }
294 } else {
295 unlink(tmpFileName->getCString());
296 }
297 delete tmpFileName;
298 #endif
299 } else {
300 if (!codeToGID && !useCIDs && ff->isOpenTypeCFF()) {
301 cidToGIDMap = ff->getCIDToGIDMap(&nCIDs);
302 }
303 ret = SplashFTFontFile::loadCIDFont(this, idA,
304 #if LOAD_FONTS_FROM_MEM
305 fontBuf,
306 #else
307 fileName, deleteFile,
308 #endif
309 codeToGID ? codeToGID : cidToGIDMap,
310 codeToGID ? codeToGIDLen : nCIDs);
311 }
312 delete ff;
313 if (!ret) {
314 gfree(cidToGIDMap);
315 }
316 return ret;
317 }
318
319 SplashFontFile *SplashFTFontEngine::loadTrueTypeFont(SplashFontFileID *idA,
320 #if LOAD_FONTS_FROM_MEM
321 GString *fontBuf,
322 #else
323 char *fileName,
324 GBool deleteFile,
325 #endif
326 int fontNum,
327 int *codeToGID,
328 int codeToGIDLen) {
329 FoFiTrueType *ff;
330 #if LOAD_FONTS_FROM_MEM
331 GString *fontBuf2;
332 #else
333 GString *tmpFileName;
334 FILE *tmpFile;
335 #endif
336 SplashFontFile *ret;
337
338 #if LOAD_FONTS_FROM_MEM
339 if (!(ff = FoFiTrueType::make(fontBuf->getCString(), fontBuf->getLength(),
340 fontNum))) {
341 #else
342 if (!(ff = FoFiTrueType::load(fileName, fontNum))) {
343 #endif
344 return NULL;
345 }
346 #if LOAD_FONTS_FROM_MEM
347 fontBuf2 = new GString;
348 ff->writeTTF(&gstringWrite, fontBuf2);
349 #else
350 tmpFileName = NULL;
351 if (!openTempFile(&tmpFileName, &tmpFile, "wb", NULL)) {
352 delete ff;
353 return NULL;
354 }
355 ff->writeTTF(&fileWrite, tmpFile);
356 fclose(tmpFile);
357 #endif
358 delete ff;
359 ret = SplashFTFontFile::loadTrueTypeFont(this, idA,
360 #if LOAD_FONTS_FROM_MEM
361 fontBuf2,
362 #else
363 tmpFileName->getCString(), gTrue,
364 #endif
365 0, codeToGID, codeToGIDLen);
366 #if LOAD_FONTS_FROM_MEM
367 if (ret) {
368 delete fontBuf;
369 } else {
370 delete fontBuf2;
371 }
372 #else
373 if (ret) {
374 if (deleteFile) {
375 unlink(fileName);
376 }
377 } else {
378 unlink(tmpFileName->getCString());
379 }
380 delete tmpFileName;
381 #endif
382 return ret;
383 }
384
385 #endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
386