1 /* Written by Krzysztof Kowalczyk (http://blog.kowalczyk.info)
2 but mostly based on xpdf code.
3
4 // Copyright (C) 2010, 2012 Hib Eris <hib@hiberis.nl>
5 // Copyright (C) 2012, 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
6 // Copyright (C) 2012 Suzuki Toshiya <mpsuzuki@hiroshima-u.ac.jp>
7 // Copyright (C) 2012, 2017 Adrian Johnson <ajohnson@redneon.com>
8 // Copyright (C) 2012 Mark Brand <mabrand@mabrand.nl>
9 // Copyright (C) 2013, 2018, 2019 Adam Reichold <adamreichold@myopera.com>
10 // Copyright (C) 2013 Dmytro Morgun <lztoad@gmail.com>
11 // Copyright (C) 2017 Christoph Cullmann <cullmann@kde.org>
12 // Copyright (C) 2017, 2018, 2020, 2021 Albert Astals Cid <aacid@kde.org>
13 // Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, <info@kdab.com>. Work sponsored by the LiMux project of the city of Munich
14 // Copyright (C) 2019 Christian Persch <chpe@src.gnome.org>
15 // Copyright (C) 2019 Oliver Sander <oliver.sander@tu-dresden.de>
16
17 TODO: instead of a fixed mapping defined in displayFontTab, it could
18 scan the whole fonts directory, parse TTF files and build font
19 description for all fonts available in Windows. That's how MuPDF works.
20 */
21
22 #ifndef PACKAGE_NAME
23 # include <config.h>
24 #endif
25
26 #include <windows.h>
27 #if !(_WIN32_IE >= 0x0500)
28 # error "_WIN32_IE must be defined >= 0x0500 for SHGFP_TYPE_CURRENT from shlobj.h"
29 #endif
30 #include <shlobj.h>
31 #include <cstring>
32 #include <cstdio>
33 #include <cctype>
34 #include <cassert>
35
36 #include "goo/gmem.h"
37 #include "goo/GooString.h"
38 #include "goo/gfile.h"
39 #include "Error.h"
40 #include "NameToCharCode.h"
41 #include "CharCodeToUnicode.h"
42 #include "UnicodeMap.h"
43 #include "CMap.h"
44 #include "FontEncodingTables.h"
45 #include "GlobalParams.h"
46 #include "GfxFont.h"
47 #include <sys/stat.h>
48 #include "Object.h"
49 #include "Stream.h"
50 #include "Lexer.h"
51 #include "Parser.h"
52
53 #define DEFAULT_SUBSTITUTE_FONT "Helvetica"
54 #define DEFAULT_CID_FONT_AC1_MSWIN "MingLiU" /* Adobe-CNS1 for Taiwan, HongKong */
55 #define DEFAULT_CID_FONT_AG1_MSWIN "SimSun" /* Adobe-GB1 for PRC, Singapore */
56 #define DEFAULT_CID_FONT_AJ1_MSWIN "MS-Mincho" /* Adobe-Japan1 */
57 #define DEFAULT_CID_FONT_AJ2_MSWIN "MS-Mincho" /* Adobe-Japan2 (legacy) */
58 #define DEFAULT_CID_FONT_AK1_MSWIN "Batang" /* Adobe-Korea1 */
59 #define DEFAULT_CID_FONT_MSWIN "ArialUnicode" /* Unknown */
60
61 static const struct
62 {
63 const char *name;
64 const char *t1FileName;
65 const char *ttFileName;
66 bool warnIfMissing;
67 } displayFontTab[] = { { "Courier", "n022003l.pfb", "cour.ttf", true },
68 { "Courier-Bold", "n022004l.pfb", "courbd.ttf", true },
69 { "Courier-BoldOblique", "n022024l.pfb", "courbi.ttf", true },
70 { "Courier-Oblique", "n022023l.pfb", "couri.ttf", true },
71 { "Helvetica", "n019003l.pfb", "arial.ttf", true },
72 { "Helvetica-Bold", "n019004l.pfb", "arialbd.ttf", true },
73 { "Helvetica-BoldOblique", "n019024l.pfb", "arialbi.ttf", true },
74 { "Helvetica-Oblique", "n019023l.pfb", "ariali.ttf", true },
75 // TODO: not sure if "symbol.ttf" is right
76 { "Symbol", "s050000l.pfb", "symbol.ttf", true },
77 { "Times-Bold", "n021004l.pfb", "timesbd.ttf", true },
78 { "Times-BoldItalic", "n021024l.pfb", "timesbi.ttf", true },
79 { "Times-Italic", "n021023l.pfb", "timesi.ttf", true },
80 { "Times-Roman", "n021003l.pfb", "times.ttf", true },
81 // TODO: not sure if "wingding.ttf" is right
82 { "ZapfDingbats", "d050000l.pfb", "wingding.ttf", true },
83
84 // those seem to be frequently accessed by PDF files and I kind of guess
85 // which font file do the refer to
86 { "Palatino", nullptr, "pala.ttf", true },
87 { "Palatino-Roman", nullptr, "pala.ttf", true },
88 { "Palatino-Bold", nullptr, "palab.ttf", true },
89 { "Palatino-Italic", nullptr, "palai.ttf", true },
90 { "Palatino,Italic", nullptr, "palai.ttf", true },
91 { "Palatino-BoldItalic", nullptr, "palabi.ttf", true },
92
93 { "ArialBlack", nullptr, "arialbd.ttf", true },
94
95 { "ArialNarrow", nullptr, "arialn.ttf", true },
96 { "ArialNarrow,Bold", nullptr, "arialnb.ttf", true },
97 { "ArialNarrow,Italic", nullptr, "arialni.ttf", true },
98 { "ArialNarrow,BoldItalic", nullptr, "arialnbi.ttf", true },
99 { "ArialNarrow-Bold", nullptr, "arialnb.ttf", true },
100 { "ArialNarrow-Italic", nullptr, "arialni.ttf", true },
101 { "ArialNarrow-BoldItalic", nullptr, "arialnbi.ttf", true },
102
103 { "HelveticaNarrow", nullptr, "arialn.ttf", true },
104 { "HelveticaNarrow,Bold", nullptr, "arialnb.ttf", true },
105 { "HelveticaNarrow,Italic", nullptr, "arialni.ttf", true },
106 { "HelveticaNarrow,BoldItalic", nullptr, "arialnbi.ttf", true },
107 { "HelveticaNarrow-Bold", nullptr, "arialnb.ttf", true },
108 { "HelveticaNarrow-Italic", nullptr, "arialni.ttf", true },
109 { "HelveticaNarrow-BoldItalic", nullptr, "arialnbi.ttf", true },
110
111 { "BookAntiqua", nullptr, "bkant.ttf", true },
112 { "BookAntiqua,Bold", nullptr, "bkant.ttf", true },
113 { "BookAntiqua,Italic", nullptr, "bkant.ttf", true },
114 { "BookAntiqua,BoldItalic", nullptr, "bkant.ttf", true },
115 { "BookAntiqua-Bold", nullptr, "bkant.ttf", true },
116 { "BookAntiqua-Italic", nullptr, "bkant.ttf", true },
117 { "BookAntiqua-BoldItalic", nullptr, "bkant.ttf", true },
118
119 { "Verdana", nullptr, "verdana.ttf", true },
120 { "Verdana,Bold", nullptr, "verdanab.ttf", true },
121 { "Verdana,Italic", nullptr, "verdanai.ttf", true },
122 { "Verdana,BoldItalic", nullptr, "verdanaz.ttf", true },
123 { "Verdana-Bold", nullptr, "verdanab.ttf", true },
124 { "Verdana-Italic", nullptr, "verdanai.ttf", true },
125 { "Verdana-BoldItalic", nullptr, "verdanaz.ttf", true },
126
127 { "Tahoma", nullptr, "tahoma.ttf", true },
128 { "Tahoma,Bold", nullptr, "tahomabd.ttf", true },
129 { "Tahoma,Italic", nullptr, "tahoma.ttf", true },
130 { "Tahoma,BoldItalic", nullptr, "tahomabd.ttf", true },
131 { "Tahoma-Bold", nullptr, "tahomabd.ttf", true },
132 { "Tahoma-Italic", nullptr, "tahoma.ttf", true },
133 { "Tahoma-BoldItalic", nullptr, "tahomabd.ttf", true },
134
135 { "CCRIKH+Verdana", nullptr, "verdana.ttf", true },
136 { "CCRIKH+Verdana,Bold", nullptr, "verdanab.ttf", true },
137 { "CCRIKH+Verdana,Italic", nullptr, "verdanai.ttf", true },
138 { "CCRIKH+Verdana,BoldItalic", nullptr, "verdanaz.ttf", true },
139 { "CCRIKH+Verdana-Bold", nullptr, "verdanab.ttf", true },
140 { "CCRIKH+Verdana-Italic", nullptr, "verdanai.ttf", true },
141 { "CCRIKH+Verdana-BoldItalic", nullptr, "verdanaz.ttf", true },
142
143 { "Georgia", nullptr, "georgia.ttf", true },
144 { "Georgia,Bold", nullptr, "georgiab.ttf", true },
145 { "Georgia,Italic", nullptr, "georgiai.ttf", true },
146 { "Georgia,BoldItalic", nullptr, "georgiaz.ttf", true },
147 { "Georgia-Bold", nullptr, "georgiab.ttf", true },
148 { "Georgia-Italic", nullptr, "georgiai.ttf", true },
149 { "Georgia-BoldItalic", nullptr, "georgiaz.ttf", true },
150
151 // fallback for Adobe CID fonts:
152 { "MingLiU", nullptr, "mingliu.ttf", false },
153 { "SimSun", nullptr, "simsun.ttf", false },
154 { "MS-Mincho", nullptr, "msmincho.ttf", false },
155 { "Batang", nullptr, "batang.ttf", false },
156 { "ArialUnicode", nullptr, "arialuni.ttf", true },
157 {} };
158
159 #define FONTS_SUBDIR "\\fonts"
160
GetWindowsFontDir(char * winFontDir,int cbWinFontDirLen)161 static void GetWindowsFontDir(char *winFontDir, int cbWinFontDirLen)
162 {
163 BOOL(__stdcall * SHGetSpecialFolderPathFunc)(HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate);
164 HRESULT(__stdcall * SHGetFolderPathFunc)(HWND hwndOwner, int nFolder, HANDLE hToken, DWORD dwFlags, LPSTR pszPath);
165
166 // SHGetSpecialFolderPath isn't available in older versions of shell32.dll (Win95 and
167 // WinNT4), so do a dynamic load of ANSI versions.
168 winFontDir[0] = '\0';
169
170 HMODULE hLib = LoadLibraryA("shell32.dll");
171 if (hLib) {
172 SHGetFolderPathFunc = (HRESULT(__stdcall *)(HWND, int, HANDLE, DWORD, LPSTR))GetProcAddress(hLib, "SHGetFolderPathA");
173 if (SHGetFolderPathFunc)
174 (*SHGetFolderPathFunc)(nullptr, CSIDL_FONTS, nullptr, SHGFP_TYPE_CURRENT, winFontDir);
175
176 if (!winFontDir[0]) {
177 // Try an older function
178 SHGetSpecialFolderPathFunc = (BOOL(__stdcall *)(HWND, LPSTR, int, BOOL))GetProcAddress(hLib, "SHGetSpecialFolderPathA");
179 if (SHGetSpecialFolderPathFunc)
180 (*SHGetSpecialFolderPathFunc)(nullptr, winFontDir, CSIDL_FONTS, FALSE);
181 }
182 FreeLibrary(hLib);
183 }
184 if (winFontDir[0])
185 return;
186
187 // Try older DLL
188 hLib = LoadLibraryA("SHFolder.dll");
189 if (hLib) {
190 SHGetFolderPathFunc = (HRESULT(__stdcall *)(HWND, int, HANDLE, DWORD, LPSTR))GetProcAddress(hLib, "SHGetFolderPathA");
191 if (SHGetFolderPathFunc)
192 (*SHGetFolderPathFunc)(nullptr, CSIDL_FONTS, nullptr, SHGFP_TYPE_CURRENT, winFontDir);
193 FreeLibrary(hLib);
194 }
195 if (winFontDir[0])
196 return;
197
198 // Everything else failed so the standard fonts directory.
199 GetWindowsDirectoryA(winFontDir, cbWinFontDirLen);
200 if (winFontDir[0]) {
201 strncat(winFontDir, FONTS_SUBDIR, cbWinFontDirLen);
202 winFontDir[cbWinFontDirLen - 1] = 0;
203 }
204 }
205
FileExists(const char * path)206 static bool FileExists(const char *path)
207 {
208 FILE *f = openFile(path, "rb");
209 if (f) {
210 fclose(f);
211 return true;
212 }
213 return false;
214 }
215
scanWindowsFonts(GooString * winFontDir)216 void SysFontList::scanWindowsFonts(GooString *winFontDir)
217 {
218 OSVERSIONINFO version;
219 const char *path;
220 DWORD idx, valNameLen, dataLen, type;
221 HKEY regKey;
222 char valName[1024], data[1024];
223 int n, fontNum;
224 char *p0, *p1;
225 GooString *fontPath;
226
227 version.dwOSVersionInfoSize = sizeof(version);
228 GetVersionEx(&version);
229 if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) {
230 path = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts\\";
231 } else {
232 path = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Fonts\\";
233 }
234 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, path, 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, ®Key) == ERROR_SUCCESS) {
235 idx = 0;
236 while (1) {
237 valNameLen = sizeof(valName) - 1;
238 dataLen = sizeof(data) - 1;
239 if (RegEnumValueA(regKey, idx, valName, &valNameLen, nullptr, &type, (LPBYTE)data, &dataLen) != ERROR_SUCCESS) {
240 break;
241 }
242 if (type == REG_SZ && valNameLen > 0 && valNameLen < sizeof(valName) && dataLen > 0 && dataLen < sizeof(data)) {
243 valName[valNameLen] = '\0';
244 data[dataLen] = '\0';
245 n = strlen(data);
246 if (!strcasecmp(data + n - 4, ".ttf") || !strcasecmp(data + n - 4, ".ttc") || !strcasecmp(data + n - 4, ".otf")) {
247 fontPath = new GooString(data);
248 if (!(dataLen >= 3 && data[1] == ':' && data[2] == '\\')) {
249 fontPath->insert(0, '\\');
250 fontPath->insert(0, winFontDir);
251 fontPath->append('\0');
252 }
253 p0 = valName;
254 fontNum = 0;
255 while (*p0) {
256 p1 = strstr(p0, " & ");
257 if (p1) {
258 *p1 = '\0';
259 p1 = p1 + 3;
260 } else {
261 p1 = p0 + strlen(p0);
262 }
263 fonts.push_back(makeWindowsFont(p0, fontNum, fontPath->c_str()));
264 p0 = p1;
265 ++fontNum;
266 }
267 delete fontPath;
268 }
269 }
270 ++idx;
271 }
272 RegCloseKey(regKey);
273 }
274 }
275
makeWindowsFont(const char * name,int fontNum,const char * path)276 SysFontInfo *SysFontList::makeWindowsFont(const char *name, int fontNum, const char *path)
277 {
278 int n;
279 bool bold, italic, oblique, fixedWidth;
280 GooString *s;
281 char c;
282 int i;
283 SysFontType type;
284 GooString substituteName;
285
286 n = strlen(name);
287 bold = italic = oblique = fixedWidth = false;
288
289 // remove trailing ' (TrueType)'
290 if (n > 11 && !strncmp(name + n - 11, " (TrueType)", 11)) {
291 n -= 11;
292 }
293
294 // remove trailing ' (OpenType)'
295 if (n > 11 && !strncmp(name + n - 11, " (OpenType)", 11)) {
296 n -= 11;
297 }
298
299 // remove trailing ' Italic'
300 if (n > 7 && !strncmp(name + n - 7, " Italic", 7)) {
301 n -= 7;
302 italic = true;
303 }
304
305 // remove trailing ' Oblique'
306 if (n > 7 && !strncmp(name + n - 8, " Oblique", 8)) {
307 n -= 8;
308 oblique = true;
309 }
310
311 // remove trailing ' Bold'
312 if (n > 5 && !strncmp(name + n - 5, " Bold", 5)) {
313 n -= 5;
314 bold = true;
315 }
316
317 // remove trailing ' Regular'
318 if (n > 5 && !strncmp(name + n - 8, " Regular", 8)) {
319 n -= 8;
320 }
321
322 // the familyname cannot indicate whether a font is fixedWidth or not.
323 // some well-known fixedWidth typeface family names or keyword are checked.
324 if (strstr(name, "Courier") || strstr(name, "Fixed") || (strstr(name, "Mono") && !strstr(name, "Monotype")) || strstr(name, "Typewriter"))
325 fixedWidth = true;
326 else
327 fixedWidth = false;
328
329 //----- normalize the font name
330 s = new GooString(name, n);
331 i = 0;
332 while (i < s->getLength()) {
333 c = s->getChar(i);
334 if (c == ' ' || c == ',' || c == '-') {
335 s->del(i);
336 } else {
337 ++i;
338 }
339 }
340
341 if (!strcasecmp(path + strlen(path) - 4, ".ttc")) {
342 type = sysFontTTC;
343 } else {
344 type = sysFontTTF;
345 }
346
347 return new SysFontInfo(s, bold, italic, oblique, fixedWidth, new GooString(path), type, fontNum, substituteName.copy());
348 }
349
replaceSuffix(GooString * path,const char * suffixA,const char * suffixB)350 static GooString *replaceSuffix(GooString *path, const char *suffixA, const char *suffixB)
351 {
352 int suffLenA = strlen(suffixA);
353 int suffLenB = strlen(suffixB);
354 int baseLenA = path->getLength() - suffLenA;
355 int baseLenB = path->getLength() - suffLenB;
356
357 if (!strcasecmp(path->c_str() + baseLenA, suffixA)) {
358 path->del(baseLenA, suffLenA)->append(suffixB);
359 } else if (!strcasecmp(path->c_str() + baseLenB, suffixB)) {
360 path->del(baseLenB, suffLenB)->append(suffixA);
361 }
362
363 return path;
364 }
365
setupBaseFonts(const char * dir)366 void GlobalParams::setupBaseFonts(const char *dir)
367 {
368 const char *dataRoot = popplerDataDir ? popplerDataDir : POPPLER_DATADIR;
369 GooString *fileName = nullptr;
370 GooFile *file;
371
372 if (baseFontsInitialized)
373 return;
374 baseFontsInitialized = true;
375
376 char winFontDir[MAX_PATH];
377 GetWindowsFontDir(winFontDir, sizeof(winFontDir));
378
379 for (int i = 0; displayFontTab[i].name; ++i) {
380 if (fontFiles.count(displayFontTab[i].name) > 0)
381 continue;
382
383 GooString *fontName = new GooString(displayFontTab[i].name);
384
385 if (dir) {
386 GooString *fontPath = appendToPath(new GooString(dir), displayFontTab[i].t1FileName);
387 if (FileExists(fontPath->c_str()) || FileExists(replaceSuffix(fontPath, ".pfb", ".pfa")->c_str())) {
388 addFontFile(fontName, fontPath);
389 continue;
390 }
391 delete fontPath;
392 }
393
394 if (winFontDir[0] && displayFontTab[i].ttFileName) {
395 GooString *fontPath = appendToPath(new GooString(winFontDir), displayFontTab[i].ttFileName);
396 if (FileExists(fontPath->c_str()) || FileExists(replaceSuffix(fontPath, ".ttc", ".ttf")->c_str())) {
397 addFontFile(fontName, fontPath);
398 continue;
399 }
400 delete fontPath;
401 }
402
403 if (displayFontTab[i].warnIfMissing) {
404 error(errSyntaxError, -1, "No display font for '{0:s}'", displayFontTab[i].name);
405 delete fontName;
406 }
407 }
408 if (winFontDir[0]) {
409 GooString gooWinFontsDir(winFontDir);
410 sysFonts->scanWindowsFonts(&gooWinFontsDir);
411 }
412
413 fileName = new GooString(dataRoot);
414 fileName->append("/cidfmap");
415
416 // try to open file
417 file = GooFile::open(fileName->toStr());
418
419 if (file != nullptr) {
420 Parser *parser;
421 parser = new Parser(nullptr, new FileStream(file, 0, false, file->size(), Object(objNull)), true);
422 Object obj1 = parser->getObj();
423 while (!obj1.isEOF()) {
424 Object obj2 = parser->getObj();
425 if (obj1.isName()) {
426 // Substitutions
427 if (obj2.isDict()) {
428 Object obj3 = obj2.getDict()->lookup("Path");
429 if (obj3.isString())
430 addFontFile(new GooString(obj1.getName()), obj3.getString()->copy());
431 // Aliases
432 } else if (obj2.isName()) {
433 substFiles.emplace(obj1.getName(), obj2.getName());
434 }
435 }
436 obj1 = parser->getObj();
437 // skip trailing ';'
438 while (obj1.isCmd(";")) {
439 obj1 = parser->getObj();
440 }
441 }
442 delete file;
443 delete parser;
444 } else {
445 delete fileName;
446 }
447 }
448
findSubstituteName(const GfxFont * font,const std::unordered_map<std::string,std::string> & fontFiles,const std::unordered_map<std::string,std::string> & substFiles,const char * origName)449 static const char *findSubstituteName(const GfxFont *font, const std::unordered_map<std::string, std::string> &fontFiles, const std::unordered_map<std::string, std::string> &substFiles, const char *origName)
450 {
451 assert(origName);
452 if (!origName)
453 return nullptr;
454 GooString *name2 = new GooString(origName);
455 int n = strlen(origName);
456 // remove trailing "-Identity-H"
457 if (n > 11 && !strcmp(name2->c_str() + n - 11, "-Identity-H")) {
458 name2->del(n - 11, 11);
459 n -= 11;
460 }
461 // remove trailing "-Identity-V"
462 if (n > 11 && !strcmp(name2->c_str() + n - 11, "-Identity-V")) {
463 name2->del(n - 11, 11);
464 n -= 11;
465 }
466 const auto substFile = substFiles.find(name2->c_str());
467 if (substFile != substFiles.end()) {
468 delete name2;
469 return substFile->second.c_str();
470 }
471
472 /* TODO: try to at least guess bold/italic/bolditalic from the name */
473 delete name2;
474 if (font->isCIDFont()) {
475 const GooString *collection = ((GfxCIDFont *)font)->getCollection();
476
477 const char *name3 = nullptr;
478 if (!collection->cmp("Adobe-CNS1"))
479 name3 = DEFAULT_CID_FONT_AC1_MSWIN;
480 else if (!collection->cmp("Adobe-GB1"))
481 name3 = DEFAULT_CID_FONT_AG1_MSWIN;
482 else if (!collection->cmp("Adobe-Japan1"))
483 name3 = DEFAULT_CID_FONT_AJ1_MSWIN;
484 else if (!collection->cmp("Adobe-Japan2"))
485 name3 = DEFAULT_CID_FONT_AJ2_MSWIN;
486 else if (!collection->cmp("Adobe-Korea1"))
487 name3 = DEFAULT_CID_FONT_AK1_MSWIN;
488
489 if (name3 && fontFiles.count(name3) != 0)
490 return name3;
491
492 if (fontFiles.count(DEFAULT_CID_FONT_MSWIN) != 0)
493 return DEFAULT_CID_FONT_MSWIN;
494 }
495 return DEFAULT_SUBSTITUTE_FONT;
496 }
497
498 /* Windows implementation of external font matching code */
findSystemFontFile(const GfxFont * font,SysFontType * type,int * fontNum,GooString * substituteFontName,const GooString * base14Name)499 GooString *GlobalParams::findSystemFontFile(const GfxFont *font, SysFontType *type, int *fontNum, GooString *substituteFontName, const GooString *base14Name)
500 {
501 const SysFontInfo *fi;
502 GooString *path = nullptr;
503 const GooString *fontName = font->getName();
504 if (!fontName)
505 return nullptr;
506 std::unique_lock<std::recursive_mutex> locker(mutex);
507 setupBaseFonts(nullptr);
508
509 // TODO: base14Name should be changed?
510 // In the system using FontConfig, findSystemFontFile() uses
511 // base14Name only for the creation of query pattern.
512
513 if ((fi = sysFonts->find(fontName, false, false))) {
514 path = fi->path->copy();
515 *type = fi->type;
516 *fontNum = fi->fontNum;
517 if (substituteFontName)
518 substituteFontName->Set(fi->substituteName->c_str());
519 } else {
520 GooString *substFontName = new GooString(findSubstituteName(font, fontFiles, substFiles, fontName->c_str()));
521 error(errSyntaxError, -1, "Couldn't find a font for '{0:t}', subst is '{1:t}'", fontName, substFontName);
522 const auto fontFile = fontFiles.find(substFontName->toStr());
523 if (fontFile != fontFiles.end()) {
524 path = new GooString(fontFile->second.c_str());
525 if (substituteFontName)
526 substituteFontName->Set(path->c_str());
527 if (!strcasecmp(path->c_str() + path->getLength() - 4, ".ttc")) {
528 *type = sysFontTTC;
529 } else {
530 *type = sysFontTTF;
531 }
532 *fontNum = 0;
533 }
534 }
535
536 return path;
537 }
538