Coverage Report

Created: 2025-07-23 08:13

/src/poppler/splash/SplashFont.cc
Line
Count
Source (jump to first uncovered line)
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 Albert Astals Cid <aacid@kde.org>
15
// Copyright (C) 2018 Oliver Sander <oliver.sander@tu-dresden.de>
16
//
17
// To see a description of the changes please see the Changelog file that
18
// came with your tarball or type make ChangeLog if you are building from git
19
//
20
//========================================================================
21
22
#include <config.h>
23
24
#include <climits>
25
#include <cstring>
26
#include "goo/gmem.h"
27
#include "SplashMath.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
SplashFont::SplashFont(SplashFontFile *fontFileA, const SplashCoord *matA, const SplashCoord *textMatA, bool aaA)
47
230k
{
48
230k
    fontFile = fontFileA;
49
230k
    fontFile->incRefCnt();
50
230k
    mat[0] = matA[0];
51
230k
    mat[1] = matA[1];
52
230k
    mat[2] = matA[2];
53
230k
    mat[3] = matA[3];
54
230k
    textMat[0] = textMatA[0];
55
230k
    textMat[1] = textMatA[1];
56
230k
    textMat[2] = textMatA[2];
57
230k
    textMat[3] = textMatA[3];
58
230k
    aa = aaA;
59
60
230k
    cache = nullptr;
61
230k
    cacheTags = nullptr;
62
63
230k
    xMin = yMin = xMax = yMax = 0;
64
230k
}
65
66
void SplashFont::initCache()
67
230k
{
68
230k
    int i;
69
70
    // this should be (max - min + 1), but we add some padding to
71
    // deal with rounding errors
72
230k
    glyphW = xMax - xMin + 3;
73
230k
    glyphH = yMax - yMin + 3;
74
230k
    if (glyphW > INT_MAX / glyphH) {
75
795
        glyphSize = -1;
76
229k
    } else {
77
229k
        if (aa) {
78
0
            glyphSize = glyphW * glyphH;
79
229k
        } else {
80
229k
            glyphSize = ((glyphW + 7) >> 3) * glyphH;
81
229k
        }
82
229k
    }
83
84
    // set up the glyph pixmap cache
85
230k
    cacheAssoc = 8;
86
230k
    if (glyphSize <= 64) {
87
68.3k
        cacheSets = 32;
88
161k
    } else if (glyphSize <= 128) {
89
21.9k
        cacheSets = 16;
90
139k
    } else if (glyphSize <= 256) {
91
34.3k
        cacheSets = 8;
92
105k
    } else if (glyphSize <= 512) {
93
48.8k
        cacheSets = 4;
94
56.6k
    } else if (glyphSize <= 1024) {
95
16.6k
        cacheSets = 2;
96
39.9k
    } else {
97
39.9k
        cacheSets = 1;
98
39.9k
    }
99
230k
    cache = (unsigned char *)gmallocn_checkoverflow(cacheSets * cacheAssoc, glyphSize);
100
230k
    if (cache != nullptr) {
101
229k
        cacheTags = (SplashFontCacheTag *)gmallocn(cacheSets * cacheAssoc, sizeof(SplashFontCacheTag));
102
24.6M
        for (i = 0; i < cacheSets * cacheAssoc; ++i) {
103
24.4M
            cacheTags[i].mru = i & (cacheAssoc - 1);
104
24.4M
        }
105
229k
    } else {
106
799
        cacheAssoc = 0;
107
799
    }
108
230k
}
109
110
SplashFont::~SplashFont()
111
230k
{
112
230k
    fontFile->decRefCnt();
113
230k
    if (cache) {
114
229k
        gfree(cache);
115
229k
    }
116
230k
    if (cacheTags) {
117
229k
        gfree(cacheTags);
118
229k
    }
119
230k
}
120
121
bool SplashFont::getGlyph(int c, int xFrac, int yFrac, SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes)
122
45.2M
{
123
45.2M
    SplashGlyphBitmap bitmap2;
124
45.2M
    int size;
125
45.2M
    unsigned char *p;
126
45.2M
    int i, j, k;
127
128
    // no fractional coordinates for large glyphs or non-anti-aliased
129
    // glyphs
130
45.2M
    if (!aa || glyphH > 50) {
131
45.2M
        xFrac = yFrac = 0;
132
45.2M
    }
133
134
    // check the cache
135
45.2M
    i = (c & (cacheSets - 1)) * cacheAssoc;
136
344M
    for (j = 0; j < cacheAssoc; ++j) {
137
332M
        if ((cacheTags[i + j].mru & 0x80000000) && cacheTags[i + j].c == c && (int)cacheTags[i + j].xFrac == xFrac && (int)cacheTags[i + j].yFrac == yFrac) {
138
33.6M
            bitmap->x = cacheTags[i + j].x;
139
33.6M
            bitmap->y = cacheTags[i + j].y;
140
33.6M
            bitmap->w = cacheTags[i + j].w;
141
33.6M
            bitmap->h = cacheTags[i + j].h;
142
302M
            for (k = 0; k < cacheAssoc; ++k) {
143
269M
                if (k != j && (cacheTags[i + k].mru & 0x7fffffff) < (cacheTags[i + j].mru & 0x7fffffff)) {
144
24.3M
                    ++cacheTags[i + k].mru;
145
24.3M
                }
146
269M
            }
147
33.6M
            cacheTags[i + j].mru = 0x80000000;
148
33.6M
            bitmap->aa = aa;
149
33.6M
            bitmap->data = cache + (i + j) * glyphSize;
150
33.6M
            bitmap->freeData = false;
151
152
33.6M
            *clipRes = clip->testRect(x0 - bitmap->x, y0 - bitmap->y, x0 - bitmap->x + bitmap->w - 1, y0 - bitmap->y + bitmap->h - 1);
153
154
33.6M
            return true;
155
33.6M
        }
156
332M
    }
157
158
    // generate the glyph bitmap
159
11.5M
    if (!makeGlyph(c, xFrac, yFrac, &bitmap2, x0, y0, clip, clipRes)) {
160
5.00M
        return false;
161
5.00M
    }
162
163
6.54M
    if (*clipRes == splashClipAllOutside) {
164
3.57M
        bitmap->freeData = false;
165
3.57M
        if (bitmap2.freeData) {
166
0
            gfree(bitmap2.data);
167
0
        }
168
3.57M
        return true;
169
3.57M
    }
170
171
    // if the glyph doesn't fit in the bounding box, return a temporary
172
    // uncached bitmap
173
2.97M
    if (bitmap2.w > glyphW || bitmap2.h > glyphH) {
174
25.8k
        *bitmap = bitmap2;
175
25.8k
        return true;
176
25.8k
    }
177
178
    // insert glyph pixmap in cache
179
2.94M
    if (aa) {
180
0
        size = bitmap2.w * bitmap2.h;
181
2.94M
    } else {
182
2.94M
        size = ((bitmap2.w + 7) >> 3) * bitmap2.h;
183
2.94M
    }
184
2.94M
    p = nullptr; // make gcc happy
185
2.94M
    if (cacheAssoc == 0) {
186
        // we had problems on the malloc of the cache, so ignore it
187
1.49k
        *bitmap = bitmap2;
188
2.94M
    } else {
189
26.4M
        for (j = 0; j < cacheAssoc; ++j) {
190
23.5M
            if ((cacheTags[i + j].mru & 0x7fffffff) == cacheAssoc - 1) {
191
2.94M
                cacheTags[i + j].mru = 0x80000000;
192
2.94M
                cacheTags[i + j].c = c;
193
2.94M
                cacheTags[i + j].xFrac = (short)xFrac;
194
2.94M
                cacheTags[i + j].yFrac = (short)yFrac;
195
2.94M
                cacheTags[i + j].x = bitmap2.x;
196
2.94M
                cacheTags[i + j].y = bitmap2.y;
197
2.94M
                cacheTags[i + j].w = bitmap2.w;
198
2.94M
                cacheTags[i + j].h = bitmap2.h;
199
2.94M
                p = cache + (i + j) * glyphSize;
200
2.94M
                memcpy(p, bitmap2.data, size);
201
20.6M
            } else {
202
20.6M
                ++cacheTags[i + j].mru;
203
20.6M
            }
204
23.5M
        }
205
2.94M
        *bitmap = bitmap2;
206
2.94M
        bitmap->data = p;
207
2.94M
        bitmap->freeData = false;
208
2.94M
        if (bitmap2.freeData) {
209
2.94M
            gfree(bitmap2.data);
210
2.94M
        }
211
2.94M
    }
212
2.94M
    return true;
213
2.97M
}