diff options
Diffstat (limited to 'vgui2/vgui_surfacelib/linuxfont.cpp')
| -rw-r--r-- | vgui2/vgui_surfacelib/linuxfont.cpp | 777 |
1 files changed, 777 insertions, 0 deletions
diff --git a/vgui2/vgui_surfacelib/linuxfont.cpp b/vgui2/vgui_surfacelib/linuxfont.cpp new file mode 100644 index 0000000..b80d908 --- /dev/null +++ b/vgui2/vgui_surfacelib/linuxfont.cpp @@ -0,0 +1,777 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + + +#include "vgui_surfacelib/linuxfont.h" + +#include <assert.h> +#include <stdio.h> +#include <string.h> +#include <math.h> +#include <malloc.h> +#include <tier0/dbg.h> +#include <vgui/ISurface.h> +#include <utlbuffer.h> +#include <fontconfig/fontconfig.h> +#include <freetype/ftbitmap.h> +#include "materialsystem/imaterialsystem.h" + +#include "vgui_surfacelib/FontManager.h" +#include "FontEffects.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#define FT_LOAD_FLAGS 0 //$ (FT_LOAD_TARGET_LIGHT) + +namespace { + +// Freetype uses a lot of fixed float values that are 26.6 splits of a 32 bit word. +// to make it an int, shift down the 6 bits and round up if the high bit of the 6 +// bits was set. +inline int32_t FIXED6_2INT(int32_t x) { return ( (x>>6) + ( (x&0x20) ? (x<0 ? -1 : 1) : 0) ); } +inline float FIXED6_2FLOAT(int32_t x) { return (float)x / 64.0f; } +inline int32_t INT_2FIXED6(int32_t x) { return x << 6; } + +} + +bool CLinuxFont::ms_bSetFriendlyNameCacheLessFunc = false; +CUtlRBTree< CLinuxFont::font_name_entry > CLinuxFont::m_FriendlyNameCache; + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CLinuxFont::CLinuxFont() : + m_ExtendedABCWidthsCache(256, 0, &ExtendedABCWidthsCacheLessFunc), + m_ExtendedKernedABCWidthsCache( 256, 0, &ExtendedKernedABCWidthsCacheLessFunc ) +{ + m_face = NULL; + m_faceValid = false; + m_iTall = 0; + m_iHeight = 0; + m_iHeightRequested = 0; + m_iWeight = 0; + m_iFlags = 0; + m_iMaxCharWidth = 0; + m_bAntiAliased = false; + m_bUnderlined = false; + m_iBlur = 0; + m_iScanLines = 0; + m_bRotary = false; + m_bAdditive = false; + if ( !ms_bSetFriendlyNameCacheLessFunc ) + { + ms_bSetFriendlyNameCacheLessFunc = true; + SetDefLessFunc( m_FriendlyNameCache ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Destructor +//----------------------------------------------------------------------------- +CLinuxFont::~CLinuxFont() +{ + if( m_faceValid ) + { + FT_Done_Face( m_face ); + m_face = NULL; + m_faceValid = false; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: build a map of friendly (char *) name to crazy ATSU bytestream, so we can ask for "Tahoma" and actually load it +//----------------------------------------------------------------------------- +void CLinuxFont::CreateFontList() +{ + if ( m_FriendlyNameCache.Count() > 0 ) + return; + + if(!FcInit()) + return; + FcConfig *config; + FcPattern *pat; + FcObjectSet *os; + FcFontSet *fontset; + int i; + char *file; + const char *name; + + config = FcConfigGetCurrent(); + pat = FcPatternCreate(); + os = FcObjectSetCreate(); + FcObjectSetAdd(os, FC_FILE); + FcObjectSetAdd(os, FC_FULLNAME); + FcObjectSetAdd(os, FC_FAMILY); + FcObjectSetAdd(os, FC_SCALABLE); + fontset = FcFontList(config, pat, os); + if(!fontset) + return; + for(i = 0; i < fontset->nfont; i++) + { + FcBool scalable; + + if ( FcPatternGetBool(fontset->fonts[i], FC_SCALABLE, 0, &scalable) == FcResultMatch && !scalable ) + continue; + + if ( FcPatternGetString(fontset->fonts[i], FC_FAMILY, 0, (FcChar8**)&name) != FcResultMatch ) + continue; + if ( FcPatternGetString(fontset->fonts[i], FC_FILE, 0, (FcChar8**)&file) != FcResultMatch ) + continue; + + font_name_entry entry; + entry.m_pchFile = (char *)malloc( Q_strlen(file) + 1 ); + entry.m_pchFriendlyName = (char *)malloc( Q_strlen(name) +1); + Q_memcpy( entry.m_pchFile, file, Q_strlen(file) + 1 ); + Q_memcpy( entry.m_pchFriendlyName, name, Q_strlen(name) +1); + m_FriendlyNameCache.Insert( entry ); + + // substitute Vera Sans for Tahoma on X + if ( !V_stricmp( name, "Bitstream Vera Sans" ) ) + { + name = "Tahoma"; + entry.m_pchFile = (char *)malloc( Q_strlen(file) + 1 ); + entry.m_pchFriendlyName = (char *)malloc( Q_strlen(name) +1); + Q_memcpy( entry.m_pchFile, file, Q_strlen(file) + 1 ); + Q_memcpy( entry.m_pchFriendlyName, name, Q_strlen(name) +1); + m_FriendlyNameCache.Insert( entry ); + + name = "Verdana"; + entry.m_pchFile = (char *)malloc( Q_strlen(file) + 1 ); + entry.m_pchFriendlyName = (char *)malloc( Q_strlen(name) +1); + Q_memcpy( entry.m_pchFile, file, Q_strlen(file) + 1 ); + Q_memcpy( entry.m_pchFriendlyName, name, Q_strlen(name) +1); + m_FriendlyNameCache.Insert( entry ); + + name = "Lucidia Console"; + entry.m_pchFile = (char *)malloc( Q_strlen(file) + 1 ); + entry.m_pchFriendlyName = (char *)malloc( Q_strlen(name) +1); + Q_memcpy( entry.m_pchFile, file, Q_strlen(file) + 1 ); + Q_memcpy( entry.m_pchFriendlyName, name, Q_strlen(name) +1); + m_FriendlyNameCache.Insert( entry ); + } + } + + FcFontSetDestroy(fontset); + FcObjectSetDestroy(os); + FcPatternDestroy(pat); +} + +static FcPattern* FontMatch(const char* type, FcType vtype, const void* value, + ...) +{ + va_list ap; + va_start(ap, value); + + FcPattern* pattern = FcPatternCreate(); + + for (;;) + { + FcValue fcvalue; + fcvalue.type = vtype; + switch (vtype) { + case FcTypeString: + fcvalue.u.s = (FcChar8*) value; + break; + case FcTypeInteger: + fcvalue.u.i = (int) value; + break; + default: + Assert(!"FontMatch unhandled type"); + } + FcPatternAdd(pattern, type, fcvalue, 0); + + type = va_arg(ap, const char *); + if (!type) + break; + // FcType is promoted to int when passed through ... + vtype = static_cast<FcType>(va_arg(ap, int)); + value = va_arg(ap, const void *); + }; + va_end(ap); + + FcConfigSubstitute(0, pattern, FcMatchPattern); + FcDefaultSubstitute(pattern); + + FcResult result; + FcPattern* match = FcFontMatch(0, pattern, &result); + FcPatternDestroy(pattern); + + return match; +} + +bool CLinuxFont::CreateFromMemory(const char *windowsFontName, void *data, int datasize, int tall, int weight, int blur, int scanlines, int flags) +{ + // setup font properties + m_szName = windowsFontName; + m_iTall = tall; + m_iWeight = weight; + m_iFlags = flags; + m_bAntiAliased = flags & vgui::ISurface::FONTFLAG_ANTIALIAS; + m_bUnderlined = flags & vgui::ISurface::FONTFLAG_UNDERLINE; + m_iDropShadowOffset = (flags & vgui::ISurface::FONTFLAG_DROPSHADOW) ? 1 : 0; + m_iOutlineSize = (flags & vgui::ISurface::FONTFLAG_OUTLINE) ? 1 : 0; + m_iBlur = blur; + m_iScanLines = scanlines; + m_bRotary = flags & vgui::ISurface::FONTFLAG_ROTARY; + m_bAdditive = flags & vgui::ISurface::FONTFLAG_ADDITIVE; + + if ( !HushAsserts() ) + { + // These flags are NYI in Linux right now. + Assert( !m_bAntiAliased ); + Assert( !m_bUnderlined ); + Assert( !m_bAdditive ); + } + + Assert( !m_faceValid ); + FT_Error error = FT_New_Memory_Face( FontManager().GetFontLibraryHandle(), (FT_Byte *)data, datasize, 0, &m_face ); + if ( error ) + { + // FT_Err_Unknown_File_Format? + Msg( "FT_New_Memory_Face failed. font:%s error:%d\n", windowsFontName, error ); + return false; + } + + if ( m_face->charmap == NULL ) + { + FT_Error error = FT_Select_Charmap( m_face, FT_ENCODING_APPLE_ROMAN ); + if ( error ) + { + FT_Done_Face( m_face ); + m_face = NULL; + + Msg( "Font %s has no valid charmap\n", windowsFontName ); + return false; + } + } + + m_iHeightRequested = m_iTall; + + // Loop through until we get a height that is less than or equal to the requested height. + // We tried using the BBOX ascender / descender, but it was overly large compared to Windows. + // We also tried using the size metrics, but the ascender wasn't high enough and accents were cut off. + // Descender from size metrics was too low for fonts with no lower case characters. + // Compromise: Use ascent from O' and descent from bbox. Diffs on textures indicate this is best choice. + // Used these command lines vars and convars to help beyond compare linux and windows: + // -precachefontintlchars / -enable_font_bounding_boxes / vgui_spew_fonts / mat_texture_save_fonts + + bool bFirstTimeThrough = true; + int IncAmount = -1; + + for ( ;; ) + { + bool SetPixelSizesFailed = false; + + FT_Error error = FT_Set_Pixel_Sizes( m_face, 0, m_iHeightRequested ); + if ( error ) + { + SetPixelSizesFailed = true; + + // If FT_Set_Pixel_Sizes fails, it should be because we've got a fixed-size font. + Assert( m_face->face_flags & FT_FACE_FLAG_FIXED_SIZES ); + Assert( !( m_face->face_flags & FT_FACE_FLAG_SCALABLE ) ); + + if ( m_face->num_fixed_sizes ) + { + // Pick width/height of first size. + int width = m_face->available_sizes[ 0 ].width; + m_iHeightRequested = m_face->available_sizes[ 0 ].height; + + // Loop through all the other available sizes and find the closest match. + for ( int i = 1; i < m_face->num_fixed_sizes; i++ ) + { + if ( ( m_face->available_sizes[ i ].height <= m_iTall ) && + ( m_face->available_sizes[ i ].height > m_iHeightRequested ) ) + { + width = m_face->available_sizes[ i ].width; + m_iHeightRequested = m_face->available_sizes[ i ].height; + } + } + + FT_Size_RequestRec req; + + Q_memset( &req, 0, sizeof( req ) ); + req.type = FT_SIZE_REQUEST_TYPE_REAL_DIM; + req.width = INT_2FIXED6( width ); + req.height = INT_2FIXED6( m_iHeightRequested ); + req.horiResolution = 0; + req.vertResolution = 0; + + error = FT_Request_Size( m_face, &req ); + if ( error ) + { + Msg( "FT_Request_Size failed on %s / %s\n", + m_face->family_name ? m_face->family_name : "??", + m_face->style_name ? m_face->style_name : "??" ); + } + } + } + + FT_Pos ascender, descender; + + if( SetPixelSizesFailed ) + { + // If SetPixelSizesFailed failed, then we've hopefully got a fixed size + // font, and we can just use the metrics. + ascender = m_face->size->metrics.ascender; + descender = m_face->size->metrics.descender; + } + else + { + // Full bounding box ascent and descent: + // ( a * b ) / 0x10000. y_scale is 16.16. + //$ ascender = FT_MulFix( m_face->bbox.yMax, m_face->size->metrics.y_scale ); + descender = FT_MulFix( m_face->bbox.yMin, m_face->size->metrics.y_scale ); + + // Metrics ascent and descent + ascender = m_face->size->metrics.ascender; + //$ descender = m_face->size->metrics.descender; + + // While running with Spanish, the m_face->size->metrics.ascender is less + // than the bitmap_top for the character. This makes GetCharRGBA() chop off + // the top of the O and the accent is skipped. Complete hack here, but we + // check for the tallest character we know about (O') and bump up the ascender + // value if it is greater than what we've currently got. + wchar_t ch = 0xd3; + error = FT_Load_Char( m_face, ch, FT_LOAD_RENDER | FT_LOAD_TARGET_NORMAL); + if ( !error ) + { + int glyph_index = FT_Get_Char_Index( m_face, ch ); + error = FT_Load_Glyph( m_face, glyph_index, FT_LOAD_RENDER ); + if ( !error ) + { + FT_GlyphSlot slot = m_face->glyph; + FT_Pos ascenderTop = INT_2FIXED6( slot->bitmap_top ); + + if( ascenderTop > ascender ) + { + ascender = ascenderTop; + } + else if ( !slot->bitmap.rows || !slot->bitmap.width ) + { + // We didn't find an O' character in this font: use the full BBox. + ascender = FT_MulFix( m_face->bbox.yMax, m_face->size->metrics.y_scale ); + } + } + } + } + + m_iAscent = FIXED6_2INT( ascender ); + + m_iMaxCharWidth = FIXED6_2INT( m_face->size->metrics.max_advance ); + + const int fxpHeight = ascender + -descender + INT_2FIXED6( m_iDropShadowOffset + 2 * m_iOutlineSize ); + m_iHeight = FIXED6_2INT( fxpHeight ); + + // If we're exact or we got too small, bail. + if ( SetPixelSizesFailed || ( m_iHeight == m_iTall ) || ( m_iHeight < 7 ) || ( m_iHeightRequested <= 1 ) ) + break; + + if( bFirstTimeThrough ) + { + bFirstTimeThrough = false; + + // If we're smaller than requested, start searching up. + if ( m_iHeight < m_iTall ) + IncAmount = +1; + } + else if( IncAmount > 0 ) + { + // If we're searching up and went too far, drop IncAmount and run down. + if( m_iHeight > m_iTall ) + IncAmount = -1; + } + else if ( m_iHeight <= m_iTall ) + { + // If the height is less than tall, we're done. + break; + } + + m_iHeightRequested += IncAmount; + } + + m_faceValid = true; + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Given a font name from windows, match it to the filename and return that. +//----------------------------------------------------------------------------- +char *CLinuxFont::GetFontFileName( const char *windowsFontName, int flags ) +{ + bool bBold = false; + const char *pchFontName = windowsFontName; + + if ( !Q_stricmp( pchFontName, "Tahoma" ) ) + pchFontName = "Bitstream Vera Sans"; + else if ( !Q_stricmp( pchFontName, "Arial Black" ) || Q_stristr( pchFontName, "bold" ) ) + bBold = true; + + const int italic = ( flags & vgui::ISurface::FONTFLAG_ITALIC ) ? FC_SLANT_ITALIC : FC_SLANT_ROMAN; + const int nFcWeight = bBold ? FC_WEIGHT_BOLD : FC_WEIGHT_NORMAL; + + FcPattern *match = FontMatch( FC_FAMILY, FcTypeString, pchFontName, + FC_WEIGHT, FcTypeInteger, nFcWeight, + FC_SLANT, FcTypeInteger, italic, + NULL); + if ( !match ) + { + AssertMsg1( false, "Unable to find font named %s\n", windowsFontName ); + return NULL; + } + else + { + char *filenameret = NULL; + FcChar8* filename = NULL; + + if ( FcPatternGetString(match, FC_FILE, 0, &filename) != FcResultMatch ) + { + AssertMsg1( false, "Unable to find font named %s\n", windowsFontName ); + } + else + { + filenameret = strdup( ( char * )filename ); + } + + FcPatternDestroy( match ); + return filenameret; + } +} + +//----------------------------------------------------------------------------- +// Purpose: writes the char into the specified 32bpp texture +//----------------------------------------------------------------------------- +void CLinuxFont::GetCharRGBA( wchar_t ch, int rgbaWide, int rgbaTall, unsigned char *prgba ) +{ + bool bShouldAntialias = m_bAntiAliased; + + // filter out + if ( ( ch > 0x00FF ) && !( m_iFlags & vgui::ISurface::FONTFLAG_CUSTOM ) ) + { + bShouldAntialias = false; + } + + FT_Error error = FT_Load_Char( m_face, ch, FT_LOAD_RENDER | FT_LOAD_TARGET_NORMAL ); + if ( error ) + { + Msg( "Error in FT_Load_Char: ch:%x error:%x\n", (int)ch, error ); + return; + } + + int glyph_index = FT_Get_Char_Index( m_face, ch ); + error = FT_Load_Glyph( m_face, glyph_index, FT_LOAD_RENDER | FT_LOAD_FLAGS ); + if ( error ) + { + Msg( "Error in FL_Load_Glyph: glyph_index:%d error:%x\n", glyph_index, error ); + return; + } + + int yBitmapStart = 0; + FT_GlyphSlot slot = m_face->glyph; + int nSkipRows = ( m_iAscent - slot->bitmap_top ); + + if( nSkipRows < 0 ) + { + yBitmapStart = -nSkipRows; + nSkipRows = 0; + } + if ( nSkipRows >= rgbaTall ) + { + Msg( "nSkipRows(%d) > rgbaTall(%d) ch:%d\n", nSkipRows, rgbaTall, (int)ch ); + return; + } + + if ( m_face->glyph->bitmap.width == 0 ) + { + Msg( "m_face->glyph->bitmap.width is 0 for ch:%d %s\n", (int)ch, m_face->family_name ? m_face->family_name : "??" ); + return; + } + + FT_Bitmap bitmap; + FT_Library ftLibrary = FontManager().GetFontLibraryHandle(); + + FT_Bitmap_New( &bitmap ); + + error = FT_Bitmap_Convert( ftLibrary, &m_face->glyph->bitmap, &bitmap, 1 ); + if( error == 0 ) + { + uint32 alpha_scale = 1; + int Width = min( rgbaWide, bitmap.width ); + unsigned char *rgba = prgba + ( nSkipRows * rgbaWide * 4 ); + + switch( m_face->glyph->bitmap.pixel_mode ) + { + case FT_PIXEL_MODE_MONO: // 8-bit per pixel bitmap + alpha_scale *= 256; + break; + case FT_PIXEL_MODE_GRAY2: // 2-bit per pixel bitmap + alpha_scale *= 64; + break; + case FT_PIXEL_MODE_GRAY4: // 4-bit per pixel bitmap + alpha_scale *= 16; + break; + } + + /* now draw to our target surface */ + for ( int y = yBitmapStart; y < MIN( bitmap.rows, rgbaTall - nSkipRows ); y++ ) + { + for ( int x = 0; x < Width; x++ ) + { + int rgbaOffset = 4 * ( x + m_iBlur ); // +(rgbaTall-y-1)*rgbaWide*4 + uint32 alpha = Min( 255U, alpha_scale * bitmap.buffer[ x + y * bitmap.pitch ] ); + + rgba[ rgbaOffset + 0 ] = 255; + rgba[ rgbaOffset + 1 ] = 255; + rgba[ rgbaOffset + 2 ] = 255; + rgba[ rgbaOffset + 3 ] = alpha; + } + rgba += ( rgbaWide * 4 ); + } + + // apply requested effects in specified order + ApplyDropShadowToTexture( rgbaWide, rgbaTall, prgba, m_iDropShadowOffset ); + ApplyOutlineToTexture( rgbaWide, rgbaTall, prgba, m_iOutlineSize ); + ApplyGaussianBlurToTexture( rgbaWide, rgbaTall, prgba, m_iBlur ); + ApplyScanlineEffectToTexture( rgbaWide, rgbaTall, prgba, m_iScanLines ); + ApplyRotaryEffectToTexture( rgbaWide, rgbaTall, prgba, m_bRotary ); + } + else + { + Msg( "FT_Bitmap_Convert failed: %d on %s\n", error, m_face->family_name ? m_face->family_name : "??" ); + } + + FT_Bitmap_Done( ftLibrary, &bitmap ); +} + +void CLinuxFont::GetKernedCharWidth( wchar_t ch, wchar_t chBefore, wchar_t chAfter, float &wide, float &abcA, float &abcC ) +{ + abcA = abcC = wide = 0.0f; + + // look for it in the cache + kerned_abc_cache_t finder = { ch, chBefore, chAfter }; + + unsigned short iKerned = m_ExtendedKernedABCWidthsCache.Find(finder); + if (m_ExtendedKernedABCWidthsCache.IsValidIndex(iKerned)) + { + abcA = 0; //$ NYI. m_ExtendedKernedABCWidthsCache[iKerned].abc.abcA; + abcC = 0; //$ NYI. m_ExtendedKernedABCWidthsCache[iKerned].abc.abcC; + wide = m_ExtendedKernedABCWidthsCache[iKerned].abc.wide; + return; + } + + FT_UInt glyph_index; + FT_Bool use_kerning; + FT_UInt previous; + int32_t iFxpPenX; + + iFxpPenX = 0; + wide = 0; + + use_kerning = FT_HAS_KERNING( m_face ); + previous = chBefore; + + /* convert character code to glyph index */ + glyph_index = FT_Get_Char_Index( m_face, ch ); + + /* retrieve kerning distance and move pen position */ + if ( use_kerning && previous && glyph_index ) + { + FT_Vector delta; + + FT_Get_Kerning( m_face, previous, glyph_index, + FT_KERNING_DEFAULT, &delta ); + + iFxpPenX += delta.x; + } + + /* load glyph image into the slot (erase previous one) */ + int error = FT_Load_Glyph( m_face, glyph_index, FT_LOAD_DEFAULT | FT_LOAD_FLAGS ); + if ( error ) + { + Error( "Error in FL_Load_Glyph: glyph_index:%d ch:%x error:%x\n", glyph_index, (int)ch, error ); + } + + FT_GlyphSlot slot = m_face->glyph; + iFxpPenX += slot->advance.x; + + if ( FIXED6_2INT(iFxpPenX) > wide ) + wide = FIXED6_2INT(iFxpPenX); + + //$ NYI: finder.abc.abcA = abcA; + //$ NYI: finder.abc.abcC = abcC; + finder.abc.wide = wide; + m_ExtendedKernedABCWidthsCache.Insert(finder); +} + +//----------------------------------------------------------------------------- +// Purpose: gets the abc widths for a character +//----------------------------------------------------------------------------- +void CLinuxFont::GetCharABCWidths(int ch, int &a, int &b, int &c) +{ + Assert(IsValid()); + + // look for it in the cache + abc_cache_t finder = { (wchar_t)ch }; + + unsigned short i = m_ExtendedABCWidthsCache.Find(finder); + if (m_ExtendedABCWidthsCache.IsValidIndex(i)) + { + a = m_ExtendedABCWidthsCache[i].abc.a; + b = m_ExtendedABCWidthsCache[i].abc.b; + c = m_ExtendedABCWidthsCache[i].abc.c; + return; + } + + a = b = c = 0; + + FT_Error error = FT_Load_Char( m_face, ch, 0 ); + if ( error ) + { + Msg( "Error in FT_Load_Char: ch:%x error:%x\n", ch, error ); + return; + } + + // width: The glyph's width. + // horiBearingX: Left side bearing for horizontal layout. + // horiAdvance: Advance width for horizontal layout. + FT_Glyph_Metrics metrics = m_face->glyph->metrics; + + finder.abc.a = metrics.horiBearingX / 64 - m_iBlur - m_iOutlineSize; + finder.abc.b = metrics.width / 64 + ( ( m_iBlur + m_iOutlineSize ) * 2 ) + m_iDropShadowOffset; + finder.abc.c = ( metrics.horiAdvance - metrics.horiBearingX - metrics.width ) / 64 - m_iBlur - m_iDropShadowOffset - m_iOutlineSize; + + m_ExtendedABCWidthsCache.Insert( finder ); + + a = finder.abc.a; + b = finder.abc.b; + c = finder.abc.c; +} + + +//----------------------------------------------------------------------------- +// Purpose: returns true if the font is equivalent to that specified +//----------------------------------------------------------------------------- +bool CLinuxFont::IsEqualTo(const char *windowsFontName, int tall, int weight, int blur, int scanlines, int flags) +{ + if (!Q_stricmp(windowsFontName, m_szName.String() ) + && m_iTall == tall + && m_iWeight == weight + && m_iBlur == blur + && m_iFlags == flags) + return true; + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: returns true only if this font is valid for use +//----------------------------------------------------------------------------- +bool CLinuxFont::IsValid() +{ + if ( !m_szName.IsEmpty() ) + return true; + + return false; +} + + +//----------------------------------------------------------------------------- +// Purpose: returns the height of the font, in pixels +//----------------------------------------------------------------------------- +int CLinuxFont::GetHeight() +{ + assert(IsValid()); + return m_iHeight; +} + +//----------------------------------------------------------------------------- +// Purpose: returns the requested height of the font +//----------------------------------------------------------------------------- +int CLinuxFont::GetHeightRequested() +{ + assert(IsValid()); + return m_iHeightRequested; +} + +//----------------------------------------------------------------------------- +// Purpose: returns the ascent of the font, in pixels (ascent=units above the base line) +//----------------------------------------------------------------------------- +int CLinuxFont::GetAscent() +{ + assert(IsValid()); + return m_iAscent; +} + +//----------------------------------------------------------------------------- +// Purpose: returns the maximum width of a character, in pixels +//----------------------------------------------------------------------------- +int CLinuxFont::GetMaxCharWidth() +{ + assert(IsValid()); + return m_iMaxCharWidth; +} + +//----------------------------------------------------------------------------- +// Purpose: returns the flags used to make this font, used by the dynamic resizing code +//----------------------------------------------------------------------------- +int CLinuxFont::GetFlags() +{ + return m_iFlags; +} + +//----------------------------------------------------------------------------- +// Purpose: Comparison function for abc widths storage +//----------------------------------------------------------------------------- +bool CLinuxFont::ExtendedABCWidthsCacheLessFunc(const abc_cache_t &lhs, const abc_cache_t &rhs) +{ + return lhs.wch < rhs.wch; +} + +//----------------------------------------------------------------------------- +// Purpose: Comparison function for abc widths storage +//----------------------------------------------------------------------------- +bool CLinuxFont::ExtendedKernedABCWidthsCacheLessFunc(const kerned_abc_cache_t &lhs, const kerned_abc_cache_t &rhs) +{ + return ( lhs.wch < rhs.wch ) || + ( lhs.wch == rhs.wch && lhs.wchBefore < rhs.wchBefore ) || + ( lhs.wch == rhs.wch && lhs.wchBefore == rhs.wchBefore && lhs.wchAfter < rhs.wchAfter ); +} + +void *CLinuxFont::SetAsActiveFont( void *cglContext ) +{ + Assert( false ); + return NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: returns true if this font has a glyph for the code point. +//----------------------------------------------------------------------------- +bool CLinuxFont::HasChar(wchar_t wch) +{ + return FT_Get_Char_Index( m_face, wch ) != 0; +} + + +#ifdef DBGFLAG_VALIDATE +//----------------------------------------------------------------------------- +// Purpose: Ensure that all of our internal structures are consistent, and +// account for all memory that we've allocated. +// Input: validator - Our global validator object +// pchName - Our name (typically a member var in our container) +//----------------------------------------------------------------------------- +void CLinuxFont::Validate( CValidator &validator, const char *pchName ) +{ + validator.Push( "CLinuxFont", this, pchName ); + + m_ExtendedABCWidthsCache.Validate( validator, "m_ExtendedABCWidthsCache" ); + m_ExtendedKernedABCWidthsCache.Validate( validator, "m_ExtendedKernedABCWidthsCache" ); + + validator.Pop(); +} +#endif // DBGFLAG_VALIDATE |