Coverage Report

Created: 2026-06-07 08:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/poppler/splash/SplashFont.cc
Line
Count
Source
1
//========================================================================
2
//
3
// SplashFont.cc
4
//
5
//========================================================================
6
7
//========================================================================
8
//
9
// Modified under the Poppler project - http://poppler.freedesktop.org
10
//
11
// All changes made under the Poppler project to this file are licensed
12
// under GPL version 2 or later
13
//
14
// Copyright (C) 2007-2008, 2010, 2014, 2019, 2025, 2026 Albert Astals Cid <aacid@kde.org>
15
// Copyright (C) 2018 Oliver Sander <oliver.sander@tu-dresden.de>
16
// Copyright (C) 2026 g10 Code GmbH, Author: Sune Stolborg Vuorela <sune@vuorela.dk>
17
//
18
// To see a description of the changes please see the Changelog file that
19
// came with your tarball or type make ChangeLog if you are building from git
20
//
21
//========================================================================
22
23
#include <config.h>
24
25
#include <climits>
26
#include <cstring>
27
#include "goo/gmem.h"
28
#include "SplashGlyphBitmap.h"
29
#include "SplashFontFile.h"
30
#include "SplashFont.h"
31
32
//------------------------------------------------------------------------
33
34
struct SplashFontCacheTag
35
{
36
    int c;
37
    short xFrac, yFrac; // x and y fractions
38
    int mru; // valid bit (0x80000000) and MRU index
39
    int x, y, w, h; // offset and size of glyph
40
};
41
42
//------------------------------------------------------------------------
43
// SplashFont
44
//------------------------------------------------------------------------
45
46
205k
SplashFont::SplashFont(const std::shared_ptr<SplashFontFile> &fontFileA, const std::array<double, 4> &matA, const std::array<double, 4> &textMatA, bool aaA) : mat(matA), textMat(textMatA)
47
205k
{
48
205k
    fontFile = fontFileA;
49
205k
    aa = aaA;
50
51
205k
    cache = nullptr;
52
205k
    cacheTags = nullptr;
53
54
205k
    xMin = yMin = xMax = yMax = 0;
55
205k
}
56
57
void SplashFont::initCache()
58
205k
{
59
205k
    int i;
60
61
    // this should be (max - min + 1), but we add some padding to
62
    // deal with rounding errors
63
205k
    glyphW = xMax - xMin + 3;
64
205k
    glyphH = yMax - yMin + 3;
65
205k
    if (glyphW > INT_MAX / glyphH) {
66
591
        glyphSize = -1;
67
204k
    } else {
68
204k
        if (aa) {
69
0
            glyphSize = glyphW * glyphH;
70
204k
        } else {
71
204k
            glyphSize = ((glyphW + 7) >> 3) * glyphH;
72
204k
        }
73
204k
    }
74
75
    // set up the glyph pixmap cache
76
205k
    cacheAssoc = 8;
77
205k
    if (glyphSize <= 64) {
78
56.1k
        cacheSets = 32;
79
148k
    } else if (glyphSize <= 128) {
80
19.4k
        cacheSets = 16;
81
129k
    } else if (glyphSize <= 256) {
82
26.7k
        cacheSets = 8;
83
102k
    } else if (glyphSize <= 512) {
84
42.4k
        cacheSets = 4;
85
60.2k
    } else if (glyphSize <= 1024) {
86
18.9k
        cacheSets = 2;
87
41.3k
    } else {
88
41.3k
        cacheSets = 1;
89
41.3k
    }
90
205k
    cache = static_cast<unsigned char *>(gmallocn_checkoverflow(cacheSets * cacheAssoc, glyphSize));
91
205k
    if (cache != nullptr) {
92
204k
        cacheTags = static_cast<SplashFontCacheTag *>(gmallocn(cacheSets * cacheAssoc, sizeof(SplashFontCacheTag)));
93
20.6M
        for (i = 0; i < cacheSets * cacheAssoc; ++i) {
94
20.4M
            cacheTags[i].mru = i & (cacheAssoc - 1);
95
20.4M
        }
96
204k
    } else {
97
603
        cacheAssoc = 0;
98
603
    }
99
205k
}
100
101
SplashFont::~SplashFont()
102
205k
{
103
205k
    if (cache) {
104
204k
        gfree(cache);
105
204k
    }
106
205k
    if (cacheTags) {
107
204k
        gfree(cacheTags);
108
204k
    }
109
205k
}
110
111
bool SplashFont::getGlyph(int c, int xFrac, int yFrac, SplashGlyphBitmap *bitmap, int x0, int y0, const SplashClip &clip, SplashClipResult *clipRes)
112
29.0M
{
113
29.0M
    SplashGlyphBitmap bitmap2;
114
29.0M
    int size;
115
29.0M
    unsigned char *p;
116
29.0M
    int i, j, k;
117
118
    // no fractional coordinates for large glyphs or non-anti-aliased
119
    // glyphs
120
29.0M
    if (!aa || glyphH > 50) {
121
29.0M
        xFrac = yFrac = 0;
122
29.0M
    }
123
124
    // check the cache
125
29.0M
    i = (c & (cacheSets - 1)) * cacheAssoc;
126
220M
    for (j = 0; j < cacheAssoc; ++j) {
127
212M
        if ((cacheTags[i + j].mru & 0x80000000) && cacheTags[i + j].c == c && static_cast<int>(cacheTags[i + j].xFrac) == xFrac && static_cast<int>(cacheTags[i + j].yFrac) == yFrac) {
128
20.7M
            bitmap->x = cacheTags[i + j].x;
129
20.7M
            bitmap->y = cacheTags[i + j].y;
130
20.7M
            bitmap->w = cacheTags[i + j].w;
131
20.7M
            bitmap->h = cacheTags[i + j].h;
132
187M
            for (k = 0; k < cacheAssoc; ++k) {
133
166M
                if (k != j && (cacheTags[i + k].mru & 0x7fffffff) < (cacheTags[i + j].mru & 0x7fffffff)) {
134
17.5M
                    ++cacheTags[i + k].mru;
135
17.5M
                }
136
166M
            }
137
20.7M
            cacheTags[i + j].mru = 0x80000000;
138
20.7M
            bitmap->aa = aa;
139
20.7M
            bitmap->data = cache + (i + j) * glyphSize;
140
20.7M
            bitmap->freeData = false;
141
142
20.7M
            int rectXMin, rectYMin;
143
20.7M
            if (checkedSubtraction(x0, bitmap->x, &rectXMin)) {
144
161
                return false;
145
161
            }
146
20.7M
            if (checkedSubtraction(y0, bitmap->y, &rectYMin)) {
147
151
                return false;
148
151
            }
149
20.7M
            *clipRes = clip.testRect(rectXMin, rectYMin, rectXMin + bitmap->w - 1, rectYMin + bitmap->h - 1);
150
151
20.7M
            return true;
152
20.7M
        }
153
212M
    }
154
155
    // generate the glyph bitmap
156
8.30M
    if (!makeGlyph(c, xFrac, yFrac, &bitmap2, x0, y0, clip, clipRes)) {
157
4.32M
        return false;
158
4.32M
    }
159
160
3.98M
    if (*clipRes == splashClipAllOutside) {
161
1.58M
        bitmap->freeData = false;
162
1.58M
        if (bitmap2.freeData) {
163
0
            gfree(bitmap2.data);
164
0
        }
165
1.58M
        return true;
166
1.58M
    }
167
168
    // if the glyph doesn't fit in the bounding box, return a temporary
169
    // uncached bitmap
170
2.39M
    if (bitmap2.w > glyphW || bitmap2.h > glyphH) {
171
19.2k
        *bitmap = bitmap2;
172
19.2k
        return true;
173
19.2k
    }
174
175
    // insert glyph pixmap in cache
176
2.37M
    if (aa) {
177
0
        size = bitmap2.w * bitmap2.h;
178
2.37M
    } else {
179
2.37M
        size = ((bitmap2.w + 7) >> 3) * bitmap2.h;
180
2.37M
    }
181
2.37M
    p = nullptr; // make gcc happy
182
2.37M
    if (cacheAssoc == 0) {
183
        // we had problems on the malloc of the cache, so ignore it
184
1.50k
        *bitmap = bitmap2;
185
2.37M
    } else {
186
21.3M
        for (j = 0; j < cacheAssoc; ++j) {
187
19.0M
            if ((cacheTags[i + j].mru & 0x7fffffff) == cacheAssoc - 1) {
188
2.37M
                cacheTags[i + j].mru = 0x80000000;
189
2.37M
                cacheTags[i + j].c = c;
190
2.37M
                cacheTags[i + j].xFrac = static_cast<short>(xFrac);
191
2.37M
                cacheTags[i + j].yFrac = static_cast<short>(yFrac);
192
2.37M
                cacheTags[i + j].x = bitmap2.x;
193
2.37M
                cacheTags[i + j].y = bitmap2.y;
194
2.37M
                cacheTags[i + j].w = bitmap2.w;
195
2.37M
                cacheTags[i + j].h = bitmap2.h;
196
2.37M
                p = cache + (i + j) * glyphSize;
197
2.37M
                memcpy(p, bitmap2.data, size);
198
16.6M
            } else {
199
16.6M
                ++cacheTags[i + j].mru;
200
16.6M
            }
201
19.0M
        }
202
2.37M
        *bitmap = bitmap2;
203
2.37M
        bitmap->data = p;
204
2.37M
        bitmap->freeData = false;
205
2.37M
        if (bitmap2.freeData) {
206
2.37M
            gfree(bitmap2.data);
207
2.37M
        }
208
2.37M
    }
209
2.37M
    return true;
210
2.39M
}