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