1 /*
2
3 Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
4 and the "Aleph One" developers.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 This license is contained in the file "COPYING",
17 which is included with this source code; it is available online at
18 http://www.gnu.org/licenses/gpl.html
19
20 */
21
22 /*
23 * sdl_fonts.cpp - SDL font handling
24 *
25 * Written in 2000 by Christian Bauer
26 */
27
28 #include "cseries.h"
29 #include "sdl_fonts.h"
30 #include "byte_swapping.h"
31 #include "game_errors.h"
32 #include "resource_manager.h"
33 #include "FileHandler.h"
34 #include "Logging.h"
35
36 #include <SDL_endian.h>
37 #include <vector>
38 #include <map>
39
40 #include <boost/tokenizer.hpp>
41 #include <string>
42
43 #ifndef NO_STD_NAMESPACE
44 using std::vector;
45 using std::pair;
46 using std::map;
47 #endif
48
49 #include <boost/tuple/tuple_comparison.hpp>
50 #include "preferences.h" // smooth_font
51 #include "AlephSansMono-Bold.h"
52 #include "ProFontAO.h"
53
54 #include "CourierPrime.h"
55 #include "CourierPrimeBold.h"
56 #include "CourierPrimeItalic.h"
57 #include "CourierPrimeBoldItalic.h"
58
59 // Global variables
60 typedef pair<int, int> id_and_size_t;
61 typedef map<id_and_size_t, sdl_font_info *> font_list_t;
62 static font_list_t font_list; // List of all loaded fonts
63
64 typedef pair<TTF_Font *, int> ref_counted_ttf_font_t;
65 typedef map<ttf_font_key_t, ref_counted_ttf_font_t> ttf_font_list_t;
66 static ttf_font_list_t ttf_font_list;
67
68 // From shell_sdl.cpp
69 extern vector<DirectorySpecifier> data_search_path;
70
71
72 /*
73 * Initialize font management
74 */
75
76 typedef struct builtin_font
77 {
78 std::string name;
79 unsigned char *data;
80 unsigned int size;
81 } builtin_font_t;
82
83 static builtin_font_t builtin_fontspecs[] = {
84 { "mono", aleph_sans_mono_bold, sizeof(aleph_sans_mono_bold) },
85 { "Monaco", pro_font_ao, sizeof(pro_font_ao) },
86 { "Courier Prime", courier_prime, sizeof(courier_prime) },
87 { "Courier Prime Bold", courier_prime_bold, sizeof(courier_prime_bold) },
88 { "Courier Prime Italic", courier_prime_italic, sizeof(courier_prime_italic) },
89 {" Courier Prime Bold Italic", courier_prime_bold_italic, sizeof(courier_prime_bold_italic) }
90 };
91
92 #define NUMBER_OF_BUILTIN_FONTS sizeof(builtin_fontspecs) / sizeof(builtin_font)
93
94 typedef std::map<std::string, builtin_font_t> builtin_fonts_t;
95 builtin_fonts_t builtin_fonts;
96
initialize_fonts(bool last_chance)97 void initialize_fonts(bool last_chance)
98 {
99 logContext("initializing fonts");
100
101 // Initialize builtin TTF fonts
102 for (int j = 0; j < NUMBER_OF_BUILTIN_FONTS; ++j)
103 builtin_fonts[builtin_fontspecs[j].name] = builtin_fontspecs[j];
104
105 // Open font resource files
106 bool found = false;
107 vector<DirectorySpecifier>::const_iterator i = data_search_path.begin(), end = data_search_path.end();
108 while (i != end) {
109 FileSpecifier fonts = *i + "Fonts";
110
111 if (open_res_file(fonts))
112 found = true;
113
114 if (!found)
115 {
116 fonts = *i + "Fonts.fntA";
117 if (open_res_file(fonts))
118 found = true;
119 }
120 i++;
121 }
122 }
123
124
125 /*
126 * Load font from resources and allocate sdl_font_info
127 */
128
load_sdl_font(const TextSpec & spec)129 sdl_font_info *load_sdl_font(const TextSpec &spec)
130 {
131 sdl_font_info *info = NULL;
132
133 // Look for ID/size in list of loaded fonts
134 id_and_size_t id_and_size(spec.font, spec.size);
135 font_list_t::const_iterator it = font_list.find(id_and_size);
136 if (it != font_list.end()) { // already loaded
137 info = it->second;
138 info->ref_count++;
139 return info;
140 }
141
142 // Load font family resource
143 LoadedResource fond;
144 if (!get_resource(FOUR_CHARS_TO_INT('F', 'O', 'N', 'D'), spec.font, fond)) {
145 fprintf(stderr, "Font family resource for font ID %d not found\n", spec.font);
146 return NULL;
147 }
148 SDL_RWops *p = SDL_RWFromMem(fond.GetPointer(), (int)fond.GetLength());
149 assert(p);
150
151 // Look for font size in association table
152 SDL_RWseek(p, 52, SEEK_SET);
153 int num_assoc = SDL_ReadBE16(p) + 1;
154 while (num_assoc--) {
155 int size = SDL_ReadBE16(p);
156 SDL_ReadBE16(p); // skip style
157 int id = SDL_ReadBE16(p);
158 if (size == spec.size) {
159
160 // Size found, load bitmap font resource
161 info = new sdl_font_info;
162 if (!get_resource(FOUR_CHARS_TO_INT('N', 'F', 'N', 'T'), id, info->rsrc))
163 get_resource(FOUR_CHARS_TO_INT('F', 'O', 'N', 'T'), id, info->rsrc);
164 if (info->rsrc.IsLoaded()) {
165
166 // Found, switch stream to font resource
167 SDL_RWclose(p);
168 p = SDL_RWFromMem(info->rsrc.GetPointer(), (int)info->rsrc.GetLength());
169 assert(p);
170 void *font_ptr = info->rsrc.GetPointer(true);
171
172 // Read font information
173 SDL_RWseek(p, 2, SEEK_CUR);
174 info->first_character = static_cast<uint8>(SDL_ReadBE16(p));
175 info->last_character = static_cast<uint8>(SDL_ReadBE16(p));
176 SDL_RWseek(p, 2, SEEK_CUR);
177 info->maximum_kerning = SDL_ReadBE16(p);
178 SDL_RWseek(p, 2, SEEK_CUR);
179 info->rect_width = SDL_ReadBE16(p);
180 info->rect_height = SDL_ReadBE16(p);
181 SDL_RWseek(p, 2, SEEK_CUR);
182 info->ascent = SDL_ReadBE16(p);
183 info->descent = SDL_ReadBE16(p);
184 info->leading = SDL_ReadBE16(p);
185 int bytes_per_row = SDL_ReadBE16(p) * 2;
186
187 //printf(" first %d, last %d, max_kern %d, rect_w %d, rect_h %d, ascent %d, descent %d, leading %d, bytes_per_row %d\n",
188 // info->first_character, info->last_character, info->maximum_kerning,
189 // info->rect_width, info->rect_height, info->ascent, info->descent, info->leading, bytes_per_row);
190
191 // Convert bitmap to pixmap (1 byte/pixel)
192 info->bytes_per_row = bytes_per_row * 8;
193 uint8 *src = (uint8 *)font_ptr + SDL_RWtell(p);
194 uint8 *dst = info->pixmap = (uint8 *)malloc(info->rect_height * info->bytes_per_row);
195 assert(dst);
196 for (int y=0; y<info->rect_height; y++) {
197 for (int x=0; x<bytes_per_row; x++) {
198 uint8 b = *src++;
199 *dst++ = (b & 0x80) ? 0xff : 0x00;
200 *dst++ = (b & 0x40) ? 0xff : 0x00;
201 *dst++ = (b & 0x20) ? 0xff : 0x00;
202 *dst++ = (b & 0x10) ? 0xff : 0x00;
203 *dst++ = (b & 0x08) ? 0xff : 0x00;
204 *dst++ = (b & 0x04) ? 0xff : 0x00;
205 *dst++ = (b & 0x02) ? 0xff : 0x00;
206 *dst++ = (b & 0x01) ? 0xff : 0x00;
207 }
208 }
209 SDL_RWseek(p, info->rect_height * bytes_per_row, SEEK_CUR);
210
211 // Set table pointers
212 int table_size = info->last_character - info->first_character + 3; // Tables contain 2 additional entries
213 info->location_table = (uint16 *)((uint8 *)font_ptr + SDL_RWtell(p));
214 byte_swap_memory(info->location_table, _2byte, table_size);
215 SDL_RWseek(p, table_size * 2, SEEK_CUR);
216 info->width_table = (int8 *)font_ptr + SDL_RWtell(p);
217
218 // Add font information to list of known fonts
219 info->ref_count++;
220 font_list[id_and_size] = info;
221
222 } else {
223 delete info;
224 info = NULL;
225 fprintf(stderr, "Bitmap font resource ID %d not found\n", id);
226 }
227 }
228 }
229
230 // Free resources
231 SDL_RWclose(p);
232 return info;
233 }
234
load_ttf_font(const std::string & path,uint16 style,int16 size)235 static TTF_Font *load_ttf_font(const std::string& path, uint16 style, int16 size)
236 {
237 // already loaded? increment reference counter and return pointer
238 ttf_font_key_t search_key(path, style, size);
239 ttf_font_list_t::iterator it = ttf_font_list.find(search_key);
240 if (it != ttf_font_list.end())
241 {
242 TTF_Font *font = it->second.first;
243 it->second.second++;
244
245 return font;
246 }
247
248 TTF_Font *font = 0;
249 builtin_fonts_t::iterator j = builtin_fonts.find(path);
250 if (j != builtin_fonts.end())
251 {
252 font = TTF_OpenFontRW(SDL_RWFromConstMem(j->second.data, j->second.size), 0, size);
253 }
254 else
255 {
256 short SavedType, SavedError = get_game_error(&SavedType);
257
258 FileSpecifier fileSpec(path);
259 OpenedFile file;
260 if (fileSpec.Open(file))
261 {
262 font = TTF_OpenFontRW(file.TakeRWops(), 1, size);
263 }
264
265 set_game_error(SavedType, SavedError);
266 }
267
268 if (font)
269 {
270 int ttf_style = TTF_STYLE_NORMAL;
271 if (style & styleBold)
272 ttf_style |= TTF_STYLE_BOLD;
273 if (style & styleItalic)
274 ttf_style |= TTF_STYLE_ITALIC;
275
276 TTF_SetFontStyle(font, ttf_style);
277 #ifdef TTF_HINTING_LIGHT
278 if (environment_preferences->smooth_text)
279 TTF_SetFontHinting(font, TTF_HINTING_LIGHT);
280 else
281 TTF_SetFontHinting(font, TTF_HINTING_MONO);
282 #endif
283
284 ttf_font_key_t key(path, style, size);
285 ref_counted_ttf_font_t value(font, 1);
286
287 ttf_font_list[key] = value;
288 }
289
290 return font;
291 }
292
locate_font(const std::string & path)293 static const char *locate_font(const std::string& path)
294 {
295 builtin_fonts_t::iterator j = builtin_fonts.find(path);
296 if (j != builtin_fonts.end() || path == "")
297 {
298 return path.c_str();
299 }
300 else
301 {
302 static FileSpecifier file;
303 if (file.SetNameWithPath(path.c_str()))
304 return file.GetPath();
305 else
306 return "";
307 }
308 }
309
load_font(const TextSpec & spec)310 font_info *load_font(const TextSpec &spec) {
311 // return static_cast<font_info*>(load_font(spec));
312
313 if (spec.normal != "")
314 {
315 std::string file;
316 file = locate_font(spec.normal);
317 TTF_Font *font = load_ttf_font(file, 0, spec.size);
318 if (font)
319 {
320 ttf_font_info *info = new ttf_font_info;
321 info->m_adjust_height = spec.adjust_height;
322 info->m_styles[styleNormal] = font;
323 info->m_keys[styleNormal] = ttf_font_key_t(file, 0, spec.size);
324
325 // load bold face
326 file = locate_font(spec.bold);
327 font = load_ttf_font(file, styleNormal, spec.size);
328 if (font)
329 {
330 info->m_styles[styleBold] = font;
331 info->m_keys[styleBold] = ttf_font_key_t(file, styleNormal, spec.size);
332 }
333 else
334 {
335 file = locate_font(spec.normal);
336 font = load_ttf_font(file, styleBold, spec.size);
337 assert(font); // I loaded you once, you should load again
338 info->m_styles[styleBold] = font;
339 info->m_keys[styleBold] = ttf_font_key_t(file, styleBold, spec.size);
340 }
341
342 // oblique
343 file = locate_font(spec.oblique);
344 font = load_ttf_font(file, styleNormal, spec.size);
345 if (font)
346 {
347 info->m_styles[styleItalic] = font;
348 info->m_keys[styleItalic] = ttf_font_key_t(file, styleNormal, spec.size);
349 }
350 else
351 {
352 file = locate_font(spec.normal);
353 font = load_ttf_font(file, styleItalic, spec.size);
354 assert(font); // same as above
355 info->m_styles[styleItalic] = font;
356 info->m_keys[styleItalic] = ttf_font_key_t(file, styleItalic, spec.size);
357 }
358
359 // bold oblique
360 file = locate_font(spec.bold_oblique);
361 font = load_ttf_font(file, styleNormal, spec.size);
362 if (font)
363 {
364 info->m_styles[styleBold | styleItalic] = font;
365 info->m_keys[styleBold | styleItalic] = ttf_font_key_t(file, styleNormal, spec.size);
366 }
367 else
368 {
369 // try boldening the oblique
370 file = locate_font(spec.oblique);
371 font = load_ttf_font(file, styleBold, spec.size);
372 if (font)
373 {
374 info->m_styles[styleBold | styleItalic] = font;
375 info->m_keys[styleBold | styleItalic] = ttf_font_key_t(file, styleBold, spec.size);
376 }
377 else
378 {
379 // try obliquing the bold!
380 file = locate_font(spec.bold);
381 font = load_ttf_font(file, styleItalic, spec.size);
382 if (font)
383 {
384 info->m_styles[styleBold | styleItalic] = font;
385 info->m_keys[styleBold | styleItalic] = ttf_font_key_t(file, styleItalic, spec.size);
386 }
387 else
388 {
389 file = locate_font(spec.normal);
390 font = load_ttf_font(file, styleBold | styleItalic, spec.size);
391 assert(font);
392 info->m_styles[styleBold | styleItalic] = font;
393 info->m_keys[styleBold | styleItalic] = ttf_font_key_t(file, styleBold | styleItalic, spec.size);
394 }
395 }
396 }
397
398
399 return info;
400 }
401 else if (spec.font != -1)
402 {
403 return static_cast<font_info *>(load_sdl_font(spec));
404 }
405 else
406 return 0;
407 }
408 else
409 if (spec.font != -1)
410 {
411 return static_cast<font_info *>(load_sdl_font(spec));
412 }
413 else
414 return 0;
415 }
416
417
418 /*
419 * Unload font, free sdl_font_info
420 */
421
_unload()422 void sdl_font_info::_unload()
423 {
424 // Look for font in list of loaded fonts
425 font_list_t::const_iterator i = font_list.begin(), end = font_list.end();
426 while (i != end) {
427 if (i->second == this) {
428
429 // Found, decrement reference counter and delete
430 ref_count--;
431 if (ref_count <= 0) {
432 delete this; // !
433 font_list.erase(i->first);
434 return;
435 }
436 }
437 i++;
438 }
439 }
440
_unload()441 void ttf_font_info::_unload()
442 {
443 for (int i = 0; i < styleUnderline; ++i)
444 {
445 ttf_font_list_t::iterator it = ttf_font_list.find(m_keys[i]);
446 if (it != ttf_font_list.end())
447 {
448 --(it->second.second);
449 if (it->second.second <= 0)
450 {
451 TTF_CloseFont(it->second.first);
452 ttf_font_list.erase(m_keys[i]);
453 }
454 }
455
456 m_styles[i] = 0;
457 }
458
459 delete this;
460 }
461
unload_font(font_info * info)462 void unload_font(font_info *info)
463 {
464 info->_unload();
465 }
466
char_width(uint8 c,uint16 style) const467 int8 sdl_font_info::char_width(uint8 c, uint16 style) const
468 {
469 if (c < first_character || c > last_character)
470 return 0;
471 int8 width = width_table[(c - first_character) * 2 + 1] + ((style & styleBold) ? 1 : 0);
472 if (width == -1) // non-existant character
473 width = width_table[(last_character - first_character + 1) * 2 + 1] + ((style & styleBold) ? 1 : 0);
474 return width;
475 }
476
_text_width(const char * text,uint16 style,bool) const477 uint16 sdl_font_info::_text_width(const char *text, uint16 style, bool) const
478 {
479 int width = 0;
480 char c;
481 while ((c = *text++) != 0)
482 width += char_width(c, style);
483 assert(0 <= width);
484 assert(width == static_cast<int>(static_cast<uint16>(width)));
485 return width;
486 }
487
_text_width(const char * text,size_t length,uint16 style,bool) const488 uint16 sdl_font_info::_text_width(const char *text, size_t length, uint16 style, bool) const
489 {
490 int width = 0;
491 while (length--)
492 width += char_width(*text++, style);
493 assert(0 <= width);
494 assert(width == static_cast<int>(static_cast<uint16>(width)));
495 return width;
496 }
497
_trunc_text(const char * text,int max_width,uint16 style) const498 int sdl_font_info::_trunc_text(const char *text, int max_width, uint16 style) const
499 {
500 int width = 0;
501 int num = 0;
502 char c;
503 while ((c = *text++) != 0) {
504 width += char_width(c, style);
505 if (width > max_width)
506 break;
507 num++;
508 }
509 return num;
510 }
511
512 // sdl_font_info::_draw_text is in screen_drawing.cpp
513
char_width(uint8 c,uint16 style) const514 int8 ttf_font_info::char_width(uint8 c, uint16 style) const
515 {
516 int advance;
517 TTF_GlyphMetrics(get_ttf(style), mac_roman_to_unicode(static_cast<char>(c)), 0, 0, 0, 0, &advance);
518
519 return advance;
520 }
_text_width(const char * text,uint16 style,bool utf8) const521 uint16 ttf_font_info::_text_width(const char *text, uint16 style, bool utf8) const
522 {
523 return _text_width(text, strlen(text), style, utf8);
524 }
525
_text_width(const char * text,size_t length,uint16 style,bool utf8) const526 uint16 ttf_font_info::_text_width(const char *text, size_t length, uint16 style, bool utf8) const
527 {
528 int width = 0;
529 if (utf8)
530 {
531 char *temp = process_printable(text, length);
532 TTF_SizeUTF8(get_ttf(style), temp, &width, 0);
533 }
534 else
535 {
536 uint16 *temp = process_macroman(text, length);
537 TTF_SizeUNICODE(get_ttf(style), temp, &width, 0);
538 }
539
540 return width;
541 }
542
_trunc_text(const char * text,int max_width,uint16 style) const543 int ttf_font_info::_trunc_text(const char *text, int max_width, uint16 style) const
544 {
545 int width;
546 static uint16 temp[1024];
547 mac_roman_to_unicode(text, temp, 1024);
548 TTF_SizeUNICODE(get_ttf(style), temp, &width, 0);
549 if (width < max_width) return strlen(text);
550
551 int num = strlen(text) - 1;
552
553 while (num > 0 && width > max_width)
554 {
555 num--;
556 temp[num] = 0x0;
557 TTF_SizeUNICODE(get_ttf(style), temp, &width, 0);
558 }
559
560 return num;
561 }
562
563 // ttf_font_info::_draw_text is in screen_drawing.cpp
564
process_printable(const char * src,int len) const565 char *ttf_font_info::process_printable(const char *src, int len) const
566 {
567 static char dst[1024];
568 if (len > 1023) len = 1023;
569 char *p = dst;
570 while (*src && len-- > 0)
571 {
572 if ((unsigned char) *src >= ' ') *p++ = *src;
573 src++;
574 }
575
576 *p = '\0';
577 return dst;
578 }
579
process_macroman(const char * src,int len) const580 uint16 *ttf_font_info::process_macroman(const char *src, int len) const
581 {
582 static uint16 dst[1024];
583 if (len > 1023) len = 1023;
584 uint16 *p = dst;
585 while (*src && len-- > 0)
586 {
587 if ((unsigned char) *src >= ' ') *p++ = mac_roman_to_unicode(*src);
588 else if ((unsigned char) *src == '\t')
589 *p++ = ' ';
590
591 src++;
592 }
593
594 *p = 0x0;
595 return dst;
596 }
597
text_width(const char * text,uint16 style,bool utf8) const598 uint16 font_info::text_width(const char *text, uint16 style, bool utf8) const
599 {
600 if (style & styleShadow)
601 return _text_width(text, style, utf8) + 1;
602 else
603 return _text_width(text, style, utf8);
604 }
605
text_width(const char * text,size_t length,uint16 style,bool utf8) const606 uint16 font_info::text_width(const char *text, size_t length, uint16 style, bool utf8) const
607 {
608 if (style & styleShadow)
609 return _text_width(text, length, style, utf8) + 1;
610 else
611 return _text_width(text, length, style, utf8);
612 }
613
style_code(char c)614 static inline bool style_code(char c)
615 {
616 switch(tolower(c)) {
617 case 'p':
618 case 'b':
619 case 'i':
620 case 'l':
621 case 'r':
622 case 'c':
623 case 's':
624 return true;
625 default:
626 return false;
627 }
628 }
629
630 class style_separator
631 {
632 public:
operator ()(std::string::const_iterator & next,std::string::const_iterator end,std::string & token)633 bool operator() (std::string::const_iterator& next, std::string::const_iterator end, std::string& token)
634 {
635 if (next == end) return false;
636
637 token = std::string();
638
639 // if we start with a token, return it
640 if (*next == '|' && next + 1 != end && style_code(*(next + 1)))
641 {
642 token += *next;
643 ++next;
644 token += *next;
645 ++next;
646 return true;
647 }
648
649 token += *next;
650 ++next;
651
652 // add characters until we hit a token
653 for (;next != end && !(*next == '|' && next + 1 != end && style_code(*(next + 1))); ++next)
654 {
655 token += *next;
656 }
657
658 return true;
659 }
660
reset()661 void reset() { }
662
663 };
664
is_style_token(const std::string & token)665 static inline bool is_style_token(const std::string& token)
666 {
667 return (token.size() == 2 && token[0] == '|' && style_code(token[1]));
668 }
669
update_style(uint16 & style,const std::string & token)670 static void update_style(uint16& style, const std::string& token)
671 {
672 if (tolower(token[1]) == 'p')
673 style &= ~(styleBold | styleItalic);
674 else if (tolower(token[1]) == 'b')
675 {
676 style |= styleBold;
677 style &= ~styleItalic;
678 }
679 else if (tolower(token[1]) == 'i')
680 {
681 style |= styleItalic;
682 style &= ~styleBold;
683 }
684 }
685
686
draw_styled_text(SDL_Surface * s,const std::string & text,size_t length,int x,int y,uint32 pixel,uint16 style,bool utf8) const687 int font_info::draw_styled_text(SDL_Surface *s, const std::string& text, size_t length, int x, int y, uint32 pixel, uint16 style, bool utf8) const
688 {
689 int width = 0;
690 boost::tokenizer<style_separator> tok(text.begin(), text.begin() + length);
691 for (boost::tokenizer<style_separator>::iterator it = tok.begin(); it != tok.end(); ++it)
692 {
693 if (is_style_token(*it))
694 {
695 update_style(style, *it);
696 }
697 else
698 {
699 if (style & styleShadow)
700 {
701 _draw_text(s, it->c_str(), it->size(), x + width + 1, y + 1, SDL_MapRGB(s->format, 0x0, 0x0, 0x0), style, utf8);
702 }
703 width += _draw_text(s, it->c_str(), it->size(), x + width, y, pixel, style, utf8);
704 }
705 }
706
707 return width;
708 }
709
styled_text_width(const std::string & text,size_t length,uint16 style,bool utf8) const710 int font_info::styled_text_width(const std::string& text, size_t length, uint16 style, bool utf8) const
711 {
712 int width = 0;
713 boost::tokenizer<style_separator> tok(text.begin(), text.begin() + length);
714 for (boost::tokenizer<style_separator>::iterator it = tok.begin(); it != tok.end(); ++it)
715 {
716 if (is_style_token(*it))
717 {
718 update_style(style, *it);
719 }
720 else
721 {
722 width += _text_width(it->c_str(), it->length(), style, utf8);
723 }
724 }
725
726 if (style & styleShadow)
727 return width + 1;
728 else
729 return width;
730 }
731
trunc_styled_text(const std::string & text,int max_width,uint16 style) const732 int font_info::trunc_styled_text(const std::string& text, int max_width, uint16 style) const
733 {
734 if (style & styleShadow)
735 {
736 max_width -= 1;
737 style &= (~styleShadow);
738 }
739
740 int length = 0;
741 boost::tokenizer<style_separator> tok(text);
742 for (boost::tokenizer<style_separator>::iterator it = tok.begin(); it != tok.end(); ++it)
743 {
744 if (is_style_token(*it))
745 {
746 update_style(style, *it);
747 length += 2;
748 }
749 else
750 {
751 int additional_length = _trunc_text(it->c_str(), max_width, style);
752 max_width -= _text_width(it->c_str(), additional_length, style);
753 length += additional_length;
754 if (additional_length < it->size())
755 return length;
756 }
757 }
758
759 return length;
760 }
761
style_at(const std::string & text,std::string::const_iterator pos,uint16 style) const762 std::string font_info::style_at(const std::string& text, std::string::const_iterator pos, uint16 style) const
763 {
764 boost::tokenizer<style_separator> tok(text.begin(), pos);
765 for (boost::tokenizer<style_separator>::iterator it = tok.begin(); it != tok.end(); ++it)
766 {
767 if (is_style_token(*it))
768 update_style(style, *it);
769 }
770
771 if (style & styleBold)
772 return string("|b");
773 else if (style & styleItalic)
774 return string("|i");
775 else
776 return string();
777 }
778
draw_text(SDL_Surface * s,const char * text,size_t length,int x,int y,uint32 pixel,uint16 style,bool utf8) const779 int font_info::draw_text(SDL_Surface *s, const char *text, size_t length, int x, int y, uint32 pixel, uint16 style, bool utf8) const
780 {
781 if (style & styleShadow)
782 {
783 _draw_text(s, text, length, x + 1, y + 1, SDL_MapRGB(s->format, 0x0, 0x0, 0x0), style, utf8);
784 }
785
786 return _draw_text(s, text, length, x, y, pixel, style, utf8);
787 }
788
trunc_text(const char * text,int max_width,uint16 style) const789 int font_info::trunc_text(const char *text, int max_width, uint16 style) const
790 {
791 if (style & styleShadow)
792 return _trunc_text(text, max_width - 1, style);
793 else
794 return _trunc_text(text, max_width, style);
795 }
796