File indexing completed on 2024-05-12 16:06:37

0001 // -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; c-brace-offset: 0; -*-
0002 // fontMap.cpp
0003 //
0004 // Part of KDVI - A DVI previewer for the KDE desktop environment
0005 //
0006 // SPDX-FileCopyrightText: 2003 Stefan Kebekus
0007 // SPDX-License-Identifier: GPL-2.0-or-later
0008 
0009 #include <config.h>
0010 
0011 #ifdef HAVE_FREETYPE
0012 
0013 #include "debug_dvi.h"
0014 #include "fontMap.h"
0015 #include <QFile>
0016 #include <QLoggingCategory>
0017 #include <QProcess>
0018 #include <QStandardPaths>
0019 #include <QTextStream>
0020 
0021 //#define DEBUG_FONTMAP
0022 
0023 fontMap::fontMap()
0024 {
0025     // Make sure kpsewhich is in PATH and not just in the CWD
0026     static const QString kpsewhichFullPath = QStandardPaths::findExecutable(QStringLiteral("kpsewhich"));
0027 
0028     // Read the map file of ps2pk which will provide us with a
0029     // dictionary "TeX Font names" <-> "Name of font files, Font Names
0030     // and Encodings" (example: the font "Times-Roman" is called
0031     // "ptmr8y" in the DVI file, but the Type1 font file name is
0032     // "utmr8a.pfb". We use the map file of "ps2pk" because that program
0033     // has, like kdvi (and unlike dvips), no built-in fonts.
0034 
0035     // Finding ps2pk.map is not easy. In teTeX < 3.0, the kpsewhich
0036     // program REQUIRES the option "--format=dvips config". In teTeX =
0037     // 3.0, the option "--format=map" MUST be used. Since there is no
0038     // way to give both options at the same time, there is seemingly no
0039     // other way than to try both options one after another. We use the
0040     // teTeX 3.0 format first.
0041     QProcess kpsewhich;
0042     kpsewhich.start(kpsewhichFullPath, QStringList() << QStringLiteral("--format=map") << QStringLiteral("ps2pk.map"), QIODevice::ReadOnly | QIODevice::Text);
0043 
0044     if (!kpsewhich.waitForStarted()) {
0045         qCCritical(OkularDviDebug) << "fontMap::fontMap(): kpsewhich could not be started.";
0046         return;
0047     }
0048 
0049     // We wait here while the external program runs concurrently.
0050     kpsewhich.waitForFinished(-1);
0051 
0052     QString map_fileName = QString::fromLocal8Bit(kpsewhich.readAll()).trimmed();
0053     if (map_fileName.isEmpty()) {
0054         // Map file not found? Then we try the teTeX < 3.0 way of finding
0055         // the file.
0056         kpsewhich.start(kpsewhichFullPath, QStringList() << QStringLiteral("--format=dvips config") << QStringLiteral("ps2pk.map"), QIODevice::ReadOnly | QIODevice::Text);
0057         if (!kpsewhich.waitForStarted()) {
0058             qCCritical(OkularDviDebug) << "fontMap::fontMap(): kpsewhich could not be started.";
0059             return;
0060         }
0061 
0062         kpsewhich.waitForFinished(-1);
0063 
0064         map_fileName = QString::fromLocal8Bit(kpsewhich.readAll()).trimmed();
0065         // If both versions fail, then there is nothing left to do.
0066         if (map_fileName.isEmpty()) {
0067             qCCritical(OkularDviDebug) << "fontMap::fontMap(): The file 'ps2pk.map' could not be found by kpsewhich.";
0068             return;
0069         }
0070     }
0071 
0072     QFile file(map_fileName);
0073     if (file.open(QIODevice::ReadOnly)) {
0074         QTextStream stream(&file);
0075         QString line;
0076         while (!stream.atEnd()) {
0077             line = stream.readLine().simplified();
0078             if (line.isEmpty() || (line.at(0) == QLatin1Char('%'))) {
0079                 continue;
0080             }
0081 
0082             QString TeXName = line.section(QLatin1Char(' '), 0, 0);
0083             QString FullName = line.section(QLatin1Char(' '), 1, 1);
0084             QString fontFileName = line.section(QLatin1Char('<'), -1).trimmed().section(QLatin1Char(' '), 0, 0);
0085             QString encodingName = line.section(QLatin1Char('<'), -2, -2).trimmed().section(QLatin1Char(' '), 0, 0);
0086             // It seems that sometimes the encoding is prepended by the
0087             // letter '[', which we ignore
0088             if ((!encodingName.isEmpty()) && (encodingName[0] == QLatin1Char('['))) {
0089                 encodingName = encodingName.mid(1);
0090             }
0091 
0092             double slant = 0.0;
0093             int i = line.indexOf(QStringLiteral("SlantFont"));
0094             if (i >= 0) {
0095                 bool ok;
0096                 slant = line.left(i).section(QLatin1Char(' '), -1, -1, QString::SectionSkipEmpty).toDouble(&ok);
0097                 if (ok == false) {
0098                     slant = 0.0;
0099                 }
0100             }
0101 
0102             fontMapEntry &entry = fontMapEntries[TeXName];
0103 
0104             entry.slant = slant;
0105             entry.fontFileName = fontFileName;
0106             entry.fullFontName = FullName;
0107             if (encodingName.endsWith(QLatin1String(".enc"))) {
0108                 entry.fontEncoding = encodingName;
0109             } else {
0110                 entry.fontEncoding.clear();
0111             }
0112         }
0113         file.close();
0114     } else {
0115         qCCritical(OkularDviDebug) << QStringLiteral("fontMap::fontMap(): The file '%1' could not be opened.").arg(map_fileName);
0116     }
0117 
0118 #ifdef DEBUG_FONTMAP
0119     qCDebug(OkularDviDebug) << "FontMap file parsed. Results:";
0120     QMap<QString, fontMapEntry>::Iterator it;
0121     for (it = fontMapEntries.begin(); it != fontMapEntries.end(); ++it)
0122         qCDebug(OkularDviDebug) << "TeXName: " << it.key() << ", FontFileName=" << it.data().fontFileName << ", FullName=" << it.data().fullFontName << ", Encoding=" << it.data().fontEncoding << ".";
0123     ;
0124 #endif
0125 }
0126 
0127 const QString &fontMap::findFileName(const QString &TeXName)
0128 {
0129     QMap<QString, fontMapEntry>::Iterator it = fontMapEntries.find(TeXName);
0130 
0131     if (it != fontMapEntries.end()) {
0132         return it.value().fontFileName;
0133     }
0134 
0135     static const QString nullstring;
0136     return nullstring;
0137 }
0138 
0139 const QString &fontMap::findFontName(const QString &TeXName)
0140 {
0141     QMap<QString, fontMapEntry>::Iterator it = fontMapEntries.find(TeXName);
0142 
0143     if (it != fontMapEntries.end()) {
0144         return it.value().fullFontName;
0145     }
0146 
0147     static const QString nullstring;
0148     return nullstring;
0149 }
0150 
0151 const QString &fontMap::findEncoding(const QString &TeXName)
0152 {
0153     QMap<QString, fontMapEntry>::Iterator it = fontMapEntries.find(TeXName);
0154 
0155     if (it != fontMapEntries.end()) {
0156         return it.value().fontEncoding;
0157     }
0158 
0159     static const QString nullstring;
0160     return nullstring;
0161 }
0162 
0163 double fontMap::findSlant(const QString &TeXName)
0164 {
0165     QMap<QString, fontMapEntry>::Iterator it = fontMapEntries.find(TeXName);
0166 
0167     if (it != fontMapEntries.end()) {
0168         return it.value().slant;
0169     } else {
0170         return 0.0;
0171     }
0172 }
0173 
0174 #endif // HAVE_FREETYPE