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