Coverage Report

Created: 2026-08-25 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/poppler/poppler/FontInfo.cc
Line
Count
Source
1
//========================================================================
2
//
3
// FontInfo.cc
4
//
5
// Copyright (C) 2005, 2006 Kristian Høgsberg <krh@redhat.com>
6
// Copyright (C) 2005-2008, 2010, 2017-2020, 2023-2026 Albert Astals Cid <aacid@kde.org>
7
// Copyright (C) 2005 Brad Hards <bradh@frogmouth.net>
8
// Copyright (C) 2006 Kouhei Sutou <kou@cozmixng.org>
9
// Copyright (C) 2009 Pino Toscano <pino@kde.org>
10
// Copyright (C) 2010 Hib Eris <hib@hiberis.nl>
11
// Copyright (C) 2010, 2012 Adrian Johnson <ajohnson@redneon.com>
12
// Copyright (C) 2010, 2013 Thomas Freitag <Thomas.Freitag@alfa.de>
13
// Copyright (C) 2011 Carlos Garcia Campos <carlosgc@gnome.org>
14
// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
15
// 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
16
// Copyright (C) 2018, 2019 Adam Reichold <adam.reichold@t-online.de>
17
// Copyright (C) 2019, 2021, 2022 Oliver Sander <oliver.sander@tu-dresden.de>
18
// Copyright (C) 2023 Suzuki Toshiya <mpsuzuki@hiroshima-u.ac.jp>
19
// Copyright (C) 2025, 2026 g10 Code GmbH, Author: Sune Stolborg Vuorela <sune@vuorela.dk>
20
//
21
// To see a description of the changes please see the Changelog file that
22
// came with your tarball or type make ChangeLog if you are building from git
23
//
24
//========================================================================
25
26
//========================================================================
27
//
28
// Based on code from pdffonts.cc
29
//
30
// Copyright 2001-2007 Glyph & Cog, LLC
31
//
32
//========================================================================
33
34
#include "FontInfo.h"
35
36
#include "config.h"
37
#include "GlobalParams.h"
38
#include "Object.h"
39
#include "Dict.h"
40
#include "GfxFont.h"
41
#include "Annot.h"
42
#include "PDFDoc.h"
43
44
FontInfoScanner::FontInfoScanner(PDFDoc *docA, int firstPage)
45
0
{
46
0
    doc = docA;
47
0
    currentPage = firstPage + 1;
48
0
}
49
50
0
FontInfoScanner::~FontInfoScanner() = default;
51
52
std::vector<FontInfo *> FontInfoScanner::scan(int nPages)
53
0
{
54
0
    Page *page;
55
0
    Annots *annots;
56
0
    int lastPage;
57
58
0
    std::vector<FontInfo *> result;
59
60
0
    if (currentPage > doc->getNumPages()) {
61
0
        return result;
62
0
    }
63
64
0
    lastPage = currentPage + nPages;
65
0
    if (lastPage > doc->getNumPages() + 1) {
66
0
        lastPage = doc->getNumPages() + 1;
67
0
    }
68
69
0
    std::unique_ptr<XRef> xrefA;
70
0
    for (int pg = currentPage; pg < lastPage; ++pg) {
71
0
        page = doc->getPage(pg);
72
0
        if (!page) {
73
0
            continue;
74
0
        }
75
0
        if (!xrefA) {
76
0
            xrefA = doc->getXRef()->copy();
77
0
        }
78
79
0
        if (std::unique_ptr<Dict> resDict = page->getResourceDictCopy(xrefA.get())) {
80
0
            scanFonts(xrefA.get(), resDict.get(), &result);
81
0
        }
82
0
        annots = page->getAnnots();
83
0
        for (const std::shared_ptr<Annot> &annot : annots->getAnnots()) {
84
0
            Object obj1 = annot->getAppearanceResDict();
85
0
            if (obj1.isDict()) {
86
0
                scanFonts(xrefA.get(), obj1.getDict(), &result);
87
0
            }
88
0
        }
89
0
    }
90
91
0
    currentPage = lastPage;
92
93
0
    return result;
94
0
}
95
96
void FontInfoScanner::scanFonts(XRef *xrefA, Dict *resDict, std::vector<FontInfo *> *fontsList)
97
0
{
98
    // scan the fonts in this resource dictionary
99
0
    Ref fontDictRef;
100
0
    const Object &fontObj = resDict->lookup("Font", &fontDictRef);
101
0
    if (fontObj.isDict()) {
102
0
        GfxFontDict gfxFontDict(xrefA, fontDictRef, *fontObj.getDict());
103
0
        for (int i = 0; i < gfxFontDict.getNumFonts(); ++i) {
104
0
            if (const std::shared_ptr<GfxFont> &font = gfxFontDict.getFont(i)) {
105
0
                Ref fontRef = *font->getID();
106
107
                // add this font to the list if not already found
108
0
                if (fonts.insert(fontRef.num).second) {
109
0
                    fontsList->push_back(new FontInfo(font.get(), xrefA));
110
0
                }
111
0
            }
112
0
        }
113
0
    }
114
115
    // recursively scan any resource dictionaries in objects in this
116
    // resource dictionary
117
0
    const char *resTypes[] = { "XObject", "Pattern" };
118
0
    for (const char *resType : resTypes) {
119
0
        Ref objDictRef;
120
0
        Object objDict = resDict->lookup(resType, &objDictRef);
121
0
        if (!visitedObjects.insert(objDictRef)) {
122
0
            continue;
123
0
        }
124
0
        if (objDict.isDict()) {
125
0
            for (int i = 0; i < objDict.dictGetLength(); ++i) {
126
0
                Ref obj2Ref;
127
0
                const Object obj2 = objDict.getDict()->getVal(i, &obj2Ref);
128
                // check for an already-seen object
129
0
                if (!visitedObjects.insert(obj2Ref)) {
130
0
                    continue;
131
0
                }
132
133
0
                if (obj2.isStream()) {
134
0
                    Ref resourcesRef;
135
0
                    const Object resObj = obj2.getStream()->getDict()->lookup("Resources", &resourcesRef);
136
0
                    if (!visitedObjects.insert(resourcesRef)) {
137
0
                        continue;
138
0
                    }
139
140
0
                    if (resObj.isDict() && resObj.getDict() != resDict) {
141
0
                        scanFonts(xrefA, resObj.getDict(), fontsList);
142
0
                    }
143
0
                }
144
0
            }
145
0
        }
146
0
    }
147
0
}
148
149
FontInfo::FontInfo(GfxFont *font, XRef *xref)
150
0
{
151
0
    fontRef = *font->getID();
152
153
    // font name
154
0
    const std::optional<std::string> &origName = font->getName();
155
0
    if (origName) {
156
0
        name = *origName;
157
0
    }
158
159
    // font type
160
0
    type = static_cast<FontInfo::Type>(font->getType());
161
162
    // check for an embedded font
163
0
    if (font->getType() == fontType3) {
164
0
        emb = true;
165
0
        embRef = Ref::INVALID();
166
0
    } else {
167
0
        emb = font->getEmbeddedFontID(&embRef);
168
0
    }
169
170
0
    if (!emb) {
171
0
        GooString substituteNameAux;
172
0
        const std::optional<GfxFontLoc> fontLoc = font->locateFont(xref, nullptr, &substituteNameAux);
173
0
        if (fontLoc && fontLoc->locType == gfxFontLocExternal) {
174
0
            file = fontLoc->path;
175
0
        }
176
0
        if (!substituteNameAux.empty()) {
177
0
            substituteName = substituteNameAux.toStr();
178
0
        }
179
0
    }
180
0
    encoding = font->getEncodingName();
181
182
    // look for a ToUnicode map
183
0
    hasToUnicode = false;
184
0
    Object fontObj = xref->fetch(fontRef);
185
0
    if (fontObj.isDict()) {
186
0
        hasToUnicode = fontObj.dictLookup("ToUnicode").isStream();
187
0
    }
188
189
    // check for a font subset name: capital letters followed by a '+'
190
    // sign
191
0
    subset = font->isSubset();
192
0
}