PageRenderTime 45ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/branches/shader-support/Source_Files/RenderOther/sdl_fonts.cpp

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