PageRenderTime 27ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/branches/release-1.0/Source_Files/RenderOther/sdl_fonts.cpp

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