Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

847 lines
25 KiB

  1. //========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=====================================================================================//
  6. #include <locale.h>
  7. #include "vgui_surfacelib/BitmapFont.h"
  8. #include "vgui_surfacelib/fontmanager.h"
  9. #include "convar.h"
  10. #include <vgui/ISurface.h>
  11. #include <tier0/dbg.h>
  12. // memdbgon must be the last include file in a .cpp file!!!
  13. #include <tier0/memdbgon.h>
  14. static CFontManager s_FontManager;
  15. #ifdef WIN32
  16. extern bool s_bSupportsUnicode;
  17. #endif
  18. #if !defined( _X360 )
  19. #define MAX_INITIAL_FONTS 100
  20. #else
  21. #define MAX_INITIAL_FONTS 1
  22. #endif
  23. //-----------------------------------------------------------------------------
  24. // Purpose: singleton accessor
  25. //-----------------------------------------------------------------------------
  26. CFontManager &FontManager()
  27. {
  28. return s_FontManager;
  29. }
  30. //-----------------------------------------------------------------------------
  31. // Purpose: Constructor
  32. //-----------------------------------------------------------------------------
  33. CFontManager::CFontManager()
  34. {
  35. // add a single empty font, to act as an invalid font handle 0
  36. m_FontAmalgams.EnsureCapacity( MAX_INITIAL_FONTS );
  37. m_FontAmalgams.AddToTail();
  38. m_Win32Fonts.EnsureCapacity( MAX_INITIAL_FONTS );
  39. #ifdef LINUX
  40. FT_Error error = FT_Init_FreeType( &library );
  41. if ( error )
  42. Error( "Unable to initalize freetype library, is it installed?" );
  43. pFontDataHelper = NULL;
  44. #endif
  45. // setup our text locale
  46. setlocale( LC_CTYPE, "" );
  47. setlocale( LC_TIME, "" );
  48. setlocale( LC_COLLATE, "" );
  49. setlocale( LC_MONETARY, "" );
  50. m_pFileSystem = NULL;
  51. m_pMaterialSystem = NULL;
  52. }
  53. //-----------------------------------------------------------------------------
  54. // Purpose: language setting for font fallbacks
  55. //-----------------------------------------------------------------------------
  56. void CFontManager::SetLanguage(const char *language)
  57. {
  58. Q_strncpy(m_szLanguage, language, sizeof(m_szLanguage));
  59. }
  60. //-----------------------------------------------------------------------------
  61. //
  62. //-----------------------------------------------------------------------------
  63. const char *CFontManager::GetLanguage()
  64. {
  65. return m_szLanguage;
  66. }
  67. //-----------------------------------------------------------------------------
  68. // Purpose: Destructor
  69. //-----------------------------------------------------------------------------
  70. CFontManager::~CFontManager()
  71. {
  72. ClearAllFonts();
  73. #ifdef LINUX
  74. FT_Done_FreeType( library );
  75. #endif
  76. }
  77. //-----------------------------------------------------------------------------
  78. // Purpose: frees the fonts
  79. //-----------------------------------------------------------------------------
  80. void CFontManager::ClearAllFonts()
  81. {
  82. // free the fonts
  83. for (int i = 0; i < m_Win32Fonts.Count(); i++)
  84. {
  85. delete m_Win32Fonts[i];
  86. }
  87. m_Win32Fonts.RemoveAll();
  88. m_FontAmalgams.RemoveAll();
  89. }
  90. //-----------------------------------------------------------------------------
  91. // Purpose:
  92. //-----------------------------------------------------------------------------
  93. vgui::HFont CFontManager::CreateFont()
  94. {
  95. int i = m_FontAmalgams.AddToTail();
  96. return i;
  97. }
  98. //-----------------------------------------------------------------------------
  99. // Purpose: Sets the valid glyph ranges for a font created by CreateFont()
  100. //-----------------------------------------------------------------------------
  101. bool CFontManager::SetFontGlyphSet(HFont font, const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags)
  102. {
  103. return SetFontGlyphSet( font, windowsFontName, tall, weight, blur, scanlines, flags, 0, 0);
  104. }
  105. //-----------------------------------------------------------------------------
  106. // Purpose: Sets the valid glyph ranges for a font created by CreateFont()
  107. //-----------------------------------------------------------------------------
  108. bool CFontManager::SetFontGlyphSet(HFont font, const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags, int nRangeMin, int nRangeMax)
  109. {
  110. // ignore all but the first font added
  111. // need to rev vgui versions and change the name of this function
  112. if ( m_FontAmalgams[font].GetCount() > 0 )
  113. {
  114. // clear any existing fonts
  115. m_FontAmalgams[font].RemoveAll();
  116. }
  117. bool bForceSingleFont = false;
  118. if ( IsX360() )
  119. {
  120. //-----//
  121. // 360 //
  122. //-----//
  123. // AV - The 360 must use the same size font for 0-255 and 256-0xFFFF regardless of the font since the
  124. // fontAmalgam can only deal with a consistent font height for all fonts in a single amalgam. We
  125. // could change this if we forced all fonts within a single amalgam to have the same height with
  126. // the font baselines aligned, but even then the fonts wouldn't look great, because different
  127. // fonts set to the same size don't necessarily have the same height visually. We need to revisit
  128. // this before shipping l4d2 on the PC!
  129. bForceSingleFont = true;
  130. // discovered xbox only allows glyphs from these languages from the foreign fallback font
  131. // prefer to have the entire range of chars from the font so UI doesn't suffer from glyph disparity
  132. if ( !V_stricmp( windowsFontName, "toolbox" ) || !V_stricmp( windowsFontName, "courier new" ) )
  133. {
  134. // toolbox stays as-is
  135. // courier new is an internal debug font, not part of customer UI, need it stay as is
  136. }
  137. else
  138. {
  139. bool bUseFallback = false;
  140. if ( !V_stricmp( m_szLanguage, "portuguese" ) ||
  141. !V_stricmp( m_szLanguage, "polish" ) )
  142. {
  143. static ConVarRef mat_xbox_iswidescreen( "mat_xbox_iswidescreen" );
  144. static ConVarRef mat_xbox_ishidef( "mat_xbox_ishidef" );
  145. // we can support these languages with our desired fonts in hidef/widescreen modes only
  146. // we must fallback to the more legible font in the lowdef or non-widescreen
  147. bUseFallback = !( mat_xbox_iswidescreen.GetBool() && mat_xbox_ishidef.GetBool() );
  148. }
  149. if ( bUseFallback ||
  150. !V_stricmp( m_szLanguage, "japanese" ) ||
  151. !V_stricmp( m_szLanguage, "korean" ) ||
  152. !V_stricmp( m_szLanguage, "schinese" ) ||
  153. !V_stricmp( m_szLanguage, "tchinese" ) ||
  154. !V_stricmp( m_szLanguage, "russian" ) )
  155. {
  156. // these languages must use the font that has their glyphs
  157. // these language require a high degree of legibility
  158. windowsFontName = GetForeignFallbackFontName();
  159. }
  160. }
  161. }
  162. else
  163. {
  164. //----//
  165. // PC //
  166. //----//
  167. // AV - The PC has the same issues caused by multiple fonts in a single amalgam with different font
  168. // heights...see comment above. Given the available languages in Steam, the languages below
  169. // were illegible at 1024x768. Resolutions of 800x600 and 640x480 are a complete mess for all
  170. // languages, including English. We probably need to fallback to Tahoma for all languages when
  171. // the vertical resolution < 720. This will probably be the next check-in, but we need to evaluate
  172. // this further tomorrow.
  173. if ( !V_stricmp( windowsFontName, "toolbox" ) || !V_stricmp( windowsFontName, "courier new" ) )
  174. {
  175. // toolbox stays as-is
  176. // courier new is an internal debug font, not part of customer UI, need it stay as is
  177. }
  178. else
  179. {
  180. // These languages are illegible @ vertical resolutions <= 768
  181. if ( !V_stricmp( m_szLanguage, "korean" ) ||
  182. !V_stricmp( m_szLanguage, "schinese" ) ||
  183. !V_stricmp( m_szLanguage, "tchinese" ) ||
  184. !V_stricmp( m_szLanguage, "russian" ) ||
  185. !V_stricmp( m_szLanguage, "thai" ) ||
  186. !V_stricmp( m_szLanguage, "japanese" ) ||
  187. !V_stricmp( m_szLanguage, "czech" ) )
  188. {
  189. windowsFontName = GetForeignFallbackFontName();
  190. bForceSingleFont = true;
  191. }
  192. }
  193. }
  194. // AV - If we actually want to support multiple fonts within an amalgam, we need a change here. Currently,
  195. // the code will use winFont for 0-255 and pExtendedFont for 256-0xFFFF! But since the functions for
  196. // getting the font height from the amalgam can only return one height, the heights of the two fonts
  197. // need to be identical. This isn't trivial because even if we query both fonts for their height
  198. // first, that won't force their baselines within the font pages to be aligned. So we would have to
  199. // do something much more complicated where we loop over all characters in each font to find the
  200. // absolute ascent and descent above/below the baseline and then when we create the font, align both
  201. // fonts to the shared baseline with a shared height. But even with the font baselines aligned with a
  202. // shared height, the fonts still wouldn't look great, because different fonts set to the same size
  203. // don't necessarily have the same height visually. We need to revisit this before shipping l4d2 on the PC!
  204. // And there are still issues with what I'm suggesting here because when we ask the font API what
  205. // the maxHeight, maxAscent, maxDescent is, we get inconsistent results, so I'm not even sure we could
  206. // successfully align the baseline of two fonts in the font pages.
  207. font_t *winFont = CreateOrFindWin32Font( windowsFontName, tall, weight, blur, scanlines, flags );
  208. // cycle until valid english/extended font support has been created
  209. do
  210. {
  211. // add to the amalgam
  212. if ( bForceSingleFont || IsFontForeignLanguageCapable( windowsFontName ) )
  213. {
  214. if ( winFont )
  215. {
  216. // font supports the full range of characters
  217. m_FontAmalgams[font].AddFont( winFont, 0x0000, 0xFFFF );
  218. return true;
  219. }
  220. }
  221. else
  222. {
  223. // font cannot provide glyphs and just supports the normal range
  224. // redirect to a font that can supply glyps
  225. const char *localizedFontName = GetForeignFallbackFontName();
  226. if ( winFont && !stricmp( localizedFontName, windowsFontName ) )
  227. {
  228. // it's the same font and can support the full range
  229. m_FontAmalgams[font].AddFont( winFont, 0x0000, 0xFFFF );
  230. return true;
  231. }
  232. // create the extended support font
  233. font_t *pExtendedFont = CreateOrFindWin32Font( localizedFontName, tall, weight, blur, scanlines, flags );
  234. if ( winFont && pExtendedFont )
  235. {
  236. // use the normal font for english characters, and the extended font for the rest
  237. int nMin = 0x0000, nMax = 0x00FF;
  238. // did we specify a range?
  239. if ( nRangeMin > 0 || nRangeMax > 0 )
  240. {
  241. nMin = nRangeMin;
  242. nMax = nRangeMax;
  243. // make sure they're in the correct order
  244. if ( nMin > nMax )
  245. {
  246. int nTemp = nMin;
  247. nMin = nMax;
  248. nMax = nTemp;
  249. }
  250. }
  251. if ( nMin > 0 )
  252. {
  253. m_FontAmalgams[font].AddFont( pExtendedFont, 0x0000, nMin - 1 );
  254. }
  255. m_FontAmalgams[font].AddFont( winFont, nMin, nMax );
  256. if ( nMax < 0xFFFF )
  257. {
  258. m_FontAmalgams[font].AddFont( pExtendedFont, nMax + 1, 0xFFFF );
  259. }
  260. return true;
  261. }
  262. else if ( pExtendedFont )
  263. {
  264. // the normal font failed to create
  265. // just use the extended font for the full range
  266. m_FontAmalgams[font].AddFont( pExtendedFont, 0x0000, 0xFFFF );
  267. return true;
  268. }
  269. }
  270. // no valid font has been created, so fallback to a different font and try again
  271. }
  272. while ( NULL != ( windowsFontName = GetFallbackFontName( windowsFontName ) ) );
  273. // nothing successfully created
  274. return false;
  275. }
  276. //-----------------------------------------------------------------------------
  277. // Purpose: adds glyphs to a font created by CreateFont()
  278. //-----------------------------------------------------------------------------
  279. bool CFontManager::SetBitmapFontGlyphSet(HFont font, const char *windowsFontName, float scalex, float scaley, int flags)
  280. {
  281. if ( m_FontAmalgams[font].GetCount() > 0 )
  282. {
  283. // clear any existing fonts
  284. m_FontAmalgams[font].RemoveAll();
  285. }
  286. CBitmapFont *winFont = CreateOrFindBitmapFont( windowsFontName, scalex, scaley, flags );
  287. if ( winFont )
  288. {
  289. // bitmap fonts are only 0-255
  290. m_FontAmalgams[font].AddFont( winFont, 0x0000, 0x00FF );
  291. return true;
  292. }
  293. // nothing successfully created
  294. return false;
  295. }
  296. //-----------------------------------------------------------------------------
  297. // Purpose: Creates a new win32 font, or reuses one if possible
  298. //-----------------------------------------------------------------------------
  299. font_t *CFontManager::CreateOrFindWin32Font(const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags)
  300. {
  301. // see if we already have the win32 font
  302. font_t *winFont = NULL;
  303. int i;
  304. for (i = 0; i < m_Win32Fonts.Count(); i++)
  305. {
  306. if (m_Win32Fonts[i]->IsEqualTo(windowsFontName, tall, weight, blur, scanlines, flags))
  307. {
  308. winFont = m_Win32Fonts[i];
  309. break;
  310. }
  311. }
  312. // create the new win32font if we didn't find it
  313. if (!winFont)
  314. {
  315. MEM_ALLOC_CREDIT();
  316. i = m_Win32Fonts.AddToTail();
  317. #ifdef LINUX
  318. int memSize = 0;
  319. void *pchFontData = pFontDataHelper( windowsFontName, memSize );
  320. if ( pchFontData )
  321. {
  322. m_Win32Fonts[i] = new font_t();
  323. if (m_Win32Fonts[i]->CreateFromMemory( windowsFontName, pchFontData, memSize, tall, weight, blur, scanlines, flags))
  324. {
  325. // add to the list
  326. winFont = m_Win32Fonts[i];
  327. }
  328. else
  329. {
  330. // failed to create, remove
  331. delete m_Win32Fonts[i];
  332. m_Win32Fonts.Remove(i);
  333. return NULL;
  334. }
  335. }
  336. else
  337. {
  338. #endif
  339. m_Win32Fonts[i] = new font_t();
  340. if (m_Win32Fonts[i]->Create(windowsFontName, tall, weight, blur, scanlines, flags))
  341. {
  342. // add to the list
  343. winFont = m_Win32Fonts[i];
  344. }
  345. else
  346. {
  347. // failed to create, remove
  348. delete m_Win32Fonts[i];
  349. m_Win32Fonts.Remove(i);
  350. return NULL;
  351. }
  352. #ifdef LINUX
  353. }
  354. #endif
  355. }
  356. return winFont;
  357. }
  358. //-----------------------------------------------------------------------------
  359. // Purpose: Creates a new win32 font, or reuses one if possible
  360. //-----------------------------------------------------------------------------
  361. CBitmapFont *CFontManager::CreateOrFindBitmapFont(const char *windowsFontName, float scalex, float scaley, int flags)
  362. {
  363. // see if we already have the font
  364. CBitmapFont *winFont = NULL;
  365. int i;
  366. for ( i = 0; i < m_Win32Fonts.Count(); i++ )
  367. {
  368. font_t *font = m_Win32Fonts[i];
  369. // Only looking for bitmap fonts
  370. int testflags = font->GetFlags();
  371. if ( !( testflags & FONTFLAG_BITMAP ) )
  372. {
  373. continue;
  374. }
  375. CBitmapFont *bitmapFont = reinterpret_cast< CBitmapFont* >( font );
  376. if ( bitmapFont->IsEqualTo( windowsFontName, scalex, scaley, flags ) )
  377. {
  378. winFont = bitmapFont;
  379. break;
  380. }
  381. }
  382. // create the font if we didn't find it
  383. if ( !winFont )
  384. {
  385. MEM_ALLOC_CREDIT();
  386. i = m_Win32Fonts.AddToTail();
  387. CBitmapFont *bitmapFont = new CBitmapFont();
  388. if ( bitmapFont->Create( windowsFontName, scalex, scaley, flags ) )
  389. {
  390. // add to the list
  391. m_Win32Fonts[i] = bitmapFont;
  392. winFont = bitmapFont;
  393. }
  394. else
  395. {
  396. // failed to create, remove
  397. delete bitmapFont;
  398. m_Win32Fonts.Remove(i);
  399. return NULL;
  400. }
  401. }
  402. return winFont;
  403. }
  404. //-----------------------------------------------------------------------------
  405. // Purpose: sets the scale of a bitmap font
  406. //-----------------------------------------------------------------------------
  407. void CFontManager::SetFontScale(vgui::HFont font, float sx, float sy)
  408. {
  409. m_FontAmalgams[font].SetFontScale( sx, sy );
  410. }
  411. const char *CFontManager::GetFontName( HFont font )
  412. {
  413. // ignore the amalgam of disparate char ranges, assume the first font
  414. return m_FontAmalgams[font].GetFontName( 0 );
  415. }
  416. //-----------------------------------------------------------------------------
  417. // Purpose: gets the windows font for the particular font in the amalgam
  418. //-----------------------------------------------------------------------------
  419. font_t *CFontManager::GetFontForChar( vgui::HFont font, wchar_t wch )
  420. {
  421. return m_FontAmalgams[font].GetFontForChar(wch);
  422. }
  423. //-----------------------------------------------------------------------------
  424. // Purpose: returns the abc widths of a single character
  425. //-----------------------------------------------------------------------------
  426. void CFontManager::GetCharABCwide(HFont font, int ch, int &a, int &b, int &c)
  427. {
  428. font_t *winFont = m_FontAmalgams[font].GetFontForChar(ch);
  429. if (winFont)
  430. {
  431. winFont->GetCharABCWidths(ch, a, b, c);
  432. }
  433. else
  434. {
  435. // no font for this range, just use the default width
  436. a = c = 0;
  437. b = m_FontAmalgams[font].GetFontMaxWidth();
  438. }
  439. }
  440. //-----------------------------------------------------------------------------
  441. // Purpose: returns the max height of a font
  442. //-----------------------------------------------------------------------------
  443. int CFontManager::GetFontTall(HFont font)
  444. {
  445. return m_FontAmalgams[font].GetFontHeight();
  446. }
  447. //-----------------------------------------------------------------------------
  448. // Purpose: returns the ascent of a font
  449. //-----------------------------------------------------------------------------
  450. int CFontManager::GetFontAscent(HFont font, wchar_t wch)
  451. {
  452. font_t *winFont = m_FontAmalgams[font].GetFontForChar(wch);
  453. if ( winFont )
  454. {
  455. return winFont->GetAscent();
  456. }
  457. else
  458. {
  459. return 0;
  460. }
  461. }
  462. //-----------------------------------------------------------------------------
  463. // Purpose:
  464. //-----------------------------------------------------------------------------
  465. bool CFontManager::IsFontAdditive(HFont font)
  466. {
  467. return ( m_FontAmalgams[font].GetFlags( 0 ) & FONTFLAG_ADDITIVE ) ? true : false;
  468. }
  469. //-----------------------------------------------------------------------------
  470. // Purpose:
  471. //-----------------------------------------------------------------------------
  472. bool CFontManager::IsBitmapFont(HFont font)
  473. {
  474. // A FontAmalgam is either some number of non-bitmap fonts, or a single bitmap font - so this check is valid
  475. return ( m_FontAmalgams[font].GetFlags( 0 ) & FONTFLAG_BITMAP ) ? true : false;
  476. }
  477. //-----------------------------------------------------------------------------
  478. // Purpose: returns the pixel width of a single character
  479. //-----------------------------------------------------------------------------
  480. int CFontManager::GetCharacterWidth(HFont font, int ch)
  481. {
  482. if ( !iswcntrl( ch ) )
  483. {
  484. int a, b, c;
  485. GetCharABCwide(font, ch, a, b, c);
  486. return (a + b + c);
  487. }
  488. return 0;
  489. }
  490. //-----------------------------------------------------------------------------
  491. // Purpose: returns the area of a text string, including newlines
  492. //-----------------------------------------------------------------------------
  493. void CFontManager::GetTextSize(HFont font, const wchar_t *text, int &wide, int &tall)
  494. {
  495. wide = 0;
  496. tall = 0;
  497. if (!text)
  498. return;
  499. // AV - Calling GetFontTall() for an amalgam with multiple fonts will return
  500. // the font height of the first font only! We should be doing something like:
  501. //
  502. // tall = FontManager().GetFontForChar( font, text[0] )->GetHeight();
  503. //
  504. // but that's a little hacky since we're only looking at the first character!
  505. // Same goes for the calls to GetFontTall() in the for loop below
  506. tall = GetFontTall(font);
  507. float xx = 0;
  508. char chBefore = 0;
  509. char chAfter = 0;
  510. for (int i = 0; ; i++)
  511. {
  512. wchar_t ch = text[i];
  513. if (ch == 0)
  514. {
  515. break;
  516. }
  517. chAfter = text[i+1];
  518. if (ch == '\n')
  519. {
  520. // AV - See note above about calling this instead: tall += FontManager().GetFontForChar( font, text[0] )->GetHeight();
  521. tall += GetFontTall(font);
  522. xx=0;
  523. }
  524. else if (ch == '&')
  525. {
  526. // underscore character, so skip
  527. }
  528. else
  529. {
  530. float flWide, flabcA, flabcC;
  531. GetKernedCharWidth( font, ch, chBefore, chAfter, flWide, flabcA, flabcC );
  532. xx += flWide;
  533. if (xx > wide)
  534. {
  535. wide = ceil(xx);
  536. }
  537. }
  538. chBefore = ch;
  539. }
  540. }
  541. // font validation functions
  542. struct FallbackFont_t
  543. {
  544. const char *font;
  545. const char *fallbackFont;
  546. };
  547. const char *g_szValidAsianFonts[] = {
  548. #ifdef WIN32
  549. "Marlett",
  550. #else
  551. "Helvetica",
  552. #endif
  553. NULL };
  554. // list of how fonts fallback
  555. FallbackFont_t g_FallbackFonts[] =
  556. {
  557. { "Times New Roman", "Courier New" },
  558. { "Courier New", "Courier" },
  559. { "Verdana", "Arial" },
  560. { "Trebuchet MS", "Arial" },
  561. #ifdef WIN32
  562. { "Tahoma", NULL },
  563. { NULL, "Tahoma" }, // every other font falls back to this
  564. #else
  565. { "Tahoma", "Helvetica" },
  566. { "Helvetica", NULL },
  567. { NULL, "Helvetica" } // every other font falls back to this
  568. #endif
  569. };
  570. //-----------------------------------------------------------------------------
  571. // Purpose: returns true if the font is in the list of OK asian fonts
  572. //-----------------------------------------------------------------------------
  573. bool CFontManager::IsFontForeignLanguageCapable(const char *windowsFontName)
  574. {
  575. if ( IsX360() )
  576. {
  577. return false;
  578. }
  579. for (int i = 0; g_szValidAsianFonts[i] != NULL; i++)
  580. {
  581. if (!stricmp(g_szValidAsianFonts[i], windowsFontName))
  582. return true;
  583. }
  584. // typeface isn't supported by asian languages
  585. return false;
  586. }
  587. //-----------------------------------------------------------------------------
  588. // Purpose: fallback fonts
  589. //-----------------------------------------------------------------------------
  590. const char *CFontManager::GetFallbackFontName(const char *windowsFontName)
  591. {
  592. int i;
  593. for ( i = 0; g_FallbackFonts[i].font != NULL; i++ )
  594. {
  595. if (!stricmp(g_FallbackFonts[i].font, windowsFontName))
  596. return g_FallbackFonts[i].fallbackFont;
  597. }
  598. // the ultimate fallback
  599. return g_FallbackFonts[i].fallbackFont;
  600. }
  601. struct Win98ForeignFallbackFont_t
  602. {
  603. const char *language;
  604. const char *fallbackFont;
  605. };
  606. // list of how fonts fallback
  607. Win98ForeignFallbackFont_t g_Win98ForeignFallbackFonts[] =
  608. {
  609. { "russian", "system" },
  610. { "japanese", "win98japanese" },
  611. { "thai", "system" },
  612. #ifdef WIN32
  613. { NULL, "Tahoma" }, // every other font falls back to this
  614. #else
  615. { NULL, "Helvetica" }, // every other font falls back to this
  616. #endif
  617. };
  618. //-----------------------------------------------------------------------------
  619. // Purpose: specialized fonts
  620. //-----------------------------------------------------------------------------
  621. const char *CFontManager::GetForeignFallbackFontName()
  622. {
  623. #ifdef WIN32
  624. if ( s_bSupportsUnicode )
  625. {
  626. if ( IsX360() )
  627. {
  628. return "arial unicode ms";
  629. }
  630. // tahoma has all the necessary characters for asian/russian languages for winXP/2K+
  631. return "Tahoma";
  632. }
  633. #endif
  634. int i;
  635. for (i = 0; g_Win98ForeignFallbackFonts[i].language != NULL; i++)
  636. {
  637. if (!stricmp(g_Win98ForeignFallbackFonts[i].language, m_szLanguage))
  638. return g_Win98ForeignFallbackFonts[i].fallbackFont;
  639. }
  640. // the ultimate fallback
  641. return g_Win98ForeignFallbackFonts[i].fallbackFont;
  642. }
  643. #if defined( _X360 )
  644. bool CFontManager::GetCachedXUIMetrics( const char *pFontName, int tall, int style, XUIFontMetrics *pFontMetrics, XUICharMetrics charMetrics[256] )
  645. {
  646. // linear lookup is good enough
  647. CUtlSymbol fontSymbol = pFontName;
  648. bool bFound = false;
  649. int i;
  650. for ( i = 0; i < m_XUIMetricCache.Count(); i++ )
  651. {
  652. if ( m_XUIMetricCache[i].fontSymbol == fontSymbol && m_XUIMetricCache[i].tall == tall && m_XUIMetricCache[i].style == style )
  653. {
  654. bFound = true;
  655. break;
  656. }
  657. }
  658. if ( !bFound )
  659. {
  660. return false;
  661. }
  662. // get from the cache
  663. *pFontMetrics = m_XUIMetricCache[i].fontMetrics;
  664. V_memcpy( charMetrics, m_XUIMetricCache[i].charMetrics, 256 * sizeof( XUICharMetrics ) );
  665. return true;
  666. }
  667. #endif
  668. #if defined( _X360 )
  669. void CFontManager::SetCachedXUIMetrics( const char *pFontName, int tall, int style, XUIFontMetrics *pFontMetrics, XUICharMetrics charMetrics[256] )
  670. {
  671. MEM_ALLOC_CREDIT();
  672. int i = m_XUIMetricCache.AddToTail();
  673. m_XUIMetricCache[i].fontSymbol = pFontName;
  674. m_XUIMetricCache[i].tall = tall;
  675. m_XUIMetricCache[i].style = style;
  676. m_XUIMetricCache[i].fontMetrics = *pFontMetrics;
  677. V_memcpy( m_XUIMetricCache[i].charMetrics, charMetrics, 256 * sizeof( XUICharMetrics ) );
  678. }
  679. #endif
  680. void CFontManager::ClearTemporaryFontCache()
  681. {
  682. #if defined( _X360 )
  683. COM_TimestampedLog( "ClearTemporaryFontCache(): Start" );
  684. m_XUIMetricCache.Purge();
  685. // many fonts are blindly precached by vgui and never used
  686. // font will re-open if glyph is actually requested
  687. for ( int i = 0; i < m_Win32Fonts.Count(); i++ )
  688. {
  689. m_Win32Fonts[i]->CloseResource();
  690. }
  691. COM_TimestampedLog( "ClearTemporaryFontCache(): Finish" );
  692. #endif
  693. }
  694. //-----------------------------------------------------------------------------
  695. // Purpose: returns the max height of a font
  696. //-----------------------------------------------------------------------------
  697. bool CFontManager::GetFontUnderlined( HFont font )
  698. {
  699. return m_FontAmalgams[font].GetUnderlined();
  700. }
  701. void CFontManager::GetKernedCharWidth( vgui::HFont font, wchar_t ch, wchar_t chBefore, wchar_t chAfter, float &wide, float &flabcA, float &flabcC )
  702. {
  703. wide = 0.0f;
  704. flabcA = 0.0f;
  705. Assert( font != vgui::INVALID_FONT );
  706. if ( font == vgui::INVALID_FONT )
  707. return;
  708. font_t *pFont = m_FontAmalgams[font].GetFontForChar(ch);
  709. if ( !pFont )
  710. {
  711. // no font for this range, just use the default width
  712. flabcA = 0.0f;
  713. wide = m_FontAmalgams[font].GetFontMaxWidth();
  714. return;
  715. }
  716. if ( m_FontAmalgams[font].GetFontForChar( chBefore ) != pFont )
  717. chBefore = 0;
  718. if ( m_FontAmalgams[font].GetFontForChar( chAfter ) != pFont )
  719. chAfter = 0;
  720. pFont->GetKernedCharWidth( ch, chBefore, chAfter, wide, flabcA, flabcC );
  721. }
  722. #ifdef DBGFLAG_VALIDATE
  723. //-----------------------------------------------------------------------------
  724. // Purpose: Ensure that all of our internal structures are consistent, and
  725. // account for all memory that we've allocated.
  726. // Input: validator - Our global validator object
  727. // pchName - Our name (typically a member var in our container)
  728. //-----------------------------------------------------------------------------
  729. void CFontManager::Validate( CValidator &validator, char *pchName )
  730. {
  731. validator.Push( "CFontManager", this, pchName );
  732. ValidateObj( m_FontAmalgams );
  733. for ( int iFont = 0; iFont < m_FontAmalgams.Count(); iFont++ )
  734. {
  735. ValidateObj( m_FontAmalgams[iFont] );
  736. }
  737. ValidateObj( m_Win32Fonts );
  738. for ( int iWin32Font = 0; iWin32Font < m_Win32Fonts.Count(); iWin32Font++ )
  739. {
  740. ValidatePtr( m_Win32Fonts[ iWin32Font ] );
  741. }
  742. validator.Pop();
  743. }
  744. #endif // DBGFLAG_VALIDATE