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