/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 | } |