1 //========================================================================
2 //
3 // SplashFontEngine.cc
4 //
5 // Copyright 2003-2013 Glyph & Cog, LLC
6 //
7 //========================================================================
8 
9 #include <aconf.h>
10 
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
13 #endif
14 
15 #include <stdlib.h>
16 #include <stdio.h>
17 #ifndef _WIN32
18 #  include <unistd.h>
19 #endif
20 #include "gmem.h"
21 #include "gmempp.h"
22 #include "GString.h"
23 #include "GList.h"
24 #include "SplashMath.h"
25 #include "SplashFTFontEngine.h"
26 #include "SplashFontFile.h"
27 #include "SplashFontFileID.h"
28 #include "SplashFont.h"
29 #include "SplashFontEngine.h"
30 
31 #ifdef VMS
32 #if (__VMS_VER < 70000000)
33 extern "C" int unlink(char *filename);
34 #endif
35 #endif
36 
37 //------------------------------------------------------------------------
38 // SplashFontEngine
39 //------------------------------------------------------------------------
40 
SplashFontEngine(GBool enableFreeType,Guint freeTypeFlags,GBool aa)41 SplashFontEngine::SplashFontEngine(
42 #if HAVE_FREETYPE_H
43 				   GBool enableFreeType,
44 				   Guint freeTypeFlags,
45 #endif
46 				   GBool aa) {
47   int i;
48 
49   for (i = 0; i < splashFontCacheSize; ++i) {
50     fontCache[i] = NULL;
51   }
52   badFontFiles = new GList();
53 
54 #if HAVE_FREETYPE_H
55   if (enableFreeType) {
56     ftEngine = SplashFTFontEngine::init(aa, freeTypeFlags);
57   } else {
58     ftEngine = NULL;
59   }
60 #endif
61 }
62 
~SplashFontEngine()63 SplashFontEngine::~SplashFontEngine() {
64   int i;
65 
66   for (i = 0; i < splashFontCacheSize; ++i) {
67     if (fontCache[i]) {
68       delete fontCache[i];
69     }
70   }
71   deleteGList(badFontFiles, SplashFontFileID);
72 
73 #if HAVE_FREETYPE_H
74   if (ftEngine) {
75     delete ftEngine;
76   }
77 #endif
78 }
79 
getFontFile(SplashFontFileID * id)80 SplashFontFile *SplashFontEngine::getFontFile(SplashFontFileID *id) {
81   SplashFontFile *fontFile;
82   int i;
83 
84   for (i = 0; i < splashFontCacheSize; ++i) {
85     if (fontCache[i]) {
86       fontFile = fontCache[i]->getFontFile();
87       if (fontFile && fontFile->getID()->matches(id)) {
88 	return fontFile;
89       }
90     }
91   }
92   return NULL;
93 }
94 
checkForBadFontFile(SplashFontFileID * id)95 GBool SplashFontEngine::checkForBadFontFile(SplashFontFileID *id) {
96   for (int i = 0; i < badFontFiles->getLength(); ++i) {
97     if (((SplashFontFileID *)badFontFiles->get(i))->matches(id)) {
98       return gTrue;
99     }
100   }
101   return gFalse;
102 }
103 
loadType1Font(SplashFontFileID * idA,GString * fontBuf,const char ** enc)104 SplashFontFile *SplashFontEngine::loadType1Font(SplashFontFileID *idA,
105 #if LOAD_FONTS_FROM_MEM
106 						GString *fontBuf,
107 #else
108 						char *fileName,
109 						GBool deleteFile,
110 #endif
111 						const char **enc) {
112   SplashFontFile *fontFile;
113 
114   fontFile = NULL;
115 #if HAVE_FREETYPE_H
116   if (!fontFile && ftEngine) {
117     fontFile = ftEngine->loadType1Font(idA,
118 #if LOAD_FONTS_FROM_MEM
119 				       fontBuf,
120 #else
121 				       fileName, deleteFile,
122 #endif
123 				       enc);
124   }
125 #endif
126 
127 #if !LOAD_FONTS_FROM_MEM && !defined(_WIN32) && !defined(__ANDROID__)
128   // delete the (temporary) font file -- with Unix hard link
129   // semantics, this will remove the last link; otherwise it will
130   // return an error, leaving the file to be deleted later (if
131   // loadXYZFont failed, the file will always be deleted)
132   if (deleteFile) {
133     unlink(fontFile ? fontFile->fileName->getCString() : fileName);
134   }
135 #endif
136 
137   if (!fontFile) {
138     badFontFiles->append(idA);
139   }
140 
141   return fontFile;
142 }
143 
loadType1CFont(SplashFontFileID * idA,GString * fontBuf,int * codeToGID,const char ** enc)144 SplashFontFile *SplashFontEngine::loadType1CFont(SplashFontFileID *idA,
145 #if LOAD_FONTS_FROM_MEM
146 						 GString *fontBuf,
147 #else
148 						 char *fileName,
149 						 GBool deleteFile,
150 #endif
151 						 int *codeToGID,
152 						 const char **enc) {
153   SplashFontFile *fontFile;
154 
155   fontFile = NULL;
156   if (!fontFile) {
157     gfree(codeToGID);
158   }
159 #if HAVE_FREETYPE_H
160   if (!fontFile && ftEngine) {
161     fontFile = ftEngine->loadType1CFont(idA,
162 #if LOAD_FONTS_FROM_MEM
163 					fontBuf,
164 #else
165 					fileName, deleteFile,
166 #endif
167 					enc);
168   }
169 #endif
170 
171 #if !LOAD_FONTS_FROM_MEM && !defined(_WIN32) && !defined(__ANDROID__)
172   // delete the (temporary) font file -- with Unix hard link
173   // semantics, this will remove the last link; otherwise it will
174   // return an error, leaving the file to be deleted later (if
175   // loadXYZFont failed, the file will always be deleted)
176   if (deleteFile) {
177     unlink(fontFile ? fontFile->fileName->getCString() : fileName);
178   }
179 #endif
180 
181   if (!fontFile) {
182     badFontFiles->append(idA);
183   }
184 
185   return fontFile;
186 }
187 
loadOpenTypeT1CFont(SplashFontFileID * idA,GString * fontBuf,int * codeToGID,const char ** enc)188 SplashFontFile *SplashFontEngine::loadOpenTypeT1CFont(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 						      const char **enc) {
197   SplashFontFile *fontFile;
198 
199   fontFile = NULL;
200   if (!fontFile) {
201     gfree(codeToGID);
202   }
203 #if HAVE_FREETYPE_H
204   if (!fontFile && ftEngine) {
205     fontFile = ftEngine->loadOpenTypeT1CFont(idA,
206 #if LOAD_FONTS_FROM_MEM
207 					     fontBuf,
208 #else
209 					     fileName, deleteFile,
210 #endif
211 					     enc);
212   }
213 #endif
214 
215 #if !LOAD_FONTS_FROM_MEM && !defined(_WIN32) && !defined(__ANDROID__)
216   // delete the (temporary) font file -- with Unix hard link
217   // semantics, this will remove the last link; otherwise it will
218   // return an error, leaving the file to be deleted later (if
219   // loadXYZFont failed, the file will always be deleted)
220   if (deleteFile) {
221     unlink(fontFile ? fontFile->fileName->getCString() : fileName);
222   }
223 #endif
224 
225   if (!fontFile) {
226     badFontFiles->append(idA);
227   }
228 
229   return fontFile;
230 }
231 
loadCIDFont(SplashFontFileID * idA,GString * fontBuf,int * codeToGID,int codeToGIDLen)232 SplashFontFile *SplashFontEngine::loadCIDFont(SplashFontFileID *idA,
233 #if LOAD_FONTS_FROM_MEM
234 					      GString *fontBuf,
235 #else
236 					      char *fileName,
237 					      GBool deleteFile,
238 #endif
239 					      int *codeToGID,
240 					      int codeToGIDLen) {
241   SplashFontFile *fontFile;
242 
243   fontFile = NULL;
244 #if HAVE_FREETYPE_H
245   if (!fontFile && ftEngine) {
246     fontFile = ftEngine->loadCIDFont(idA,
247 #if LOAD_FONTS_FROM_MEM
248 				     fontBuf,
249 #else
250 				     fileName, deleteFile,
251 #endif
252 				     codeToGID, codeToGIDLen);
253   }
254 #endif
255 
256   if (!fontFile) {
257     gfree(codeToGID);
258   }
259 
260 #if !LOAD_FONTS_FROM_MEM && !defined(_WIN32) && !defined(__ANDROID__)
261   // delete the (temporary) font file -- with Unix hard link
262   // semantics, this will remove the last link; otherwise it will
263   // return an error, leaving the file to be deleted later (if
264   // loadXYZFont failed, the file will always be deleted)
265   if (deleteFile) {
266     unlink(fontFile ? fontFile->fileName->getCString() : fileName);
267   }
268 #endif
269 
270   if (!fontFile) {
271     badFontFiles->append(idA);
272   }
273 
274   return fontFile;
275 }
276 
loadOpenTypeCFFFont(SplashFontFileID * idA,GString * fontBuf,int * codeToGID,int codeToGIDLen)277 SplashFontFile *SplashFontEngine::loadOpenTypeCFFFont(SplashFontFileID *idA,
278 #if LOAD_FONTS_FROM_MEM
279 						      GString *fontBuf,
280 #else
281 						      char *fileName,
282 						      GBool deleteFile,
283 #endif
284 						      int *codeToGID,
285 						      int codeToGIDLen) {
286   SplashFontFile *fontFile;
287 
288   fontFile = NULL;
289 #if HAVE_FREETYPE_H
290   if (!fontFile && ftEngine) {
291     fontFile = ftEngine->loadOpenTypeCFFFont(idA,
292 #if LOAD_FONTS_FROM_MEM
293 					     fontBuf,
294 #else
295 					     fileName, deleteFile,
296 #endif
297 					     codeToGID, codeToGIDLen);
298   }
299 #endif
300 
301   if (!fontFile) {
302     gfree(codeToGID);
303   }
304 
305 #if !LOAD_FONTS_FROM_MEM && !defined(_WIN32) && !defined(__ANDROID__)
306   // delete the (temporary) font file -- with Unix hard link
307   // semantics, this will remove the last link; otherwise it will
308   // return an error, leaving the file to be deleted later (if
309   // loadXYZFont failed, the file will always be deleted)
310   if (deleteFile) {
311     unlink(fontFile ? fontFile->fileName->getCString() : fileName);
312   }
313 #endif
314 
315   if (!fontFile) {
316     badFontFiles->append(idA);
317   }
318 
319   return fontFile;
320 }
321 
loadTrueTypeFont(SplashFontFileID * idA,GString * fontBuf,int fontNum,int * codeToGID,int codeToGIDLen,char * fontName)322 SplashFontFile *SplashFontEngine::loadTrueTypeFont(SplashFontFileID *idA,
323 #if LOAD_FONTS_FROM_MEM
324 						   GString *fontBuf,
325 #else
326 						   char *fileName,
327 						   GBool deleteFile,
328 #endif
329 						   int fontNum,
330 						   int *codeToGID,
331 						   int codeToGIDLen,
332 						   char *fontName) {
333   SplashFontFile *fontFile;
334 
335   fontFile = NULL;
336 #if HAVE_FREETYPE_H
337   if (!fontFile && ftEngine) {
338     fontFile = ftEngine->loadTrueTypeFont(idA,
339 #if LOAD_FONTS_FROM_MEM
340 					  fontBuf,
341 #else
342 					  fileName, deleteFile,
343 #endif
344 					  fontNum, codeToGID, codeToGIDLen);
345   }
346 #endif
347 
348   if (!fontFile) {
349     gfree(codeToGID);
350   }
351 
352 #if !LOAD_FONTS_FROM_MEM && !defined(_WIN32) && !defined(__ANDROID__)
353   // delete the (temporary) font file -- with Unix hard link
354   // semantics, this will remove the last link; otherwise it will
355   // return an error, leaving the file to be deleted later (if
356   // loadXYZFont failed, the file will always be deleted)
357   if (deleteFile) {
358     unlink(fontFile ? fontFile->fileName->getCString() : fileName);
359   }
360 #endif
361 
362   if (!fontFile) {
363     badFontFiles->append(idA);
364   }
365 
366   return fontFile;
367 }
368 
getFont(SplashFontFile * fontFile,SplashCoord * textMat,SplashCoord * ctm)369 SplashFont *SplashFontEngine::getFont(SplashFontFile *fontFile,
370 				      SplashCoord *textMat,
371 				      SplashCoord *ctm) {
372   SplashCoord mat[4];
373   SplashFont *font;
374   int i, j;
375 
376   mat[0] = textMat[0] * ctm[0] + textMat[1] * ctm[2];
377   mat[1] = -(textMat[0] * ctm[1] + textMat[1] * ctm[3]);
378   mat[2] = textMat[2] * ctm[0] + textMat[3] * ctm[2];
379   mat[3] = -(textMat[2] * ctm[1] + textMat[3] * ctm[3]);
380   if (!splashCheckDet(mat[0], mat[1], mat[2], mat[3], 0.01)) {
381     // avoid a singular (or close-to-singular) matrix
382     mat[0] = 0.01;  mat[1] = 0;
383     mat[2] = 0;     mat[3] = 0.01;
384   }
385 
386   font = fontCache[0];
387   if (font && font->matches(fontFile, mat, textMat)) {
388     return font;
389   }
390   for (i = 1; i < splashFontCacheSize; ++i) {
391     font = fontCache[i];
392     if (font && font->matches(fontFile, mat, textMat)) {
393       for (j = i; j > 0; --j) {
394 	fontCache[j] = fontCache[j-1];
395       }
396       fontCache[0] = font;
397       return font;
398     }
399   }
400   font = fontFile->makeFont(mat, textMat);
401   if (fontCache[splashFontCacheSize - 1]) {
402     delete fontCache[splashFontCacheSize - 1];
403   }
404   for (j = splashFontCacheSize - 1; j > 0; --j) {
405     fontCache[j] = fontCache[j-1];
406   }
407   fontCache[0] = font;
408   return font;
409 }
410