1//========================================================================
2//
3// GlobalParams.cc
4//
5// Copyright 2001-2003 Glyph & Cog, LLC
6//
7//========================================================================
8
9//========================================================================
10//
11// Modified under the Poppler project - http://poppler.freedesktop.org
12//
13// All changes made under the Poppler project to this file are licensed
14// under GPL version 2 or later
15//
16// Copyright (C) 2005 Martin Kretzschmar <martink@gnome.org>
17// Copyright (C) 2005, 2006 Kristian Høgsberg <krh@redhat.com>
18// Copyright (C) 2005, 2007-2010, 2012, 2015, 2017-2023 Albert Astals Cid <aacid@kde.org>
19// Copyright (C) 2005 Jonathan Blandford <jrb@redhat.com>
20// Copyright (C) 2006, 2007 Jeff Muizelaar <jeff@infidigm.net>
21// Copyright (C) 2006 Takashi Iwai <tiwai@suse.de>
22// Copyright (C) 2006 Ed Catmur <ed@catmur.co.uk>
23// Copyright (C) 2007 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
24// Copyright (C) 2007, 2009 Jonathan Kew <jonathan_kew@sil.org>
25// Copyright (C) 2009 Petr Gajdos <pgajdos@novell.com>
26// Copyright (C) 2009, 2011, 2012, 2015 William Bader <williambader@hotmail.com>
27// Copyright (C) 2009 Kovid Goyal <kovid@kovidgoyal.net>
28// Copyright (C) 2010, 2012 Hib Eris <hib@hiberis.nl>
29// Copyright (C) 2010 Patrick Spendrin <ps_ml@gmx.de>
30// Copyright (C) 2010 Jakub Wilk <jwilk@jwilk.net>
31// Copyright (C) 2011 Pino Toscano <pino@kde.org>
32// Copyright (C) 2011 Koji Otani <sho@bbr.jp>
33// Copyright (C) 2012 Yi Yang <ahyangyi@gmail.com>
34// Copyright (C) 2012, 2017 Adrian Johnson <ajohnson@redneon.com>
35// Copyright (C) 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
36// Copyright (C) 2012 Peter Breitenlohner <peb@mppmu.mpg.de>
37// Copyright (C) 2013, 2014 Jason Crain <jason@aquaticape.us>
38// Copyright (C) 2017 Christoph Cullmann <cullmann@kde.org>
39// Copyright (C) 2017 Jean Ghali <jghali@libertysurf.fr>
40// 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
41// Copyright (C) 2018, 2020 Adam Reichold <adam.reichold@t-online.de>
42// Copyright (C) 2019 Christian Persch <chpe@src.gnome.org>
43// Copyright (C) 2019, 2024 Oliver Sander <oliver.sander@tu-dresden.de>
44// Copyright (C) 2020 Kai Pastor <dg0yt@darc.de>
45// Copyright (C) 2021, 2022 Stefan Löffler <st.loeffler@gmail.com>
46// Copyright (C) 2021 sunderme <sunderme@gmx.de>
47// Copyright (C) 2022 Even Rouault <even.rouault@spatialys.com>
48// Copyright (C) 2022 Claes Nästén <pekdon@gmail.com>
49// Copyright (C) 2023 g10 Code GmbH, Author: Sune Stolborg Vuorela <sune@vuorela.dk>
50// Copyright (C) 2023 Shivodit Gill <shivodit.gill@gmail.com>
51// Copyright (C) 2024 Keyu Tao <me@taoky.moe>
52//
53// To see a description of the changes please see the Changelog file that
54// came with your tarball or type make ChangeLog if you are building from git
55//
56//========================================================================
57
58#include <config.h>
59
60#include <algorithm>
61#include <cstring>
62#include <cstdio>
63#include <cctype>
64#ifdef _WIN32
65# include <shlobj.h>
66# include <mbstring.h>
67#endif
68#ifdef ANDROID
69# include <android/font.h>
70# include <android/font_matcher.h>
71# include <android/system_fonts.h>
72#endif
73#include "goo/glibc.h"
74#include "goo/gmem.h"
75#include "goo/GooString.h"
76#include "goo/gfile.h"
77#include "goo/gdir.h"
78#include "Error.h"
79#include "NameToCharCode.h"
80#include "CharCodeToUnicode.h"
81#include "UnicodeMap.h"
82#include "CMap.h"
83#include "FontEncodingTables.h"
84#include "GlobalParams.h"
85#include "GfxFont.h"
86
87#ifdef WITH_FONTCONFIGURATION_FONTCONFIG
88# include <fontconfig/fontconfig.h>
89#endif
90
91#ifndef _MSC_VER
92# include <strings.h>
93#endif
94
95#ifndef FC_WEIGHT_BOOK
96# define FC_WEIGHT_BOOK 75
97#endif
98
99#include "NameToUnicodeTable.h"
100#include "UnicodeMapTables.h"
101#include "UnicodeMapFuncs.h"
102
103#include "fofi/FoFiTrueType.h"
104#include "fofi/FoFiIdentifier.h"
105
106//------------------------------------------------------------------------
107
108#define cidToUnicodeCacheSize 4
109#define unicodeToUnicodeCacheSize 4
110
111//------------------------------------------------------------------------
112
113std::unique_ptr<GlobalParams> globalParams;
114
115#if defined(ENABLE_RELOCATABLE) && defined(_WIN32)
116
117/* search for data relative to where we are installed */
118
119static HMODULE hmodule;
120
121extern "C" {
122/* Provide declaration to squelch -Wmissing-declarations warning */
123BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved);
124
125BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
126{
127 switch (fdwReason) {
128 case DLL_PROCESS_ATTACH:
129 hmodule = hinstDLL;
130 break;
131 }
132
133 return TRUE;
134}
135}
136
137static std::string get_poppler_localdir(const std::string &suffix)
138{
139 const std::string binSuffix("\\bin");
140 std::string retval(MAX_PATH, '\0');
141
142 if (!GetModuleFileNameA(hmodule, retval.data(), retval.size())) {
143 return POPPLER_DATADIR;
144 }
145
146 const std::string::size_type p = retval.rfind('\\');
147 if (p != std::string::npos) {
148 retval.erase(p);
149 if (retval.size() > binSuffix.size() && stricmp(retval.substr(p - binSuffix.size()).c_str(), binSuffix.c_str()) == 0) {
150 retval.erase(p - binSuffix.size());
151 }
152 }
153 retval += suffix;
154 retval.shrink_to_fit();
155 return retval;
156}
157
158static const char *get_poppler_datadir(void)
159{
160 static std::string retval;
161 static bool beenhere = false;
162
163 if (!beenhere) {
164 retval = get_poppler_localdir("\\share\\poppler");
165 beenhere = true;
166 }
167
168 return retval.c_str();
169}
170
171# undef POPPLER_DATADIR
172# define POPPLER_DATADIR get_poppler_datadir()
173
174static const char *get_poppler_fontsdir(void)
175{
176 static std::string retval;
177 static bool beenhere = false;
178
179 if (!beenhere) {
180 retval = get_poppler_localdir("\\share\\fonts");
181 beenhere = true;
182 }
183
184 return retval.c_str();
185}
186# undef POPPLER_FONTSDIR
187# define POPPLER_FONTSDIR get_poppler_fontsdir()
188
189#else
190# define POPPLER_FONTSDIR nullptr
191#endif
192
193//------------------------------------------------------------------------
194// SysFontInfo
195//------------------------------------------------------------------------
196
197class SysFontInfo
198{
199public:
200 GooString *name;
201 bool bold;
202 bool italic;
203 bool oblique;
204 bool fixedWidth;
205 GooString *path;
206 SysFontType type;
207 int fontNum; // for TrueType collections
208 GooString *substituteName;
209
210 SysFontInfo(GooString *nameA, bool boldA, bool italicA, bool obliqueA, bool fixedWidthA, GooString *pathA, SysFontType typeA, int fontNumA, GooString *substituteNameA);
211 ~SysFontInfo();
212 SysFontInfo(const SysFontInfo &) = delete;
213 SysFontInfo &operator=(const SysFontInfo &) = delete;
214 bool match(const SysFontInfo *fi) const;
215 bool match(const GooString *nameA, bool boldA, bool italicA, bool obliqueA, bool fixedWidthA) const;
216 bool match(const GooString *nameA, bool boldA, bool italicA) const;
217};
218
219SysFontInfo::SysFontInfo(GooString *nameA, bool boldA, bool italicA, bool obliqueA, bool fixedWidthA, GooString *pathA, SysFontType typeA, int fontNumA, GooString *substituteNameA)
220{
221 name = nameA;
222 bold = boldA;
223 italic = italicA;
224 oblique = obliqueA;
225 fixedWidth = fixedWidthA;
226 path = pathA;
227 type = typeA;
228 fontNum = fontNumA;
229 substituteName = substituteNameA;
230}
231
232SysFontInfo::~SysFontInfo()
233{
234 delete name;
235 delete path;
236 delete substituteName;
237}
238
239bool SysFontInfo::match(const SysFontInfo *fi) const
240{
241 return !strcasecmp(s1: name->c_str(), s2: fi->name->c_str()) && bold == fi->bold && italic == fi->italic && oblique == fi->oblique && fixedWidth == fi->fixedWidth;
242}
243
244bool SysFontInfo::match(const GooString *nameA, bool boldA, bool italicA, bool obliqueA, bool fixedWidthA) const
245{
246 return !strcasecmp(s1: name->c_str(), s2: nameA->c_str()) && bold == boldA && italic == italicA && oblique == obliqueA && fixedWidth == fixedWidthA;
247}
248
249bool SysFontInfo::match(const GooString *nameA, bool boldA, bool italicA) const
250{
251 return !strcasecmp(s1: name->c_str(), s2: nameA->c_str()) && bold == boldA && italic == italicA;
252}
253
254//------------------------------------------------------------------------
255// SysFontList
256//------------------------------------------------------------------------
257
258class SysFontList
259{
260public:
261 SysFontList();
262 ~SysFontList();
263 SysFontList(const SysFontList &) = delete;
264 SysFontList &operator=(const SysFontList &) = delete;
265 const SysFontInfo *find(const std::string &name, bool isFixedWidth, bool exact, const std::vector<std::string> &filesToIgnore = {});
266
267 const std::vector<SysFontInfo *> &getFonts() const { return fonts; }
268
269#ifdef _WIN32
270 void scanWindowsFonts(const std::string &winFontDir);
271#endif
272#ifdef WITH_FONTCONFIGURATION_FONTCONFIG
273 void addFcFont(SysFontInfo *si) { fonts.push_back(x: si); }
274#endif
275private:
276#ifdef _WIN32
277 SysFontInfo *makeWindowsFont(const char *name, int fontNum, const char *path);
278#endif
279
280 std::vector<SysFontInfo *> fonts;
281};
282
283SysFontList::SysFontList() { }
284
285SysFontList::~SysFontList()
286{
287 for (auto entry : fonts) {
288 delete entry;
289 }
290}
291
292const SysFontInfo *SysFontList::find(const std::string &name, bool fixedWidth, bool exact, const std::vector<std::string> &filesToIgnore)
293{
294 GooString *name2;
295 bool bold, italic, oblique;
296 int n;
297
298 name2 = new GooString(name);
299
300 // remove space, comma, dash chars
301 {
302 int i = 0;
303 while (i < name2->getLength()) {
304 const char c = name2->getChar(i);
305 if (c == ' ' || c == ',' || c == '-') {
306 name2->del(i);
307 } else {
308 ++i;
309 }
310 }
311 n = name2->getLength();
312 }
313
314 // remove trailing "MT" (Foo-MT, Foo-BoldMT, etc.)
315 if (n > 2 && !strcmp(s1: name2->c_str() + n - 2, s2: "MT")) {
316 name2->del(i: n - 2, n: 2);
317 n -= 2;
318 }
319
320 // look for "Regular"
321 if (n > 7 && !strcmp(s1: name2->c_str() + n - 7, s2: "Regular")) {
322 name2->del(i: n - 7, n: 7);
323 n -= 7;
324 }
325
326 // look for "Italic"
327 if (n > 6 && !strcmp(s1: name2->c_str() + n - 6, s2: "Italic")) {
328 name2->del(i: n - 6, n: 6);
329 italic = true;
330 n -= 6;
331 } else {
332 italic = false;
333 }
334
335 // look for "Oblique"
336 if (n > 6 && !strcmp(s1: name2->c_str() + n - 7, s2: "Oblique")) {
337 name2->del(i: n - 7, n: 7);
338 oblique = true;
339 n -= 6;
340 } else {
341 oblique = false;
342 }
343
344 // look for "Bold"
345 if (n > 4 && !strcmp(s1: name2->c_str() + n - 4, s2: "Bold")) {
346 name2->del(i: n - 4, n: 4);
347 bold = true;
348 n -= 4;
349 } else {
350 bold = false;
351 }
352
353 // remove trailing "MT" (FooMT-Bold, etc.)
354 if (n > 2 && !strcmp(s1: name2->c_str() + n - 2, s2: "MT")) {
355 name2->del(i: n - 2, n: 2);
356 n -= 2;
357 }
358
359 // remove trailing "PS"
360 if (n > 2 && !strcmp(s1: name2->c_str() + n - 2, s2: "PS")) {
361 name2->del(i: n - 2, n: 2);
362 n -= 2;
363 }
364
365 // remove trailing "IdentityH"
366 if (n > 9 && !strcmp(s1: name2->c_str() + n - 9, s2: "IdentityH")) {
367 name2->del(i: n - 9, n: 9);
368 n -= 9;
369 }
370
371 // search for the font
372 const SysFontInfo *fi = nullptr;
373 for (const SysFontInfo *f : fonts) {
374 fi = f;
375 if (fi->match(nameA: name2, boldA: bold, italicA: italic, obliqueA: oblique, fixedWidthA: fixedWidth)) {
376 if (std::find(first: filesToIgnore.begin(), last: filesToIgnore.end(), val: fi->path->toStr()) == filesToIgnore.end()) {
377 break;
378 }
379 }
380 fi = nullptr;
381 }
382 if (!fi && !exact && bold) {
383 // try ignoring the bold flag
384 for (const SysFontInfo *f : fonts) {
385 fi = f;
386 if (fi->match(nameA: name2, boldA: false, italicA: italic)) {
387 if (std::find(first: filesToIgnore.begin(), last: filesToIgnore.end(), val: fi->path->toStr()) == filesToIgnore.end()) {
388 break;
389 }
390 }
391 fi = nullptr;
392 }
393 }
394 if (!fi && !exact && (bold || italic)) {
395 // try ignoring the bold and italic flags
396 for (const SysFontInfo *f : fonts) {
397 fi = f;
398 if (fi->match(nameA: name2, boldA: false, italicA: false)) {
399 if (std::find(first: filesToIgnore.begin(), last: filesToIgnore.end(), val: fi->path->toStr()) == filesToIgnore.end()) {
400 break;
401 }
402 }
403 fi = nullptr;
404 }
405 }
406
407 delete name2;
408 return fi;
409}
410
411#define globalParamsLocker() const std::scoped_lock locker(mutex)
412#define unicodeMapCacheLocker() const std::scoped_lock locker(unicodeMapCacheMutex)
413#define cMapCacheLocker() const std::scoped_lock locker(cMapCacheMutex)
414
415//------------------------------------------------------------------------
416// parsing
417//------------------------------------------------------------------------
418
419GlobalParams::GlobalParams(const char *customPopplerDataDir) : popplerDataDir(customPopplerDataDir)
420{
421 // scan the encoding in reverse because we want the lowest-numbered
422 // index for each char name ('space' is encoded twice)
423 macRomanReverseMap = new NameToCharCode();
424 for (int i = 255; i >= 0; --i) {
425 if (macRomanEncoding[i]) {
426 macRomanReverseMap->add(name: macRomanEncoding[i], c: (CharCode)i);
427 }
428 }
429
430 nameToUnicodeZapfDingbats = new NameToCharCode();
431 nameToUnicodeText = new NameToCharCode();
432 sysFonts = new SysFontList();
433 textEncoding = new GooString("UTF-8");
434 printCommands = false;
435 profileCommands = false;
436 errQuiet = false;
437
438 cidToUnicodeCache = new CharCodeToUnicodeCache(cidToUnicodeCacheSize);
439 unicodeToUnicodeCache = new CharCodeToUnicodeCache(unicodeToUnicodeCacheSize);
440 unicodeMapCache = new UnicodeMapCache();
441 cMapCache = new CMapCache();
442
443 utf8Map = nullptr;
444
445 baseFontsInitialized = false;
446
447 // set up the initial nameToUnicode tables
448 for (int i = 0; nameToUnicodeZapfDingbatsTab[i].name; ++i) {
449 nameToUnicodeZapfDingbats->add(name: nameToUnicodeZapfDingbatsTab[i].name, c: nameToUnicodeZapfDingbatsTab[i].u);
450 }
451
452 for (int i = 0; nameToUnicodeTextTab[i].name; ++i) {
453 nameToUnicodeText->add(name: nameToUnicodeTextTab[i].name, c: nameToUnicodeTextTab[i].u);
454 }
455
456 // set up the residentUnicodeMaps table
457 residentUnicodeMaps.reserve(n: 6);
458 UnicodeMap map = { "Latin1", false, latin1UnicodeMapRanges, latin1UnicodeMapLen };
459 residentUnicodeMaps.emplace(args: map.getEncodingName(), args: std::move(map));
460 map = { "ASCII7", false, ascii7UnicodeMapRanges, ascii7UnicodeMapLen };
461 residentUnicodeMaps.emplace(args: map.getEncodingName(), args: std::move(map));
462 map = { "Symbol", false, symbolUnicodeMapRanges, symbolUnicodeMapLen };
463 residentUnicodeMaps.emplace(args: map.getEncodingName(), args: std::move(map));
464 map = { "ZapfDingbats", false, zapfDingbatsUnicodeMapRanges, zapfDingbatsUnicodeMapLen };
465 residentUnicodeMaps.emplace(args: map.getEncodingName(), args: std::move(map));
466 map = { "UTF-8", true, &mapUTF8 };
467 residentUnicodeMaps.emplace(args: map.getEncodingName(), args: std::move(map));
468 map = { "UTF-16", true, &mapUTF16 };
469 residentUnicodeMaps.emplace(args: map.getEncodingName(), args: std::move(map));
470
471 scanEncodingDirs();
472}
473
474void GlobalParams::scanEncodingDirs()
475{
476 GDir *dir;
477 std::unique_ptr<GDirEntry> entry;
478 const char *dataRoot = popplerDataDir ? popplerDataDir : POPPLER_DATADIR;
479
480 // allocate buffer large enough to append "/nameToUnicode"
481 size_t bufSize = strlen(s: dataRoot) + strlen(s: "/nameToUnicode") + 1;
482 char *dataPathBuffer = new char[bufSize];
483
484 snprintf(s: dataPathBuffer, maxlen: bufSize, format: "%s/nameToUnicode", dataRoot);
485 dir = new GDir(dataPathBuffer, true);
486 while (entry = dir->getNextEntry(), entry != nullptr) {
487 if (!entry->isDir()) {
488 parseNameToUnicode(name: entry->getFullPath());
489 }
490 }
491 delete dir;
492
493 snprintf(s: dataPathBuffer, maxlen: bufSize, format: "%s/cidToUnicode", dataRoot);
494 dir = new GDir(dataPathBuffer, false);
495 while (entry = dir->getNextEntry(), entry != nullptr) {
496 addCIDToUnicode(collection: entry->getName(), fileName: entry->getFullPath());
497 }
498 delete dir;
499
500 snprintf(s: dataPathBuffer, maxlen: bufSize, format: "%s/unicodeMap", dataRoot);
501 dir = new GDir(dataPathBuffer, false);
502 while (entry = dir->getNextEntry(), entry != nullptr) {
503 addUnicodeMap(encodingName: entry->getName(), fileName: entry->getFullPath());
504 }
505 delete dir;
506
507 snprintf(s: dataPathBuffer, maxlen: bufSize, format: "%s/cMap", dataRoot);
508 dir = new GDir(dataPathBuffer, false);
509 while (entry = dir->getNextEntry(), entry != nullptr) {
510 addCMapDir(collection: entry->getName(), dir: entry->getFullPath());
511 toUnicodeDirs.push_back(x: entry->getFullPath()->copy());
512 }
513 delete dir;
514
515 delete[] dataPathBuffer;
516}
517
518void GlobalParams::parseNameToUnicode(const GooString *name)
519{
520 char *tok1, *tok2;
521 FILE *f;
522 char buf[256];
523 int line;
524 Unicode u;
525 char *tokptr;
526
527 if (!(f = openFile(path: name->c_str(), mode: "r"))) {
528 error(category: errIO, pos: -1, msg: "Couldn't open 'nameToUnicode' file '{0:t}'", name);
529 return;
530 }
531 line = 1;
532 while (getLine(buf, size: sizeof(buf), f)) {
533 tok1 = strtok_r(s: buf, delim: " \t\r\n", save_ptr: &tokptr);
534 tok2 = strtok_r(s: nullptr, delim: " \t\r\n", save_ptr: &tokptr);
535 if (tok1 && tok2) {
536 sscanf(s: tok1, format: "%x", &u);
537 nameToUnicodeText->add(name: tok2, c: u);
538 } else {
539 error(category: errConfig, pos: -1, msg: "Bad line in 'nameToUnicode' file ({0:t}:{1:d})", name, line);
540 }
541 ++line;
542 }
543 fclose(stream: f);
544}
545
546void GlobalParams::addCIDToUnicode(const GooString *collection, const GooString *fileName)
547{
548 cidToUnicodes[collection->toStr()] = fileName->toStr();
549}
550
551void GlobalParams::addUnicodeMap(const GooString *encodingName, const GooString *fileName)
552{
553 unicodeMaps[encodingName->toStr()] = fileName->toStr();
554}
555
556void GlobalParams::addCMapDir(const GooString *collection, const GooString *dir)
557{
558 cMapDirs.emplace(args: collection->toStr(), args: dir->toStr());
559}
560
561bool GlobalParams::parseYesNo2(const char *token, bool *flag)
562{
563 if (!strcmp(s1: token, s2: "yes")) {
564 *flag = true;
565 } else if (!strcmp(s1: token, s2: "no")) {
566 *flag = false;
567 } else {
568 return false;
569 }
570 return true;
571}
572
573GlobalParams::~GlobalParams()
574{
575 delete macRomanReverseMap;
576
577 delete nameToUnicodeZapfDingbats;
578 delete nameToUnicodeText;
579 for (auto entry : toUnicodeDirs) {
580 delete entry;
581 }
582 delete sysFonts;
583 delete textEncoding;
584
585 delete cidToUnicodeCache;
586 delete unicodeToUnicodeCache;
587 delete unicodeMapCache;
588 delete cMapCache;
589}
590
591//------------------------------------------------------------------------
592// accessors
593//------------------------------------------------------------------------
594
595CharCode GlobalParams::getMacRomanCharCode(const char *charName)
596{
597 // no need to lock - macRomanReverseMap is constant
598 return macRomanReverseMap->lookup(name: charName);
599}
600
601Unicode GlobalParams::mapNameToUnicodeAll(const char *charName)
602{
603 // no need to lock - nameToUnicodeZapfDingbats and nameToUnicodeText are constant
604 Unicode u = nameToUnicodeZapfDingbats->lookup(name: charName);
605 if (!u) {
606 u = nameToUnicodeText->lookup(name: charName);
607 }
608 return u;
609}
610
611Unicode GlobalParams::mapNameToUnicodeText(const char *charName)
612{
613 // no need to lock - nameToUnicodeText is constant
614 return nameToUnicodeText->lookup(name: charName);
615}
616
617UnicodeMap *GlobalParams::getResidentUnicodeMap(const std::string &encodingName)
618{
619 UnicodeMap *map = nullptr;
620
621 globalParamsLocker();
622 const auto unicodeMap = residentUnicodeMaps.find(x: encodingName);
623 if (unicodeMap != residentUnicodeMaps.end()) {
624 map = &unicodeMap->second;
625 }
626
627 return map;
628}
629
630FILE *GlobalParams::getUnicodeMapFile(const std::string &encodingName)
631{
632 FILE *file = nullptr;
633
634 globalParamsLocker();
635 const auto unicodeMap = unicodeMaps.find(x: encodingName);
636 if (unicodeMap != unicodeMaps.end()) {
637 file = openFile(path: unicodeMap->second.c_str(), mode: "r");
638 }
639
640 return file;
641}
642
643FILE *GlobalParams::findCMapFile(const GooString *collection, const GooString *cMapName)
644{
645 FILE *file = nullptr;
646
647 globalParamsLocker();
648 const auto collectionCMapDirs = cMapDirs.equal_range(x: collection->toStr());
649 for (auto cMapDir = collectionCMapDirs.first; cMapDir != collectionCMapDirs.second; ++cMapDir) {
650 auto *const path = new GooString(cMapDir->second);
651 appendToPath(path, fileName: cMapName->c_str());
652 file = openFile(path: path->c_str(), mode: "r");
653 delete path;
654 if (file) {
655 break;
656 }
657 }
658
659 return file;
660}
661
662FILE *GlobalParams::findToUnicodeFile(const GooString *name)
663{
664 GooString *fileName;
665 FILE *f;
666
667 globalParamsLocker();
668 for (const GooString *dir : toUnicodeDirs) {
669 fileName = appendToPath(path: dir->copy(), fileName: name->c_str());
670 f = openFile(path: fileName->c_str(), mode: "r");
671 delete fileName;
672 if (f) {
673 return f;
674 }
675 }
676 return nullptr;
677}
678
679#ifdef WITH_FONTCONFIGURATION_FONTCONFIG
680static bool findModifier(const std::string &name, const size_t modStart, const char *modifier, size_t &start)
681{
682 if (modStart == std::string::npos) {
683 return false;
684 }
685
686 size_t match = name.find(s: modifier, pos: modStart);
687 if (match == std::string::npos) {
688 return false;
689 } else {
690 if (start == std::string::npos || match < start) {
691 start = match;
692 }
693 return true;
694 }
695}
696
697static const char *getFontLang(const GfxFont *font)
698{
699 const char *lang;
700
701 // find the language we want the font to support
702 if (font->isCIDFont()) {
703 const GooString *collection = ((GfxCIDFont *)font)->getCollection();
704 if (collection) {
705 if (strcmp(s1: collection->c_str(), s2: "Adobe-GB1") == 0) {
706 lang = "zh-cn"; // Simplified Chinese
707 } else if (strcmp(s1: collection->c_str(), s2: "Adobe-CNS1") == 0) {
708 lang = "zh-tw"; // Traditional Chinese
709 } else if (strcmp(s1: collection->c_str(), s2: "Adobe-Japan1") == 0) {
710 lang = "ja"; // Japanese
711 } else if (strcmp(s1: collection->c_str(), s2: "Adobe-Japan2") == 0) {
712 lang = "ja"; // Japanese
713 } else if (strcmp(s1: collection->c_str(), s2: "Adobe-Korea1") == 0) {
714 lang = "ko"; // Korean
715 } else if (strcmp(s1: collection->c_str(), s2: "Adobe-UCS") == 0) {
716 lang = "xx";
717 } else if (strcmp(s1: collection->c_str(), s2: "Adobe-Identity") == 0) {
718 lang = "xx";
719 } else {
720 error(category: errUnimplemented, pos: -1, msg: "Unknown CID font collection: {0:t}. If this is expected to be a valid PDF document, please report to poppler bugtracker.", collection);
721 lang = "xx";
722 }
723 } else {
724 lang = "xx";
725 }
726 } else {
727 lang = "xx";
728 }
729 return lang;
730}
731
732static FcPattern *buildFcPattern(const GfxFont *font, const GooString *base14Name)
733{
734 int weight = -1, slant = -1, width = -1, spacing = -1;
735 FcPattern *p;
736
737 // this is all heuristics will be overwritten if font had proper info
738 std::string fontName;
739 if (base14Name == nullptr) {
740 fontName = font->getNameWithoutSubsetTag();
741 } else {
742 fontName = base14Name->toStr();
743 }
744
745 size_t modStart = fontName.find(c: ',');
746 if (modStart == std::string::npos) {
747 modStart = fontName.find(c: '-');
748 }
749
750 // remove the - from the names, for some reason, Fontconfig does not
751 // understand "MS-Mincho" but does with "MS Mincho"
752 std::replace(first: fontName.begin(), last: fontName.end(), old_value: '-', new_value: ' ');
753
754 size_t start = std::string::npos;
755 findModifier(name: fontName, modStart, modifier: "Regular", start);
756 findModifier(name: fontName, modStart, modifier: "Roman", start);
757
758 if (findModifier(name: fontName, modStart, modifier: "Oblique", start)) {
759 slant = FC_SLANT_OBLIQUE;
760 }
761 if (findModifier(name: fontName, modStart, modifier: "Italic", start)) {
762 slant = FC_SLANT_ITALIC;
763 }
764 if (findModifier(name: fontName, modStart, modifier: "Bold", start)) {
765 weight = FC_WEIGHT_BOLD;
766 }
767 if (findModifier(name: fontName, modStart, modifier: "Light", start)) {
768 weight = FC_WEIGHT_LIGHT;
769 }
770 if (findModifier(name: fontName, modStart, modifier: "Medium", start)) {
771 weight = FC_WEIGHT_MEDIUM;
772 }
773 if (findModifier(name: fontName, modStart, modifier: "Condensed", start)) {
774 width = FC_WIDTH_CONDENSED;
775 }
776
777 std::string family;
778 if (start == std::string::npos) {
779 family = fontName;
780 } else {
781 // There have been "modifiers" in the name, crop them to obtain
782 // the family name
783 family = fontName.substr(pos: 0, n: modStart);
784 }
785
786 // use font flags
787 if (font->isFixedWidth()) {
788 spacing = FC_MONO;
789 }
790 if (font->isBold()) {
791 weight = FC_WEIGHT_BOLD;
792 }
793 if (font->isItalic()) {
794 slant = FC_SLANT_ITALIC;
795 }
796
797 // if the FontDescriptor specified a family name use it
798 if (font->getFamily()) {
799 family = font->getFamily()->toStr();
800 }
801
802 // if the FontDescriptor specified a weight use it
803 switch (font->getWeight()) {
804 case GfxFont::W100:
805 weight = FC_WEIGHT_EXTRALIGHT;
806 break;
807 case GfxFont::W200:
808 weight = FC_WEIGHT_LIGHT;
809 break;
810 case GfxFont::W300:
811 weight = FC_WEIGHT_BOOK;
812 break;
813 case GfxFont::W400:
814 weight = FC_WEIGHT_NORMAL;
815 break;
816 case GfxFont::W500:
817 weight = FC_WEIGHT_MEDIUM;
818 break;
819 case GfxFont::W600:
820 weight = FC_WEIGHT_DEMIBOLD;
821 break;
822 case GfxFont::W700:
823 weight = FC_WEIGHT_BOLD;
824 break;
825 case GfxFont::W800:
826 weight = FC_WEIGHT_EXTRABOLD;
827 break;
828 case GfxFont::W900:
829 weight = FC_WEIGHT_BLACK;
830 break;
831 default:
832 break;
833 }
834
835 // if the FontDescriptor specified a width use it
836 switch (font->getStretch()) {
837 case GfxFont::UltraCondensed:
838 width = FC_WIDTH_ULTRACONDENSED;
839 break;
840 case GfxFont::ExtraCondensed:
841 width = FC_WIDTH_EXTRACONDENSED;
842 break;
843 case GfxFont::Condensed:
844 width = FC_WIDTH_CONDENSED;
845 break;
846 case GfxFont::SemiCondensed:
847 width = FC_WIDTH_SEMICONDENSED;
848 break;
849 case GfxFont::Normal:
850 width = FC_WIDTH_NORMAL;
851 break;
852 case GfxFont::SemiExpanded:
853 width = FC_WIDTH_SEMIEXPANDED;
854 break;
855 case GfxFont::Expanded:
856 width = FC_WIDTH_EXPANDED;
857 break;
858 case GfxFont::ExtraExpanded:
859 width = FC_WIDTH_EXTRAEXPANDED;
860 break;
861 case GfxFont::UltraExpanded:
862 width = FC_WIDTH_ULTRAEXPANDED;
863 break;
864 default:
865 break;
866 }
867
868 const char *lang = getFontLang(font);
869
870 p = FcPatternBuild(p: nullptr, FC_FAMILY, FcTypeString, family.c_str(), FC_LANG, FcTypeString, lang, NULL);
871 if (slant != -1) {
872 FcPatternAddInteger(p, FC_SLANT, i: slant);
873 }
874 if (weight != -1) {
875 FcPatternAddInteger(p, FC_WEIGHT, i: weight);
876 }
877 if (width != -1) {
878 FcPatternAddInteger(p, FC_WIDTH, i: width);
879 }
880 if (spacing != -1) {
881 FcPatternAddInteger(p, FC_SPACING, i: spacing);
882 }
883
884 return p;
885}
886#endif
887
888GooString *GlobalParams::findFontFile(const std::string &fontName)
889{
890 GooString *path = nullptr;
891
892 setupBaseFonts(POPPLER_FONTSDIR);
893 globalParamsLocker();
894 const auto fontFile = fontFiles.find(x: fontName);
895 if (fontFile != fontFiles.end()) {
896 path = new GooString(fontFile->second);
897 }
898
899 return path;
900}
901
902#if defined(WITH_FONTCONFIGURATION_FONTCONFIG) || defined(WITH_FONTCONFIGURATION_WIN32)
903
904static bool supportedFontForEmbedding(Unicode uChar, const char *filepath, int faceIndex)
905{
906 if (!std::string_view(filepath).ends_with(x: ".ttf") && !std::string_view(filepath).ends_with(x: ".ttc") && !std::string_view(filepath).ends_with(x: ".otf")) {
907 // for now we only support ttf, ttc, otf fonts
908 return false;
909 }
910
911 const FoFiIdentifierType fontFoFiType = FoFiIdentifier::identifyFile(fileName: filepath);
912 if (fontFoFiType != fofiIdTrueType && fontFoFiType != fofiIdTrueTypeCollection && fontFoFiType != fofiIdOpenTypeCFF8Bit && fontFoFiType != fofiIdOpenTypeCFFCID) {
913 // for now we only support ttf, ttc, otf fonts
914 return false;
915 }
916
917 const std::unique_ptr<FoFiTrueType> fft = FoFiTrueType::load(fileName: filepath, faceIndexA: faceIndex);
918 if (!fft) {
919 error(category: errIO, pos: -1, msg: "Form::addFontToDefaultResources. Failed to FoFiTrueType::load {0:s}", filepath);
920 return false;
921 }
922
923 // Look for the Unicode BMP cmaps, which are 0/3 or 3/1
924 int unicodeBMPCMap = fft->findCmap(platform: 0, encoding: 3);
925 if (unicodeBMPCMap < 0) {
926 unicodeBMPCMap = fft->findCmap(platform: 3, encoding: 1);
927 }
928 if (unicodeBMPCMap < 0) {
929 // for now we only support files with unicode bmp cmaps
930 return false;
931 }
932
933 const int glyph = fft->mapCodeToGID(i: unicodeBMPCMap, c: uChar);
934 return glyph > 0;
935}
936
937#endif
938
939/* if you can't or don't want to use Fontconfig, you need to implement
940 this function for your platform. For Windows, it's in GlobalParamsWin.cc
941*/
942#ifdef WITH_FONTCONFIGURATION_FONTCONFIG
943// not needed for fontconfig
944void GlobalParams::setupBaseFonts(const char *) { }
945
946GooString *GlobalParams::findBase14FontFile(const GooString *base14Name, const GfxFont *font, GooString *substituteFontName)
947{
948 SysFontType type;
949 int fontNum;
950
951 return findSystemFontFile(font, type: &type, fontNum: &fontNum, substituteFontName, base14Name);
952}
953
954GooString *GlobalParams::findSystemFontFile(const GfxFont *font, SysFontType *type, int *fontNum, GooString *substituteFontName, const GooString *base14Name)
955{
956 const SysFontInfo *fi = nullptr;
957 FcPattern *p = nullptr;
958 GooString *path = nullptr;
959 const std::optional<std::string> &fontName = font->getName();
960 GooString substituteName;
961 if (!fontName) {
962 return nullptr;
963 }
964
965 globalParamsLocker();
966
967 if ((fi = sysFonts->find(name: *fontName, fixedWidth: font->isFixedWidth(), exact: true))) {
968 path = fi->path->copy();
969 *type = fi->type;
970 *fontNum = fi->fontNum;
971 substituteName.Set(fi->substituteName->c_str());
972 } else {
973 FcChar8 *s;
974 char *ext;
975 FcResult res;
976 FcFontSet *set;
977 int i;
978 FcLangSet *lb = nullptr;
979 p = buildFcPattern(font, base14Name);
980
981 if (!p) {
982 goto fin;
983 }
984 FcConfigSubstitute(config: nullptr, p, kind: FcMatchPattern);
985 FcDefaultSubstitute(pattern: p);
986 set = FcFontSort(config: nullptr, p, FcFalse, csp: nullptr, result: &res);
987 if (!set) {
988 goto fin;
989 }
990
991 // find the language we want the font to support
992 const char *lang = getFontLang(font);
993 if (strcmp(s1: lang, s2: "xx") != 0) {
994 lb = FcLangSetCreate();
995 FcLangSetAdd(ls: lb, lang: (FcChar8 *)lang);
996 }
997
998 /*
999 scan twice.
1000 first: fonts support the language
1001 second: all fonts (fall back)
1002 */
1003 while (fi == nullptr) {
1004 for (i = 0; i < set->nfont; ++i) {
1005 res = FcPatternGetString(p: set->fonts[i], FC_FILE, n: 0, s: &s);
1006 if (res != FcResultMatch || !s) {
1007 continue;
1008 }
1009 if (lb != nullptr) {
1010 FcLangSet *l;
1011 res = FcPatternGetLangSet(p: set->fonts[i], FC_LANG, n: 0, ls: &l);
1012 if (res != FcResultMatch || !FcLangSetContains(lsa: l, lsb: lb)) {
1013 continue;
1014 }
1015 }
1016 FcChar8 *s2;
1017 res = FcPatternGetString(p: set->fonts[i], FC_FULLNAME, n: 0, s: &s2);
1018 if (res == FcResultMatch && s2) {
1019 substituteName.Set((char *)s2);
1020 } else {
1021 // fontconfig does not extract fullname for some fonts
1022 // create the fullname from family and style
1023 res = FcPatternGetString(p: set->fonts[i], FC_FAMILY, n: 0, s: &s2);
1024 if (res == FcResultMatch && s2) {
1025 substituteName.Set((char *)s2);
1026 res = FcPatternGetString(p: set->fonts[i], FC_STYLE, n: 0, s: &s2);
1027 if (res == FcResultMatch && s2) {
1028 GooString *style = new GooString((char *)s2);
1029 if (style->cmp(sA: "Regular") != 0) {
1030 substituteName.append(str: " ");
1031 substituteName.append(str: style);
1032 }
1033 delete style;
1034 }
1035 }
1036 }
1037 ext = strrchr(s: (char *)s, c: '.');
1038 if (!ext) {
1039 continue;
1040 }
1041 if (!strncasecmp(s1: ext, s2: ".ttf", n: 4) || !strncasecmp(s1: ext, s2: ".ttc", n: 4) || !strncasecmp(s1: ext, s2: ".otf", n: 4)) {
1042 int weight, slant;
1043 bool bold = font->isBold();
1044 bool italic = font->isItalic();
1045 bool oblique = false;
1046 FcPatternGetInteger(p: set->fonts[i], FC_WEIGHT, n: 0, i: &weight);
1047 FcPatternGetInteger(p: set->fonts[i], FC_SLANT, n: 0, i: &slant);
1048 if (weight == FC_WEIGHT_DEMIBOLD || weight == FC_WEIGHT_BOLD || weight == FC_WEIGHT_EXTRABOLD || weight == FC_WEIGHT_BLACK) {
1049 bold = true;
1050 }
1051 if (slant == FC_SLANT_ITALIC) {
1052 italic = true;
1053 }
1054 if (slant == FC_SLANT_OBLIQUE) {
1055 oblique = true;
1056 }
1057 *fontNum = 0;
1058 *type = (!strncasecmp(s1: ext, s2: ".ttc", n: 4)) ? sysFontTTC : sysFontTTF;
1059 FcPatternGetInteger(p: set->fonts[i], FC_INDEX, n: 0, i: fontNum);
1060 SysFontInfo *sfi = new SysFontInfo(new GooString(*fontName), bold, italic, oblique, font->isFixedWidth(), new GooString((char *)s), *type, *fontNum, substituteName.copy());
1061 sysFonts->addFcFont(si: sfi);
1062 fi = sfi;
1063 path = new GooString((char *)s);
1064 } else if (!strncasecmp(s1: ext, s2: ".pfa", n: 4) || !strncasecmp(s1: ext, s2: ".pfb", n: 4)) {
1065 int weight, slant;
1066 bool bold = font->isBold();
1067 bool italic = font->isItalic();
1068 bool oblique = false;
1069 FcPatternGetInteger(p: set->fonts[i], FC_WEIGHT, n: 0, i: &weight);
1070 FcPatternGetInteger(p: set->fonts[i], FC_SLANT, n: 0, i: &slant);
1071 if (weight == FC_WEIGHT_DEMIBOLD || weight == FC_WEIGHT_BOLD || weight == FC_WEIGHT_EXTRABOLD || weight == FC_WEIGHT_BLACK) {
1072 bold = true;
1073 }
1074 if (slant == FC_SLANT_ITALIC) {
1075 italic = true;
1076 }
1077 if (slant == FC_SLANT_OBLIQUE) {
1078 oblique = true;
1079 }
1080 *fontNum = 0;
1081 *type = (!strncasecmp(s1: ext, s2: ".pfa", n: 4)) ? sysFontPFA : sysFontPFB;
1082 FcPatternGetInteger(p: set->fonts[i], FC_INDEX, n: 0, i: fontNum);
1083 SysFontInfo *sfi = new SysFontInfo(new GooString(*fontName), bold, italic, oblique, font->isFixedWidth(), new GooString((char *)s), *type, *fontNum, substituteName.copy());
1084 sysFonts->addFcFont(si: sfi);
1085 fi = sfi;
1086 path = new GooString((char *)s);
1087 } else {
1088 continue;
1089 }
1090 break;
1091 }
1092 if (lb != nullptr) {
1093 FcLangSetDestroy(ls: lb);
1094 lb = nullptr;
1095 } else {
1096 /* scan all fonts of the list */
1097 break;
1098 }
1099 }
1100 FcFontSetDestroy(s: set);
1101 }
1102 if (path == nullptr && (fi = sysFonts->find(name: *fontName, fixedWidth: font->isFixedWidth(), exact: false))) {
1103 path = fi->path->copy();
1104 *type = fi->type;
1105 *fontNum = fi->fontNum;
1106 }
1107 if (substituteFontName) {
1108 substituteFontName->Set(substituteName.c_str());
1109 }
1110fin:
1111 if (p) {
1112 FcPatternDestroy(p);
1113 }
1114
1115 return path;
1116}
1117
1118FamilyStyleFontSearchResult GlobalParams::findSystemFontFileForFamilyAndStyle(const std::string &fontFamily, const std::string &fontStyle, const std::vector<std::string> &filesToIgnore)
1119{
1120 FcPattern *p = FcPatternBuild(p: nullptr, FC_FAMILY, FcTypeString, fontFamily.c_str(), FC_STYLE, FcTypeString, fontStyle.c_str(), nullptr);
1121 FcConfigSubstitute(config: nullptr, p, kind: FcMatchPattern);
1122 FcDefaultSubstitute(pattern: p);
1123 if (p) {
1124 const std::unique_ptr<FcPattern, void (*)(FcPattern *)> pDeleter(p, [](FcPattern *pattern) { FcPatternDestroy(p: pattern); });
1125 FcResult res;
1126 FcFontSet *fontSet = FcFontSort(config: nullptr, p, FcFalse, csp: nullptr, result: &res);
1127 if (fontSet) {
1128 const std::unique_ptr<FcFontSet, void (*)(FcFontSet *)> fontSetDeleter(fontSet, [](FcFontSet *fSet) { FcFontSetDestroy(s: fSet); });
1129 if (res == FcResultMatch) {
1130 for (int i = 0; i < fontSet->nfont; i++) {
1131 FcChar8 *fcFilePath = nullptr;
1132 int faceIndex = 0;
1133 FcPatternGetString(p: fontSet->fonts[i], FC_FILE, n: 0, s: &fcFilePath);
1134 FcPatternGetInteger(p: fontSet->fonts[i], FC_INDEX, n: 0, i: &faceIndex);
1135
1136 const std::string sFilePath = reinterpret_cast<char *>(fcFilePath);
1137 if (std::find(first: filesToIgnore.begin(), last: filesToIgnore.end(), val: sFilePath) == filesToIgnore.end()) {
1138 return FamilyStyleFontSearchResult(sFilePath, faceIndex);
1139 }
1140 }
1141 }
1142 }
1143 }
1144
1145 error(category: errIO, pos: -1, msg: "Couldn't find font file for {0:s} {1:s}", fontFamily.c_str(), fontStyle.c_str());
1146 return {};
1147}
1148
1149UCharFontSearchResult GlobalParams::findSystemFontFileForUChar(Unicode uChar, const GfxFont &fontToEmulate)
1150{
1151 FcPattern *pattern = buildFcPattern(font: &fontToEmulate, base14Name: nullptr);
1152
1153 FcConfigSubstitute(config: nullptr, p: pattern, kind: FcMatchPattern);
1154 FcDefaultSubstitute(pattern);
1155
1156 FcResult result = FcResultMatch;
1157 FcFontSet *fontSet = FcFontSort(config: nullptr, p: pattern, FcFalse, csp: nullptr, result: &result);
1158 FcPatternDestroy(p: pattern);
1159
1160 if (fontSet) {
1161 const std::unique_ptr<FcFontSet, void (*)(FcFontSet *)> fontSetDeleter(fontSet, [](FcFontSet *fSet) { FcFontSetDestroy(s: fSet); });
1162 for (int i = 0; i < fontSet->nfont; i++) {
1163 FcChar8 *fcFilePath = nullptr;
1164 int faceIndex = 0;
1165 FcChar8 *fcFamily = nullptr;
1166 FcChar8 *fcStyle = nullptr;
1167 FcCharSet *fcCharSet = nullptr;
1168 FcPatternGetString(p: fontSet->fonts[i], FC_FILE, n: 0, s: &fcFilePath);
1169 FcPatternGetInteger(p: fontSet->fonts[i], FC_INDEX, n: 0, i: &faceIndex);
1170 FcPatternGetString(p: fontSet->fonts[i], FC_FAMILY, n: 0, s: &fcFamily);
1171 FcPatternGetString(p: fontSet->fonts[i], FC_STYLE, n: 0, s: &fcStyle);
1172 FcPatternGetCharSet(p: fontSet->fonts[i], FC_CHARSET, n: 0, c: &fcCharSet);
1173 if (!fcFilePath || !fcFamily || !fcStyle || !fcCharSet) {
1174 continue;
1175 }
1176 if (!FcCharSetHasChar(fcs: fcCharSet, ucs4: uChar)) {
1177 continue;
1178 }
1179
1180 const char *filepath = reinterpret_cast<char *>(fcFilePath);
1181
1182 if (supportedFontForEmbedding(uChar, filepath, faceIndex)) {
1183 return UCharFontSearchResult(filepath, faceIndex, reinterpret_cast<char *>(fcFamily), reinterpret_cast<char *>(fcStyle));
1184 }
1185 }
1186 }
1187
1188 return {};
1189}
1190#elif defined(WITH_FONTCONFIGURATION_ANDROID)
1191// Uses the font file mapping created by GlobalParams::setupBaseFonts
1192// to return the path to a base-14 font file
1193GooString *GlobalParams::findBase14FontFile(const GooString *base14Name, const GfxFont *font, GooString *substituteFontName)
1194{
1195 return findFontFile(base14Name->toStr());
1196}
1197
1198# if __ANDROID_API__ >= 29
1199
1200// This struct is used by the AFontMatcher unique_ptr for destroying the
1201// AFontMatcher object
1202struct AFontMatcherDestroyer
1203{
1204 void operator()(AFontMatcher *fontmatcher) { AFontMatcher_destroy(fontmatcher); }
1205};
1206
1207// This struct is used by the AFontMatcher unique_ptr for destroying the
1208// AFont object
1209struct AFontDestroyer
1210{
1211 void operator()(AFont *afont) { AFont_close(afont); }
1212};
1213
1214# endif
1215
1216GooString *GlobalParams::findSystemFontFile(const GfxFont *font, SysFontType *type, int *fontNum, GooString *substituteFontName, const GooString *base14Name)
1217{
1218 GooString *path = nullptr;
1219 const std::optional<std::string> &fontName = font->getName();
1220
1221 if (!fontName) {
1222 return nullptr;
1223 }
1224
1225 globalParamsLocker();
1226
1227# if __ANDROID_API__ >= 29
1228 // If font is not found in the default base-14 fonts,
1229 // use Android-NDK's AFontMatcher API instead.
1230 // Documentation for AFontMatcher API can be found at:
1231 // https://developer.android.com/ndk/reference/group/font
1232 std::string genericFontFamily = "serif";
1233
1234 if (!font->isSerif()) {
1235 genericFontFamily = "sans-serif";
1236 } else if (font->isFixedWidth()) {
1237 genericFontFamily = "monospace";
1238 }
1239
1240 std::unique_ptr<AFontMatcher, AFontMatcherDestroyer> fontmatcher { AFontMatcher_create() };
1241
1242 // Set font weight and italics for the font.
1243 AFontMatcher_setStyle(fontmatcher.get(), font->getWeight() * 100, font->isItalic());
1244
1245 // Get font match and the font file's path
1246 std::unique_ptr<AFont, AFontDestroyer> afont { AFontMatcher_match(fontmatcher.get(), genericFontFamily.c_str(), (uint16_t *)u"A", 1, nullptr) };
1247 path = new GooString(AFont_getFontFilePath(afont.get()));
1248
1249 // Set the type of font. Fonts returned by AFontMatcher are of
1250 // four possible types - ttf, otf, ttc, otc.
1251 if (path->ends_with(".ttf") || path->ends_with(".otf")) {
1252 *type = sysFontTTF;
1253 } else if (path->ends_with(".ttc") || path->ends_with(".otc")) {
1254 *type = sysFontTTC;
1255 }
1256# else
1257# pragma message("Compiling without AFontMatcher API due to Android API version being lower than 29.")
1258# endif
1259
1260 return path;
1261}
1262
1263static struct
1264{
1265 const char *name;
1266 const char *otFileName;
1267} displayFontTab[] = { { "Courier", "NimbusMonoPS-Regular.otf" },
1268 { "Courier-Bold", "NimbusMonoPS-Bold.otf" },
1269 { "Courier-BoldOblique", "NimbusMonoPS-BoldItalic.otf" },
1270 { "Courier-Oblique", "NimbusMonoPS-Italic.otf" },
1271 { "Helvetica", "NimbusSans-Regular.otf" },
1272 { "Helvetica-Bold", "NimbusSans-Bold.otf" },
1273 { "Helvetica-BoldOblique", "NimbusSans-BoldItalic.otf" },
1274 { "Helvetica-Oblique", "NimbusSans-Italic.otf" },
1275 { "Symbol", "StandardSymbolsPS.otf" },
1276 { "Times-Bold", "NimbusRoman-Bold.otf" },
1277 { "Times-BoldItalic", "NimbusRoman-BoldItalic.otf" },
1278 { "Times-Italic", "NimbusRoman-Italic.otf" },
1279 { "Times-Roman", "NimbusRoman-Regular.otf" },
1280 { "ZapfDingbats", "D050000L.otf" },
1281 { nullptr, nullptr } };
1282
1283// The path to the font directory. Set by GlobalParams::setFontDir()
1284static std::string displayFontDir;
1285
1286// This method creates a mapping from base-14 font names to their
1287// paths on the file system. On Android, it searches within the
1288// directory set by GlobalParams::setFontDir().
1289void GlobalParams::setupBaseFonts(const char *dir)
1290{
1291 FILE *f;
1292 int i;
1293
1294 for (i = 0; displayFontTab[i].name; ++i) {
1295 if (fontFiles.count(displayFontTab[i].name) > 0) {
1296 continue;
1297 }
1298
1299 std::unique_ptr<GooString> fontName = std::make_unique<GooString>(displayFontTab[i].name);
1300 std::unique_ptr<GooString> fileName;
1301 if (dir) {
1302 fileName.reset(appendToPath(new GooString(dir), displayFontTab[i].otFileName));
1303 if ((f = openFile(fileName->c_str(), "rb"))) {
1304 fclose(f);
1305 } else {
1306 fileName.reset();
1307 }
1308 }
1309 if (!displayFontDir.empty()) {
1310 fileName.reset(appendToPath(new GooString(displayFontDir), displayFontTab[i].otFileName));
1311 if ((f = openFile(fileName->c_str(), "rb"))) {
1312 fclose(f);
1313 } else {
1314 fileName.reset();
1315 }
1316 }
1317 if (!fileName) {
1318 error(errConfig, -1, "No display font for '{0:s}'", displayFontTab[i].name);
1319 continue;
1320 }
1321 addFontFile(fontName->toStr(), fileName->toStr());
1322 }
1323}
1324
1325FamilyStyleFontSearchResult GlobalParams::findSystemFontFileForFamilyAndStyle(const std::string &fontFamily, const std::string &fontStyle, const std::vector<std::string> &filesToIgnore)
1326{
1327 error(errUnimplemented, -1, "GlobalParams::findSystemFontFileForFamilyAndStyle not implemented for this platform");
1328 return {};
1329}
1330
1331UCharFontSearchResult GlobalParams::findSystemFontFileForUChar(Unicode uChar, const GfxFont &fontToEmulate)
1332{
1333 error(errUnimplemented, -1, "GlobalParams::findSystemFontFileForUChar not implemented for this platform");
1334 return {};
1335}
1336
1337#elif defined(WITH_FONTCONFIGURATION_WIN32)
1338# include "GlobalParamsWin.cc"
1339
1340GooString *GlobalParams::findBase14FontFile(const GooString *base14Name, const GfxFont *font, GooString * /*substituteFontName*/)
1341{
1342 return findFontFile(base14Name->toStr());
1343}
1344
1345#else
1346
1347FamilyStyleFontSearchResult GlobalParams::findSystemFontFileForFamilyAndStyle(const std::string &fontFamily, const std::string &fontStyle, const std::vector<std::string> &filesToIgnore)
1348{
1349 error(errUnimplemented, -1, "GlobalParams::findSystemFontFileForFamilyAndStyle not implemented for this platform");
1350 return {};
1351}
1352
1353UCharFontSearchResult GlobalParams::findSystemFontFileForUChar(Unicode uChar, const GfxFont &fontToEmulate)
1354{
1355 error(errUnimplemented, -1, "GlobalParams::findSystemFontFileForUChar not implemented for this platform");
1356 return {};
1357}
1358
1359GooString *GlobalParams::findBase14FontFile(const GooString *base14Name, const GfxFont *font, GooString * /*substituteFontName*/)
1360{
1361 return findFontFile(base14Name->toStr());
1362}
1363
1364static struct
1365{
1366 const char *name;
1367 const char *t1FileName;
1368 const char *ttFileName;
1369} displayFontTab[] = { { "Courier", "n022003l.pfb", "cour.ttf" },
1370 { "Courier-Bold", "n022004l.pfb", "courbd.ttf" },
1371 { "Courier-BoldOblique", "n022024l.pfb", "courbi.ttf" },
1372 { "Courier-Oblique", "n022023l.pfb", "couri.ttf" },
1373 { "Helvetica", "n019003l.pfb", "arial.ttf" },
1374 { "Helvetica-Bold", "n019004l.pfb", "arialbd.ttf" },
1375 { "Helvetica-BoldOblique", "n019024l.pfb", "arialbi.ttf" },
1376 { "Helvetica-Oblique", "n019023l.pfb", "ariali.ttf" },
1377 { "Symbol", "s050000l.pfb", nullptr },
1378 { "Times-Bold", "n021004l.pfb", "timesbd.ttf" },
1379 { "Times-BoldItalic", "n021024l.pfb", "timesbi.ttf" },
1380 { "Times-Italic", "n021023l.pfb", "timesi.ttf" },
1381 { "Times-Roman", "n021003l.pfb", "times.ttf" },
1382 { "ZapfDingbats", "d050000l.pfb", nullptr },
1383 { nullptr, nullptr, nullptr } };
1384
1385static const char *displayFontDirs[] = { "/usr/share/ghostscript/fonts", "/usr/local/share/ghostscript/fonts", "/usr/share/fonts/default/Type1", "/usr/share/fonts/default/ghostscript", "/usr/share/fonts/type1/gsfonts", nullptr };
1386
1387void GlobalParams::setupBaseFonts(const char *dir)
1388{
1389 FILE *f;
1390 int i, j;
1391
1392 for (i = 0; displayFontTab[i].name; ++i) {
1393 if (fontFiles.count(displayFontTab[i].name) > 0) {
1394 continue;
1395 }
1396 std::unique_ptr<GooString> fontName = std::make_unique<GooString>(displayFontTab[i].name);
1397 std::unique_ptr<GooString> fileName;
1398 if (dir) {
1399 fileName.reset(appendToPath(new GooString(dir), displayFontTab[i].t1FileName));
1400 if ((f = openFile(fileName->c_str(), "rb"))) {
1401 fclose(f);
1402 } else {
1403 fileName.reset();
1404 }
1405 }
1406 for (j = 0; !fileName && displayFontDirs[j]; ++j) {
1407 fileName.reset(appendToPath(new GooString(displayFontDirs[j]), displayFontTab[i].t1FileName));
1408 if ((f = openFile(fileName->c_str(), "rb"))) {
1409 fclose(f);
1410 } else {
1411 fileName.reset();
1412 }
1413 }
1414 if (!fileName) {
1415 error(errConfig, -1, "No display font for '{0:s}'", displayFontTab[i].name);
1416 continue;
1417 }
1418 addFontFile(fontName->toStr(), fileName->toStr());
1419 }
1420}
1421
1422GooString *GlobalParams::findSystemFontFile(const GfxFont *font, SysFontType *type, int *fontNum, GooString * /*substituteFontName*/, const GooString * /*base14Name*/)
1423{
1424 const SysFontInfo *fi;
1425 GooString *path;
1426
1427 const std::optional<std::string> &fontName = font->getName();
1428 if (!fontName) {
1429 return nullptr;
1430 }
1431
1432 path = nullptr;
1433 globalParamsLocker();
1434 if ((fi = sysFonts->find(*fontName, font->isFixedWidth(), false))) {
1435 path = fi->path->copy();
1436 *type = fi->type;
1437 *fontNum = fi->fontNum;
1438 }
1439
1440 return path;
1441}
1442#endif
1443
1444std::string GlobalParams::getTextEncodingName() const
1445{
1446 globalParamsLocker();
1447 return textEncoding->toStr();
1448}
1449
1450const UnicodeMap *GlobalParams::getUtf8Map()
1451{
1452 if (!utf8Map) {
1453 utf8Map = globalParams->getUnicodeMap(encodingName: "UTF-8");
1454 }
1455
1456 return utf8Map;
1457}
1458
1459bool GlobalParams::getPrintCommands()
1460{
1461 globalParamsLocker();
1462 return printCommands;
1463}
1464
1465bool GlobalParams::getProfileCommands()
1466{
1467 globalParamsLocker();
1468 return profileCommands;
1469}
1470
1471bool GlobalParams::getErrQuiet()
1472{
1473 // no locking -- this function may get called from inside a locked
1474 // section
1475 return errQuiet;
1476}
1477
1478CharCodeToUnicode *GlobalParams::getCIDToUnicode(const GooString *collection)
1479{
1480 CharCodeToUnicode *ctu;
1481
1482 globalParamsLocker();
1483 if (!(ctu = cidToUnicodeCache->getCharCodeToUnicode(tag: collection))) {
1484 const auto cidToUnicode = cidToUnicodes.find(x: collection->toStr());
1485 if (cidToUnicode != cidToUnicodes.end()) {
1486 if ((ctu = CharCodeToUnicode::parseCIDToUnicode(fileName: cidToUnicode->second.c_str(), collection))) {
1487 cidToUnicodeCache->add(ctu);
1488 }
1489 }
1490 }
1491
1492 return ctu;
1493}
1494
1495const UnicodeMap *GlobalParams::getUnicodeMap(const std::string &encodingName)
1496{
1497 const UnicodeMap *map;
1498
1499 if (!(map = getResidentUnicodeMap(encodingName))) {
1500 unicodeMapCacheLocker();
1501 map = unicodeMapCache->getUnicodeMap(encodingName);
1502 }
1503
1504 return map;
1505}
1506
1507std::shared_ptr<CMap> GlobalParams::getCMap(const GooString *collection, const GooString *cMapName)
1508{
1509 cMapCacheLocker();
1510 return cMapCache->getCMap(collection, cMapName);
1511}
1512
1513const UnicodeMap *GlobalParams::getTextEncoding()
1514{
1515 return getUnicodeMap(encodingName: textEncoding->toStr());
1516}
1517
1518std::vector<std::string> GlobalParams::getEncodingNames()
1519{
1520 std::vector<std::string> result;
1521 result.reserve(n: residentUnicodeMaps.size() + unicodeMaps.size());
1522 for (const auto &unicodeMap : residentUnicodeMaps) {
1523 result.push_back(x: unicodeMap.first);
1524 }
1525 for (const auto &unicodeMap : unicodeMaps) {
1526 result.push_back(x: unicodeMap.first);
1527 }
1528 return result;
1529}
1530
1531//------------------------------------------------------------------------
1532// functions to set parameters
1533//------------------------------------------------------------------------
1534
1535void GlobalParams::addFontFile(const std::string &fontName, const std::string &path)
1536{
1537 globalParamsLocker();
1538 fontFiles[fontName] = path;
1539}
1540
1541void GlobalParams::setTextEncoding(const char *encodingName)
1542{
1543 globalParamsLocker();
1544 delete textEncoding;
1545 textEncoding = new GooString(encodingName);
1546}
1547
1548void GlobalParams::setPrintCommands(bool printCommandsA)
1549{
1550 globalParamsLocker();
1551 printCommands = printCommandsA;
1552}
1553
1554void GlobalParams::setProfileCommands(bool profileCommandsA)
1555{
1556 globalParamsLocker();
1557 profileCommands = profileCommandsA;
1558}
1559
1560void GlobalParams::setErrQuiet(bool errQuietA)
1561{
1562 globalParamsLocker();
1563 errQuiet = errQuietA;
1564}
1565
1566#ifdef ANDROID
1567void GlobalParams::setFontDir(const std::string &fontDir)
1568{
1569# if defined(WITH_FONTCONFIGURATION_ANDROID)
1570 displayFontDir = fontDir;
1571# endif
1572}
1573#endif
1574
1575GlobalParamsIniter::GlobalParamsIniter(ErrorCallback errorCallback)
1576{
1577 const std::scoped_lock lock { mutex };
1578
1579 if (count == 0) {
1580 globalParams = std::make_unique<GlobalParams>(args: !customDataDir.empty() ? customDataDir.c_str() : nullptr);
1581
1582 setErrorCallback(errorCallback);
1583 }
1584
1585 count++;
1586}
1587
1588GlobalParamsIniter::~GlobalParamsIniter()
1589{
1590 const std::scoped_lock lock { mutex };
1591
1592 --count;
1593
1594 if (count == 0) {
1595 globalParams.reset();
1596 }
1597}
1598
1599bool GlobalParamsIniter::setCustomDataDir(const std::string &dir)
1600{
1601 const std::scoped_lock lock { mutex };
1602
1603 if (count == 0) {
1604 customDataDir = dir;
1605 return true;
1606 }
1607
1608 return false;
1609}
1610
1611std::mutex GlobalParamsIniter::mutex;
1612int GlobalParamsIniter::count = 0;
1613std::string GlobalParamsIniter::customDataDir;
1614

source code of poppler/poppler/GlobalParams.cc