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