2003-02-16 04:01:45 +00:00
#include "global.h"
2002-03-30 20:00:13 +00:00
#include "Font.h"
#include "IniFile.h"
2002-08-23 01:06:36 +00:00
2002-03-30 20:00:13 +00:00
#include "RageTextureManager.h"
#include "RageUtil.h"
2002-05-01 19:14:55 +00:00
#include "RageLog.h"
2003-01-05 07:55:31 +00:00
#include "FontManager.h"
2003-01-10 02:02:51 +00:00
#include "ThemeManager.h"
2003-01-16 20:21:07 +00:00
#include "FontCharmaps.h"
#include "FontCharAliases.h"
2007-02-16 11:34:29 +00:00
#include "arch/Dialog/Dialog.h"
2003-01-05 07:55:31 +00:00
2003-01-04 05:17:51 +00:00
FontPage :: FontPage ()
2002-03-30 20:00:13 +00:00
{
2005-05-19 06:55:31 +00:00
m_iDrawExtraPixelsLeft = m_iDrawExtraPixelsRight = 0 ;
2003-01-03 22:53:22 +00:00
}
2005-08-26 18:33:42 +00:00
void FontPage :: Load ( const FontPageSettings & cfg )
2003-01-03 22:53:22 +00:00
{
2005-05-19 06:55:31 +00:00
m_sTexturePath = cfg . m_sTexturePath ;
2003-01-03 22:53:22 +00:00
// load texture
2008-02-15 09:41:19 +00:00
RageTextureID ID1 ( m_sTexturePath );
2005-05-19 06:55:31 +00:00
if ( cfg . m_sTextureHints != "default" )
2008-02-15 09:41:19 +00:00
ID1 . AdditionalTextureHints = cfg . m_sTextureHints ;
2003-01-11 21:20:35 +00:00
2008-02-15 09:41:19 +00:00
m_FontPageTextures . m_pTextureMain = TEXTUREMAN -> LoadTexture ( ID1 );
ASSERT ( m_FontPageTextures . m_pTextureMain != NULL );
RageTextureID ID2 = ID1 ;
{
/* "arial 20 16x16.png" => "arial 20 16x16 (stroke).png" */
size_t pos = ID2 . filename . find_last_of ( '.' );
if ( pos == RString :: npos )
ID2 . filename += " (stroke)" ;
else
ID2 . filename . insert ( pos , " (stroke)" );
}
if ( IsAFile ( ID2 . filename ) )
{
m_FontPageTextures . m_pTextureStroke = TEXTUREMAN -> LoadTexture ( ID2 );
ASSERT ( m_FontPageTextures . m_pTextureStroke != NULL );
ASSERT_M ( m_FontPageTextures . m_pTextureMain -> GetSourceFrameWidth () == m_FontPageTextures . m_pTextureStroke -> GetSourceFrameWidth (), ssprintf ( "'%s' and '%s' must have the same frame widths" , ID1 . filename . c_str (), ID2 . filename . c_str ()) );
ASSERT_M ( m_FontPageTextures . m_pTextureMain -> GetNumFrames () == m_FontPageTextures . m_pTextureStroke -> GetNumFrames (), ssprintf ( "'%s' and '%s' must have the same frame dimensions" , ID1 . filename . c_str (), ID2 . filename . c_str ()) );
}
2003-01-03 22:53:22 +00:00
// load character widths
2005-05-19 06:55:31 +00:00
vector < int > aiFrameWidths ;
2003-01-16 20:21:07 +00:00
2008-02-15 09:41:19 +00:00
int default_width = m_FontPageTextures . m_pTextureMain -> GetSourceFrameWidth ();
2005-05-19 06:55:31 +00:00
if ( cfg . m_iDefaultWidth != - 1 )
default_width = cfg . m_iDefaultWidth ;
2003-01-16 20:21:07 +00:00
2003-01-03 22:53:22 +00:00
// Assume each character is the width of the frame by default.
2008-02-15 09:41:19 +00:00
for ( int i = 0 ; i < m_FontPageTextures . m_pTextureMain -> GetNumFrames (); i ++ )
2002-03-30 20:00:13 +00:00
{
2005-05-19 06:55:31 +00:00
map < int , int >:: const_iterator it = cfg . m_mapGlyphWidths . find ( i );
if ( it != cfg . m_mapGlyphWidths . end () )
aiFrameWidths . push_back ( it -> second );
else
aiFrameWidths . push_back ( default_width );
2002-03-30 20:00:13 +00:00
}
2005-05-19 06:55:31 +00:00
if ( cfg . m_iAddToAllWidths )
2003-01-03 22:53:22 +00:00
{
2008-02-15 09:41:19 +00:00
for ( int i = 0 ; i < m_FontPageTextures . m_pTextureMain -> GetNumFrames (); i ++ )
2005-05-19 06:55:31 +00:00
aiFrameWidths [ i ] += cfg . m_iAddToAllWidths ;
2003-01-03 22:53:22 +00:00
}
2005-05-19 06:55:31 +00:00
if ( cfg . m_fScaleAllWidthsBy != 1 )
2003-01-03 22:53:22 +00:00
{
2008-02-15 09:41:19 +00:00
for ( int i = 0 ; i < m_FontPageTextures . m_pTextureMain -> GetNumFrames (); i ++ )
2007-01-03 05:05:28 +00:00
aiFrameWidths [ i ] = lrintf ( aiFrameWidths [ i ] * cfg . m_fScaleAllWidthsBy );
2003-01-03 22:53:22 +00:00
}
2003-01-05 03:32:41 +00:00
m_iCharToGlyphNo = cfg . CharToGlyphNo ;
2005-05-19 06:55:31 +00:00
m_iLineSpacing = cfg . m_iLineSpacing ;
if ( m_iLineSpacing == - 1 )
2008-02-15 09:41:19 +00:00
m_iLineSpacing = m_FontPageTextures . m_pTextureMain -> GetSourceFrameHeight ();
2003-01-03 22:53:22 +00:00
2005-05-19 06:55:31 +00:00
int iBaseline = 0 ;
2003-01-18 03:14:10 +00:00
/* If we don't have a top and/or baseline, assume we're centered in the
* frame, and that LineSpacing is the total height. */
2005-08-26 18:33:42 +00:00
iBaseline = cfg . m_iBaseline ;
if ( iBaseline == - 1 )
2003-01-08 02:32:30 +00:00
{
2008-02-15 09:41:19 +00:00
float center = m_FontPageTextures . m_pTextureMain -> GetSourceFrameHeight () / 2.0f ;
2005-08-26 18:33:42 +00:00
iBaseline = int ( center + m_iLineSpacing / 2 );
2003-01-08 02:32:30 +00:00
}
2005-05-19 06:55:31 +00:00
2005-08-26 18:33:42 +00:00
int iTop = cfg . m_iTop ;
if ( iTop == - 1 )
2003-01-08 02:32:30 +00:00
{
2008-02-15 09:41:19 +00:00
float center = m_FontPageTextures . m_pTextureMain -> GetSourceFrameHeight () / 2.0f ;
2005-08-26 18:33:42 +00:00
iTop = int ( center - m_iLineSpacing / 2 );
2003-01-08 02:32:30 +00:00
}
2005-08-26 18:33:42 +00:00
m_iHeight = iBaseline - iTop ;
2005-05-19 06:55:31 +00:00
m_iDrawExtraPixelsLeft = cfg . m_iDrawExtraPixelsLeft ;
m_iDrawExtraPixelsRight = cfg . m_iDrawExtraPixelsRight ;
2003-01-08 02:32:30 +00:00
/* Shift the character up so the top will be rendered at the baseline. */
2005-05-19 06:55:31 +00:00
m_fVshift = ( float ) - iBaseline ;
2003-01-08 02:32:30 +00:00
2005-05-19 06:55:31 +00:00
SetTextureCoords ( aiFrameWidths , cfg . m_iAdvanceExtraPixels );
SetExtraPixels ( cfg . m_iDrawExtraPixelsLeft , cfg . m_iDrawExtraPixelsRight );
2003-01-08 02:32:30 +00:00
2003-01-24 01:35:05 +00:00
// LOG->Trace("Font %s: height %i, baseline %i ( == top %i)",
2003-04-25 00:01:35 +00:00
// m_sTexturePath.c_str(), height, baseline, baseline-height);
2003-01-03 20:59:50 +00:00
}
2005-05-19 06:55:31 +00:00
void FontPage :: SetTextureCoords ( const vector < int > & widths , int iAdvanceExtraPixels )
2003-01-03 20:59:50 +00:00
{
2008-02-15 09:41:19 +00:00
for ( int i = 0 ; i < m_FontPageTextures . m_pTextureMain -> GetNumFrames (); ++ i )
2003-01-03 20:59:50 +00:00
{
2003-06-06 20:30:57 +00:00
glyph g ;
2005-05-19 06:55:31 +00:00
g . m_pPage = this ;
2003-06-06 20:30:57 +00:00
/* Make a copy of each texture rect, reducing each to the actual dimensions
* of the character (most characters don't take a full block). */
2008-02-15 09:41:19 +00:00
g . m_TexRect = * m_FontPageTextures . m_pTextureMain -> GetTextureCoordRect ( i );
2003-06-06 20:30:57 +00:00
/* Set the width and height to the width and line spacing, respectively. */
2005-05-19 06:55:31 +00:00
g . m_fWidth = float ( widths [ i ] );
2008-02-15 09:41:19 +00:00
g . m_fHeight = float ( m_FontPageTextures . m_pTextureMain -> GetSourceFrameHeight ());
2003-06-06 20:30:57 +00:00
2005-05-19 06:55:31 +00:00
g . m_iHadvance = int ( g . m_fWidth ) + iAdvanceExtraPixels ;
2003-06-06 20:30:57 +00:00
/* Do the same thing with X. Do this by changing the actual rendered
2005-05-19 06:55:31 +00:00
* m_TexRect, instead of shifting it, so we don't render more than we
* need to. */
g . m_fHshift = 0 ;
2003-01-04 01:47:01 +00:00
{
2008-02-15 09:41:19 +00:00
int iSourcePixelsToChopOff = m_FontPageTextures . m_pTextureMain -> GetSourceFrameWidth () - widths [ i ];
2005-05-19 06:55:31 +00:00
if ( ( iSourcePixelsToChopOff % 2 ) == 1 )
2003-01-04 07:55:42 +00:00
{
2003-06-06 20:30:57 +00:00
/* We don't want to chop off an odd number of pixels, since that'll
* put our texture coordinates between texels and make things blurrier.
2005-05-19 06:55:31 +00:00
* Note that, since we set m_iHadvance above, this merely expands what
2003-06-06 20:30:57 +00:00
* we render; it doesn't advance the cursor further. So, glyphs
* that have an odd width should err to being a pixel offcenter left,
* not right. */
2005-05-19 06:55:31 +00:00
-- iSourcePixelsToChopOff ;
++ g . m_fWidth ;
2003-01-04 07:55:42 +00:00
}
2003-06-21 20:05:37 +00:00
2008-02-15 09:41:19 +00:00
const float fTexCoordsToChopOff = iSourcePixelsToChopOff * m_FontPageTextures . m_pTextureMain -> GetSourceToTexCoordsRatioX ();
2003-01-04 07:55:42 +00:00
2005-05-19 06:55:31 +00:00
g . m_TexRect . left += fTexCoordsToChopOff / 2 ;
g . m_TexRect . right -= fTexCoordsToChopOff / 2 ;
2003-01-04 01:47:01 +00:00
}
2003-06-06 20:30:57 +00:00
2008-02-15 09:41:19 +00:00
g . m_FontPageTextures = m_FontPageTextures ;
2003-06-06 20:30:57 +00:00
2005-05-19 06:55:31 +00:00
m_aGlyphs . push_back ( g );
2003-01-03 20:59:50 +00:00
}
}
2005-05-19 06:55:31 +00:00
void FontPage :: SetExtraPixels ( int iDrawExtraPixelsLeft , int iDrawExtraPixelsRight )
2003-01-03 20:59:50 +00:00
{
2003-01-04 05:17:51 +00:00
/* Hack: do one more than we were asked to; I think a lot of fonts are one
* too low. */
2005-05-19 06:55:31 +00:00
iDrawExtraPixelsRight ++ ;
iDrawExtraPixelsLeft ++ ;
2003-01-04 05:17:51 +00:00
2005-05-19 06:55:31 +00:00
if ( ( iDrawExtraPixelsLeft % 2 ) == 1 )
++ iDrawExtraPixelsLeft ;
2003-01-04 07:55:42 +00:00
2005-05-19 06:55:31 +00:00
/* Adjust for iDrawExtraPixelsLeft and iDrawExtraPixelsRight. */
for ( unsigned i = 0 ; i < m_aGlyphs . size (); ++ i )
2003-01-03 20:59:50 +00:00
{
2008-02-15 09:41:19 +00:00
int iFrameWidth = m_FontPageTextures . m_pTextureMain -> GetSourceFrameWidth ();
2005-05-19 06:55:31 +00:00
float fCharWidth = m_aGlyphs [ i ]. m_fWidth ;
2003-01-03 20:59:50 +00:00
2003-01-04 07:55:42 +00:00
/* Extra pixels to draw to the left and right. We don't have to
2005-05-19 06:55:31 +00:00
* worry about alignment here; fCharWidth is always even (by
2003-01-04 07:55:42 +00:00
* SetTextureCoords) and iFrameWidth are almost always even. */
2005-05-19 06:55:31 +00:00
float fExtraLeft = min ( float ( iDrawExtraPixelsLeft ), ( iFrameWidth - fCharWidth ) / 2.0f );
float fExtraRight = min ( float ( iDrawExtraPixelsRight ), ( iFrameWidth - fCharWidth ) / 2.0f );
2003-01-03 20:59:50 +00:00
/* Move left and expand right. */
2008-02-15 09:41:19 +00:00
m_aGlyphs [ i ]. m_TexRect . left -= fExtraLeft * m_FontPageTextures . m_pTextureMain -> GetSourceToTexCoordsRatioX ();
m_aGlyphs [ i ]. m_TexRect . right += fExtraRight * m_FontPageTextures . m_pTextureMain -> GetSourceToTexCoordsRatioX ();
2005-05-19 06:55:31 +00:00
m_aGlyphs [ i ]. m_fHshift -= fExtraLeft ;
m_aGlyphs [ i ]. m_fWidth += fExtraLeft + fExtraRight ;
2003-01-03 20:59:50 +00:00
}
}
2002-08-13 23:26:46 +00:00
2003-01-04 05:17:51 +00:00
FontPage ::~ FontPage ()
2002-03-30 20:00:13 +00:00
{
2008-02-15 09:41:19 +00:00
if ( m_FontPageTextures . m_pTextureMain != NULL )
{
TEXTUREMAN -> UnloadTexture ( m_FontPageTextures . m_pTextureMain );
m_FontPageTextures . m_pTextureMain = NULL ;
}
if ( m_FontPageTextures . m_pTextureStroke != NULL )
{
TEXTUREMAN -> UnloadTexture ( m_FontPageTextures . m_pTextureStroke );
m_FontPageTextures . m_pTextureStroke = NULL ;
}
2002-03-30 20:00:13 +00:00
}
2003-01-28 00:45:01 +00:00
int Font :: GetLineWidthInSourcePixels ( const wstring & szLine ) const
2002-03-30 20:00:13 +00:00
{
2005-05-19 06:55:31 +00:00
int iLineWidth = 0 ;
2002-03-30 20:00:13 +00:00
2002-12-29 22:55:26 +00:00
for ( unsigned i = 0 ; i < szLine . size (); i ++ )
2005-05-19 06:55:31 +00:00
iLineWidth += GetGlyph ( szLine [ i ]). m_iHadvance ;
2002-03-30 20:00:13 +00:00
2005-05-19 06:55:31 +00:00
return iLineWidth ;
2002-03-30 20:00:13 +00:00
}
2003-01-28 00:45:01 +00:00
int Font :: GetLineHeightInSourcePixels ( const wstring & szLine ) const
2003-01-08 02:32:30 +00:00
{
int iLineHeight = 0 ;
2003-03-27 08:04:28 +00:00
/* The height of a line is the height of its tallest used font page. */
2003-01-08 02:32:30 +00:00
for ( unsigned i = 0 ; i < szLine . size (); i ++ )
2005-05-19 06:55:31 +00:00
iLineHeight = max ( iLineHeight , GetGlyph ( szLine [ i ]). m_pPage -> m_iHeight );
2003-01-10 03:54:29 +00:00
2003-01-08 02:32:30 +00:00
return iLineHeight ;
}
2003-01-04 05:17:51 +00:00
Font :: Font ()
{
2003-04-25 00:01:35 +00:00
//LOG->Trace( "Font::LoadFromFontName(%s)", sASCIITexturePath.c_str() );
2003-01-04 05:17:51 +00:00
m_iRefCount = 1 ;
2005-05-19 06:55:31 +00:00
m_pDefault = NULL ;
2005-09-22 16:49:51 +00:00
m_bRightToLeft = false ;
2003-01-04 05:17:51 +00:00
}
Font ::~ Font ()
2003-01-10 00:31:46 +00:00
{
Unload ();
}
void Font :: Unload ()
2003-01-04 05:17:51 +00:00
{
2005-05-19 06:55:31 +00:00
for ( unsigned i = 0 ; i < m_apPages . size (); ++ i )
delete m_apPages [ i ];
m_apPages . clear ();
2003-01-10 00:31:46 +00:00
m_iCharToGlyph . clear ();
2005-05-19 06:55:31 +00:00
m_pDefault = NULL ;
2003-01-10 00:31:46 +00:00
/* Don't clear the refcount. We've unloaded, but that doesn't mean things
* aren't still pointing to us. */
2003-01-04 05:17:51 +00:00
}
2003-01-10 02:02:51 +00:00
void Font :: Reload ()
{
Unload ();
2005-05-19 06:55:31 +00:00
ASSERT ( ! path . empty () );
Load ( path , m_sChars );
2003-01-10 02:02:51 +00:00
}
2003-01-10 00:31:46 +00:00
2005-05-19 06:55:31 +00:00
void Font :: AddPage ( FontPage * m_pPage )
2003-01-04 05:17:51 +00:00
{
2005-05-19 06:55:31 +00:00
m_apPages . push_back ( m_pPage );
2003-01-04 05:17:51 +00:00
2006-09-14 09:32:04 +00:00
for ( map < wchar_t , int >:: const_iterator it = m_pPage -> m_iCharToGlyphNo . begin ();
2005-05-19 06:55:31 +00:00
it != m_pPage -> m_iCharToGlyphNo . end (); ++ it )
2003-01-04 05:17:51 +00:00
{
2005-05-19 06:55:31 +00:00
m_iCharToGlyph [ it -> first ] = & m_pPage -> m_aGlyphs [ it -> second ];
2003-01-04 05:17:51 +00:00
}
}
2003-01-10 02:02:51 +00:00
void Font :: MergeFont ( Font & f )
2003-01-05 07:55:31 +00:00
{
2003-01-16 22:49:22 +00:00
/* If we don't have a font page yet, and f does, grab the default font
* page. It'll usually be overridden later on by one of our own font
* pages; this will be used only if we don't have any font pages at
* all. */
2005-05-19 06:55:31 +00:00
if ( m_pDefault == NULL )
m_pDefault = f . m_pDefault ;
2003-01-16 22:49:22 +00:00
2006-09-14 09:32:04 +00:00
for ( map < wchar_t , glyph *>:: iterator it = f . m_iCharToGlyph . begin ();
2003-01-10 02:02:51 +00:00
it != f . m_iCharToGlyph . end (); ++ it )
2003-01-05 07:55:31 +00:00
{
m_iCharToGlyph [ it -> first ] = it -> second ;
}
2005-05-19 06:55:31 +00:00
m_apPages . insert ( m_apPages . end (), f . m_apPages . begin (), f . m_apPages . end () );
2003-01-10 02:02:51 +00:00
2005-05-19 06:55:31 +00:00
f . m_apPages . clear ();
2003-01-05 07:55:31 +00:00
}
2003-01-28 00:45:01 +00:00
const glyph & Font :: GetGlyph ( wchar_t c ) const
2003-01-04 05:17:51 +00:00
{
2004-10-01 17:25:17 +00:00
ASSERT ( c >= 0 && c <= 0xFFFFFF );
/* Fast path: */
2006-09-13 03:11:38 +00:00
if ( c < ( int ) ARRAYLEN ( m_iCharToGlyphCache ) && m_iCharToGlyphCache [ c ] )
2004-10-01 17:25:17 +00:00
return * m_iCharToGlyphCache [ c ];
2004-09-27 13:33:08 +00:00
/* Try the regular character. */
2006-09-14 09:32:04 +00:00
map < wchar_t , glyph *>:: const_iterator it = m_iCharToGlyph . find ( c );
2003-01-06 04:24:28 +00:00
2004-09-27 13:33:08 +00:00
/* If that's missing, use the default glyph. */
2006-06-12 09:14:26 +00:00
if ( it == m_iCharToGlyph . end ())
it = m_iCharToGlyph . find ( FONT_DEFAULT_GLYPH );
2003-01-06 02:50:25 +00:00
if ( it == m_iCharToGlyph . end ())
2006-09-17 01:19:19 +00:00
RageException :: Throw ( "The default glyph is missing from the font \" %s \" ." , path . c_str () );
2003-01-06 02:50:25 +00:00
2003-01-04 05:17:51 +00:00
return * it -> second ;
}
2003-02-12 19:33:30 +00:00
bool Font :: FontCompleteForString ( const wstring & str ) const
{
2006-09-14 09:32:04 +00:00
map < wchar_t , glyph *>:: const_iterator m_pDefault = m_iCharToGlyph . find ( FONT_DEFAULT_GLYPH );
2005-05-19 06:55:31 +00:00
if ( m_pDefault == m_iCharToGlyph . end () )
2006-09-17 01:19:19 +00:00
RageException :: Throw ( "The default glyph is missing from the font \" %s \" ." , path . c_str () );
2003-02-12 19:33:30 +00:00
2005-05-19 06:55:31 +00:00
for ( unsigned i = 0 ; i < str . size (); ++ i )
2003-02-12 19:33:30 +00:00
{
/* If the glyph for this character is the default glyph, we're incomplete. */
2005-05-19 06:55:31 +00:00
const glyph & g = GetGlyph ( str [ i ] );
if ( & g == m_pDefault -> second )
2003-02-12 19:33:30 +00:00
return false ;
}
return true ;
}
2003-01-05 03:32:41 +00:00
void Font :: CapsOnly ()
2003-01-04 05:17:51 +00:00
{
2003-01-05 03:32:41 +00:00
/* For each uppercase character that we have a mapping for, add
2006-02-14 11:16:39 +00:00
* a lowercase one. */
for ( char c = 'A' ; c <= 'Z' ; ++ c )
2003-01-04 05:17:51 +00:00
{
2006-09-14 09:32:04 +00:00
map < wchar_t , glyph *>:: const_iterator it = m_iCharToGlyph . find ( c );
2003-01-04 05:17:51 +00:00
2003-01-05 03:32:41 +00:00
if ( it == m_iCharToGlyph . end ())
continue ;
2003-01-04 05:17:51 +00:00
2003-01-05 05:13:45 +00:00
m_iCharToGlyph [( char ) tolower ( c )] = it -> second ;
2003-01-04 05:17:51 +00:00
}
}
2003-01-06 23:49:43 +00:00
2005-05-19 06:55:31 +00:00
void Font :: SetDefaultGlyph ( FontPage * pPage )
2003-01-06 23:49:43 +00:00
{
2005-05-19 06:55:31 +00:00
ASSERT ( pPage );
ASSERT ( ! pPage -> m_aGlyphs . empty () );
m_pDefault = pPage ;
2003-01-06 23:49:43 +00:00
}
2005-09-03 00:17:37 +00:00
/* Given the INI for a font, find all of the texture pages for the font. */
2006-01-22 01:00:06 +00:00
void Font :: GetFontPaths ( const RString & sFontIniPath , vector < RString > & asTexturePathsOut )
2003-01-16 22:49:22 +00:00
{
2006-01-22 01:00:06 +00:00
RString sPrefix = SetExtension ( sFontIniPath , "" );
vector < RString > asFiles ;
2005-09-03 00:17:37 +00:00
GetDirListing ( sPrefix + "*" , asFiles , false , true );
2003-01-16 22:49:22 +00:00
2005-05-19 06:55:31 +00:00
for ( unsigned i = 0 ; i < asFiles . size (); ++ i )
2003-01-10 02:02:51 +00:00
{
2007-02-16 11:34:29 +00:00
if ( ! asFiles [ i ]. Right ( 4 ). EqualsNoCase ( ".ini" ) )
2005-09-03 00:17:37 +00:00
asTexturePathsOut . push_back ( asFiles [ i ] );
2003-01-10 02:02:51 +00:00
}
}
2006-01-22 01:00:06 +00:00
RString Font :: GetPageNameFromFileName ( const RString & sFilename )
2003-01-10 02:02:51 +00:00
{
2005-05-19 06:55:31 +00:00
size_t begin = sFilename . find_first_of ( '[' );
if ( begin == string :: npos )
return "main" ;
size_t end = sFilename . find_first_of ( ']' , begin );
if ( end == string :: npos )
return "main" ;
begin ++ ;
end -- ;
if ( end == begin )
return "main" ;
return sFilename . substr ( begin , end - begin + 1 );
2003-01-10 02:02:51 +00:00
}
2006-01-22 01:00:06 +00:00
void Font :: LoadFontPageSettings ( FontPageSettings & cfg , IniFile & ini , const RString & sTexturePath , const RString & sPageName , RString sChars )
2003-01-10 02:02:51 +00:00
{
2005-05-19 06:55:31 +00:00
cfg . m_sTexturePath = sTexturePath ;
2003-01-10 02:02:51 +00:00
/* If we have any characters to map, add them. */
for ( unsigned n = 0 ; n < sChars . size (); n ++ )
{
char c = sChars [ n ];
cfg . CharToGlyphNo [ c ] = n ;
}
2005-05-19 06:55:31 +00:00
int iNumFramesWide , iNumFramesHigh ;
RageTexture :: GetFrameDimensionsFromFileName ( sTexturePath , & iNumFramesWide , & iNumFramesHigh );
int iNumFrames = iNumFramesWide * iNumFramesHigh ;
2003-01-10 02:02:51 +00:00
ini . RenameKey ( "Char Widths" , "main" );
2003-01-24 01:35:05 +00:00
// LOG->Trace("Loading font page '%s' settings from page name '%s'",
2005-05-19 06:55:31 +00:00
// TexturePath.c_str(), sPageName.c_str());
2003-01-10 02:02:51 +00:00
2005-05-19 06:55:31 +00:00
ini . GetValue ( sPageName , "DrawExtraPixelsLeft" , cfg . m_iDrawExtraPixelsLeft );
ini . GetValue ( sPageName , "DrawExtraPixelsRight" , cfg . m_iDrawExtraPixelsRight );
ini . GetValue ( sPageName , "AddToAllWidths" , cfg . m_iAddToAllWidths );
ini . GetValue ( sPageName , "ScaleAllWidthsBy" , cfg . m_fScaleAllWidthsBy );
ini . GetValue ( sPageName , "LineSpacing" , cfg . m_iLineSpacing );
ini . GetValue ( sPageName , "Top" , cfg . m_iTop );
ini . GetValue ( sPageName , "Baseline" , cfg . m_iBaseline );
ini . GetValue ( sPageName , "DefaultWidth" , cfg . m_iDefaultWidth );
ini . GetValue ( sPageName , "AdvanceExtraPixels" , cfg . m_iAdvanceExtraPixels );
ini . GetValue ( sPageName , "TextureHints" , cfg . m_sTextureHints );
2003-01-10 02:02:51 +00:00
/* Iterate over all keys. */
2005-05-19 06:55:31 +00:00
const XNode * pNode = ini . GetChild ( sPageName );
2005-01-07 14:28:00 +00:00
if ( pNode )
2003-01-10 02:02:51 +00:00
{
2005-01-07 14:28:00 +00:00
FOREACH_CONST_Attr ( pNode , pAttr )
2003-01-10 02:02:51 +00:00
{
2006-01-22 01:00:06 +00:00
RString sName = pAttr -> first ;
2006-10-03 00:07:01 +00:00
const XNodeValue * pValue = pAttr -> second ;
2003-01-10 02:02:51 +00:00
2005-05-19 06:55:31 +00:00
sName . MakeUpper ();
2003-01-10 02:02:51 +00:00
2004-05-31 00:11:34 +00:00
/* If val is an integer, it's a width, eg. "10=27". */
2005-05-19 06:55:31 +00:00
if ( IsAnInt ( sName ) )
2003-01-10 02:02:51 +00:00
{
2006-10-03 00:07:01 +00:00
cfg . m_mapGlyphWidths [ atoi ( sName )] = pValue -> GetValue < int > ();
2003-01-28 03:40:28 +00:00
continue ;
2003-01-17 20:44:06 +00:00
}
2003-01-10 02:02:51 +00:00
2004-05-31 00:11:34 +00:00
/* "map codepoint=frame" maps a char to a frame. */
2005-05-19 06:55:31 +00:00
if ( sName . substr ( 0 , 4 ) == "MAP " )
2003-01-28 03:40:28 +00:00
{
2005-05-19 06:55:31 +00:00
/*
* map CODEPOINT=frame. CODEPOINT can be
2004-05-31 00:11:34 +00:00
* 1. U+hexval
* 2. an alias ("oq")
2006-09-30 23:54:08 +00:00
* 3. a character in quotes ("X")
2004-05-31 00:11:34 +00:00
*
* map 1=2 is the same as
* range unicode #1-1=2
*/
2006-01-22 01:00:06 +00:00
RString sCodepoint = sName . substr ( 4 ); /* "CODEPOINT" */
2004-05-31 00:11:34 +00:00
wchar_t c ;
2005-05-19 06:55:31 +00:00
if ( sCodepoint . substr ( 0 , 2 ) == "U+" && IsHexVal ( sCodepoint . substr ( 2 )) )
sscanf ( sCodepoint . substr ( 2 ). c_str (), "%x" , & c );
else if ( sCodepoint . size () > 0 &&
utf8_get_char_len ( sCodepoint [ 0 ]) == int ( sCodepoint . size ()) )
2004-05-31 00:11:34 +00:00
{
2005-05-19 06:55:31 +00:00
c = utf8_get_char ( sCodepoint . c_str () );
2004-05-31 00:11:34 +00:00
if ( c == wchar_t ( - 1 ))
LOG -> Warn ( "Font definition '%s' has an invalid value '%s'." ,
2005-05-19 06:55:31 +00:00
ini . GetPath (). c_str (), sName . c_str () );
2004-05-31 00:11:34 +00:00
}
2005-05-19 06:55:31 +00:00
else if ( ! FontCharAliases :: GetChar ( sCodepoint , c ) )
2004-05-31 00:11:34 +00:00
{
LOG -> Warn ( "Font definition '%s' has an invalid value '%s'." ,
2005-05-19 06:55:31 +00:00
ini . GetPath (). c_str (), sName . c_str () );
2004-05-31 00:11:34 +00:00
continue ;
}
2006-10-03 00:07:01 +00:00
cfg . CharToGlyphNo [ c ] = pValue -> GetValue < int > ();
2004-05-31 00:11:34 +00:00
continue ;
2003-01-28 03:40:28 +00:00
}
2003-01-10 02:02:51 +00:00
2005-05-19 06:55:31 +00:00
if ( sName . substr ( 0 , 6 ) == "RANGE " )
2003-01-16 20:21:07 +00:00
{
2005-05-19 06:55:31 +00:00
/*
* range CODESET=first_frame or
2004-05-31 00:11:34 +00:00
* range CODESET #start-end=first_frame
* eg
* range CP1252=0 (default for 256-frame fonts)
* range ASCII=0 (default for 128-frame fonts)
*
* (Start and end are in hex.)
*
* Map two high-bit portions of ISO-8859- to one font:
* range ISO-8859-2 #80-FF=0
* range ISO-8859-3 #80-FF=128
*
* Map hiragana to 0-84:
* range Unicode #3041-3094=0
*/
2006-01-22 01:00:06 +00:00
vector < RString > asMatches ;
2006-03-02 07:15:25 +00:00
static Regex parse ( "^RANGE ([A-Z0-9 \\ -]+) ( ? # ([ 0 - 9 A - F ] + ) - ([ 0 - 9 A - F ] + )) ? $ ") ;
2005-05-19 06:55:31 +00:00
bool bMatch = parse . Compare ( sName , asMatches );
2004-05-31 00:11:34 +00:00
2005-05-19 06:55:31 +00:00
ASSERT ( asMatches . size () == 4 ); /* 4 parens */
2003-01-16 20:21:07 +00:00
2005-05-19 06:55:31 +00:00
if ( ! bMatch || asMatches [ 0 ]. empty () )
2006-09-17 01:19:19 +00:00
RageException :: Throw ( "Font definition \" %s \" has an invalid range \" %s \" : parse error." ,
2005-05-19 06:55:31 +00:00
ini . GetPath (). c_str (), sName . c_str () );
2004-05-31 00:11:34 +00:00
/* We must have either 1 match (just the codeset) or 4 (the whole thing). */
2005-05-19 06:55:31 +00:00
int iCount = - 1 ;
int iFirst = 0 ;
if ( ! asMatches [ 2 ]. empty () )
2004-05-31 00:11:34 +00:00
{
2005-05-19 06:55:31 +00:00
sscanf ( asMatches [ 2 ]. c_str (), "%x" , & iFirst );
int iLast ;
sscanf ( asMatches [ 3 ]. c_str (), "%x" , & iLast );
if ( iLast < iFirst )
2006-09-17 01:19:19 +00:00
RageException :: Throw ( "Font definition \" %s \" has an invalid range \" %s \" : %i < %i." ,
ini . GetPath (). c_str (), sName . c_str (), iLast , iFirst );
2004-05-31 00:11:34 +00:00
2005-05-19 06:55:31 +00:00
iCount = iLast - iFirst + 1 ;
2004-05-31 00:11:34 +00:00
}
2006-10-03 00:07:01 +00:00
RString sRet = cfg . MapRange ( asMatches [ 0 ], iFirst , pValue -> GetValue < int > (), iCount );
2005-05-19 06:55:31 +00:00
if ( ! sRet . empty () )
2006-09-17 01:19:19 +00:00
RageException :: Throw ( "Font definition \" %s \" has an invalid range \" %s \" : %s." ,
2005-05-19 06:55:31 +00:00
ini . GetPath (). c_str (), sName . c_str (), sRet . c_str () );
2004-05-31 00:11:34 +00:00
continue ;
2003-01-10 02:02:51 +00:00
}
2005-05-19 06:55:31 +00:00
if ( sName . substr ( 0 , 5 ) == "LINE " )
2004-05-31 00:11:34 +00:00
{
/* line ROW=CHAR1CHAR2CHAR3CHAR4
* eg.
* line 0=ABCDEFGH
*
* This lets us assign characters very compactly and readably. */
2003-01-10 02:02:51 +00:00
2006-01-22 01:00:06 +00:00
RString sRowStr = sName . substr ( 5 );
2005-05-19 06:55:31 +00:00
ASSERT ( IsAnInt ( sRowStr ) );
const int iRow = atoi ( sRowStr . c_str () );
const int iFirstFrame = iRow * iNumFramesWide ;
2003-02-11 19:56:13 +00:00
2005-05-19 06:55:31 +00:00
if ( iRow > iNumFramesHigh )
2006-09-17 01:19:19 +00:00
RageException :: Throw ( "The font definition \" %s \" tries to assign line %i, but the font is only %i characters high." ,
2005-05-19 06:55:31 +00:00
ini . GetPath (). c_str (), iFirstFrame , iNumFramesHigh );
2003-02-11 19:56:13 +00:00
2004-05-31 00:11:34 +00:00
/* Decode the string. */
2006-10-03 00:07:01 +00:00
const wstring wdata ( RStringToWstring ( pValue -> GetValue < RString > ()) );
2003-02-11 19:56:13 +00:00
2005-05-19 06:55:31 +00:00
if ( int ( wdata . size ()) > iNumFramesWide )
2006-09-17 01:19:19 +00:00
RageException :: Throw ( "The font definition \" %s \" assigns %i characters to row %i ( \" %ls \" ), but the font is only %i characters wide." ,
ini . GetPath (). c_str (), ( int ) wdata . size (), iRow , wdata . c_str (), iNumFramesWide );
2003-02-11 19:56:13 +00:00
2005-05-19 06:55:31 +00:00
for ( unsigned i = 0 ; i < wdata . size (); ++ i )
cfg . CharToGlyphNo [ wdata [ i ]] = iFirstFrame + i ;
2004-05-31 00:11:34 +00:00
}
2003-02-11 19:56:13 +00:00
}
2003-01-10 02:02:51 +00:00
}
2003-01-16 20:21:07 +00:00
/* If it's 128 or 256 frames, default to ASCII or CP1252,
* respectively. If it's anything else, we don't know what it
* is, so don't make any default mappings (the INI needs to do
* it itself). */
2005-05-19 06:55:31 +00:00
if ( sPageName != "common" && cfg . CharToGlyphNo . empty () )
2004-09-09 02:59:15 +00:00
{
2008-02-15 09:41:19 +00:00
switch ( iNumFrames )
{
case 128 :
2004-09-09 02:59:15 +00:00
cfg . MapRange ( "ascii" , 0 , 0 , - 1 );
2008-02-15 09:41:19 +00:00
break ;
case 256 :
2004-09-09 02:59:15 +00:00
cfg . MapRange ( "cp1252" , 0 , 0 , - 1 );
2008-02-15 09:41:19 +00:00
break ;
case 15 :
case 16 :
2004-09-09 02:59:15 +00:00
cfg . MapRange ( "numbers" , 0 , 0 , - 1 );
2008-02-15 09:41:19 +00:00
break ;
default :
2005-05-19 06:55:31 +00:00
LOG -> Trace ( "Font page \" %s \" has no characters" , sTexturePath . c_str () );
2008-02-15 09:41:19 +00:00
}
2004-09-09 02:59:15 +00:00
}
2004-01-10 03:32:46 +00:00
/* If ' ' is set and nbsp is not, set nbsp. */
if ( cfg . CharToGlyphNo . find ( ' ' ) != cfg . CharToGlyphNo . end () )
cfg . CharToGlyphNo [ 0x00A0 ] = cfg . CharToGlyphNo [ ' ' ];
2003-01-16 20:21:07 +00:00
}
2006-01-22 01:00:06 +00:00
RString FontPageSettings :: MapRange ( RString sMapping , int iMapOffset , int iGlyphNo , int iCount )
2003-01-16 20:21:07 +00:00
{
2005-05-19 06:55:31 +00:00
if ( ! sMapping . CompareNoCase ( "Unicode" ) )
2003-01-16 20:21:07 +00:00
{
/* Special case. */
2005-05-19 06:55:31 +00:00
if ( iCount == - 1 )
2003-01-16 20:21:07 +00:00
return "Can't map all of Unicode to one font page" ; /* don't do that */
/* What's a practical limit? A 2048x2048 texture could contain 16x16 characters,
* which is 16384 glyphs. (Use a grayscale map and that's only 4 megs.) Let's use
* that as a cap. (We don't want to go crazy if someone says "range Unicode
* #0-FFFFFFFF".) */
2005-05-19 06:55:31 +00:00
if ( iCount > 16384 )
return ssprintf ( "Can't map %i glyphs to one font page" , iCount );
2003-01-16 20:21:07 +00:00
2005-05-19 06:55:31 +00:00
while ( iCount )
2003-01-16 20:21:07 +00:00
{
2005-05-19 06:55:31 +00:00
CharToGlyphNo [ iMapOffset ] = iGlyphNo ;
iMapOffset ++ ;
iGlyphNo ++ ;
iCount -- ;
2003-01-16 20:21:07 +00:00
}
2006-01-22 01:00:06 +00:00
return RString ();
2003-01-16 20:21:07 +00:00
}
2005-05-19 06:55:31 +00:00
const wchar_t * pMapping = FontCharmaps :: get_char_map ( sMapping );
if ( pMapping == NULL )
2003-01-16 20:21:07 +00:00
return "Unknown mapping" ;
2005-05-19 06:55:31 +00:00
while ( * pMapping != 0 && iMapOffset )
{
pMapping ++ ;
-- iMapOffset ;
}
if ( iMapOffset )
2003-01-16 20:21:07 +00:00
return "Map overflow" ; /* there aren't enough characters in the map */
2005-05-19 06:55:31 +00:00
/* If iCount is -1, set it to the number of characters in the map. */
if ( iCount == - 1 )
for ( iCount = 0 ; pMapping [ iCount ] != 0 ; ++ iCount ) ;
2003-01-16 20:21:07 +00:00
2005-05-19 06:55:31 +00:00
while ( * pMapping != 0 )
2003-01-16 20:21:07 +00:00
{
2005-05-19 06:55:31 +00:00
if ( * pMapping != FontCharmaps :: M_SKIP )
CharToGlyphNo [ * pMapping ] = iGlyphNo ;
pMapping ++ ;
iGlyphNo ++ ;
iCount -- ;
2003-01-16 20:21:07 +00:00
}
2005-05-19 06:55:31 +00:00
if ( iCount )
2003-01-16 20:21:07 +00:00
return "Map overflow" ; /* there aren't enough characters in the map */
2006-01-22 01:00:06 +00:00
return RString ();
2003-01-10 02:02:51 +00:00
}
2006-01-22 01:00:06 +00:00
static vector < RString > LoadStack ;
2003-01-10 02:02:51 +00:00
2005-05-19 06:55:31 +00:00
/*
* A font set is a set of files, eg:
2003-01-10 02:02:51 +00:00
*
* Normal 16x16.png
* Normal [other] 16x16.png
* Normal [more] 8x8.png
* Normal 16x16.ini (the 16x16 here is optional)
*
2005-09-03 00:17:37 +00:00
* One INI and at least one texture is required.
2003-01-10 02:02:51 +00:00
*
* The entire font can be redirected; that's handled in ThemeManager.
* Individual font files can not be redirected.
*
2005-09-03 00:17:37 +00:00
* If a file has no characters and sChars is not set, it will receive a default
2003-01-10 02:02:51 +00:00
* mapping of ASCII or ISO-8859-1 if the font has exactly 128 or 256 frames.
* However, if it doesn't, we don't know what it is and the font will receive
* no default mapping. A font isn't useful with no characters mapped.
*/
2006-01-22 01:00:06 +00:00
void Font :: Load ( const RString & sIniPath , RString sChars )
2003-01-10 02:02:51 +00:00
{
2005-09-03 00:17:37 +00:00
ASSERT_M ( ! GetExtension ( sIniPath ). CompareNoCase ( "ini" ), sIniPath );
2003-01-10 02:02:51 +00:00
/* Check for recursion (recursive imports). */
2005-11-01 15:00:50 +00:00
for ( unsigned i = 0 ; i < LoadStack . size (); ++ i )
2003-01-10 02:02:51 +00:00
{
2005-11-01 15:00:50 +00:00
if ( LoadStack [ i ] == sIniPath )
2003-01-10 02:02:51 +00:00
{
2006-01-22 01:00:06 +00:00
RString str = join ( " \n " , LoadStack );
2005-11-01 15:00:50 +00:00
str += " \n " + sIniPath ;
2006-09-17 01:19:19 +00:00
RageException :: Throw ( "Font import recursion detected \n %s" , str . c_str () );
2003-01-10 02:02:51 +00:00
}
}
2005-11-01 15:00:50 +00:00
LoadStack . push_back ( sIniPath );
2003-01-10 02:02:51 +00:00
/* The font is not already loaded. Figure out what we have. */
2005-09-03 00:17:37 +00:00
CHECKPOINT_M ( ssprintf ( "Font::Load( \" %s \" , \" %s \" )." , sIniPath . c_str (), m_sChars . c_str ()) );
2003-01-10 02:02:51 +00:00
2005-09-03 00:17:37 +00:00
path = sIniPath ;
2005-05-19 06:55:31 +00:00
m_sChars = sChars ;
2003-01-10 02:02:51 +00:00
/* Get the filenames associated with this font. */
2006-01-22 01:00:06 +00:00
vector < RString > asTexturePaths ;
2005-09-03 00:17:37 +00:00
GetFontPaths ( sIniPath , asTexturePaths );
2003-01-16 22:49:22 +00:00
2007-02-16 11:34:29 +00:00
2005-05-19 06:55:31 +00:00
bool bCapitalsOnly = false ;
2003-01-10 02:02:51 +00:00
/* If we have an INI, load it. */
IniFile ini ;
2005-05-19 06:55:31 +00:00
if ( ! sIniPath . empty () )
2003-01-10 02:02:51 +00:00
{
2005-05-19 06:55:31 +00:00
ini . ReadFile ( sIniPath );
2003-01-10 02:02:51 +00:00
ini . RenameKey ( "Char Widths" , "main" );
2005-05-19 06:55:31 +00:00
ini . GetValue ( "main" , "CapitalsOnly" , bCapitalsOnly );
2005-09-22 09:08:11 +00:00
ini . GetValue ( "main" , "RightToLeft" , m_bRightToLeft );
2003-01-10 02:02:51 +00:00
}
{
2006-01-22 01:00:06 +00:00
vector < RString > ImportList ;
2007-02-16 11:34:29 +00:00
bool bIsTopLevelFont = LoadStack . size () == 1 ;
/* If this is a top-level font (not a subfont), load the default font first. */
if ( bIsTopLevelFont )
2003-03-30 18:12:57 +00:00
ImportList . push_back ( "Common default" );
2003-01-10 02:02:51 +00:00
/* Check to see if we need to import any other fonts. Do this
* before loading this font, so any characters in this font
* override imported characters. */
2006-01-22 01:00:06 +00:00
RString imports ;
2003-01-10 02:02:51 +00:00
ini . GetValue ( "main" , "import" , imports );
split ( imports , "," , ImportList , true );
2007-02-16 11:34:29 +00:00
if ( bIsTopLevelFont && imports . empty () && asTexturePaths . empty () )
{
RString s = ssprintf ( "Font \" %s \" is a top-level font with no textures or imports." , sIniPath . c_str () );
Dialog :: OK ( s );
}
2003-01-10 02:02:51 +00:00
for ( unsigned i = 0 ; i < ImportList . size (); ++ i )
{
2006-01-22 01:00:06 +00:00
RString path = THEME -> GetPathF ( "" , ImportList [ i ], true );
2003-10-17 23:41:16 +00:00
if ( path == "" )
{
2007-02-16 11:34:29 +00:00
RString s = ssprintf ( "Font \" %s \" imports a font \" %s \" that doesn't exist" , sIniPath . c_str (), ImportList [ i ]. c_str () );
Dialog :: OK ( s );
2003-10-17 23:41:16 +00:00
continue ;
}
2003-01-10 02:02:51 +00:00
Font subfont ;
subfont . Load ( path , "" );
MergeFont ( subfont );
}
}
/* Load each font page. */
2005-11-01 15:00:50 +00:00
for ( unsigned i = 0 ; i < asTexturePaths . size (); ++ i )
2003-01-10 02:02:51 +00:00
{
2006-01-22 01:00:06 +00:00
const RString & sTexturePath = asTexturePaths [ i ];
2004-05-31 00:11:34 +00:00
2005-05-19 06:55:31 +00:00
FontPage * pPage = new FontPage ;
2003-01-10 02:02:51 +00:00
/* Grab the page name, eg "foo" from "Normal [foo].png". */
2006-01-22 01:00:06 +00:00
RString sPagename = GetPageNameFromFileName ( sTexturePath );
2003-01-10 02:02:51 +00:00
/* Load settings for this page from the INI. */
FontPageSettings cfg ;
2005-09-03 00:17:37 +00:00
LoadFontPageSettings ( cfg , ini , sTexturePath , "common" , sChars );
LoadFontPageSettings ( cfg , ini , sTexturePath , sPagename , sChars );
2003-01-10 02:02:51 +00:00
/* Go. */
2005-05-19 06:55:31 +00:00
pPage -> Load ( cfg );
2003-01-10 02:02:51 +00:00
/* Expect at least as many frames as we have premapped characters. */
/* Make sure that we don't map characters to frames we don't actually
* have. This can happen if the font is too small for an sChars. */
2006-09-14 09:32:04 +00:00
for ( map < wchar_t , int >:: const_iterator it = pPage -> m_iCharToGlyphNo . begin ();
2005-05-19 06:55:31 +00:00
it != pPage -> m_iCharToGlyphNo . end (); ++ it )
2003-01-10 02:02:51 +00:00
{
2008-02-15 09:41:19 +00:00
if ( it -> second < pPage -> m_FontPageTextures . m_pTextureMain -> GetNumFrames () )
2005-05-19 06:55:31 +00:00
continue ; /* OK */
2006-09-17 01:19:19 +00:00
RageException :: Throw ( "The font \" %s \" maps \" %s \" to frame %i, but the font only has %i frames." ,
2008-02-15 09:41:19 +00:00
sTexturePath . c_str (), WcharDisplayText ( wchar_t ( it -> first )). c_str (), it -> second , pPage -> m_FontPageTextures . m_pTextureMain -> GetNumFrames () );
2003-01-10 02:02:51 +00:00
}
2005-05-19 06:55:31 +00:00
// LOG->Trace( "Adding page %s (%s) to %s; %i glyphs",
// TexturePaths[i].c_str(), sPagename.c_str(),
// sFontOrTextureFilePath.c_str(), pPage->m_iCharToGlyphNo.size() );
AddPage ( pPage );
2003-01-10 02:02:51 +00:00
/* If this is the first font loaded, or it's called "main", this page's
* properties become the font's properties. */
2005-05-19 06:55:31 +00:00
if ( i == 0 || sPagename == "main" )
SetDefaultGlyph ( pPage );
2003-01-10 02:02:51 +00:00
}
2005-05-19 06:55:31 +00:00
if ( bCapitalsOnly )
2003-01-10 02:02:51 +00:00
CapsOnly ();
2005-05-19 06:55:31 +00:00
if ( m_iCharToGlyph . empty () )
2005-09-03 00:17:37 +00:00
LOG -> Warn ( "Font %s has no characters" , sIniPath . c_str () );
2003-01-10 02:02:51 +00:00
LoadStack . pop_back ();
2004-10-01 17:25:17 +00:00
if ( LoadStack . empty () )
{
/* Cache ASCII glyphs. */
ZERO ( m_iCharToGlyphCache );
2006-09-14 09:32:04 +00:00
map < wchar_t , glyph *>:: iterator it ;
2004-10-01 17:25:17 +00:00
for ( it = m_iCharToGlyph . begin (); it != m_iCharToGlyph . end (); ++ it )
2006-09-13 03:11:38 +00:00
if ( it -> first < ( int ) ARRAYLEN ( m_iCharToGlyphCache ) )
2004-10-01 17:25:17 +00:00
m_iCharToGlyphCache [ it -> first ] = it -> second ;
}
2003-01-10 02:02:51 +00:00
}
2004-05-31 22:42:12 +00:00
/*
* (c) 2001-2004 Glenn Maynard, Chris Danford
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/