Team Fortress 2 Source Code as on 22/4/2020
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.

638 lines
18 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=====================================================================================//
  6. #pragma warning( disable : 4244 ) // conversion from 'double' to 'float', possible loss of data
  7. #include <assert.h>
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include <math.h>
  11. #include <malloc.h>
  12. #include "vgui_surfacelib/Win32Font.h"
  13. #include <tier0/dbg.h>
  14. #include <vgui/ISurface.h>
  15. #include <tier0/mem.h>
  16. #include <utlbuffer.h>
  17. #include "FontEffects.h"
  18. // memdbgon must be the last include file in a .cpp file!!!
  19. #include "tier0/memdbgon.h"
  20. static OSVERSIONINFO s_OsVersionInfo;
  21. static bool s_bOsVersionInitialized = false;
  22. bool s_bSupportsUnicode = false;
  23. //-----------------------------------------------------------------------------
  24. // Purpose: Constructor
  25. //-----------------------------------------------------------------------------
  26. CWin32Font::CWin32Font() : m_ExtendedABCWidthsCache(256, 0, &ExtendedABCWidthsCacheLessFunc)
  27. {
  28. m_szName = UTL_INVAL_SYMBOL;
  29. m_iTall = 0;
  30. m_iWeight = 0;
  31. m_iHeight = 0;
  32. m_iAscent = 0;
  33. m_iFlags = 0;
  34. m_iMaxCharWidth = 0;
  35. m_hFont = NULL;
  36. m_hDC = NULL;
  37. m_hDIB = NULL;
  38. m_bAntiAliased = false;
  39. m_bUnderlined = false;
  40. m_iBlur = 0;
  41. m_iScanLines = 0;
  42. m_bRotary = false;
  43. m_bAdditive = false;
  44. m_rgiBitmapSize[ 0 ] = m_rgiBitmapSize[ 1 ] = 0;
  45. #if defined( _X360 )
  46. Q_memset( m_ABCWidthsCache, 0, sizeof( m_ABCWidthsCache ) );
  47. #endif
  48. m_ExtendedABCWidthsCache.EnsureCapacity( 128 );
  49. if ( !s_bOsVersionInitialized )
  50. {
  51. // get the operating system version
  52. s_bOsVersionInitialized = true;
  53. memset(&s_OsVersionInfo, 0, sizeof(s_OsVersionInfo));
  54. s_OsVersionInfo.dwOSVersionInfoSize = sizeof(s_OsVersionInfo);
  55. GetVersionEx(&s_OsVersionInfo);
  56. if (s_OsVersionInfo.dwMajorVersion >= 5)
  57. {
  58. s_bSupportsUnicode = true;
  59. }
  60. else
  61. {
  62. s_bSupportsUnicode = false;
  63. }
  64. }
  65. }
  66. //-----------------------------------------------------------------------------
  67. // Purpose: Destructor
  68. //-----------------------------------------------------------------------------
  69. CWin32Font::~CWin32Font()
  70. {
  71. if ( m_hFont )
  72. ::DeleteObject( m_hFont );
  73. if ( m_hDC )
  74. ::DeleteDC( m_hDC );
  75. if ( m_hDIB )
  76. ::DeleteObject( m_hDIB );
  77. }
  78. //-----------------------------------------------------------------------------
  79. // Purpose: Font iteration callback function
  80. // used to determine whether or not a font exists on the system
  81. //-----------------------------------------------------------------------------
  82. extern bool g_bFontFound = false;
  83. int CALLBACK FontEnumProc(
  84. const LOGFONT *lpelfe, // logical-font data
  85. const TEXTMETRIC *lpntme, // physical-font data
  86. DWORD FontType, // type of font
  87. LPARAM lParam ) // application-defined data
  88. {
  89. g_bFontFound = true;
  90. return 0;
  91. }
  92. //-----------------------------------------------------------------------------
  93. // Purpose: creates the font from windows. returns false if font does not exist in the OS.
  94. //-----------------------------------------------------------------------------
  95. bool CWin32Font::Create(const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags)
  96. {
  97. // setup font properties
  98. m_szName = windowsFontName;
  99. m_iTall = tall;
  100. m_iWeight = weight;
  101. m_iFlags = flags;
  102. m_bAntiAliased = (flags & vgui::ISurface::FONTFLAG_ANTIALIAS) ? 1 : 0;
  103. m_bUnderlined = flags & vgui::ISurface::FONTFLAG_UNDERLINE;
  104. m_iDropShadowOffset = (flags & vgui::ISurface::FONTFLAG_DROPSHADOW) ? 1 : 0;
  105. m_iOutlineSize = (flags & vgui::ISurface::FONTFLAG_OUTLINE) ? 1 : 0;
  106. m_iBlur = blur;
  107. m_iScanLines = scanlines;
  108. m_bRotary = (flags & vgui::ISurface::FONTFLAG_ROTARY) ? 1 : 0;
  109. m_bAdditive = (flags & vgui::ISurface::FONTFLAG_ADDITIVE) ? 1 : 0;
  110. int charset = (flags & vgui::ISurface::FONTFLAG_SYMBOL) ? SYMBOL_CHARSET : ANSI_CHARSET;
  111. // hack for japanese win98 support
  112. if ( !stricmp( windowsFontName, "win98japanese" ) )
  113. {
  114. // use any font that contains the japanese charset
  115. charset = SHIFTJIS_CHARSET;
  116. m_szName = "Tahoma";
  117. }
  118. // create our windows device context
  119. m_hDC = ::CreateCompatibleDC(NULL);
  120. Assert( m_hDC );
  121. // see if the font exists on the system
  122. LOGFONT logfont;
  123. logfont.lfCharSet = DEFAULT_CHARSET;
  124. logfont.lfPitchAndFamily = 0;
  125. strcpy(logfont.lfFaceName, m_szName.String());
  126. g_bFontFound = false;
  127. ::EnumFontFamiliesEx(m_hDC, &logfont, &FontEnumProc, 0, 0);
  128. if (!g_bFontFound)
  129. {
  130. // needs to go to a fallback
  131. m_szName = UTL_INVAL_SYMBOL;
  132. return false;
  133. }
  134. m_hFont = ::CreateFontA(tall, 0, 0, 0,
  135. m_iWeight,
  136. flags & vgui::ISurface::FONTFLAG_ITALIC,
  137. flags & vgui::ISurface::FONTFLAG_UNDERLINE,
  138. flags & vgui::ISurface::FONTFLAG_STRIKEOUT,
  139. charset,
  140. OUT_DEFAULT_PRECIS,
  141. CLIP_DEFAULT_PRECIS,
  142. m_bAntiAliased ? ANTIALIASED_QUALITY : NONANTIALIASED_QUALITY,
  143. DEFAULT_PITCH | FF_DONTCARE,
  144. windowsFontName);
  145. if (!m_hFont)
  146. {
  147. Error("Couldn't create windows font '%s'\n", windowsFontName);
  148. m_szName = UTL_INVAL_SYMBOL;
  149. return false;
  150. }
  151. // set as the active font
  152. ::SetMapMode(m_hDC, MM_TEXT);
  153. ::SelectObject(m_hDC, m_hFont);
  154. ::SetTextAlign(m_hDC, TA_LEFT | TA_TOP | TA_UPDATECP);
  155. // get info about the font
  156. ::TEXTMETRIC tm;
  157. memset( &tm, 0, sizeof( tm ) );
  158. if ( !GetTextMetrics(m_hDC, &tm) )
  159. {
  160. m_szName = UTL_INVAL_SYMBOL;
  161. return false;
  162. }
  163. m_iHeight = tm.tmHeight + m_iDropShadowOffset + 2 * m_iOutlineSize;
  164. m_iMaxCharWidth = tm.tmMaxCharWidth;
  165. m_iAscent = tm.tmAscent;
  166. // code for rendering to a bitmap
  167. m_rgiBitmapSize[0] = tm.tmMaxCharWidth + m_iOutlineSize * 2;
  168. m_rgiBitmapSize[1] = tm.tmHeight + m_iDropShadowOffset + m_iOutlineSize * 2;
  169. ::BITMAPINFOHEADER header;
  170. memset(&header, 0, sizeof(header));
  171. header.biSize = sizeof(header);
  172. header.biWidth = m_rgiBitmapSize[0];
  173. header.biHeight = -m_rgiBitmapSize[1];
  174. header.biPlanes = 1;
  175. header.biBitCount = 32;
  176. header.biCompression = BI_RGB;
  177. m_hDIB = ::CreateDIBSection(m_hDC, (BITMAPINFO*)&header, DIB_RGB_COLORS, (void**)(&m_pBuf), NULL, 0);
  178. ::SelectObject(m_hDC, m_hDIB);
  179. #if defined( _X360 )
  180. // get char spacing
  181. // a is space before character (can be negative)
  182. // b is the width of the character
  183. // c is the space after the character
  184. memset(m_ABCWidthsCache, 0, sizeof(m_ABCWidthsCache));
  185. ABC abc[ABCWIDTHS_CACHE_SIZE];
  186. Assert(ABCWIDTHS_CACHE_SIZE <= 256);
  187. if (::GetCharABCWidthsW(m_hDC, 0, ABCWIDTHS_CACHE_SIZE - 1, &abc[0]) || ::GetCharABCWidthsA(m_hDC, 0, ABCWIDTHS_CACHE_SIZE - 1, &abc[0]))
  188. {
  189. // copy out into our formated structure
  190. for (int i = 0; i < ABCWIDTHS_CACHE_SIZE; i++)
  191. {
  192. m_ABCWidthsCache[i].a = abc[i].abcA - m_iBlur - m_iOutlineSize;
  193. m_ABCWidthsCache[i].b = abc[i].abcB + ((m_iBlur + m_iOutlineSize) * 2) + m_iDropShadowOffset;
  194. m_ABCWidthsCache[i].c = abc[i].abcC - m_iBlur - m_iDropShadowOffset - m_iOutlineSize;
  195. }
  196. }
  197. else
  198. {
  199. Warning("GetCharABCWidths() failed for windows font '%s'\n", windowsFontName);
  200. // since that failed, it must be fixed width, zero everything so a and c will be zeros, then
  201. // fill b with the value from TEXTMETRIC
  202. for (int i = 0; i < ABCWIDTHS_CACHE_SIZE; i++)
  203. {
  204. // fallback to old method, no underhangs/overhangs (a/c)
  205. SIZE size;
  206. char mbcs[6] = { 0 };
  207. wchar_t wch = (wchar_t)i;
  208. ::WideCharToMultiByte(CP_ACP, 0, &wch, 1, mbcs, sizeof(mbcs), NULL, NULL);
  209. if (::GetTextExtentPoint32(m_hDC, mbcs, strlen(mbcs), &size))
  210. {
  211. m_ABCWidthsCache[i].b = size.cx;
  212. }
  213. else
  214. {
  215. // failed to get width, just use the average width
  216. m_ABCWidthsCache[i].b = (char)tm.tmAveCharWidth;
  217. }
  218. }
  219. }
  220. #endif
  221. return true;
  222. }
  223. //-----------------------------------------------------------------------------
  224. // Purpose: writes the char into the specified 32bpp texture
  225. //-----------------------------------------------------------------------------
  226. void CWin32Font::GetCharRGBA(wchar_t ch, int rgbaWide, int rgbaTall, unsigned char *rgba)
  227. {
  228. int a, b, c;
  229. GetCharABCWidths(ch, a, b, c);
  230. // set us up to render into our dib
  231. ::SelectObject(m_hDC, m_hFont);
  232. int wide = b;
  233. if ( m_bUnderlined )
  234. {
  235. wide += ( a + c );
  236. }
  237. int tall = m_iHeight;
  238. GLYPHMETRICS glyphMetrics;
  239. MAT2 mat2 = { { 0, 1}, { 0, 0}, { 0, 0}, { 0, 1}};
  240. int bytesNeeded = 0;
  241. bool bShouldAntialias = m_bAntiAliased;
  242. // filter out
  243. if ( ch > 0x00FF && !(m_iFlags & vgui::ISurface::FONTFLAG_CUSTOM) )
  244. {
  245. bShouldAntialias = false;
  246. }
  247. if ( !s_bSupportsUnicode )
  248. {
  249. // win98 hack, don't antialias some characters that ::GetGlyphOutline() produces bad results for
  250. if (ch == 'I' || ch == '1')
  251. {
  252. bShouldAntialias = false;
  253. }
  254. // don't antialias big fonts at all (since win98 often produces bad results)
  255. if (m_iHeight >= 13)
  256. {
  257. bShouldAntialias = false;
  258. }
  259. }
  260. // only antialias latin characters, since it essentially always fails for asian characters
  261. if (bShouldAntialias)
  262. {
  263. // try and get the glyph directly
  264. ::SelectObject(m_hDC, m_hFont);
  265. bytesNeeded = ::GetGlyphOutline(m_hDC, ch, GGO_GRAY8_BITMAP, &glyphMetrics, 0, NULL, &mat2);
  266. }
  267. if (bytesNeeded > 0)
  268. {
  269. // take it
  270. unsigned char *lpbuf = (unsigned char *)_alloca(bytesNeeded);
  271. ::GetGlyphOutline(m_hDC, ch, GGO_GRAY8_BITMAP, &glyphMetrics, bytesNeeded, lpbuf, &mat2);
  272. // rows are on DWORD boundaries
  273. wide = glyphMetrics.gmBlackBoxX;
  274. while (wide % 4 != 0)
  275. {
  276. wide++;
  277. }
  278. // see where we should start rendering
  279. int pushDown = m_iAscent - glyphMetrics.gmptGlyphOrigin.y;
  280. // set where we start copying from
  281. int xstart = 0;
  282. // don't copy the first set of pixels if the antialiased bmp is bigger than the char width
  283. if ((int)glyphMetrics.gmBlackBoxX >= b + 2)
  284. {
  285. xstart = (glyphMetrics.gmBlackBoxX - b) / 2;
  286. }
  287. // iterate through copying the generated dib into the texture
  288. for (unsigned int j = 0; j < glyphMetrics.gmBlackBoxY; j++)
  289. {
  290. for (unsigned int i = xstart; i < glyphMetrics.gmBlackBoxX; i++)
  291. {
  292. int x = i - xstart + m_iBlur + m_iOutlineSize;
  293. int y = j + pushDown;
  294. if ((x < rgbaWide) && (y < rgbaTall))
  295. {
  296. unsigned char grayscale = lpbuf[(j*wide+i)];
  297. float r, g, b, a;
  298. if (grayscale)
  299. {
  300. r = g = b = 1.0f;
  301. a = (grayscale + 0) / 64.0f;
  302. if (a > 1.0f) a = 1.0f;
  303. }
  304. else
  305. {
  306. r = g = b = a = 0.0f;
  307. }
  308. // Don't want anything drawn for tab characters.
  309. if (ch == '\t')
  310. {
  311. r = g = b = 0;
  312. }
  313. unsigned char *dst = &rgba[(y*rgbaWide+x)*4];
  314. dst[0] = (unsigned char)(r * 255.0f);
  315. dst[1] = (unsigned char)(g * 255.0f);
  316. dst[2] = (unsigned char)(b * 255.0f);
  317. dst[3] = (unsigned char)(a * 255.0f);
  318. }
  319. }
  320. }
  321. }
  322. else
  323. {
  324. // use render-to-bitmap to get our font texture
  325. ::SetBkColor(m_hDC, RGB(0, 0, 0));
  326. ::SetTextColor(m_hDC, RGB(255, 255, 255));
  327. ::SetBkMode(m_hDC, OPAQUE);
  328. if ( m_bUnderlined )
  329. {
  330. ::MoveToEx(m_hDC, 0, 0, NULL);
  331. }
  332. else
  333. {
  334. ::MoveToEx(m_hDC, -a, 0, NULL);
  335. }
  336. // render the character
  337. wchar_t wch = (wchar_t)ch;
  338. if (s_bSupportsUnicode)
  339. {
  340. // clear the background first
  341. RECT rect = { 0, 0, wide, tall};
  342. ::ExtTextOutW( m_hDC, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL );
  343. // just use the unicode renderer
  344. ::ExtTextOutW( m_hDC, 0, 0, 0, NULL, &wch, 1, NULL );
  345. }
  346. else
  347. {
  348. // clear the background first (it may not get done automatically in win98/ME
  349. RECT rect = { 0, 0, wide, tall};
  350. ::ExtTextOut(m_hDC, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
  351. // convert the character using the current codepage
  352. char mbcs[6] = { 0 };
  353. ::WideCharToMultiByte(CP_ACP, 0, &wch, 1, mbcs, sizeof(mbcs), NULL, NULL);
  354. ::ExtTextOutA(m_hDC, 0, 0, 0, NULL, mbcs, strlen(mbcs), NULL);
  355. }
  356. ::SetBkMode(m_hDC, TRANSPARENT);
  357. if (wide > m_rgiBitmapSize[0])
  358. {
  359. wide = m_rgiBitmapSize[0];
  360. }
  361. if (tall > m_rgiBitmapSize[1])
  362. {
  363. tall = m_rgiBitmapSize[1];
  364. }
  365. // iterate through copying the generated dib into the texture
  366. for (int j = (int)m_iOutlineSize; j < tall - (int)m_iOutlineSize; j++ )
  367. {
  368. // only copy from within the dib, ignore the outline border we are artificially adding
  369. for (int i = (int)m_iOutlineSize; i < wide - (int)m_iDropShadowOffset - (int)m_iOutlineSize; i++)
  370. {
  371. if ((i < rgbaWide) && (j < rgbaTall))
  372. {
  373. unsigned char *src = &m_pBuf[(i + j*m_rgiBitmapSize[0])*4];
  374. unsigned char *dst = &rgba[(i + j*rgbaWide)*4];
  375. // Don't want anything drawn for tab characters.
  376. unsigned char r, g, b;
  377. if ( ch == '\t' )
  378. {
  379. r = g = b = 0;
  380. }
  381. else
  382. {
  383. r = src[0];
  384. g = src[1];
  385. b = src[2];
  386. }
  387. // generate alpha based on luminance conversion
  388. dst[0] = r;
  389. dst[1] = g;
  390. dst[2] = b;
  391. dst[3] = (unsigned char)((float)r * 0.34f + (float)g * 0.55f + (float)b * 0.11f);
  392. }
  393. }
  394. }
  395. // if we have a dropshadow, we need to clean off the bottom row of pixels
  396. // this is because of a bug in winME that writes noise to them, only on the first time the game is run after a reboot
  397. // the bottom row should guaranteed to be empty to fit the dropshadow
  398. if ( m_iDropShadowOffset )
  399. {
  400. unsigned char *dst = &rgba[((m_iHeight - 1) * rgbaWide) * 4];
  401. for (int i = 0; i < wide; i++)
  402. {
  403. dst[0] = 0;
  404. dst[1] = 0;
  405. dst[2] = 0;
  406. dst[3] = 0;
  407. dst += 4;
  408. }
  409. }
  410. }
  411. // apply requested effects in specified order
  412. ApplyDropShadowToTexture( rgbaWide, rgbaTall, rgba, m_iDropShadowOffset );
  413. ApplyOutlineToTexture( rgbaWide, rgbaTall, rgba, m_iOutlineSize );
  414. ApplyGaussianBlurToTexture( rgbaWide, rgbaTall, rgba, m_iBlur );
  415. ApplyScanlineEffectToTexture( rgbaWide, rgbaTall, rgba, m_iScanLines );
  416. ApplyRotaryEffectToTexture( rgbaWide, rgbaTall, rgba, m_bRotary );
  417. }
  418. //-----------------------------------------------------------------------------
  419. // Purpose: returns true if the font is equivalent to that specified
  420. //-----------------------------------------------------------------------------
  421. bool CWin32Font::IsEqualTo(const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags)
  422. {
  423. if ( !stricmp(windowsFontName, m_szName.String() )
  424. && m_iTall == tall
  425. && m_iWeight == weight
  426. && m_iBlur == blur
  427. && m_iFlags == flags)
  428. return true;
  429. return false;
  430. }
  431. //-----------------------------------------------------------------------------
  432. // Purpose: returns true only if this font is valid for use
  433. //-----------------------------------------------------------------------------
  434. bool CWin32Font::IsValid()
  435. {
  436. if ( m_szName.IsValid() && m_szName.String()[0] )
  437. return true;
  438. return false;
  439. }
  440. //-----------------------------------------------------------------------------
  441. // Purpose: set the font to be the one to currently draw with in the gdi
  442. //-----------------------------------------------------------------------------
  443. void CWin32Font::SetAsActiveFont(HDC hdc)
  444. {
  445. Assert( IsValid() );
  446. ::SelectObject( hdc, m_hFont );
  447. }
  448. //-----------------------------------------------------------------------------
  449. // Purpose: gets the abc widths for a character
  450. //-----------------------------------------------------------------------------
  451. void CWin32Font::GetCharABCWidths(int ch, int &a, int &b, int &c)
  452. {
  453. Assert( IsValid() );
  454. #if defined( _X360 )
  455. if (ch < ABCWIDTHS_CACHE_SIZE)
  456. {
  457. // use the cache entry
  458. a = m_ABCWidthsCache[ch].a;
  459. b = m_ABCWidthsCache[ch].b;
  460. c = m_ABCWidthsCache[ch].c;
  461. }
  462. else
  463. #endif
  464. {
  465. // look for it in the cache
  466. abc_cache_t finder = { (wchar_t)ch };
  467. unsigned short i = m_ExtendedABCWidthsCache.Find(finder);
  468. if (m_ExtendedABCWidthsCache.IsValidIndex(i))
  469. {
  470. a = m_ExtendedABCWidthsCache[i].abc.a;
  471. b = m_ExtendedABCWidthsCache[i].abc.b;
  472. c = m_ExtendedABCWidthsCache[i].abc.c;
  473. return;
  474. }
  475. // not in the cache, get from windows (this call is a little slow)
  476. ABC abc;
  477. if (::GetCharABCWidthsW(m_hDC, ch, ch, &abc) || ::GetCharABCWidthsA(m_hDC, ch, ch, &abc))
  478. {
  479. a = abc.abcA;
  480. b = abc.abcB;
  481. c = abc.abcC;
  482. }
  483. else
  484. {
  485. // wide character version failed, try the old api function
  486. SIZE size;
  487. char mbcs[6] = { 0 };
  488. wchar_t wch = ch;
  489. ::WideCharToMultiByte(CP_ACP, 0, &wch, 1, mbcs, sizeof(mbcs), NULL, NULL);
  490. if (::GetTextExtentPoint32(m_hDC, mbcs, strlen(mbcs), &size))
  491. {
  492. a = c = 0;
  493. b = size.cx;
  494. }
  495. else
  496. {
  497. // failed to get width, just use the max width
  498. a = c = 0;
  499. b = m_iMaxCharWidth;
  500. }
  501. }
  502. // add to the cache
  503. finder.abc.a = a - m_iBlur - m_iOutlineSize;
  504. finder.abc.b = b + ((m_iBlur + m_iOutlineSize) * 2) + m_iDropShadowOffset;
  505. finder.abc.c = c - m_iBlur - m_iDropShadowOffset - m_iOutlineSize;
  506. m_ExtendedABCWidthsCache.Insert(finder);
  507. }
  508. }
  509. //-----------------------------------------------------------------------------
  510. // Purpose: returns the height of the font, in pixels
  511. //-----------------------------------------------------------------------------
  512. int CWin32Font::GetHeight()
  513. {
  514. Assert( IsValid() );
  515. return m_iHeight;
  516. }
  517. //-----------------------------------------------------------------------------
  518. // Purpose: returns the requested height of the font
  519. //-----------------------------------------------------------------------------
  520. int CWin32Font::GetHeightRequested()
  521. {
  522. assert(IsValid());
  523. return m_iTall;
  524. }
  525. //-----------------------------------------------------------------------------
  526. // Purpose: returns the ascent of the font, in pixels (ascent=units above the base line)
  527. //-----------------------------------------------------------------------------
  528. int CWin32Font::GetAscent()
  529. {
  530. Assert( IsValid() );
  531. return m_iAscent;
  532. }
  533. //-----------------------------------------------------------------------------
  534. // Purpose: returns the maximum width of a character, in pixels
  535. //-----------------------------------------------------------------------------
  536. int CWin32Font::GetMaxCharWidth()
  537. {
  538. Assert( IsValid() );
  539. return m_iMaxCharWidth;
  540. }
  541. //-----------------------------------------------------------------------------
  542. // Purpose: returns the flags used to make this font, used by the dynamic resizing code
  543. //-----------------------------------------------------------------------------
  544. int CWin32Font::GetFlags()
  545. {
  546. return m_iFlags;
  547. }
  548. //-----------------------------------------------------------------------------
  549. // Purpose: Comparison function for abc widths storage
  550. //-----------------------------------------------------------------------------
  551. bool CWin32Font::ExtendedABCWidthsCacheLessFunc(const abc_cache_t &lhs, const abc_cache_t &rhs)
  552. {
  553. return lhs.wch < rhs.wch;
  554. }
  555. //-----------------------------------------------------------------------------
  556. // Purpose: Get the kerned size of a char, for win32 just pass thru for now
  557. //-----------------------------------------------------------------------------
  558. void CWin32Font::GetKernedCharWidth( wchar_t ch, wchar_t chBefore, wchar_t chAfter, float &wide, float &abcA )
  559. {
  560. int a,b,c;
  561. GetCharABCWidths(ch, a, b, c );
  562. wide = ( a + b + c);
  563. abcA = a;
  564. }