1 |
|
|
/* |
2 |
|
|
* The ManaPlus Client |
3 |
|
|
* Copyright (C) 2004-2009 The Mana World Development Team |
4 |
|
|
* Copyright (C) 2009-2010 The Mana Developers |
5 |
|
|
* Copyright (C) 2009 Aethyra Development Team |
6 |
|
|
* Copyright (C) 2011-2019 The ManaPlus Developers |
7 |
|
|
* Copyright (C) 2019-2021 Andrei Karas |
8 |
|
|
* |
9 |
|
|
* This file is part of The ManaPlus Client. |
10 |
|
|
* |
11 |
|
|
* This program is free software; you can redistribute it and/or modify |
12 |
|
|
* it under the terms of the GNU General Public License as published by |
13 |
|
|
* the Free Software Foundation; either version 2 of the License, or |
14 |
|
|
* any later version. |
15 |
|
|
* |
16 |
|
|
* This program is distributed in the hope that it will be useful, |
17 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
18 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
19 |
|
|
* GNU General Public License for more details. |
20 |
|
|
* |
21 |
|
|
* You should have received a copy of the GNU General Public License |
22 |
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
23 |
|
|
*/ |
24 |
|
|
|
25 |
|
|
/* _______ __ __ __ ______ __ __ _______ __ __ |
26 |
|
|
* / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ |
27 |
|
|
* / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / |
28 |
|
|
* / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / |
29 |
|
|
* / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / |
30 |
|
|
* /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / |
31 |
|
|
* \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ |
32 |
|
|
* |
33 |
|
|
* Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson |
34 |
|
|
* |
35 |
|
|
* |
36 |
|
|
* Per Larsson a.k.a finalman |
37 |
|
|
* Olof Naessén a.k.a jansem/yakslem |
38 |
|
|
* |
39 |
|
|
* Visit: http://guichan.sourceforge.net |
40 |
|
|
* |
41 |
|
|
* License: (BSD) |
42 |
|
|
* Redistribution and use in source and binary forms, with or without |
43 |
|
|
* modification, are permitted provided that the following conditions |
44 |
|
|
* are met: |
45 |
|
|
* 1. Redistributions of source code must retain the above copyright |
46 |
|
|
* notice, this list of conditions and the following disclaimer. |
47 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
48 |
|
|
* notice, this list of conditions and the following disclaimer in |
49 |
|
|
* the documentation and/or other materials provided with the |
50 |
|
|
* distribution. |
51 |
|
|
* 3. Neither the name of Guichan nor the names of its contributors may |
52 |
|
|
* be used to endorse or promote products derived from this software |
53 |
|
|
* without specific prior written permission. |
54 |
|
|
* |
55 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
56 |
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
57 |
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
58 |
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
59 |
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
60 |
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED |
61 |
|
|
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
62 |
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
63 |
|
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
64 |
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
65 |
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
66 |
|
|
*/ |
67 |
|
|
|
68 |
|
|
#include "gui/fonts/font.h" |
69 |
|
|
|
70 |
|
|
#include "fs/files.h" |
71 |
|
|
#include "fs/paths.h" |
72 |
|
|
|
73 |
|
|
#include "fs/virtfs/tools.h" |
74 |
|
|
#ifdef USE_SDL2 |
75 |
|
|
#include "fs/virtfs/rwops.h" |
76 |
|
|
#endif // USE_SDL2 |
77 |
|
|
|
78 |
|
|
#include "gui/fonts/textchunk.h" |
79 |
|
|
|
80 |
|
|
#include "render/graphics.h" |
81 |
|
|
|
82 |
|
|
#include "resources/imagehelper.h" |
83 |
|
|
|
84 |
|
|
#include "resources/image/image.h" |
85 |
|
|
|
86 |
|
|
#include "utils/checkutils.h" |
87 |
|
|
#include "utils/delete2.h" |
88 |
|
|
#include "utils/sdlcheckutils.h" |
89 |
|
|
#include "utils/stringutils.h" |
90 |
|
|
#include "utils/timer.h" |
91 |
|
|
|
92 |
|
|
#include "debug.h" |
93 |
|
|
|
94 |
|
|
const unsigned int CACHE_SIZE = 256; |
95 |
|
|
const unsigned int CACHE_SIZE_SMALL1 = 2; |
96 |
|
|
const unsigned int CACHE_SIZE_SMALL2 = 50; |
97 |
|
|
const unsigned int CACHE_SIZE_SMALL3 = 170; |
98 |
|
|
const unsigned int CLEAN_TIME = 7; |
99 |
|
|
|
100 |
|
|
bool Font::mSoftMode(false); |
101 |
|
|
|
102 |
|
|
extern char *restrict strBuf; |
103 |
|
|
|
104 |
|
|
static int fontCounter; |
105 |
|
|
|
106 |
|
764 |
Font::Font(std::string filename, |
107 |
|
|
int size, |
108 |
|
764 |
const int style) : |
109 |
|
|
mFont(nullptr), |
110 |
|
|
mCreateCounter(0), |
111 |
|
|
mDeleteCounter(0), |
112 |
✓✓✓✗ ✗✗ |
764 |
mCleanTime(cur_time + CLEAN_TIME) |
113 |
|
|
{ |
114 |
✓✓ |
764 |
if (fontCounter == 0) |
115 |
|
|
{ |
116 |
|
127 |
mSoftMode = imageHelper->useOpenGL() == RENDER_SOFTWARE; |
117 |
✓✗✗✓
|
127 |
if (TTF_Init() == -1) |
118 |
|
|
{ |
119 |
|
|
logger->error("Unable to initialize SDL_ttf: " + |
120 |
|
|
std::string(SDL_GetError())); |
121 |
|
|
} |
122 |
|
|
} |
123 |
|
|
|
124 |
✗✓ |
764 |
if (size < 4) |
125 |
|
|
{ |
126 |
|
|
reportAlways("Error: requested load font %s with size %d", |
127 |
|
|
filename.c_str(), |
128 |
|
|
size) |
129 |
|
|
size = 4; |
130 |
|
|
} |
131 |
|
|
|
132 |
✓✓ |
764 |
if (fontCounter == 0) |
133 |
|
|
{ |
134 |
✓✗ |
127 |
strBuf = new char[65535]; |
135 |
|
127 |
memset(strBuf, 0, 65535); |
136 |
|
|
} |
137 |
|
|
|
138 |
|
764 |
++fontCounter; |
139 |
|
|
|
140 |
✓✗ |
764 |
fixDirSeparators(filename); |
141 |
|
764 |
logger->log("Attempt to load font: %s", |
142 |
✓✗ |
764 |
filename.c_str()); |
143 |
✓✗ |
764 |
mFont = openFont(filename.c_str(), size); |
144 |
|
|
|
145 |
✗✓ |
764 |
if (mFont == nullptr) |
146 |
|
|
{ |
147 |
|
|
logger->log("Error normal loading font " + filename); |
148 |
|
|
|
149 |
|
|
filename = "fonts/dejavusans.ttf"; |
150 |
|
|
mFont = openFont(fixDirSeparators(filename).c_str(), size); |
151 |
|
|
if (mFont == nullptr) |
152 |
|
|
{ |
153 |
|
|
#ifdef UNITTESTS |
154 |
|
|
reportAlways("Font load failed %s", |
155 |
|
|
filename.c_str()) |
156 |
|
|
#endif // UNITTESTS |
157 |
|
|
logger->error("Font::Font: " + |
158 |
|
|
std::string(SDL_GetError())); |
159 |
|
|
} |
160 |
|
|
else |
161 |
|
|
{ |
162 |
|
|
logger->log("Loaded fallback font %s, %d", |
163 |
|
|
filename.c_str(), |
164 |
|
|
size); |
165 |
|
|
} |
166 |
|
|
} |
167 |
|
|
else |
168 |
|
|
{ |
169 |
|
764 |
logger->log("Loaded font %s, %d", |
170 |
|
|
filename.c_str(), |
171 |
✓✗ |
764 |
size); |
172 |
|
|
} |
173 |
|
|
|
174 |
✓✗ |
764 |
TTF_SetFontStyle(mFont, style); |
175 |
✗✗ |
764 |
} |
176 |
|
|
|
177 |
✓✗✓✓
|
1528 |
Font::~Font() |
178 |
|
|
{ |
179 |
|
764 |
TTF_CloseFont(mFont); |
180 |
|
764 |
mFont = nullptr; |
181 |
|
764 |
--fontCounter; |
182 |
|
764 |
clear(); |
183 |
|
|
|
184 |
✓✓ |
764 |
if (fontCounter == 0) |
185 |
|
|
{ |
186 |
|
127 |
TTF_Quit(); |
187 |
✓✗ |
127 |
delete []strBuf; |
188 |
|
|
} |
189 |
|
764 |
} |
190 |
|
|
|
191 |
|
764 |
TTF_Font *Font::openFont(const char *const name, |
192 |
|
|
const int size) |
193 |
|
|
{ |
194 |
|
|
#ifdef USE_SDL2 |
195 |
✓✗ |
3056 |
SDL_RWops *const rw = VirtFs::rwopsOpenRead(name); |
196 |
✓✗ |
764 |
if (rw) |
197 |
|
|
{ |
198 |
|
764 |
logger->log("Loading virtfs font file: %s", |
199 |
|
764 |
name); |
200 |
|
764 |
return TTF_OpenFontIndexRW(rw, 1, size, 0); |
201 |
|
|
} |
202 |
|
|
#endif |
203 |
|
|
const std::string path = VirtFs::getPath(name); |
204 |
|
|
if (Files::existsLocal(path) == false) |
205 |
|
|
{ |
206 |
|
|
#ifndef UNITTESTS |
207 |
|
|
// +++ in future need trigger assert in unit tests here too |
208 |
|
|
reportAlways("Font::openFont font not exists: %s", |
209 |
|
|
path.c_str()) |
210 |
|
|
#endif // UNITTESTS |
211 |
|
|
return nullptr; |
212 |
|
|
} |
213 |
|
|
logger->log("Loading physical font file: %s", |
214 |
|
|
path.c_str()); |
215 |
|
|
return TTF_OpenFontIndex(path.c_str(), |
216 |
|
|
size, 0); |
217 |
|
|
} |
218 |
|
|
|
219 |
|
|
void Font::loadFont(std::string filename, |
220 |
|
|
const int size, |
221 |
|
|
const int style) |
222 |
|
|
{ |
223 |
|
|
if (fontCounter == 0 && TTF_Init() == -1) |
224 |
|
|
{ |
225 |
|
|
logger->log("Unable to initialize SDL_ttf: " + |
226 |
|
|
std::string(SDL_GetError())); |
227 |
|
|
return; |
228 |
|
|
} |
229 |
|
|
|
230 |
|
|
fixDirSeparators(filename); |
231 |
|
|
TTF_Font *const font = openFont(filename.c_str(), size); |
232 |
|
|
|
233 |
|
|
if (font == nullptr) |
234 |
|
|
{ |
235 |
|
|
logger->log("Font::Font: " + |
236 |
|
|
std::string(SDL_GetError())); |
237 |
|
|
return; |
238 |
|
|
} |
239 |
|
|
|
240 |
|
|
if (mFont != nullptr) |
241 |
|
|
TTF_CloseFont(mFont); |
242 |
|
|
|
243 |
|
|
mFont = font; |
244 |
|
|
TTF_SetFontStyle(mFont, style); |
245 |
|
|
clear(); |
246 |
|
|
} |
247 |
|
|
|
248 |
|
|
void Font::clear() |
249 |
|
|
{ |
250 |
✗✗✗✗ ✓✓ |
196348 |
for (size_t f = 0; f < CACHES_NUMBER; f ++) |
251 |
|
195584 |
mCache[f].clear(); |
252 |
|
|
} |
253 |
|
|
|
254 |
|
50 |
void Font::drawString(Graphics *const graphics, |
255 |
|
|
Color col, |
256 |
|
|
const Color &col2, |
257 |
|
|
const std::string &text, |
258 |
|
|
const int x, const int y) |
259 |
|
|
{ |
260 |
|
|
BLOCK_START("Font::drawString") |
261 |
✓✓ |
50 |
if (text.empty()) |
262 |
|
|
{ |
263 |
|
|
BLOCK_END("Font::drawString") |
264 |
|
|
return; |
265 |
|
|
} |
266 |
|
|
|
267 |
|
|
// Color col = graphics->getColor(); |
268 |
|
|
// const Color &col2 = graphics->getColor2(); |
269 |
|
49 |
const float alpha = static_cast<float>(col.a) / 255.0F; |
270 |
|
|
|
271 |
|
|
/* The alpha value is ignored at string generation so avoid caching the |
272 |
|
|
* same text with different alpha values. |
273 |
|
|
*/ |
274 |
|
49 |
col.a = 255; |
275 |
|
|
|
276 |
|
49 |
const unsigned char chr = text[0]; |
277 |
|
49 |
TextChunkList *const cache = &mCache[chr]; |
278 |
|
|
|
279 |
|
49 |
std::map<TextChunkSmall, TextChunk*> &search = cache->search; |
280 |
|
|
std::map<TextChunkSmall, TextChunk*>::iterator i |
281 |
|
147 |
= search.find(TextChunkSmall(text, col, col2)); |
282 |
✗✓ |
49 |
if (i != search.end()) |
283 |
|
|
{ |
284 |
|
|
TextChunk *const chunk2 = (*i).second; |
285 |
|
|
cache->moveToFirst(chunk2); |
286 |
|
|
Image *const image = chunk2->img; |
287 |
|
|
if (image != nullptr) |
288 |
|
|
{ |
289 |
|
|
image->setAlpha(alpha); |
290 |
|
|
graphics->drawImage(image, x, y); |
291 |
|
|
} |
292 |
|
|
} |
293 |
|
|
else |
294 |
|
|
{ |
295 |
✗✓ |
49 |
if (cache->size >= CACHE_SIZE) |
296 |
|
|
{ |
297 |
|
|
#ifdef DEBUG_FONT_COUNTERS |
298 |
|
|
mDeleteCounter ++; |
299 |
|
|
#endif // DEBUG_FONT_COUNTERS |
300 |
|
|
|
301 |
|
|
cache->removeBack(); |
302 |
|
|
} |
303 |
|
|
#ifdef DEBUG_FONT_COUNTERS |
304 |
|
|
mCreateCounter ++; |
305 |
|
|
#endif // DEBUG_FONT_COUNTERS |
306 |
|
|
|
307 |
✓✗ |
49 |
TextChunk *chunk2 = new TextChunk(text, col, col2, this); |
308 |
|
|
|
309 |
|
49 |
chunk2->generate(mFont, alpha); |
310 |
|
49 |
cache->insertFirst(chunk2); |
311 |
|
|
|
312 |
|
49 |
const Image *const image = chunk2->img; |
313 |
✓✗ |
49 |
if (image != nullptr) |
314 |
|
49 |
graphics->drawImage(image, x, y); |
315 |
|
|
} |
316 |
|
|
BLOCK_END("Font::drawString") |
317 |
|
|
} |
318 |
|
|
|
319 |
|
|
void Font::slowLogic(const int rnd) |
320 |
|
|
{ |
321 |
|
|
BLOCK_START("Font::slowLogic") |
322 |
|
|
if (mCleanTime == 0) |
323 |
|
|
{ |
324 |
|
|
mCleanTime = cur_time + CLEAN_TIME + rnd; |
325 |
|
|
} |
326 |
|
|
else if (mCleanTime < cur_time) |
327 |
|
|
{ |
328 |
|
|
doClean(); |
329 |
|
|
mCleanTime = cur_time + CLEAN_TIME + rnd; |
330 |
|
|
} |
331 |
|
|
BLOCK_END("Font::slowLogic") |
332 |
|
|
} |
333 |
|
|
|
334 |
|
9633 |
int Font::getWidth(const std::string &text) const |
335 |
|
|
{ |
336 |
✓✓ |
9633 |
if (text.empty()) |
337 |
|
|
return 0; |
338 |
|
|
|
339 |
|
9421 |
const unsigned char chr = text[0]; |
340 |
|
9421 |
TextChunkList *const cache = &mCache[chr]; |
341 |
|
|
|
342 |
|
9421 |
std::map<std::string, TextChunk*> &search = cache->searchWidth; |
343 |
|
9421 |
std::map<std::string, TextChunk*>::iterator i = search.find(text); |
344 |
✗✓ |
9421 |
if (i != search.end()) |
345 |
|
|
{ |
346 |
|
|
TextChunk *const chunk = (*i).second; |
347 |
|
|
cache->moveToFirst(chunk); |
348 |
|
|
const Image *const image = chunk->img; |
349 |
|
|
if (image != nullptr) |
350 |
|
|
return image->getWidth(); |
351 |
|
|
return 0; |
352 |
|
|
} |
353 |
|
|
|
354 |
|
|
// if string was not drawed |
355 |
|
|
int w; |
356 |
|
|
int h; |
357 |
✓✗ |
28263 |
getSafeUtf8String(text, strBuf); |
358 |
|
9421 |
TTF_SizeUTF8(mFont, strBuf, &w, &h); |
359 |
|
9421 |
return w; |
360 |
|
|
} |
361 |
|
|
|
362 |
|
2322 |
int Font::getHeight() const |
363 |
|
|
{ |
364 |
|
2322 |
return TTF_FontHeight(mFont); |
365 |
|
|
} |
366 |
|
|
|
367 |
|
|
void Font::doClean() |
368 |
|
|
{ |
369 |
|
|
for (unsigned int f = 0; f < CACHES_NUMBER; f ++) |
370 |
|
|
{ |
371 |
|
|
TextChunkList *const cache = &mCache[f]; |
372 |
|
|
const size_t size = CAST_SIZE(cache->size); |
373 |
|
|
#ifdef DEBUG_FONT_COUNTERS |
374 |
|
|
logger->log("ptr: %u, size: %ld", f, size); |
375 |
|
|
#endif // DEBUG_FONT_COUNTERS |
376 |
|
|
|
377 |
|
|
if (size > CACHE_SIZE_SMALL3) |
378 |
|
|
{ |
379 |
|
|
#ifdef DEBUG_FONT_COUNTERS |
380 |
|
|
mDeleteCounter += 100; |
381 |
|
|
#endif // DEBUG_FONT_COUNTERS |
382 |
|
|
|
383 |
|
|
cache->removeBack(100); |
384 |
|
|
#ifdef DEBUG_FONT_COUNTERS |
385 |
|
|
logger->log("delete3"); |
386 |
|
|
#endif // DEBUG_FONT_COUNTERS |
387 |
|
|
} |
388 |
|
|
else if (size > CACHE_SIZE_SMALL2) |
389 |
|
|
{ |
390 |
|
|
#ifdef DEBUG_FONT_COUNTERS |
391 |
|
|
mDeleteCounter += 20; |
392 |
|
|
#endif // DEBUG_FONT_COUNTERS |
393 |
|
|
|
394 |
|
|
cache->removeBack(20); |
395 |
|
|
#ifdef DEBUG_FONT_COUNTERS |
396 |
|
|
logger->log("delete2"); |
397 |
|
|
#endif // DEBUG_FONT_COUNTERS |
398 |
|
|
} |
399 |
|
|
else if (size > CACHE_SIZE_SMALL1) |
400 |
|
|
{ |
401 |
|
|
#ifdef DEBUG_FONT_COUNTERS |
402 |
|
|
mDeleteCounter ++; |
403 |
|
|
#endif // DEBUG_FONT_COUNTERS |
404 |
|
|
|
405 |
|
|
cache->removeBack(); |
406 |
|
|
#ifdef DEBUG_FONT_COUNTERS |
407 |
|
|
logger->log("delete1"); |
408 |
|
|
#endif // DEBUG_FONT_COUNTERS |
409 |
|
|
} |
410 |
|
|
} |
411 |
|
|
} |
412 |
|
|
|
413 |
|
|
int Font::getStringIndexAt(const std::string& text, const int x) const |
414 |
|
|
{ |
415 |
|
|
const size_t sz = text.size(); |
416 |
|
|
for (size_t i = 0; i < sz; ++i) |
417 |
|
|
{ |
418 |
|
|
if (getWidth(text.substr(0, i)) > x) |
419 |
|
|
return CAST_S32(i); |
420 |
|
|
} |
421 |
|
|
|
422 |
|
|
return CAST_S32(sz); |
423 |
|
|
} |
424 |
|
|
|
425 |
|
|
const TextChunkList *Font::getCache() const noexcept2 |
426 |
|
|
{ |
427 |
|
|
return mCache; |
428 |
|
|
} |
429 |
|
|
|
430 |
|
236 |
void Font::generate(TextChunk &chunk) |
431 |
|
|
{ |
432 |
|
236 |
const std::string &text = chunk.text; |
433 |
✓✓ |
236 |
if (text.empty()) |
434 |
|
41 |
return; |
435 |
|
|
|
436 |
|
195 |
const unsigned char chr = text[0]; |
437 |
|
195 |
TextChunkList *const cache = &mCache[chr]; |
438 |
|
195 |
Color &col = chunk.color; |
439 |
|
195 |
Color &col2 = chunk.color2; |
440 |
|
195 |
const int oldAlpha = col.a; |
441 |
|
195 |
col.a = 255; |
442 |
|
|
|
443 |
|
390 |
TextChunkSmall key(text, col, col2); |
444 |
|
195 |
std::map<TextChunkSmall, TextChunk*> &search = cache->search; |
445 |
|
195 |
std::map<TextChunkSmall, TextChunk*>::iterator i = search.find(key); |
446 |
✗✓ |
195 |
if (i != search.end()) |
447 |
|
|
{ |
448 |
|
|
TextChunk *const chunk2 = (*i).second; |
449 |
|
|
cache->moveToFirst(chunk2); |
450 |
|
|
// search.erase(key); |
451 |
|
|
cache->remove(chunk2); |
452 |
|
|
chunk.img = chunk2->img; |
453 |
|
|
chunk2->img = nullptr; |
454 |
|
|
delete chunk2; |
455 |
|
|
// logger->log("cached image: " + chunk.text); |
456 |
|
|
} |
457 |
|
|
else |
458 |
|
|
{ |
459 |
✗✓ |
195 |
if (cache->size >= CACHE_SIZE) |
460 |
|
|
{ |
461 |
|
|
#ifdef DEBUG_FONT_COUNTERS |
462 |
|
|
mDeleteCounter ++; |
463 |
|
|
#endif // DEBUG_FONT_COUNTERS |
464 |
|
|
|
465 |
|
|
cache->removeBack(); |
466 |
|
|
} |
467 |
|
|
#ifdef DEBUG_FONT_COUNTERS |
468 |
|
|
mCreateCounter ++; |
469 |
|
|
#endif // DEBUG_FONT_COUNTERS |
470 |
|
|
|
471 |
|
195 |
const float alpha = static_cast<float>(chunk.color.a) / 255.0F; |
472 |
✓✗ |
195 |
chunk.generate(mFont, alpha); |
473 |
|
|
// logger->log("generate image: " + chunk.text); |
474 |
|
|
} |
475 |
|
195 |
col.a = oldAlpha; |
476 |
|
|
} |
477 |
|
|
|
478 |
|
431 |
void Font::insertChunk(TextChunk *const chunk) |
479 |
|
|
{ |
480 |
✓✗✓✓ ✗✓✓✓
|
862 |
if ((chunk == nullptr) || chunk->text.empty() || (chunk->img == nullptr)) |
481 |
|
|
return; |
482 |
|
|
// logger->log("insert chunk: text=%s, color: %d,%d,%d", |
483 |
|
|
// chunk->text.c_str(), chunk->color.r, chunk->color.g, chunk->color.b); |
484 |
|
318 |
const unsigned char chr = chunk->text[0]; |
485 |
|
159 |
TextChunkList *const cache = &mCache[chr]; |
486 |
|
|
|
487 |
|
159 |
std::map<TextChunkSmall, TextChunk*> &search = cache->search; |
488 |
|
|
std::map<TextChunkSmall, TextChunk*>::iterator i |
489 |
|
318 |
= search.find(TextChunkSmall(chunk->text, |
490 |
|
159 |
chunk->color, chunk->color2)); |
491 |
✓✓ |
159 |
if (i != search.end()) |
492 |
|
|
{ |
493 |
✓✗ |
3 |
delete2(chunk->img) |
494 |
|
3 |
return; |
495 |
|
|
} |
496 |
|
|
|
497 |
|
|
TextChunk *const chunk2 = new TextChunk(chunk->text, |
498 |
✓✗ |
156 |
chunk->color, chunk->color2, chunk->textFont); |
499 |
|
156 |
chunk2->img = chunk->img; |
500 |
|
156 |
cache->insertFirst(chunk2); |
501 |
|
|
} |