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