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