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.

777 lines
24 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "vgui_surfacelib/linuxfont.h"
  8. #include <assert.h>
  9. #include <stdio.h>
  10. #include <string.h>
  11. #include <math.h>
  12. #include <malloc.h>
  13. #include <tier0/dbg.h>
  14. #include <vgui/ISurface.h>
  15. #include <utlbuffer.h>
  16. #include <fontconfig/fontconfig.h>
  17. #include <freetype/ftbitmap.h>
  18. #include "materialsystem/imaterialsystem.h"
  19. #include "vgui_surfacelib/FontManager.h"
  20. #include "FontEffects.h"
  21. // memdbgon must be the last include file in a .cpp file!!!
  22. #include "tier0/memdbgon.h"
  23. #define FT_LOAD_FLAGS 0 //$ (FT_LOAD_TARGET_LIGHT)
  24. namespace {
  25. // Freetype uses a lot of fixed float values that are 26.6 splits of a 32 bit word.
  26. // to make it an int, shift down the 6 bits and round up if the high bit of the 6
  27. // bits was set.
  28. inline int32_t FIXED6_2INT(int32_t x) { return ( (x>>6) + ( (x&0x20) ? (x<0 ? -1 : 1) : 0) ); }
  29. inline float FIXED6_2FLOAT(int32_t x) { return (float)x / 64.0f; }
  30. inline int32_t INT_2FIXED6(int32_t x) { return x << 6; }
  31. }
  32. bool CLinuxFont::ms_bSetFriendlyNameCacheLessFunc = false;
  33. CUtlRBTree< CLinuxFont::font_name_entry > CLinuxFont::m_FriendlyNameCache;
  34. //-----------------------------------------------------------------------------
  35. // Purpose: Constructor
  36. //-----------------------------------------------------------------------------
  37. CLinuxFont::CLinuxFont() :
  38. m_ExtendedABCWidthsCache(256, 0, &ExtendedABCWidthsCacheLessFunc),
  39. m_ExtendedKernedABCWidthsCache( 256, 0, &ExtendedKernedABCWidthsCacheLessFunc )
  40. {
  41. m_face = NULL;
  42. m_faceValid = false;
  43. m_iTall = 0;
  44. m_iHeight = 0;
  45. m_iHeightRequested = 0;
  46. m_iWeight = 0;
  47. m_iFlags = 0;
  48. m_iMaxCharWidth = 0;
  49. m_bAntiAliased = false;
  50. m_bUnderlined = false;
  51. m_iBlur = 0;
  52. m_iScanLines = 0;
  53. m_bRotary = false;
  54. m_bAdditive = false;
  55. if ( !ms_bSetFriendlyNameCacheLessFunc )
  56. {
  57. ms_bSetFriendlyNameCacheLessFunc = true;
  58. SetDefLessFunc( m_FriendlyNameCache );
  59. }
  60. }
  61. //-----------------------------------------------------------------------------
  62. // Purpose: Destructor
  63. //-----------------------------------------------------------------------------
  64. CLinuxFont::~CLinuxFont()
  65. {
  66. if( m_faceValid )
  67. {
  68. FT_Done_Face( m_face );
  69. m_face = NULL;
  70. m_faceValid = false;
  71. }
  72. }
  73. //-----------------------------------------------------------------------------
  74. // Purpose: build a map of friendly (char *) name to crazy ATSU bytestream, so we can ask for "Tahoma" and actually load it
  75. //-----------------------------------------------------------------------------
  76. void CLinuxFont::CreateFontList()
  77. {
  78. if ( m_FriendlyNameCache.Count() > 0 )
  79. return;
  80. if(!FcInit())
  81. return;
  82. FcConfig *config;
  83. FcPattern *pat;
  84. FcObjectSet *os;
  85. FcFontSet *fontset;
  86. int i;
  87. char *file;
  88. const char *name;
  89. config = FcConfigGetCurrent();
  90. pat = FcPatternCreate();
  91. os = FcObjectSetCreate();
  92. FcObjectSetAdd(os, FC_FILE);
  93. FcObjectSetAdd(os, FC_FULLNAME);
  94. FcObjectSetAdd(os, FC_FAMILY);
  95. FcObjectSetAdd(os, FC_SCALABLE);
  96. fontset = FcFontList(config, pat, os);
  97. if(!fontset)
  98. return;
  99. for(i = 0; i < fontset->nfont; i++)
  100. {
  101. FcBool scalable;
  102. if ( FcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable )
  103. continue;
  104. if ( FcPatternGetString(fontset->fonts[i], FC_FAMILY, 0, (FcChar8**)&name) != FcResultMatch )
  105. continue;
  106. if ( FcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch )
  107. continue;
  108. font_name_entry entry;
  109. entry.m_pchFile = (char *)malloc( Q_strlen(file) + 1 );
  110. entry.m_pchFriendlyName = (char *)malloc( Q_strlen(name) +1);
  111. Q_memcpy( entry.m_pchFile, file, Q_strlen(file) + 1 );
  112. Q_memcpy( entry.m_pchFriendlyName, name, Q_strlen(name) +1);
  113. m_FriendlyNameCache.Insert( entry );
  114. // substitute Vera Sans for Tahoma on X
  115. if ( !V_stricmp( name, "Bitstream Vera Sans" ) )
  116. {
  117. name = "Tahoma";
  118. entry.m_pchFile = (char *)malloc( Q_strlen(file) + 1 );
  119. entry.m_pchFriendlyName = (char *)malloc( Q_strlen(name) +1);
  120. Q_memcpy( entry.m_pchFile, file, Q_strlen(file) + 1 );
  121. Q_memcpy( entry.m_pchFriendlyName, name, Q_strlen(name) +1);
  122. m_FriendlyNameCache.Insert( entry );
  123. name = "Verdana";
  124. entry.m_pchFile = (char *)malloc( Q_strlen(file) + 1 );
  125. entry.m_pchFriendlyName = (char *)malloc( Q_strlen(name) +1);
  126. Q_memcpy( entry.m_pchFile, file, Q_strlen(file) + 1 );
  127. Q_memcpy( entry.m_pchFriendlyName, name, Q_strlen(name) +1);
  128. m_FriendlyNameCache.Insert( entry );
  129. name = "Lucidia Console";
  130. entry.m_pchFile = (char *)malloc( Q_strlen(file) + 1 );
  131. entry.m_pchFriendlyName = (char *)malloc( Q_strlen(name) +1);
  132. Q_memcpy( entry.m_pchFile, file, Q_strlen(file) + 1 );
  133. Q_memcpy( entry.m_pchFriendlyName, name, Q_strlen(name) +1);
  134. m_FriendlyNameCache.Insert( entry );
  135. }
  136. }
  137. FcFontSetDestroy(fontset);
  138. FcObjectSetDestroy(os);
  139. FcPatternDestroy(pat);
  140. }
  141. static FcPattern* FontMatch(const char* type, FcType vtype, const void* value,
  142. ...)
  143. {
  144. va_list ap;
  145. va_start(ap, value);
  146. FcPattern* pattern = FcPatternCreate();
  147. for (;;)
  148. {
  149. FcValue fcvalue;
  150. fcvalue.type = vtype;
  151. switch (vtype) {
  152. case FcTypeString:
  153. fcvalue.u.s = (FcChar8*) value;
  154. break;
  155. case FcTypeInteger:
  156. fcvalue.u.i = (int) value;
  157. break;
  158. default:
  159. Assert(!"FontMatch unhandled type");
  160. }
  161. FcPatternAdd(pattern, type, fcvalue, 0);
  162. type = va_arg(ap, const char *);
  163. if (!type)
  164. break;
  165. // FcType is promoted to int when passed through ...
  166. vtype = static_cast<FcType>(va_arg(ap, int));
  167. value = va_arg(ap, const void *);
  168. };
  169. va_end(ap);
  170. FcConfigSubstitute(0, pattern, FcMatchPattern);
  171. FcDefaultSubstitute(pattern);
  172. FcResult result;
  173. FcPattern* match = FcFontMatch(0, pattern, &result);
  174. FcPatternDestroy(pattern);
  175. return match;
  176. }
  177. bool CLinuxFont::CreateFromMemory(const char *windowsFontName, void *data, int datasize, int tall, int weight, int blur, int scanlines, int flags)
  178. {
  179. // setup font properties
  180. m_szName = windowsFontName;
  181. m_iTall = tall;
  182. m_iWeight = weight;
  183. m_iFlags = flags;
  184. m_bAntiAliased = flags & vgui::ISurface::FONTFLAG_ANTIALIAS;
  185. m_bUnderlined = flags & vgui::ISurface::FONTFLAG_UNDERLINE;
  186. m_iDropShadowOffset = (flags & vgui::ISurface::FONTFLAG_DROPSHADOW) ? 1 : 0;
  187. m_iOutlineSize = (flags & vgui::ISurface::FONTFLAG_OUTLINE) ? 1 : 0;
  188. m_iBlur = blur;
  189. m_iScanLines = scanlines;
  190. m_bRotary = flags & vgui::ISurface::FONTFLAG_ROTARY;
  191. m_bAdditive = flags & vgui::ISurface::FONTFLAG_ADDITIVE;
  192. if ( !HushAsserts() )
  193. {
  194. // These flags are NYI in Linux right now.
  195. Assert( !m_bAntiAliased );
  196. Assert( !m_bUnderlined );
  197. Assert( !m_bAdditive );
  198. }
  199. Assert( !m_faceValid );
  200. FT_Error error = FT_New_Memory_Face( FontManager().GetFontLibraryHandle(), (FT_Byte *)data, datasize, 0, &m_face );
  201. if ( error )
  202. {
  203. // FT_Err_Unknown_File_Format?
  204. Msg( "FT_New_Memory_Face failed. font:%s error:%d\n", windowsFontName, error );
  205. return false;
  206. }
  207. if ( m_face->charmap == NULL )
  208. {
  209. FT_Error error = FT_Select_Charmap( m_face, FT_ENCODING_APPLE_ROMAN );
  210. if ( error )
  211. {
  212. FT_Done_Face( m_face );
  213. m_face = NULL;
  214. Msg( "Font %s has no valid charmap\n", windowsFontName );
  215. return false;
  216. }
  217. }
  218. m_iHeightRequested = m_iTall;
  219. // Loop through until we get a height that is less than or equal to the requested height.
  220. // We tried using the BBOX ascender / descender, but it was overly large compared to Windows.
  221. // We also tried using the size metrics, but the ascender wasn't high enough and accents were cut off.
  222. // Descender from size metrics was too low for fonts with no lower case characters.
  223. // Compromise: Use ascent from O' and descent from bbox. Diffs on textures indicate this is best choice.
  224. // Used these command lines vars and convars to help beyond compare linux and windows:
  225. // -precachefontintlchars / -enable_font_bounding_boxes / vgui_spew_fonts / mat_texture_save_fonts
  226. bool bFirstTimeThrough = true;
  227. int IncAmount = -1;
  228. for ( ;; )
  229. {
  230. bool SetPixelSizesFailed = false;
  231. FT_Error error = FT_Set_Pixel_Sizes( m_face, 0, m_iHeightRequested );
  232. if ( error )
  233. {
  234. SetPixelSizesFailed = true;
  235. // If FT_Set_Pixel_Sizes fails, it should be because we've got a fixed-size font.
  236. Assert( m_face->face_flags & FT_FACE_FLAG_FIXED_SIZES );
  237. Assert( !( m_face->face_flags & FT_FACE_FLAG_SCALABLE ) );
  238. if ( m_face->num_fixed_sizes )
  239. {
  240. // Pick width/height of first size.
  241. int width = m_face->available_sizes[ 0 ].width;
  242. m_iHeightRequested = m_face->available_sizes[ 0 ].height;
  243. // Loop through all the other available sizes and find the closest match.
  244. for ( int i = 1; i < m_face->num_fixed_sizes; i++ )
  245. {
  246. if ( ( m_face->available_sizes[ i ].height <= m_iTall ) &&
  247. ( m_face->available_sizes[ i ].height > m_iHeightRequested ) )
  248. {
  249. width = m_face->available_sizes[ i ].width;
  250. m_iHeightRequested = m_face->available_sizes[ i ].height;
  251. }
  252. }
  253. FT_Size_RequestRec req;
  254. Q_memset( &req, 0, sizeof( req ) );
  255. req.type = FT_SIZE_REQUEST_TYPE_REAL_DIM;
  256. req.width = INT_2FIXED6( width );
  257. req.height = INT_2FIXED6( m_iHeightRequested );
  258. req.horiResolution = 0;
  259. req.vertResolution = 0;
  260. error = FT_Request_Size( m_face, &req );
  261. if ( error )
  262. {
  263. Msg( "FT_Request_Size failed on %s / %s\n",
  264. m_face->family_name ? m_face->family_name : "??",
  265. m_face->style_name ? m_face->style_name : "??" );
  266. }
  267. }
  268. }
  269. FT_Pos ascender, descender;
  270. if( SetPixelSizesFailed )
  271. {
  272. // If SetPixelSizesFailed failed, then we've hopefully got a fixed size
  273. // font, and we can just use the metrics.
  274. ascender = m_face->size->metrics.ascender;
  275. descender = m_face->size->metrics.descender;
  276. }
  277. else
  278. {
  279. // Full bounding box ascent and descent:
  280. // ( a * b ) / 0x10000. y_scale is 16.16.
  281. //$ ascender = FT_MulFix( m_face->bbox.yMax, m_face->size->metrics.y_scale );
  282. descender = FT_MulFix( m_face->bbox.yMin, m_face->size->metrics.y_scale );
  283. // Metrics ascent and descent
  284. ascender = m_face->size->metrics.ascender;
  285. //$ descender = m_face->size->metrics.descender;
  286. // While running with Spanish, the m_face->size->metrics.ascender is less
  287. // than the bitmap_top for the character. This makes GetCharRGBA() chop off
  288. // the top of the O and the accent is skipped. Complete hack here, but we
  289. // check for the tallest character we know about (O') and bump up the ascender
  290. // value if it is greater than what we've currently got.
  291. wchar_t ch = 0xd3;
  292. error = FT_Load_Char( m_face, ch, FT_LOAD_RENDER | FT_LOAD_TARGET_NORMAL);
  293. if ( !error )
  294. {
  295. int glyph_index = FT_Get_Char_Index( m_face, ch );
  296. error = FT_Load_Glyph( m_face, glyph_index, FT_LOAD_RENDER );
  297. if ( !error )
  298. {
  299. FT_GlyphSlot slot = m_face->glyph;
  300. FT_Pos ascenderTop = INT_2FIXED6( slot->bitmap_top );
  301. if( ascenderTop > ascender )
  302. {
  303. ascender = ascenderTop;
  304. }
  305. else if ( !slot->bitmap.rows || !slot->bitmap.width )
  306. {
  307. // We didn't find an O' character in this font: use the full BBox.
  308. ascender = FT_MulFix( m_face->bbox.yMax, m_face->size->metrics.y_scale );
  309. }
  310. }
  311. }
  312. }
  313. m_iAscent = FIXED6_2INT( ascender );
  314. m_iMaxCharWidth = FIXED6_2INT( m_face->size->metrics.max_advance );
  315. const int fxpHeight = ascender + -descender + INT_2FIXED6( m_iDropShadowOffset + 2 * m_iOutlineSize );
  316. m_iHeight = FIXED6_2INT( fxpHeight );
  317. // If we're exact or we got too small, bail.
  318. if ( SetPixelSizesFailed || ( m_iHeight == m_iTall ) || ( m_iHeight < 7 ) || ( m_iHeightRequested <= 1 ) )
  319. break;
  320. if( bFirstTimeThrough )
  321. {
  322. bFirstTimeThrough = false;
  323. // If we're smaller than requested, start searching up.
  324. if ( m_iHeight < m_iTall )
  325. IncAmount = +1;
  326. }
  327. else if( IncAmount > 0 )
  328. {
  329. // If we're searching up and went too far, drop IncAmount and run down.
  330. if( m_iHeight > m_iTall )
  331. IncAmount = -1;
  332. }
  333. else if ( m_iHeight <= m_iTall )
  334. {
  335. // If the height is less than tall, we're done.
  336. break;
  337. }
  338. m_iHeightRequested += IncAmount;
  339. }
  340. m_faceValid = true;
  341. return true;
  342. }
  343. //-----------------------------------------------------------------------------
  344. // Purpose: Given a font name from windows, match it to the filename and return that.
  345. //-----------------------------------------------------------------------------
  346. char *CLinuxFont::GetFontFileName( const char *windowsFontName, int flags )
  347. {
  348. bool bBold = false;
  349. const char *pchFontName = windowsFontName;
  350. if ( !Q_stricmp( pchFontName, "Tahoma" ) )
  351. pchFontName = "Bitstream Vera Sans";
  352. else if ( !Q_stricmp( pchFontName, "Arial Black" ) || Q_stristr( pchFontName, "bold" ) )
  353. bBold = true;
  354. const int italic = ( flags & vgui::ISurface::FONTFLAG_ITALIC ) ? FC_SLANT_ITALIC : FC_SLANT_ROMAN;
  355. const int nFcWeight = bBold ? FC_WEIGHT_BOLD : FC_WEIGHT_NORMAL;
  356. FcPattern *match = FontMatch( FC_FAMILY, FcTypeString, pchFontName,
  357. FC_WEIGHT, FcTypeInteger, nFcWeight,
  358. FC_SLANT, FcTypeInteger, italic,
  359. NULL);
  360. if ( !match )
  361. {
  362. AssertMsg1( false, "Unable to find font named %s\n", windowsFontName );
  363. return NULL;
  364. }
  365. else
  366. {
  367. char *filenameret = NULL;
  368. FcChar8* filename = NULL;
  369. if ( FcPatternGetString(match, FC_FILE, 0, &filename) != FcResultMatch )
  370. {
  371. AssertMsg1( false, "Unable to find font named %s\n", windowsFontName );
  372. }
  373. else
  374. {
  375. filenameret = strdup( ( char * )filename );
  376. }
  377. FcPatternDestroy( match );
  378. return filenameret;
  379. }
  380. }
  381. //-----------------------------------------------------------------------------
  382. // Purpose: writes the char into the specified 32bpp texture
  383. //-----------------------------------------------------------------------------
  384. void CLinuxFont::GetCharRGBA( wchar_t ch, int rgbaWide, int rgbaTall, unsigned char *prgba )
  385. {
  386. bool bShouldAntialias = m_bAntiAliased;
  387. // filter out
  388. if ( ( ch > 0x00FF ) && !( m_iFlags & vgui::ISurface::FONTFLAG_CUSTOM ) )
  389. {
  390. bShouldAntialias = false;
  391. }
  392. FT_Error error = FT_Load_Char( m_face, ch, FT_LOAD_RENDER | FT_LOAD_TARGET_NORMAL );
  393. if ( error )
  394. {
  395. Msg( "Error in FT_Load_Char: ch:%x error:%x\n", (int)ch, error );
  396. return;
  397. }
  398. int glyph_index = FT_Get_Char_Index( m_face, ch );
  399. error = FT_Load_Glyph( m_face, glyph_index, FT_LOAD_RENDER | FT_LOAD_FLAGS );
  400. if ( error )
  401. {
  402. Msg( "Error in FL_Load_Glyph: glyph_index:%d error:%x\n", glyph_index, error );
  403. return;
  404. }
  405. int yBitmapStart = 0;
  406. FT_GlyphSlot slot = m_face->glyph;
  407. int nSkipRows = ( m_iAscent - slot->bitmap_top );
  408. if( nSkipRows < 0 )
  409. {
  410. yBitmapStart = -nSkipRows;
  411. nSkipRows = 0;
  412. }
  413. if ( nSkipRows >= rgbaTall )
  414. {
  415. Msg( "nSkipRows(%d) > rgbaTall(%d) ch:%d\n", nSkipRows, rgbaTall, (int)ch );
  416. return;
  417. }
  418. if ( m_face->glyph->bitmap.width == 0 )
  419. {
  420. Msg( "m_face->glyph->bitmap.width is 0 for ch:%d %s\n", (int)ch, m_face->family_name ? m_face->family_name : "??" );
  421. return;
  422. }
  423. FT_Bitmap bitmap;
  424. FT_Library ftLibrary = FontManager().GetFontLibraryHandle();
  425. FT_Bitmap_New( &bitmap );
  426. error = FT_Bitmap_Convert( ftLibrary, &m_face->glyph->bitmap, &bitmap, 1 );
  427. if( error == 0 )
  428. {
  429. uint32 alpha_scale = 1;
  430. int Width = min( rgbaWide, bitmap.width );
  431. unsigned char *rgba = prgba + ( nSkipRows * rgbaWide * 4 );
  432. switch( m_face->glyph->bitmap.pixel_mode )
  433. {
  434. case FT_PIXEL_MODE_MONO: // 8-bit per pixel bitmap
  435. alpha_scale *= 256;
  436. break;
  437. case FT_PIXEL_MODE_GRAY2: // 2-bit per pixel bitmap
  438. alpha_scale *= 64;
  439. break;
  440. case FT_PIXEL_MODE_GRAY4: // 4-bit per pixel bitmap
  441. alpha_scale *= 16;
  442. break;
  443. }
  444. /* now draw to our target surface */
  445. for ( int y = yBitmapStart; y < MIN( bitmap.rows, rgbaTall - nSkipRows ); y++ )
  446. {
  447. for ( int x = 0; x < Width; x++ )
  448. {
  449. int rgbaOffset = 4 * ( x + m_iBlur ); // +(rgbaTall-y-1)*rgbaWide*4
  450. uint32 alpha = Min( 255U, alpha_scale * bitmap.buffer[ x + y * bitmap.pitch ] );
  451. rgba[ rgbaOffset + 0 ] = 255;
  452. rgba[ rgbaOffset + 1 ] = 255;
  453. rgba[ rgbaOffset + 2 ] = 255;
  454. rgba[ rgbaOffset + 3 ] = alpha;
  455. }
  456. rgba += ( rgbaWide * 4 );
  457. }
  458. // apply requested effects in specified order
  459. ApplyDropShadowToTexture( rgbaWide, rgbaTall, prgba, m_iDropShadowOffset );
  460. ApplyOutlineToTexture( rgbaWide, rgbaTall, prgba, m_iOutlineSize );
  461. ApplyGaussianBlurToTexture( rgbaWide, rgbaTall, prgba, m_iBlur );
  462. ApplyScanlineEffectToTexture( rgbaWide, rgbaTall, prgba, m_iScanLines );
  463. ApplyRotaryEffectToTexture( rgbaWide, rgbaTall, prgba, m_bRotary );
  464. }
  465. else
  466. {
  467. Msg( "FT_Bitmap_Convert failed: %d on %s\n", error, m_face->family_name ? m_face->family_name : "??" );
  468. }
  469. FT_Bitmap_Done( ftLibrary, &bitmap );
  470. }
  471. void CLinuxFont::GetKernedCharWidth( wchar_t ch, wchar_t chBefore, wchar_t chAfter, float &wide, float &abcA, float &abcC )
  472. {
  473. abcA = abcC = wide = 0.0f;
  474. // look for it in the cache
  475. kerned_abc_cache_t finder = { ch, chBefore, chAfter };
  476. unsigned short iKerned = m_ExtendedKernedABCWidthsCache.Find(finder);
  477. if (m_ExtendedKernedABCWidthsCache.IsValidIndex(iKerned))
  478. {
  479. abcA = 0; //$ NYI. m_ExtendedKernedABCWidthsCache[iKerned].abc.abcA;
  480. abcC = 0; //$ NYI. m_ExtendedKernedABCWidthsCache[iKerned].abc.abcC;
  481. wide = m_ExtendedKernedABCWidthsCache[iKerned].abc.wide;
  482. return;
  483. }
  484. FT_UInt glyph_index;
  485. FT_Bool use_kerning;
  486. FT_UInt previous;
  487. int32_t iFxpPenX;
  488. iFxpPenX = 0;
  489. wide = 0;
  490. use_kerning = FT_HAS_KERNING( m_face );
  491. previous = chBefore;
  492. /* convert character code to glyph index */
  493. glyph_index = FT_Get_Char_Index( m_face, ch );
  494. /* retrieve kerning distance and move pen position */
  495. if ( use_kerning && previous && glyph_index )
  496. {
  497. FT_Vector delta;
  498. FT_Get_Kerning( m_face, previous, glyph_index,
  499. FT_KERNING_DEFAULT, &delta );
  500. iFxpPenX += delta.x;
  501. }
  502. /* load glyph image into the slot (erase previous one) */
  503. int error = FT_Load_Glyph( m_face, glyph_index, FT_LOAD_DEFAULT | FT_LOAD_FLAGS );
  504. if ( error )
  505. {
  506. Error( "Error in FL_Load_Glyph: glyph_index:%d ch:%x error:%x\n", glyph_index, (int)ch, error );
  507. }
  508. FT_GlyphSlot slot = m_face->glyph;
  509. iFxpPenX += slot->advance.x;
  510. if ( FIXED6_2INT(iFxpPenX) > wide )
  511. wide = FIXED6_2INT(iFxpPenX);
  512. //$ NYI: finder.abc.abcA = abcA;
  513. //$ NYI: finder.abc.abcC = abcC;
  514. finder.abc.wide = wide;
  515. m_ExtendedKernedABCWidthsCache.Insert(finder);
  516. }
  517. //-----------------------------------------------------------------------------
  518. // Purpose: gets the abc widths for a character
  519. //-----------------------------------------------------------------------------
  520. void CLinuxFont::GetCharABCWidths(int ch, int &a, int &b, int &c)
  521. {
  522. Assert(IsValid());
  523. // look for it in the cache
  524. abc_cache_t finder = { (wchar_t)ch };
  525. unsigned short i = m_ExtendedABCWidthsCache.Find(finder);
  526. if (m_ExtendedABCWidthsCache.IsValidIndex(i))
  527. {
  528. a = m_ExtendedABCWidthsCache[i].abc.a;
  529. b = m_ExtendedABCWidthsCache[i].abc.b;
  530. c = m_ExtendedABCWidthsCache[i].abc.c;
  531. return;
  532. }
  533. a = b = c = 0;
  534. FT_Error error = FT_Load_Char( m_face, ch, 0 );
  535. if ( error )
  536. {
  537. Msg( "Error in FT_Load_Char: ch:%x error:%x\n", ch, error );
  538. return;
  539. }
  540. // width: The glyph's width.
  541. // horiBearingX: Left side bearing for horizontal layout.
  542. // horiAdvance: Advance width for horizontal layout.
  543. FT_Glyph_Metrics metrics = m_face->glyph->metrics;
  544. finder.abc.a = metrics.horiBearingX / 64 - m_iBlur - m_iOutlineSize;
  545. finder.abc.b = metrics.width / 64 + ( ( m_iBlur + m_iOutlineSize ) * 2 ) + m_iDropShadowOffset;
  546. finder.abc.c = ( metrics.horiAdvance - metrics.horiBearingX - metrics.width ) / 64 - m_iBlur - m_iDropShadowOffset - m_iOutlineSize;
  547. m_ExtendedABCWidthsCache.Insert( finder );
  548. a = finder.abc.a;
  549. b = finder.abc.b;
  550. c = finder.abc.c;
  551. }
  552. //-----------------------------------------------------------------------------
  553. // Purpose: returns true if the font is equivalent to that specified
  554. //-----------------------------------------------------------------------------
  555. bool CLinuxFont::IsEqualTo(const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags)
  556. {
  557. if (!Q_stricmp(windowsFontName, m_szName.String() )
  558. && m_iTall == tall
  559. && m_iWeight == weight
  560. && m_iBlur == blur
  561. && m_iFlags == flags)
  562. return true;
  563. return false;
  564. }
  565. //-----------------------------------------------------------------------------
  566. // Purpose: returns true only if this font is valid for use
  567. //-----------------------------------------------------------------------------
  568. bool CLinuxFont::IsValid()
  569. {
  570. if ( !m_szName.IsEmpty() )
  571. return true;
  572. return false;
  573. }
  574. //-----------------------------------------------------------------------------
  575. // Purpose: returns the height of the font, in pixels
  576. //-----------------------------------------------------------------------------
  577. int CLinuxFont::GetHeight()
  578. {
  579. assert(IsValid());
  580. return m_iHeight;
  581. }
  582. //-----------------------------------------------------------------------------
  583. // Purpose: returns the requested height of the font
  584. //-----------------------------------------------------------------------------
  585. int CLinuxFont::GetHeightRequested()
  586. {
  587. assert(IsValid());
  588. return m_iHeightRequested;
  589. }
  590. //-----------------------------------------------------------------------------
  591. // Purpose: returns the ascent of the font, in pixels (ascent=units above the base line)
  592. //-----------------------------------------------------------------------------
  593. int CLinuxFont::GetAscent()
  594. {
  595. assert(IsValid());
  596. return m_iAscent;
  597. }
  598. //-----------------------------------------------------------------------------
  599. // Purpose: returns the maximum width of a character, in pixels
  600. //-----------------------------------------------------------------------------
  601. int CLinuxFont::GetMaxCharWidth()
  602. {
  603. assert(IsValid());
  604. return m_iMaxCharWidth;
  605. }
  606. //-----------------------------------------------------------------------------
  607. // Purpose: returns the flags used to make this font, used by the dynamic resizing code
  608. //-----------------------------------------------------------------------------
  609. int CLinuxFont::GetFlags()
  610. {
  611. return m_iFlags;
  612. }
  613. //-----------------------------------------------------------------------------
  614. // Purpose: Comparison function for abc widths storage
  615. //-----------------------------------------------------------------------------
  616. bool CLinuxFont::ExtendedABCWidthsCacheLessFunc(const abc_cache_t &lhs, const abc_cache_t &rhs)
  617. {
  618. return lhs.wch < rhs.wch;
  619. }
  620. //-----------------------------------------------------------------------------
  621. // Purpose: Comparison function for abc widths storage
  622. //-----------------------------------------------------------------------------
  623. bool CLinuxFont::ExtendedKernedABCWidthsCacheLessFunc(const kerned_abc_cache_t &lhs, const kerned_abc_cache_t &rhs)
  624. {
  625. return ( lhs.wch < rhs.wch ) ||
  626. ( lhs.wch == rhs.wch && lhs.wchBefore < rhs.wchBefore ) ||
  627. ( lhs.wch == rhs.wch && lhs.wchBefore == rhs.wchBefore && lhs.wchAfter < rhs.wchAfter );
  628. }
  629. void *CLinuxFont::SetAsActiveFont( void *cglContext )
  630. {
  631. Assert( false );
  632. return NULL;
  633. }
  634. //-----------------------------------------------------------------------------
  635. // Purpose: returns true if this font has a glyph for the code point.
  636. //-----------------------------------------------------------------------------
  637. bool CLinuxFont::HasChar(wchar_t wch)
  638. {
  639. return FT_Get_Char_Index( m_face, wch ) != 0;
  640. }
  641. #ifdef DBGFLAG_VALIDATE
  642. //-----------------------------------------------------------------------------
  643. // Purpose: Ensure that all of our internal structures are consistent, and
  644. // account for all memory that we've allocated.
  645. // Input: validator - Our global validator object
  646. // pchName - Our name (typically a member var in our container)
  647. //-----------------------------------------------------------------------------
  648. void CLinuxFont::Validate( CValidator &validator, const char *pchName )
  649. {
  650. validator.Push( "CLinuxFont", this, pchName );
  651. m_ExtendedABCWidthsCache.Validate( validator, "m_ExtendedABCWidthsCache" );
  652. m_ExtendedKernedABCWidthsCache.Validate( validator, "m_ExtendedKernedABCWidthsCache" );
  653. validator.Pop();
  654. }
  655. #endif // DBGFLAG_VALIDATE