/src/xpdf-4.06/splash/SplashFontEngine.cc
Line | Count | Source |
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 | 10.2k | GBool aa) { |
43 | 10.2k | int i; |
44 | | |
45 | 174k | for (i = 0; i < splashFontCacheSize; ++i) { |
46 | 164k | fontCache[i] = NULL; |
47 | 164k | } |
48 | 10.2k | badFontFiles = new GList(); |
49 | | |
50 | 10.2k | #if HAVE_FREETYPE_H |
51 | 10.2k | if (enableFreeType) { |
52 | 10.2k | ftEngine = SplashFTFontEngine::init(aa, freeTypeFlags); |
53 | 10.2k | } else { |
54 | 0 | ftEngine = NULL; |
55 | 0 | } |
56 | 10.2k | #endif |
57 | 10.2k | } |
58 | | |
59 | 10.2k | SplashFontEngine::~SplashFontEngine() { |
60 | 10.2k | int i; |
61 | | |
62 | 174k | for (i = 0; i < splashFontCacheSize; ++i) { |
63 | 163k | if (fontCache[i]) { |
64 | 2.57k | delete fontCache[i]; |
65 | 2.57k | } |
66 | 163k | } |
67 | 10.2k | deleteGList(badFontFiles, SplashFontFileID); |
68 | | |
69 | 10.2k | #if HAVE_FREETYPE_H |
70 | 10.2k | if (ftEngine) { |
71 | 10.2k | delete ftEngine; |
72 | 10.2k | } |
73 | 10.2k | #endif |
74 | 10.2k | } |
75 | | |
76 | 28.7k | SplashFontFile *SplashFontEngine::getFontFile(SplashFontFileID *id) { |
77 | 28.7k | SplashFontFile *fontFile; |
78 | 28.7k | int i; |
79 | | |
80 | 285k | for (i = 0; i < splashFontCacheSize; ++i) { |
81 | 269k | if (fontCache[i]) { |
82 | 13.6k | fontFile = fontCache[i]->getFontFile(); |
83 | 13.6k | if (fontFile && fontFile->getID()->matches(id)) { |
84 | 12.6k | return fontFile; |
85 | 12.6k | } |
86 | 13.6k | } |
87 | 269k | } |
88 | 16.0k | return NULL; |
89 | 28.7k | } |
90 | | |
91 | 31.1k | GBool SplashFontEngine::checkForBadFontFile(SplashFontFileID *id) { |
92 | 35.2k | for (int i = 0; i < badFontFiles->getLength(); ++i) { |
93 | 6.57k | if (((SplashFontFileID *)badFontFiles->get(i))->matches(id)) { |
94 | 2.46k | return gTrue; |
95 | 2.46k | } |
96 | 6.57k | } |
97 | 28.7k | return gFalse; |
98 | 31.1k | } |
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 | 905 | const char **enc) { |
108 | 905 | SplashFontFile *fontFile; |
109 | | |
110 | 905 | fontFile = NULL; |
111 | 905 | #if HAVE_FREETYPE_H |
112 | 905 | if (!fontFile && ftEngine) { |
113 | 905 | fontFile = ftEngine->loadType1Font(idA, |
114 | | #if LOAD_FONTS_FROM_MEM |
115 | | fontBuf, |
116 | | #else |
117 | 905 | fileName, deleteFile, |
118 | 905 | #endif |
119 | 905 | enc); |
120 | 905 | } |
121 | 905 | #endif |
122 | | |
123 | 905 | #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 | 905 | if (deleteFile) { |
129 | 905 | unlink(fontFile ? fontFile->fileName->getCString() : fileName); |
130 | 905 | } |
131 | 905 | #endif |
132 | | |
133 | 905 | if (!fontFile) { |
134 | 825 | badFontFiles->append(idA); |
135 | 825 | } |
136 | | |
137 | 905 | return fontFile; |
138 | 905 | } |
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 | 1.20k | const char **enc) { |
149 | 1.20k | SplashFontFile *fontFile; |
150 | | |
151 | 1.20k | fontFile = NULL; |
152 | 1.20k | if (!fontFile) { |
153 | 1.20k | gfree(codeToGID); |
154 | 1.20k | } |
155 | 1.20k | #if HAVE_FREETYPE_H |
156 | 1.20k | if (!fontFile && ftEngine) { |
157 | 1.20k | fontFile = ftEngine->loadType1CFont(idA, |
158 | | #if LOAD_FONTS_FROM_MEM |
159 | | fontBuf, |
160 | | #else |
161 | 1.20k | fileName, deleteFile, |
162 | 1.20k | #endif |
163 | 1.20k | enc); |
164 | 1.20k | } |
165 | 1.20k | #endif |
166 | | |
167 | 1.20k | #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 | 1.20k | if (deleteFile) { |
173 | 1.20k | unlink(fontFile ? fontFile->fileName->getCString() : fileName); |
174 | 1.20k | } |
175 | 1.20k | #endif |
176 | | |
177 | 1.20k | if (!fontFile) { |
178 | 248 | badFontFiles->append(idA); |
179 | 248 | } |
180 | | |
181 | 1.20k | return fontFile; |
182 | 1.20k | } |
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 | 19 | int codeToGIDLen) { |
237 | 19 | SplashFontFile *fontFile; |
238 | | |
239 | 19 | fontFile = NULL; |
240 | 19 | #if HAVE_FREETYPE_H |
241 | 19 | if (!fontFile && ftEngine) { |
242 | 19 | fontFile = ftEngine->loadCIDFont(idA, |
243 | | #if LOAD_FONTS_FROM_MEM |
244 | | fontBuf, |
245 | | #else |
246 | 19 | fileName, deleteFile, |
247 | 19 | #endif |
248 | 19 | codeToGID, codeToGIDLen); |
249 | 19 | } |
250 | 19 | #endif |
251 | | |
252 | 19 | if (!fontFile) { |
253 | 4 | gfree(codeToGID); |
254 | 4 | } |
255 | | |
256 | 19 | #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 | 19 | if (deleteFile) { |
262 | 19 | unlink(fontFile ? fontFile->fileName->getCString() : fileName); |
263 | 19 | } |
264 | 19 | #endif |
265 | | |
266 | 19 | if (!fontFile) { |
267 | 4 | badFontFiles->append(idA); |
268 | 4 | } |
269 | | |
270 | 19 | return fontFile; |
271 | 19 | } |
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 | 1.57k | char *fontName) { |
329 | 1.57k | SplashFontFile *fontFile; |
330 | | |
331 | 1.57k | fontFile = NULL; |
332 | 1.57k | #if HAVE_FREETYPE_H |
333 | 1.57k | if (!fontFile && ftEngine) { |
334 | 1.57k | fontFile = ftEngine->loadTrueTypeFont(idA, |
335 | | #if LOAD_FONTS_FROM_MEM |
336 | | fontBuf, |
337 | | #else |
338 | 1.57k | fileName, deleteFile, |
339 | 1.57k | #endif |
340 | 1.57k | fontNum, codeToGID, codeToGIDLen); |
341 | 1.57k | } |
342 | 1.57k | #endif |
343 | | |
344 | 1.57k | if (!fontFile) { |
345 | 115 | gfree(codeToGID); |
346 | 115 | } |
347 | | |
348 | 1.57k | #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 | 1.57k | if (deleteFile) { |
354 | 1.57k | unlink(fontFile ? fontFile->fileName->getCString() : fileName); |
355 | 1.57k | } |
356 | 1.57k | #endif |
357 | | |
358 | 1.57k | if (!fontFile) { |
359 | 115 | badFontFiles->append(idA); |
360 | 115 | } |
361 | | |
362 | 1.57k | return fontFile; |
363 | 1.57k | } |
364 | | |
365 | | SplashFont *SplashFontEngine::getFont(SplashFontFile *fontFile, |
366 | | SplashCoord *textMat, |
367 | 15.1k | SplashCoord *ctm) { |
368 | 15.1k | SplashCoord mat[4]; |
369 | 15.1k | SplashFont *font; |
370 | 15.1k | int i, j; |
371 | | |
372 | 15.1k | mat[0] = textMat[0] * ctm[0] + textMat[1] * ctm[2]; |
373 | 15.1k | mat[1] = -(textMat[0] * ctm[1] + textMat[1] * ctm[3]); |
374 | 15.1k | mat[2] = textMat[2] * ctm[0] + textMat[3] * ctm[2]; |
375 | 15.1k | mat[3] = -(textMat[2] * ctm[1] + textMat[3] * ctm[3]); |
376 | 15.1k | if (!splashCheckDet(mat[0], mat[1], mat[2], mat[3], 0.01)) { |
377 | | // avoid a singular (or close-to-singular) matrix |
378 | 15.1k | mat[0] = 0.01; mat[1] = 0; |
379 | 15.1k | mat[2] = 0; mat[3] = 0.01; |
380 | 15.1k | } |
381 | | |
382 | 15.1k | font = fontCache[0]; |
383 | 15.1k | if (font && font->matches(fontFile, mat, textMat)) { |
384 | 12.5k | return font; |
385 | 12.5k | } |
386 | 41.2k | for (i = 1; i < splashFontCacheSize; ++i) { |
387 | 38.6k | font = fontCache[i]; |
388 | 38.6k | if (font && font->matches(fontFile, mat, textMat)) { |
389 | 154 | for (j = i; j > 0; --j) { |
390 | 81 | fontCache[j] = fontCache[j-1]; |
391 | 81 | } |
392 | 73 | fontCache[0] = font; |
393 | 73 | return font; |
394 | 73 | } |
395 | 38.6k | } |
396 | 2.57k | font = fontFile->makeFont(mat, textMat); |
397 | 2.57k | if (fontCache[splashFontCacheSize - 1]) { |
398 | 0 | delete fontCache[splashFontCacheSize - 1]; |
399 | 0 | } |
400 | 41.1k | for (j = splashFontCacheSize - 1; j > 0; --j) { |
401 | 38.6k | fontCache[j] = fontCache[j-1]; |
402 | 38.6k | } |
403 | 2.57k | fontCache[0] = font; |
404 | 2.57k | return font; |
405 | 2.64k | } |