blob: 4f90cdc677f87b048b083221749d9d8c9c9fbd41 [file] [log] [blame] [edit]
//========================================================================
//
// GlobalParams.cc
//
// Copyright 2001-2003 Glyph & Cog, LLC
//
//========================================================================
//========================================================================
//
// Modified under the Poppler project - http://poppler.freedesktop.org
//
// All changes made under the Poppler project to this file are licensed
// under GPL version 2 or later
//
// Copyright (C) 2005 Martin Kretzschmar <martink@gnome.org>
// Copyright (C) 2005, 2006 Kristian Høgsberg <krh@redhat.com>
// Copyright (C) 2005, 2007-2010, 2012, 2015, 2017-2024 Albert Astals Cid <aacid@kde.org>
// Copyright (C) 2005 Jonathan Blandford <jrb@redhat.com>
// Copyright (C) 2006, 2007 Jeff Muizelaar <jeff@infidigm.net>
// Copyright (C) 2006 Takashi Iwai <tiwai@suse.de>
// Copyright (C) 2006 Ed Catmur <ed@catmur.co.uk>
// Copyright (C) 2007 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
// Copyright (C) 2007, 2009 Jonathan Kew <jonathan_kew@sil.org>
// Copyright (C) 2009 Petr Gajdos <pgajdos@novell.com>
// Copyright (C) 2009, 2011, 2012, 2015 William Bader <williambader@hotmail.com>
// Copyright (C) 2009 Kovid Goyal <kovid@kovidgoyal.net>
// Copyright (C) 2010, 2012 Hib Eris <hib@hiberis.nl>
// Copyright (C) 2010 Patrick Spendrin <ps_ml@gmx.de>
// Copyright (C) 2010 Jakub Wilk <jwilk@jwilk.net>
// Copyright (C) 2011 Pino Toscano <pino@kde.org>
// Copyright (C) 2011 Koji Otani <sho@bbr.jp>
// Copyright (C) 2012 Yi Yang <ahyangyi@gmail.com>
// Copyright (C) 2012, 2017 Adrian Johnson <ajohnson@redneon.com>
// Copyright (C) 2012 Thomas Freitag <Thomas.Freitag@alfa.de>
// Copyright (C) 2012 Peter Breitenlohner <peb@mppmu.mpg.de>
// Copyright (C) 2013, 2014 Jason Crain <jason@aquaticape.us>
// Copyright (C) 2017 Christoph Cullmann <cullmann@kde.org>
// Copyright (C) 2017 Jean Ghali <jghali@libertysurf.fr>
// 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
// Copyright (C) 2018, 2020 Adam Reichold <adam.reichold@t-online.de>
// Copyright (C) 2019 Christian Persch <chpe@src.gnome.org>
// Copyright (C) 2019, 2024 Oliver Sander <oliver.sander@tu-dresden.de>
// Copyright (C) 2020 Kai Pastor <dg0yt@darc.de>
// Copyright (C) 2021, 2022 Stefan Löffler <st.loeffler@gmail.com>
// Copyright (C) 2021 sunderme <sunderme@gmx.de>
// Copyright (C) 2022 Even Rouault <even.rouault@spatialys.com>
// Copyright (C) 2022 Claes Nästén <pekdon@gmail.com>
// Copyright (C) 2023, 2024 g10 Code GmbH, Author: Sune Stolborg Vuorela <sune@vuorela.dk>
// Copyright (C) 2023 Shivodit Gill <shivodit.gill@gmail.com>
// Copyright (C) 2024 Keyu Tao <me@taoky.moe>
//
// To see a description of the changes please see the Changelog file that
// came with your tarball or type make ChangeLog if you are building from git
//
//========================================================================
#include <config.h>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cctype>
#ifdef _WIN32
# include <shlobj.h>
# include <mbstring.h>
#endif
#ifdef ANDROID
# include <android/font.h>
# include <android/font_matcher.h>
# include <android/system_fonts.h>
#endif
#include "goo/glibc.h"
#include "goo/gmem.h"
#include "goo/GooString.h"
#include "goo/gfile.h"
#include "goo/gdir.h"
#include "Error.h"
#include "NameToCharCode.h"
#include "CharCodeToUnicode.h"
#include "UnicodeMap.h"
#include "CMap.h"
#include "FontEncodingTables.h"
#include "GlobalParams.h"
#include "GfxFont.h"
#ifdef WITH_FONTCONFIGURATION_FONTCONFIG
# include <fontconfig/fontconfig.h>
#endif
#ifndef _MSC_VER
# include <strings.h>
#endif
#ifndef FC_WEIGHT_BOOK
# define FC_WEIGHT_BOOK 75
#endif
#include "NameToUnicodeTable.h"
#include "UnicodeMapTables.h"
#include "UnicodeMapFuncs.h"
#include "fofi/FoFiTrueType.h"
#include "fofi/FoFiIdentifier.h"
//------------------------------------------------------------------------
#define cidToUnicodeCacheSize 4
#define unicodeToUnicodeCacheSize 4
//------------------------------------------------------------------------
std::unique_ptr<GlobalParams> globalParams;
#if defined(ENABLE_RELOCATABLE) && defined(_WIN32)
/* search for data relative to where we are installed */
static HMODULE hmodule;
extern "C" {
/* Provide declaration to squelch -Wmissing-declarations warning */
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved);
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason) {
case DLL_PROCESS_ATTACH:
hmodule = hinstDLL;
break;
}
return TRUE;
}
}
static std::string get_poppler_localdir(const std::string &suffix)
{
const std::string binSuffix("\\bin");
std::string retval(MAX_PATH, '\0');
if (!GetModuleFileNameA(hmodule, retval.data(), retval.size())) {
return POPPLER_DATADIR;
}
const std::string::size_type p = retval.rfind('\\');
if (p != std::string::npos) {
retval.erase(p);
if (retval.size() > binSuffix.size() && stricmp(retval.substr(p - binSuffix.size()).c_str(), binSuffix.c_str()) == 0) {
retval.erase(p - binSuffix.size());
}
}
retval += suffix;
retval.shrink_to_fit();
return retval;
}
static const char *get_poppler_datadir(void)
{
static std::string retval;
static bool beenhere = false;
if (!beenhere) {
retval = get_poppler_localdir("\\share\\poppler");
beenhere = true;
}
return retval.c_str();
}
# undef POPPLER_DATADIR
# define POPPLER_DATADIR get_poppler_datadir()
static const char *get_poppler_fontsdir(void)
{
static std::string retval;
static bool beenhere = false;
if (!beenhere) {
retval = get_poppler_localdir("\\share\\fonts");
beenhere = true;
}
return retval.c_str();
}
# undef POPPLER_FONTSDIR
# define POPPLER_FONTSDIR get_poppler_fontsdir()
#else
# define POPPLER_FONTSDIR nullptr
#endif
//------------------------------------------------------------------------
// SysFontInfo
//------------------------------------------------------------------------
class SysFontInfo
{
public:
const std::unique_ptr<GooString> name;
bool bold;
bool italic;
bool oblique;
bool fixedWidth;
const std::unique_ptr<GooString> path;
SysFontType type;
int fontNum; // for TrueType collections
const std::unique_ptr<GooString> substituteName;
SysFontInfo(std::unique_ptr<GooString> &&nameA, bool boldA, bool italicA, bool obliqueA, bool fixedWidthA, std::unique_ptr<GooString> &&pathA, SysFontType typeA, int fontNumA, std::unique_ptr<GooString> &&substituteNameA);
~SysFontInfo();
SysFontInfo(const SysFontInfo &) = delete;
SysFontInfo &operator=(const SysFontInfo &) = delete;
bool match(const SysFontInfo *fi) const;
bool match(const GooString *nameA, bool boldA, bool italicA, bool obliqueA, bool fixedWidthA) const;
bool match(const GooString *nameA, bool boldA, bool italicA) const;
};
SysFontInfo::SysFontInfo(std::unique_ptr<GooString> &&nameA, bool boldA, bool italicA, bool obliqueA, bool fixedWidthA, std::unique_ptr<GooString> &&pathA, SysFontType typeA, int fontNumA, std::unique_ptr<GooString> &&substituteNameA)
: name(std::move(nameA)), path(std::move(pathA)), substituteName(std::move(substituteNameA))
{
bold = boldA;
italic = italicA;
oblique = obliqueA;
fixedWidth = fixedWidthA;
type = typeA;
fontNum = fontNumA;
}
SysFontInfo::~SysFontInfo() = default;
bool SysFontInfo::match(const SysFontInfo *fi) const
{
return !strcasecmp(name->c_str(), fi->name->c_str()) && bold == fi->bold && italic == fi->italic && oblique == fi->oblique && fixedWidth == fi->fixedWidth;
}
bool SysFontInfo::match(const GooString *nameA, bool boldA, bool italicA, bool obliqueA, bool fixedWidthA) const
{
return !strcasecmp(name->c_str(), nameA->c_str()) && bold == boldA && italic == italicA && oblique == obliqueA && fixedWidth == fixedWidthA;
}
bool SysFontInfo::match(const GooString *nameA, bool boldA, bool italicA) const
{
return !strcasecmp(name->c_str(), nameA->c_str()) && bold == boldA && italic == italicA;
}
//------------------------------------------------------------------------
// SysFontList
//------------------------------------------------------------------------
class SysFontList
{
public:
SysFontList();
~SysFontList();
SysFontList(const SysFontList &) = delete;
SysFontList &operator=(const SysFontList &) = delete;
const SysFontInfo *find(const std::string &name, bool isFixedWidth, bool exact, const std::vector<std::string> &filesToIgnore = {});
const std::vector<SysFontInfo *> &getFonts() const { return fonts; }
#ifdef _WIN32
void scanWindowsFonts(const std::string &winFontDir);
#endif
#ifdef WITH_FONTCONFIGURATION_FONTCONFIG
void addFcFont(SysFontInfo *si) { fonts.push_back(si); }
#endif
private:
#ifdef _WIN32
SysFontInfo *makeWindowsFont(const char *name, int fontNum, const char *path);
#endif
std::vector<SysFontInfo *> fonts;
};
SysFontList::SysFontList() { }
SysFontList::~SysFontList()
{
for (auto entry : fonts) {
delete entry;
}
}
const SysFontInfo *SysFontList::find(const std::string &name, bool fixedWidth, bool exact, const std::vector<std::string> &filesToIgnore)
{
GooString *name2;
bool bold, italic, oblique;
int n;
name2 = new GooString(name);
// remove space, comma, dash chars
{
int i = 0;
while (i < name2->getLength()) {
const char c = name2->getChar(i);
if (c == ' ' || c == ',' || c == '-') {
name2->del(i);
} else {
++i;
}
}
n = name2->getLength();
}
// remove trailing "MT" (Foo-MT, Foo-BoldMT, etc.)
if (n > 2 && !strcmp(name2->c_str() + n - 2, "MT")) {
name2->del(n - 2, 2);
n -= 2;
}
// look for "Regular"
if (n > 7 && !strcmp(name2->c_str() + n - 7, "Regular")) {
name2->del(n - 7, 7);
n -= 7;
}
// look for "Italic"
if (n > 6 && !strcmp(name2->c_str() + n - 6, "Italic")) {
name2->del(n - 6, 6);
italic = true;
n -= 6;
} else {
italic = false;
}
// look for "Oblique"
if (n > 6 && !strcmp(name2->c_str() + n - 7, "Oblique")) {
name2->del(n - 7, 7);
oblique = true;
n -= 6;
} else {
oblique = false;
}
// look for "Bold"
if (n > 4 && !strcmp(name2->c_str() + n - 4, "Bold")) {
name2->del(n - 4, 4);
bold = true;
n -= 4;
} else {
bold = false;
}
// remove trailing "MT" (FooMT-Bold, etc.)
if (n > 2 && !strcmp(name2->c_str() + n - 2, "MT")) {
name2->del(n - 2, 2);
n -= 2;
}
// remove trailing "PS"
if (n > 2 && !strcmp(name2->c_str() + n - 2, "PS")) {
name2->del(n - 2, 2);
n -= 2;
}
// remove trailing "IdentityH"
if (n > 9 && !strcmp(name2->c_str() + n - 9, "IdentityH")) {
name2->del(n - 9, 9);
n -= 9;
}
// search for the font
const SysFontInfo *fi = nullptr;
for (const SysFontInfo *f : fonts) {
fi = f;
if (fi->match(name2, bold, italic, oblique, fixedWidth)) {
if (std::ranges::find(filesToIgnore, fi->path->toStr()) == filesToIgnore.end()) {
break;
}
}
fi = nullptr;
}
if (!fi && !exact && bold) {
// try ignoring the bold flag
for (const SysFontInfo *f : fonts) {
fi = f;
if (fi->match(name2, false, italic)) {
if (std::ranges::find(filesToIgnore, fi->path->toStr()) == filesToIgnore.end()) {
break;
}
}
fi = nullptr;
}
}
if (!fi && !exact && (bold || italic)) {
// try ignoring the bold and italic flags
for (const SysFontInfo *f : fonts) {
fi = f;
if (fi->match(name2, false, false)) {
if (std::ranges::find(filesToIgnore, fi->path->toStr()) == filesToIgnore.end()) {
break;
}
}
fi = nullptr;
}
}
delete name2;
return fi;
}
#define globalParamsLocker() const std::scoped_lock locker(mutex)
#define unicodeMapCacheLocker() const std::scoped_lock locker(unicodeMapCacheMutex)
#define cMapCacheLocker() const std::scoped_lock locker(cMapCacheMutex)
//------------------------------------------------------------------------
// parsing
//------------------------------------------------------------------------
GlobalParams::GlobalParams(const char *customPopplerDataDir) : popplerDataDir(customPopplerDataDir)
{
// scan the encoding in reverse because we want the lowest-numbered
// index for each char name ('space' is encoded twice)
macRomanReverseMap = new NameToCharCode();
for (int i = 255; i >= 0; --i) {
if (macRomanEncoding[i]) {
macRomanReverseMap->add(macRomanEncoding[i], (CharCode)i);
}
}
nameToUnicodeZapfDingbats = new NameToCharCode();
nameToUnicodeText = new NameToCharCode();
sysFonts = new SysFontList();
textEncoding = new GooString("UTF-8");
printCommands = false;
profileCommands = false;
errQuiet = false;
cidToUnicodeCache = std::make_unique<CharCodeToUnicodeCache>(cidToUnicodeCacheSize);
unicodeToUnicodeCache = std::make_unique<CharCodeToUnicodeCache>(unicodeToUnicodeCacheSize);
unicodeMapCache = new UnicodeMapCache();
cMapCache = new CMapCache();
utf8Map = nullptr;
baseFontsInitialized = false;
// set up the initial nameToUnicode tables
for (int i = 0; nameToUnicodeZapfDingbatsTab[i].name; ++i) {
nameToUnicodeZapfDingbats->add(nameToUnicodeZapfDingbatsTab[i].name, nameToUnicodeZapfDingbatsTab[i].u);
}
for (int i = 0; nameToUnicodeTextTab[i].name; ++i) {
nameToUnicodeText->add(nameToUnicodeTextTab[i].name, nameToUnicodeTextTab[i].u);
}
// set up the residentUnicodeMaps table
residentUnicodeMaps.reserve(6);
UnicodeMap map = { "Latin1", false, latin1UnicodeMapRanges, latin1UnicodeMapLen };
residentUnicodeMaps.emplace(map.getEncodingName(), std::move(map));
map = { "ASCII7", false, ascii7UnicodeMapRanges, ascii7UnicodeMapLen };
residentUnicodeMaps.emplace(map.getEncodingName(), std::move(map));
map = { "Symbol", false, symbolUnicodeMapRanges, symbolUnicodeMapLen };
residentUnicodeMaps.emplace(map.getEncodingName(), std::move(map));
map = { "ZapfDingbats", false, zapfDingbatsUnicodeMapRanges, zapfDingbatsUnicodeMapLen };
residentUnicodeMaps.emplace(map.getEncodingName(), std::move(map));
map = { "UTF-8", true, &mapUTF8 };
residentUnicodeMaps.emplace(map.getEncodingName(), std::move(map));
map = { "UTF-16", true, &mapUTF16 };
residentUnicodeMaps.emplace(map.getEncodingName(), std::move(map));
scanEncodingDirs();
}
void GlobalParams::scanEncodingDirs()
{
GDir *dir;
std::unique_ptr<GDirEntry> entry;
const char *dataRoot = popplerDataDir ? popplerDataDir : POPPLER_DATADIR;
// allocate buffer large enough to append "/nameToUnicode"
size_t bufSize = strlen(dataRoot) + strlen("/nameToUnicode") + 1;
char *dataPathBuffer = new char[bufSize];
snprintf(dataPathBuffer, bufSize, "%s/nameToUnicode", dataRoot);
dir = new GDir(dataPathBuffer, true);
while (entry = dir->getNextEntry(), entry != nullptr) {
if (!entry->isDir()) {
parseNameToUnicode(entry->getFullPath());
}
}
delete dir;
snprintf(dataPathBuffer, bufSize, "%s/cidToUnicode", dataRoot);
dir = new GDir(dataPathBuffer, false);
while (entry = dir->getNextEntry(), entry != nullptr) {
addCIDToUnicode(entry->getName(), entry->getFullPath());
}
delete dir;
snprintf(dataPathBuffer, bufSize, "%s/unicodeMap", dataRoot);
dir = new GDir(dataPathBuffer, false);
while (entry = dir->getNextEntry(), entry != nullptr) {
addUnicodeMap(entry->getName(), entry->getFullPath());
}
delete dir;
snprintf(dataPathBuffer, bufSize, "%s/cMap", dataRoot);
dir = new GDir(dataPathBuffer, false);
while (entry = dir->getNextEntry(), entry != nullptr) {
addCMapDir(entry->getName(), entry->getFullPath());
toUnicodeDirs.push_back(entry->getFullPath()->copy());
}
delete dir;
delete[] dataPathBuffer;
}
void GlobalParams::parseNameToUnicode(const GooString *name)
{
char *tok1, *tok2;
FILE *f;
char buf[256];
int line;
Unicode u;
char *tokptr;
if (!(f = openFile(name->c_str(), "r"))) {
error(errIO, -1, "Couldn't open 'nameToUnicode' file '{0:t}'", name);
return;
}
line = 1;
while (getLine(buf, sizeof(buf), f)) {
tok1 = strtok_r(buf, " \t\r\n", &tokptr);
tok2 = strtok_r(nullptr, " \t\r\n", &tokptr);
if (tok1 && tok2) {
sscanf(tok1, "%x", &u);
nameToUnicodeText->add(tok2, u);
} else {
error(errConfig, -1, "Bad line in 'nameToUnicode' file ({0:t}:{1:d})", name, line);
}
++line;
}
fclose(f);
}
void GlobalParams::addCIDToUnicode(const GooString *collection, const GooString *fileName)
{
cidToUnicodes[collection->toStr()] = fileName->toStr();
}
void GlobalParams::addUnicodeMap(const GooString *encodingName, const GooString *fileName)
{
unicodeMaps[encodingName->toStr()] = fileName->toStr();
}
void GlobalParams::addCMapDir(const GooString *collection, const GooString *dir)
{
cMapDirs.emplace(collection->toStr(), dir->toStr());
}
bool GlobalParams::parseYesNo2(const char *token, bool *flag)
{
if (!strcmp(token, "yes")) {
*flag = true;
} else if (!strcmp(token, "no")) {
*flag = false;
} else {
return false;
}
return true;
}
GlobalParams::~GlobalParams()
{
delete macRomanReverseMap;
delete nameToUnicodeZapfDingbats;
delete nameToUnicodeText;
delete sysFonts;
delete textEncoding;
delete unicodeMapCache;
delete cMapCache;
}
//------------------------------------------------------------------------
// accessors
//------------------------------------------------------------------------
CharCode GlobalParams::getMacRomanCharCode(const char *charName)
{
// no need to lock - macRomanReverseMap is constant
return macRomanReverseMap->lookup(charName);
}
Unicode GlobalParams::mapNameToUnicodeAll(const char *charName)
{
// no need to lock - nameToUnicodeZapfDingbats and nameToUnicodeText are constant
Unicode u = nameToUnicodeZapfDingbats->lookup(charName);
if (!u) {
u = nameToUnicodeText->lookup(charName);
}
return u;
}
Unicode GlobalParams::mapNameToUnicodeText(const char *charName)
{
// no need to lock - nameToUnicodeText is constant
return nameToUnicodeText->lookup(charName);
}
UnicodeMap *GlobalParams::getResidentUnicodeMap(const std::string &encodingName)
{
UnicodeMap *map = nullptr;
globalParamsLocker();
const auto unicodeMap = residentUnicodeMaps.find(encodingName);
if (unicodeMap != residentUnicodeMaps.end()) {
map = &unicodeMap->second;
}
return map;
}
FILE *GlobalParams::getUnicodeMapFile(const std::string &encodingName)
{
FILE *file = nullptr;
globalParamsLocker();
const auto unicodeMap = unicodeMaps.find(encodingName);
if (unicodeMap != unicodeMaps.end()) {
file = openFile(unicodeMap->second.c_str(), "r");
}
return file;
}
FILE *GlobalParams::findCMapFile(const GooString &collection, const GooString &cMapName)
{
FILE *file = nullptr;
globalParamsLocker();
const auto collectionCMapDirs = cMapDirs.equal_range(collection.toStr());
for (auto cMapDir = collectionCMapDirs.first; cMapDir != collectionCMapDirs.second; ++cMapDir) {
auto *const path = new GooString(cMapDir->second);
appendToPath(path, cMapName.c_str());
file = openFile(path->c_str(), "r");
delete path;
if (file) {
break;
}
}
return file;
}
FILE *GlobalParams::findToUnicodeFile(const GooString *name)
{
GooString *fileName;
FILE *f;
globalParamsLocker();
for (const std::unique_ptr<GooString> &dir : toUnicodeDirs) {
fileName = appendToPath(dir->copy().release(), name->c_str());
f = openFile(fileName->c_str(), "r");
delete fileName;
if (f) {
return f;
}
}
return nullptr;
}
#ifdef WITH_FONTCONFIGURATION_FONTCONFIG
static bool findModifier(const std::string &name, const size_t modStart, const char *modifier, size_t &start)
{
if (modStart == std::string::npos) {
return false;
}
size_t match = name.find(modifier, modStart);
if (match == std::string::npos) {
return false;
} else {
if (start == std::string::npos || match < start) {
start = match;
}
return true;
}
}
static const char *getFontLang(const GfxFont *font)
{
const char *lang;
// find the language we want the font to support
if (font->isCIDFont()) {
const GooString *collection = ((GfxCIDFont *)font)->getCollection();
if (collection) {
if (strcmp(collection->c_str(), "Adobe-GB1") == 0) {
lang = "zh-cn"; // Simplified Chinese
} else if (strcmp(collection->c_str(), "Adobe-CNS1") == 0) {
lang = "zh-tw"; // Traditional Chinese
} else if (strcmp(collection->c_str(), "Adobe-Japan1") == 0) {
lang = "ja"; // Japanese
} else if (strcmp(collection->c_str(), "Adobe-Japan2") == 0) {
lang = "ja"; // Japanese
} else if (strcmp(collection->c_str(), "Adobe-Korea1") == 0) {
lang = "ko"; // Korean
} else if (strcmp(collection->c_str(), "Adobe-UCS") == 0) {
lang = "xx";
} else if (strcmp(collection->c_str(), "Adobe-Identity") == 0) {
lang = "xx";
} else {
error(errUnimplemented, -1, "Unknown CID font collection: {0:t}. If this is expected to be a valid PDF document, please report to poppler bugtracker.", collection);
lang = "xx";
}
} else {
lang = "xx";
}
} else {
lang = "xx";
}
return lang;
}
static FcPattern *buildFcPattern(const GfxFont *font, const GooString *base14Name)
{
int weight = -1, slant = -1, width = -1, spacing = -1;
FcPattern *p;
// this is all heuristics will be overwritten if font had proper info
std::string fontName;
if (base14Name == nullptr) {
fontName = font->getNameWithoutSubsetTag();
} else {
fontName = base14Name->toStr();
}
size_t modStart = fontName.find(',');
if (modStart == std::string::npos) {
modStart = fontName.find('-');
}
// remove the - from the names, for some reason, Fontconfig does not
// understand "MS-Mincho" but does with "MS Mincho"
std::replace(fontName.begin(), fontName.end(), '-', ' ');
size_t start = std::string::npos;
findModifier(fontName, modStart, "Regular", start);
findModifier(fontName, modStart, "Roman", start);
if (findModifier(fontName, modStart, "Oblique", start)) {
slant = FC_SLANT_OBLIQUE;
}
if (findModifier(fontName, modStart, "Italic", start)) {
slant = FC_SLANT_ITALIC;
}
if (findModifier(fontName, modStart, "Bold", start)) {
weight = FC_WEIGHT_BOLD;
}
if (findModifier(fontName, modStart, "Light", start)) {
weight = FC_WEIGHT_LIGHT;
}
if (findModifier(fontName, modStart, "Medium", start)) {
weight = FC_WEIGHT_MEDIUM;
}
if (findModifier(fontName, modStart, "Condensed", start)) {
width = FC_WIDTH_CONDENSED;
}
std::string family;
if (start == std::string::npos) {
family = fontName;
} else {
// There have been "modifiers" in the name, crop them to obtain
// the family name
family = fontName.substr(0, modStart);
}
// use font flags
if (font->isFixedWidth()) {
spacing = FC_MONO;
}
if (font->isBold()) {
weight = FC_WEIGHT_BOLD;
}
if (font->isItalic()) {
slant = FC_SLANT_ITALIC;
}
// if the FontDescriptor specified a family name use it
if (font->getFamily()) {
family = font->getFamily()->toStr();
}
// if the FontDescriptor specified a weight use it
switch (font->getWeight()) {
case GfxFont::W100:
weight = FC_WEIGHT_EXTRALIGHT;
break;
case GfxFont::W200:
weight = FC_WEIGHT_LIGHT;
break;
case GfxFont::W300:
weight = FC_WEIGHT_BOOK;
break;
case GfxFont::W400:
weight = FC_WEIGHT_NORMAL;
break;
case GfxFont::W500:
weight = FC_WEIGHT_MEDIUM;
break;
case GfxFont::W600:
weight = FC_WEIGHT_DEMIBOLD;
break;
case GfxFont::W700:
weight = FC_WEIGHT_BOLD;
break;
case GfxFont::W800:
weight = FC_WEIGHT_EXTRABOLD;
break;
case GfxFont::W900:
weight = FC_WEIGHT_BLACK;
break;
default:
break;
}
// if the FontDescriptor specified a width use it
switch (font->getStretch()) {
case GfxFont::UltraCondensed:
width = FC_WIDTH_ULTRACONDENSED;
break;
case GfxFont::ExtraCondensed:
width = FC_WIDTH_EXTRACONDENSED;
break;
case GfxFont::Condensed:
width = FC_WIDTH_CONDENSED;
break;
case GfxFont::SemiCondensed:
width = FC_WIDTH_SEMICONDENSED;
break;
case GfxFont::Normal:
width = FC_WIDTH_NORMAL;
break;
case GfxFont::SemiExpanded:
width = FC_WIDTH_SEMIEXPANDED;
break;
case GfxFont::Expanded:
width = FC_WIDTH_EXPANDED;
break;
case GfxFont::ExtraExpanded:
width = FC_WIDTH_EXTRAEXPANDED;
break;
case GfxFont::UltraExpanded:
width = FC_WIDTH_ULTRAEXPANDED;
break;
default:
break;
}
const char *lang = getFontLang(font);
p = FcPatternBuild(nullptr, FC_FAMILY, FcTypeString, family.c_str(), FC_LANG, FcTypeString, lang, NULL);
if (slant != -1) {
FcPatternAddInteger(p, FC_SLANT, slant);
}
if (weight != -1) {
FcPatternAddInteger(p, FC_WEIGHT, weight);
}
if (width != -1) {
FcPatternAddInteger(p, FC_WIDTH, width);
}
if (spacing != -1) {
FcPatternAddInteger(p, FC_SPACING, spacing);
}
return p;
}
#endif
std::optional<std::string> GlobalParams::findFontFile(const std::string &fontName)
{
setupBaseFonts(POPPLER_FONTSDIR);
globalParamsLocker();
const auto fontFile = fontFiles.find(fontName);
if (fontFile != fontFiles.end()) {
return fontFile->second;
}
return {};
}
#if defined(WITH_FONTCONFIGURATION_FONTCONFIG) || defined(WITH_FONTCONFIGURATION_WIN32)
static bool supportedFontForEmbedding(Unicode uChar, const char *filepath, int faceIndex)
{
if (!std::string_view(filepath).ends_with(".ttf") && !std::string_view(filepath).ends_with(".ttc") && !std::string_view(filepath).ends_with(".otf")) {
// for now we only support ttf, ttc, otf fonts
return false;
}
const FoFiIdentifierType fontFoFiType = FoFiIdentifier::identifyFile(filepath);
if (fontFoFiType != fofiIdTrueType && fontFoFiType != fofiIdTrueTypeCollection && fontFoFiType != fofiIdOpenTypeCFF8Bit && fontFoFiType != fofiIdOpenTypeCFFCID) {
// for now we only support ttf, ttc, otf fonts
return false;
}
const std::unique_ptr<FoFiTrueType> fft = FoFiTrueType::load(filepath, faceIndex);
if (!fft) {
error(errIO, -1, "Form::addFontToDefaultResources. Failed to FoFiTrueType::load {0:s}", filepath);
return false;
}
// Look for the Unicode BMP cmaps, which are 0/3 or 3/1
int unicodeBMPCMap = fft->findCmap(0, 3);
if (unicodeBMPCMap < 0) {
unicodeBMPCMap = fft->findCmap(3, 1);
}
if (unicodeBMPCMap < 0) {
// for now we only support files with unicode bmp cmaps
return false;
}
const int glyph = fft->mapCodeToGID(unicodeBMPCMap, uChar);
return glyph > 0;
}
#endif
/* if you can't or don't want to use Fontconfig, you need to implement
this function for your platform. For Windows, it's in GlobalParamsWin.cc
*/
#ifdef WITH_FONTCONFIGURATION_FONTCONFIG
// not needed for fontconfig
void GlobalParams::setupBaseFonts(const char *) { }
std::optional<std::string> GlobalParams::findBase14FontFile(const GooString *base14Name, const GfxFont *font, GooString *substituteFontName)
{
SysFontType type;
int fontNum;
return findSystemFontFile(font, &type, &fontNum, substituteFontName, base14Name);
}
std::optional<std::string> GlobalParams::findSystemFontFile(const GfxFont *font, SysFontType *type, int *fontNum, GooString *substituteFontName, const GooString *base14Name)
{
const SysFontInfo *fi = nullptr;
FcPattern *p = nullptr;
std::optional<std::string> path;
const std::optional<std::string> &fontName = font->getName();
GooString substituteName;
if (!fontName) {
return {};
}
globalParamsLocker();
if ((fi = sysFonts->find(*fontName, font->isFixedWidth(), true))) {
path = fi->path->toStr();
*type = fi->type;
*fontNum = fi->fontNum;
substituteName.Set(fi->substituteName->c_str());
} else {
FcChar8 *s;
char *ext;
FcResult res;
FcFontSet *set;
int i;
FcLangSet *lb = nullptr;
p = buildFcPattern(font, base14Name);
if (!p) {
goto fin;
}
FcConfigSubstitute(nullptr, p, FcMatchPattern);
FcDefaultSubstitute(p);
set = FcFontSort(nullptr, p, FcFalse, nullptr, &res);
if (!set) {
goto fin;
}
// find the language we want the font to support
const char *lang = getFontLang(font);
if (strcmp(lang, "xx") != 0) {
lb = FcLangSetCreate();
FcLangSetAdd(lb, (FcChar8 *)lang);
}
/*
scan twice.
first: fonts support the language
second: all fonts (fall back)
*/
while (fi == nullptr) {
for (i = 0; i < set->nfont; ++i) {
res = FcPatternGetString(set->fonts[i], FC_FILE, 0, &s);
if (res != FcResultMatch || !s) {
continue;
}
if (lb != nullptr) {
FcLangSet *l;
res = FcPatternGetLangSet(set->fonts[i], FC_LANG, 0, &l);
if (res != FcResultMatch || !FcLangSetContains(l, lb)) {
continue;
}
}
FcChar8 *s2;
res = FcPatternGetString(set->fonts[i], FC_FULLNAME, 0, &s2);
if (res == FcResultMatch && s2) {
substituteName.Set((char *)s2);
} else {
// fontconfig does not extract fullname for some fonts
// create the fullname from family and style
res = FcPatternGetString(set->fonts[i], FC_FAMILY, 0, &s2);
if (res == FcResultMatch && s2) {
substituteName.Set((char *)s2);
res = FcPatternGetString(set->fonts[i], FC_STYLE, 0, &s2);
if (res == FcResultMatch && s2) {
GooString *style = new GooString((char *)s2);
if (style->cmp("Regular") != 0) {
substituteName.append(" ");
substituteName.append(style);
}
delete style;
}
}
}
ext = strrchr((char *)s, '.');
if (!ext) {
continue;
}
if (!strncasecmp(ext, ".ttf", 4) || !strncasecmp(ext, ".ttc", 4) || !strncasecmp(ext, ".otf", 4)) {
int weight, slant;
bool bold = font->isBold();
bool italic = font->isItalic();
bool oblique = false;
FcPatternGetInteger(set->fonts[i], FC_WEIGHT, 0, &weight);
FcPatternGetInteger(set->fonts[i], FC_SLANT, 0, &slant);
if (weight == FC_WEIGHT_DEMIBOLD || weight == FC_WEIGHT_BOLD || weight == FC_WEIGHT_EXTRABOLD || weight == FC_WEIGHT_BLACK) {
bold = true;
}
if (slant == FC_SLANT_ITALIC) {
italic = true;
}
if (slant == FC_SLANT_OBLIQUE) {
oblique = true;
}
*fontNum = 0;
*type = (!strncasecmp(ext, ".ttc", 4)) ? sysFontTTC : sysFontTTF;
FcPatternGetInteger(set->fonts[i], FC_INDEX, 0, fontNum);
SysFontInfo *sfi = new SysFontInfo(std::make_unique<GooString>(*fontName), bold, italic, oblique, font->isFixedWidth(), std::make_unique<GooString>((char *)s), *type, *fontNum, substituteName.copy());
sysFonts->addFcFont(sfi);
fi = sfi;
path = std::string((char *)s);
} else if (!strncasecmp(ext, ".pfa", 4) || !strncasecmp(ext, ".pfb", 4)) {
int weight, slant;
bool bold = font->isBold();
bool italic = font->isItalic();
bool oblique = false;
FcPatternGetInteger(set->fonts[i], FC_WEIGHT, 0, &weight);
FcPatternGetInteger(set->fonts[i], FC_SLANT, 0, &slant);
if (weight == FC_WEIGHT_DEMIBOLD || weight == FC_WEIGHT_BOLD || weight == FC_WEIGHT_EXTRABOLD || weight == FC_WEIGHT_BLACK) {
bold = true;
}
if (slant == FC_SLANT_ITALIC) {
italic = true;
}
if (slant == FC_SLANT_OBLIQUE) {
oblique = true;
}
*fontNum = 0;
*type = (!strncasecmp(ext, ".pfa", 4)) ? sysFontPFA : sysFontPFB;
FcPatternGetInteger(set->fonts[i], FC_INDEX, 0, fontNum);
SysFontInfo *sfi = new SysFontInfo(std::make_unique<GooString>(*fontName), bold, italic, oblique, font->isFixedWidth(), std::make_unique<GooString>((char *)s), *type, *fontNum, substituteName.copy());
sysFonts->addFcFont(sfi);
fi = sfi;
path = std::string((char *)s);
} else {
continue;
}
break;
}
if (lb != nullptr) {
FcLangSetDestroy(lb);
lb = nullptr;
} else {
/* scan all fonts of the list */
break;
}
}
FcFontSetDestroy(set);
}
if (!path && (fi = sysFonts->find(*fontName, font->isFixedWidth(), false))) {
path = fi->path->toStr();
*type = fi->type;
*fontNum = fi->fontNum;
}
if (substituteFontName) {
substituteFontName->Set(substituteName.c_str());
}
fin:
if (p) {
FcPatternDestroy(p);
}
return path;
}
FamilyStyleFontSearchResult GlobalParams::findSystemFontFileForFamilyAndStyle(const std::string &fontFamily, const std::string &fontStyle, const std::vector<std::string> &filesToIgnore)
{
FcPattern *p = FcPatternBuild(nullptr, FC_FAMILY, FcTypeString, fontFamily.c_str(), FC_STYLE, FcTypeString, fontStyle.c_str(), nullptr);
FcConfigSubstitute(nullptr, p, FcMatchPattern);
FcDefaultSubstitute(p);
if (p) {
const std::unique_ptr<FcPattern, void (*)(FcPattern *)> pDeleter(p, [](FcPattern *pattern) { FcPatternDestroy(pattern); });
FcResult res;
FcFontSet *fontSet = FcFontSort(nullptr, p, FcFalse, nullptr, &res);
if (fontSet) {
const std::unique_ptr<FcFontSet, void (*)(FcFontSet *)> fontSetDeleter(fontSet, [](FcFontSet *fSet) { FcFontSetDestroy(fSet); });
if (res == FcResultMatch) {
for (int i = 0; i < fontSet->nfont; i++) {
FcChar8 *fcFilePath = nullptr;
int faceIndex = 0;
FcPatternGetString(fontSet->fonts[i], FC_FILE, 0, &fcFilePath);
FcPatternGetInteger(fontSet->fonts[i], FC_INDEX, 0, &faceIndex);
const std::string sFilePath = reinterpret_cast<char *>(fcFilePath);
if (std::ranges::find(filesToIgnore, sFilePath) == filesToIgnore.end()) {
return FamilyStyleFontSearchResult(sFilePath, faceIndex);
}
}
}
}
}
error(errIO, -1, "Couldn't find font file for {0:s} {1:s}", fontFamily.c_str(), fontStyle.c_str());
return {};
}
UCharFontSearchResult GlobalParams::findSystemFontFileForUChar(Unicode uChar, const GfxFont &fontToEmulate)
{
FcPattern *pattern = buildFcPattern(&fontToEmulate, nullptr);
FcConfigSubstitute(nullptr, pattern, FcMatchPattern);
FcDefaultSubstitute(pattern);
FcResult result = FcResultMatch;
FcFontSet *fontSet = FcFontSort(nullptr, pattern, FcFalse, nullptr, &result);
FcPatternDestroy(pattern);
if (fontSet) {
const std::unique_ptr<FcFontSet, void (*)(FcFontSet *)> fontSetDeleter(fontSet, [](FcFontSet *fSet) { FcFontSetDestroy(fSet); });
for (int i = 0; i < fontSet->nfont; i++) {
FcChar8 *fcFilePath = nullptr;
int faceIndex = 0;
FcChar8 *fcFamily = nullptr;
FcChar8 *fcStyle = nullptr;
FcCharSet *fcCharSet = nullptr;
FcPatternGetString(fontSet->fonts[i], FC_FILE, 0, &fcFilePath);
FcPatternGetInteger(fontSet->fonts[i], FC_INDEX, 0, &faceIndex);
FcPatternGetString(fontSet->fonts[i], FC_FAMILY, 0, &fcFamily);
FcPatternGetString(fontSet->fonts[i], FC_STYLE, 0, &fcStyle);
FcPatternGetCharSet(fontSet->fonts[i], FC_CHARSET, 0, &fcCharSet);
if (!fcFilePath || !fcFamily || !fcStyle || !fcCharSet) {
continue;
}
if (!FcCharSetHasChar(fcCharSet, uChar)) {
continue;
}
const char *filepath = reinterpret_cast<char *>(fcFilePath);
if (supportedFontForEmbedding(uChar, filepath, faceIndex)) {
return UCharFontSearchResult(filepath, faceIndex, reinterpret_cast<char *>(fcFamily), reinterpret_cast<char *>(fcStyle));
}
}
}
return {};
}
#elif defined(WITH_FONTCONFIGURATION_ANDROID)
// Uses the font file mapping created by GlobalParams::setupBaseFonts
// to return the path to a base-14 font file
std::optional<std::string> GlobalParams::findBase14FontFile(const GooString *base14Name, const GfxFont *font, GooString *substituteFontName)
{
return findFontFile(base14Name->toStr());
}
# if __ANDROID_API__ >= 29
// This struct is used by the AFontMatcher unique_ptr for destroying the
// AFontMatcher object
struct AFontMatcherDestroyer
{
void operator()(AFontMatcher *fontmatcher) { AFontMatcher_destroy(fontmatcher); }
};
// This struct is used by the AFontMatcher unique_ptr for destroying the
// AFont object
struct AFontDestroyer
{
void operator()(AFont *afont) { AFont_close(afont); }
};
# endif
std::optional<std::string> GlobalParams::findSystemFontFile(const GfxFont *font, SysFontType *type, int *fontNum, GooString *substituteFontName, const GooString *base14Name)
{
const std::optional<std::string> &fontName = font->getName();
if (!fontName) {
return {};
}
globalParamsLocker();
# if __ANDROID_API__ >= 29
// If font is not found in the default base-14 fonts,
// use Android-NDK's AFontMatcher API instead.
// Documentation for AFontMatcher API can be found at:
// https://developer.android.com/ndk/reference/group/font
std::string genericFontFamily = "serif";
if (!font->isSerif()) {
genericFontFamily = "sans-serif";
} else if (font->isFixedWidth()) {
genericFontFamily = "monospace";
}
std::unique_ptr<AFontMatcher, AFontMatcherDestroyer> fontmatcher { AFontMatcher_create() };
// Set font weight and italics for the font.
AFontMatcher_setStyle(fontmatcher.get(), font->getWeight() * 100, font->isItalic());
// Get font match and the font file's path
std::unique_ptr<AFont, AFontDestroyer> afont { AFontMatcher_match(fontmatcher.get(), genericFontFamily.c_str(), (uint16_t *)u"A", 1, nullptr) };
std::string path = std::string(AFont_getFontFilePath(afont.get()));
// Set the type of font. Fonts returned by AFontMatcher are of
// four possible types - ttf, otf, ttc, otc.
if (path.ends_with(".ttf") || path.ends_with(".otf")) {
*type = sysFontTTF;
} else if (path.ends_with(".ttc") || path.ends_with(".otc")) {
*type = sysFontTTC;
}
# else
# pragma message("Compiling without AFontMatcher API due to Android API version being lower than 29.")
# endif
return path;
}
static struct
{
const char *name;
const char *otFileName;
} displayFontTab[] = { { "Courier", "NimbusMonoPS-Regular.otf" },
{ "Courier-Bold", "NimbusMonoPS-Bold.otf" },
{ "Courier-BoldOblique", "NimbusMonoPS-BoldItalic.otf" },
{ "Courier-Oblique", "NimbusMonoPS-Italic.otf" },
{ "Helvetica", "NimbusSans-Regular.otf" },
{ "Helvetica-Bold", "NimbusSans-Bold.otf" },
{ "Helvetica-BoldOblique", "NimbusSans-BoldItalic.otf" },
{ "Helvetica-Oblique", "NimbusSans-Italic.otf" },
{ "Symbol", "StandardSymbolsPS.otf" },
{ "Times-Bold", "NimbusRoman-Bold.otf" },
{ "Times-BoldItalic", "NimbusRoman-BoldItalic.otf" },
{ "Times-Italic", "NimbusRoman-Italic.otf" },
{ "Times-Roman", "NimbusRoman-Regular.otf" },
{ "ZapfDingbats", "D050000L.otf" },
{ nullptr, nullptr } };
// The path to the font directory. Set by GlobalParams::setFontDir()
static std::string displayFontDir;
// This method creates a mapping from base-14 font names to their
// paths on the file system. On Android, it searches within the
// directory set by GlobalParams::setFontDir().
void GlobalParams::setupBaseFonts(const char *dir)
{
FILE *f;
int i;
for (i = 0; displayFontTab[i].name; ++i) {
if (fontFiles.count(displayFontTab[i].name) > 0) {
continue;
}
std::unique_ptr<GooString> fontName = std::make_unique<GooString>(displayFontTab[i].name);
std::unique_ptr<GooString> fileName;
if (dir) {
fileName.reset(appendToPath(new GooString(dir), displayFontTab[i].otFileName));
if ((f = openFile(fileName->c_str(), "rb"))) {
fclose(f);
} else {
fileName.reset();
}
}
if (!displayFontDir.empty()) {
fileName.reset(appendToPath(new GooString(displayFontDir), displayFontTab[i].otFileName));
if ((f = openFile(fileName->c_str(), "rb"))) {
fclose(f);
} else {
fileName.reset();
}
}
if (!fileName) {
error(errConfig, -1, "No display font for '{0:s}'", displayFontTab[i].name);
continue;
}
addFontFile(fontName->toStr(), fileName->toStr());
}
}
FamilyStyleFontSearchResult GlobalParams::findSystemFontFileForFamilyAndStyle(const std::string &fontFamily, const std::string &fontStyle, const std::vector<std::string> &filesToIgnore)
{
error(errUnimplemented, -1, "GlobalParams::findSystemFontFileForFamilyAndStyle not implemented for this platform");
return {};
}
UCharFontSearchResult GlobalParams::findSystemFontFileForUChar(Unicode uChar, const GfxFont &fontToEmulate)
{
error(errUnimplemented, -1, "GlobalParams::findSystemFontFileForUChar not implemented for this platform");
return {};
}
#elif defined(WITH_FONTCONFIGURATION_WIN32)
# include "GlobalParamsWin.cc"
std::optional<std::string> GlobalParams::findBase14FontFile(const GooString *base14Name, const GfxFont *font, GooString * /*substituteFontName*/)
{
return findFontFile(base14Name->toStr());
}
#else
FamilyStyleFontSearchResult GlobalParams::findSystemFontFileForFamilyAndStyle(const std::string &fontFamily, const std::string &fontStyle, const std::vector<std::string> &filesToIgnore)
{
error(errUnimplemented, -1, "GlobalParams::findSystemFontFileForFamilyAndStyle not implemented for this platform");
return {};
}
UCharFontSearchResult GlobalParams::findSystemFontFileForUChar(Unicode uChar, const GfxFont &fontToEmulate)
{
error(errUnimplemented, -1, "GlobalParams::findSystemFontFileForUChar not implemented for this platform");
return {};
}
std::optional<std::string> GlobalParams::findBase14FontFile(const GooString *base14Name, const GfxFont *font, GooString * /*substituteFontName*/)
{
return findFontFile(base14Name->toStr());
}
static struct
{
const char *name;
const char *t1FileName;
const char *ttFileName;
} displayFontTab[] = { { "Courier", "n022003l.pfb", "cour.ttf" },
{ "Courier-Bold", "n022004l.pfb", "courbd.ttf" },
{ "Courier-BoldOblique", "n022024l.pfb", "courbi.ttf" },
{ "Courier-Oblique", "n022023l.pfb", "couri.ttf" },
{ "Helvetica", "n019003l.pfb", "arial.ttf" },
{ "Helvetica-Bold", "n019004l.pfb", "arialbd.ttf" },
{ "Helvetica-BoldOblique", "n019024l.pfb", "arialbi.ttf" },
{ "Helvetica-Oblique", "n019023l.pfb", "ariali.ttf" },
{ "Symbol", "s050000l.pfb", nullptr },
{ "Times-Bold", "n021004l.pfb", "timesbd.ttf" },
{ "Times-BoldItalic", "n021024l.pfb", "timesbi.ttf" },
{ "Times-Italic", "n021023l.pfb", "timesi.ttf" },
{ "Times-Roman", "n021003l.pfb", "times.ttf" },
{ "ZapfDingbats", "d050000l.pfb", nullptr },
{ nullptr, nullptr, nullptr } };
static 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 };
void GlobalParams::setupBaseFonts(const char *dir)
{
FILE *f;
int i, j;
for (i = 0; displayFontTab[i].name; ++i) {
if (fontFiles.count(displayFontTab[i].name) > 0) {
continue;
}
std::unique_ptr<GooString> fontName = std::make_unique<GooString>(displayFontTab[i].name);
std::unique_ptr<GooString> fileName;
if (dir) {
fileName.reset(appendToPath(new GooString(dir), displayFontTab[i].t1FileName));
if ((f = openFile(fileName->c_str(), "rb"))) {
fclose(f);
} else {
fileName.reset();
}
}
for (j = 0; !fileName && displayFontDirs[j]; ++j) {
fileName.reset(appendToPath(new GooString(displayFontDirs[j]), displayFontTab[i].t1FileName));
if ((f = openFile(fileName->c_str(), "rb"))) {
fclose(f);
} else {
fileName.reset();
}
}
if (!fileName) {
error(errConfig, -1, "No display font for '{0:s}'", displayFontTab[i].name);
continue;
}
addFontFile(fontName->toStr(), fileName->toStr());
}
}
std::optional<std::string> GlobalParams::findSystemFontFile(const GfxFont *font, SysFontType *type, int *fontNum, GooString * /*substituteFontName*/, const GooString * /*base14Name*/)
{
const SysFontInfo *fi;
std::optional<std::string> path;
const std::optional<std::string> &fontName = font->getName();
if (!fontName) {
return {};
}
globalParamsLocker();
if ((fi = sysFonts->find(*fontName, font->isFixedWidth(), false))) {
path = fi->path->toStr();
*type = fi->type;
*fontNum = fi->fontNum;
}
return path;
}
#endif
std::string GlobalParams::getTextEncodingName() const
{
globalParamsLocker();
return textEncoding->toStr();
}
const UnicodeMap *GlobalParams::getUtf8Map()
{
if (!utf8Map) {
utf8Map = globalParams->getUnicodeMap("UTF-8");
}
return utf8Map;
}
bool GlobalParams::getPrintCommands()
{
globalParamsLocker();
return printCommands;
}
bool GlobalParams::getProfileCommands()
{
globalParamsLocker();
return profileCommands;
}
bool GlobalParams::getErrQuiet()
{
// no locking -- this function may get called from inside a locked
// section
return errQuiet;
}
std::shared_ptr<CharCodeToUnicode> GlobalParams::getCIDToUnicode(const GooString *collection)
{
std::shared_ptr<CharCodeToUnicode> ctu;
globalParamsLocker();
if (!(ctu = cidToUnicodeCache->getCharCodeToUnicode(collection))) {
const auto cidToUnicode = cidToUnicodes.find(collection->toStr());
if (cidToUnicode != cidToUnicodes.end()) {
if ((ctu = CharCodeToUnicode::parseCIDToUnicode(cidToUnicode->second.c_str(), collection))) {
cidToUnicodeCache->add(ctu);
}
}
}
return ctu;
}
const UnicodeMap *GlobalParams::getUnicodeMap(const std::string &encodingName)
{
const UnicodeMap *map;
if (!(map = getResidentUnicodeMap(encodingName))) {
unicodeMapCacheLocker();
map = unicodeMapCache->getUnicodeMap(encodingName);
}
return map;
}
std::shared_ptr<CMap> GlobalParams::getCMap(const GooString &collection, const GooString &cMapName)
{
cMapCacheLocker();
return cMapCache->getCMap(collection, cMapName);
}
const UnicodeMap *GlobalParams::getTextEncoding()
{
return getUnicodeMap(textEncoding->toStr());
}
std::vector<std::string> GlobalParams::getEncodingNames()
{
std::vector<std::string> result;
result.reserve(residentUnicodeMaps.size() + unicodeMaps.size());
for (const auto &unicodeMap : residentUnicodeMaps) {
result.push_back(unicodeMap.first);
}
for (const auto &unicodeMap : unicodeMaps) {
result.push_back(unicodeMap.first);
}
return result;
}
//------------------------------------------------------------------------
// functions to set parameters
//------------------------------------------------------------------------
void GlobalParams::addFontFile(const std::string &fontName, const std::string &path)
{
globalParamsLocker();
fontFiles[fontName] = path;
}
void GlobalParams::setTextEncoding(const char *encodingName)
{
globalParamsLocker();
delete textEncoding;
textEncoding = new GooString(encodingName);
}
void GlobalParams::setPrintCommands(bool printCommandsA)
{
globalParamsLocker();
printCommands = printCommandsA;
}
void GlobalParams::setProfileCommands(bool profileCommandsA)
{
globalParamsLocker();
profileCommands = profileCommandsA;
}
void GlobalParams::setErrQuiet(bool errQuietA)
{
globalParamsLocker();
errQuiet = errQuietA;
}
#ifdef ANDROID
void GlobalParams::setFontDir(const std::string &fontDir)
{
# if defined(WITH_FONTCONFIGURATION_ANDROID)
displayFontDir = fontDir;
# endif
}
#endif
GlobalParamsIniter::GlobalParamsIniter(ErrorCallback errorCallback)
{
const std::scoped_lock lock { mutex };
if (count == 0) {
globalParams = std::make_unique<GlobalParams>(!customDataDir.empty() ? customDataDir.c_str() : nullptr);
setErrorCallback(errorCallback);
}
count++;
}
GlobalParamsIniter::~GlobalParamsIniter()
{
const std::scoped_lock lock { mutex };
--count;
if (count == 0) {
globalParams.reset();
}
}
bool GlobalParamsIniter::setCustomDataDir(const std::string &dir)
{
const std::scoped_lock lock { mutex };
if (count == 0) {
customDataDir = dir;
return true;
}
return false;
}
std::mutex GlobalParamsIniter::mutex;
int GlobalParamsIniter::count = 0;
std::string GlobalParamsIniter::customDataDir;