utf-8 support is working
This commit is contained in:
@@ -22,6 +22,86 @@
|
||||
#include "GameConstantsAndTypes.h"
|
||||
#include "Font.h"
|
||||
|
||||
char *g_utf8_find_next_char (const char *p,
|
||||
const char *end)
|
||||
{
|
||||
if (*p) {
|
||||
if (end)
|
||||
for (++p; p < end && (*p & 0xc0) == 0x80; ++p)
|
||||
;
|
||||
else
|
||||
for (++p; (*p & 0xc0) == 0x80; ++p)
|
||||
;
|
||||
}
|
||||
return (p == end) ? NULL : (char *)p;
|
||||
}
|
||||
|
||||
#define UTF8_GET \
|
||||
|
||||
wchar_t
|
||||
g_utf8_get_char (const char *p)
|
||||
{
|
||||
int i, mask = 0, len;
|
||||
wchar_t result;
|
||||
unsigned char c = (unsigned char) *p;
|
||||
|
||||
if (c < 128) {
|
||||
len = 1;
|
||||
mask = 0x7f;
|
||||
} else if ((c & 0xe0) == 0xc0) {
|
||||
len = 2;
|
||||
mask = 0x1f;
|
||||
} else if ((c & 0xf0) == 0xe0) {
|
||||
len = 3;
|
||||
mask = 0x0f;
|
||||
} else if ((c & 0xf8) == 0xf0) {
|
||||
len = 4;
|
||||
mask = 0x07;
|
||||
} else if ((c & 0xfc) == 0xf8) {
|
||||
len = 5;
|
||||
mask = 0x03;
|
||||
} else if ((c & 0xfe) == 0xfc) {
|
||||
len = 6;
|
||||
mask = 0x01;
|
||||
} else
|
||||
return (wchar_t)-1;
|
||||
|
||||
result = wchar_t(p[0] & mask);
|
||||
for (i = 1; i < len; ++i) {
|
||||
if ((p[i] & 0xc0) != 0x80)
|
||||
return (wchar_t) -1;
|
||||
|
||||
result <<= 6;
|
||||
result |= p[i] & 0x3f;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
wstring CStringToWstring(const CString &str)
|
||||
{
|
||||
const char *ptr = str.c_str(), *end = str.c_str()+str.size();
|
||||
|
||||
wstring ret;
|
||||
|
||||
while(ptr)
|
||||
{
|
||||
wchar_t c = g_utf8_get_char (ptr);
|
||||
if(c != wchar_t(-1))
|
||||
ret.push_back(c);
|
||||
|
||||
ptr = g_utf8_find_next_char (ptr, end);
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define RAINBOW_COLOR(n) THEME->GetMetricC("BitmapText",ssprintf("RainbowColor%i", n+1))
|
||||
|
||||
@@ -118,7 +198,7 @@ void BitmapText::BuildChars()
|
||||
|
||||
for( i=0; i<m_szTextLines.size(); i++ ) // foreach line
|
||||
{
|
||||
const CString &szLine = m_szTextLines[i];
|
||||
const wstring &szLine = m_szTextLines[i];
|
||||
const int iLineWidth = m_iLineWidths[i];
|
||||
|
||||
int iX;
|
||||
@@ -172,6 +252,8 @@ void BitmapText::DrawChars()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* sText is UTF-8. */
|
||||
void BitmapText::SetText( CString sText )
|
||||
{
|
||||
ASSERT( m_pFont );
|
||||
@@ -185,7 +267,7 @@ void BitmapText::SetText( CString sText )
|
||||
m_iLineWidths.clear();
|
||||
m_iLineHeights.clear();
|
||||
|
||||
split(m_szText, "\n", m_szTextLines, false);
|
||||
split(CStringToWstring(sText), L"\n", m_szTextLines, false);
|
||||
|
||||
/* calculate line lengths and widths */
|
||||
m_iWidestLineWidth = 0;
|
||||
|
||||
@@ -46,8 +46,8 @@ public:
|
||||
protected:
|
||||
|
||||
// recalculate the items below on SetText()
|
||||
CString m_szText;
|
||||
vector<CString> m_szTextLines;
|
||||
CString m_szText;
|
||||
vector<wstring> m_szTextLines;
|
||||
vector<int> m_iLineWidths; // in source pixels
|
||||
vector<int> m_iLineHeights; // in source pixels
|
||||
int m_iWidestLineWidth; // in source pixels
|
||||
|
||||
+10
-10
@@ -34,7 +34,7 @@ void FontPage::Load( const CString &TexturePath, const FontPageSettings &cfg )
|
||||
ASSERT( m_pTexture != NULL );
|
||||
|
||||
// load character widths
|
||||
vector<int> FrameWidths; // = cfg.GlyphWidths;
|
||||
vector<int> FrameWidths;
|
||||
int i;
|
||||
// Assume each character is the width of the frame by default.
|
||||
for( i=0; i<m_pTexture->GetNumFrames(); i++ )
|
||||
@@ -155,7 +155,7 @@ FontPage::~FontPage()
|
||||
}
|
||||
|
||||
|
||||
int Font::GetLineWidthInSourcePixels( const CString &szLine ) const
|
||||
int Font::GetLineWidthInSourcePixels( const wstring &szLine ) const
|
||||
{
|
||||
int LineWidth = 0;
|
||||
|
||||
@@ -165,7 +165,7 @@ int Font::GetLineWidthInSourcePixels( const CString &szLine ) const
|
||||
return LineWidth;
|
||||
}
|
||||
|
||||
int Font::GetLineHeightInSourcePixels( const CString &szLine ) const
|
||||
int Font::GetLineHeightInSourcePixels( const wstring &szLine ) const
|
||||
{
|
||||
int iLineSpacing = 0;
|
||||
|
||||
@@ -194,16 +194,16 @@ void Font::AddPage(FontPage *fp)
|
||||
{
|
||||
pages.push_back(fp);
|
||||
|
||||
for(map<int,int>::const_iterator it = fp->m_iCharToGlyphNo.begin();
|
||||
for(map<wchar_t,int>::const_iterator it = fp->m_iCharToGlyphNo.begin();
|
||||
it != fp->m_iCharToGlyphNo.end(); ++it)
|
||||
{
|
||||
m_iCharToGlyph[it->first] = &fp->glyphs[it->second];
|
||||
}
|
||||
}
|
||||
|
||||
const glyph &Font::GetGlyph( int c ) const
|
||||
const glyph &Font::GetGlyph( wchar_t c ) const
|
||||
{
|
||||
map<int,glyph*>::const_iterator it = m_iCharToGlyph.find(c);
|
||||
map<wchar_t,glyph*>::const_iterator it = m_iCharToGlyph.find(c);
|
||||
|
||||
if(it == m_iCharToGlyph.end())
|
||||
RageException::Throw( "The font '%s' does not implement the character '%c'", path.GetString(), c );
|
||||
@@ -211,9 +211,9 @@ const glyph &Font::GetGlyph( int c ) const
|
||||
return *it->second;
|
||||
}
|
||||
|
||||
RageTexture *Font::GetGlyphTexture( int c )
|
||||
RageTexture *Font::GetGlyphTexture( wchar_t c )
|
||||
{
|
||||
map<int,glyph*>::iterator it = m_iCharToGlyph.find(c);
|
||||
map<wchar_t,glyph*>::iterator it = m_iCharToGlyph.find(c);
|
||||
|
||||
if(it == m_iCharToGlyph.end())
|
||||
RageException::Throw( "The font '%s' does not implement the character '%c'", path.GetString(), c );
|
||||
@@ -227,11 +227,11 @@ void Font::CapsOnly()
|
||||
* a lowercase one. */
|
||||
for(char c = 'A'; c <= 'Z'; ++c)
|
||||
{
|
||||
map<int,glyph*>::const_iterator it = m_iCharToGlyph.find(c);
|
||||
map<wchar_t,glyph*>::const_iterator it = m_iCharToGlyph.find(c);
|
||||
|
||||
if(it == m_iCharToGlyph.end())
|
||||
continue;
|
||||
|
||||
m_iCharToGlyph[tolower(c)] = it->second;
|
||||
m_iCharToGlyph[(char) tolower(c)] = it->second;
|
||||
}
|
||||
}
|
||||
|
||||
+8
-10
@@ -37,7 +37,7 @@ struct FontPageSettings {
|
||||
LineSpacing;
|
||||
float ScaleAllWidthsBy;
|
||||
|
||||
map<int,int> CharToGlyphNo;
|
||||
map<wchar_t,int> CharToGlyphNo;
|
||||
/* If a value is missing, the width of the texture frame is used. */
|
||||
map<int,int> GlyphWidths;
|
||||
|
||||
@@ -49,6 +49,7 @@ struct FontPageSettings {
|
||||
{ }
|
||||
};
|
||||
|
||||
// typedef basic_string<wchar_t> wstring;
|
||||
|
||||
class FontPage
|
||||
{
|
||||
@@ -60,14 +61,11 @@ public:
|
||||
/* All glyphs in this list will point to m_pTexture. */
|
||||
vector<glyph> glyphs;
|
||||
|
||||
map<int,int> m_iCharToGlyphNo;
|
||||
map<wchar_t,int> m_iCharToGlyphNo;
|
||||
|
||||
FontPage();
|
||||
~FontPage();
|
||||
|
||||
int GetLineWidthInSourcePixels( const CString &szLine );
|
||||
int GetLineHeightInSourcePixels( const CString &szLine );
|
||||
|
||||
void Load( const CString &sASCIITexturePath, const FontPageSettings &cfg );
|
||||
|
||||
private:
|
||||
@@ -80,16 +78,16 @@ class Font
|
||||
public:
|
||||
int m_iRefCount;
|
||||
CString path;
|
||||
map<int,glyph*> m_iCharToGlyph;
|
||||
map<wchar_t,glyph*> m_iCharToGlyph;
|
||||
|
||||
Font();
|
||||
~Font();
|
||||
|
||||
RageTexture *GetGlyphTexture( int c );
|
||||
const glyph &GetGlyph( int c ) const;
|
||||
RageTexture *GetGlyphTexture( wchar_t c );
|
||||
const glyph &GetGlyph( wchar_t c ) const;
|
||||
|
||||
int GetLineWidthInSourcePixels( const CString &szLine ) const;
|
||||
int GetLineHeightInSourcePixels( const CString &szLine ) const;
|
||||
int GetLineWidthInSourcePixels( const wstring &szLine ) const;
|
||||
int GetLineHeightInSourcePixels( const wstring &szLine ) const;
|
||||
|
||||
/* Add a FontPage to this font. */
|
||||
void AddPage(FontPage *fp);
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include "RageException.h"
|
||||
#include "RageTimer.h"
|
||||
|
||||
static map <CString, int, StdStringLessNoCase> CharAliases;
|
||||
static map <CString, wchar_t, StdStringLessNoCase> CharAliases;
|
||||
|
||||
FontManager* FONT = NULL;
|
||||
|
||||
@@ -53,7 +53,7 @@ void FontManager::LoadFontPageSettings(FontPageSettings &cfg, IniFile &ini, cons
|
||||
else if(NumFrames == 256)
|
||||
cfg.MapRange("ISO-8859-1", 0, 255, 0);
|
||||
*/
|
||||
for( int i=0; i<NumFrames; i++ )
|
||||
for( wchar_t i=0; i<NumFrames; i++ )
|
||||
cfg.CharToGlyphNo[i] = i;
|
||||
}
|
||||
ini.RenameKey("Char Widths", "main");
|
||||
@@ -93,14 +93,13 @@ void FontManager::LoadFontPageSettings(FontPageSettings &cfg, IniFile &ini, cons
|
||||
*/
|
||||
CString codepoint = val.substr(4); /* "XXXX" */
|
||||
|
||||
int c = -1;
|
||||
wchar_t c;
|
||||
|
||||
if(codepoint.substr(0, 2) == "U+" && IsHexVal(codepoint.substr(2)))
|
||||
sscanf(codepoint.substr(2).c_str(), "%x", &c);
|
||||
else if(CharAliases.find(codepoint) != CharAliases.end())
|
||||
c = CharAliases[codepoint];
|
||||
|
||||
if(c == -1)
|
||||
else
|
||||
RageException::Throw( "Font definition '%s' has an invalid value '%s'.",
|
||||
ini.GetPath().GetString(), val.GetString() );
|
||||
|
||||
|
||||
@@ -116,10 +116,7 @@ CString ThemeManager::GetThemeDirFromName( CString sThemeName )
|
||||
|
||||
CString ThemeManager::GetPathTo( CString sAssetCategory, CString sFileName )
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
try_element_again:
|
||||
#endif
|
||||
|
||||
sAssetCategory.MakeLower();
|
||||
sFileName.MakeLower();
|
||||
|
||||
@@ -139,6 +136,7 @@ try_element_again:
|
||||
static const char *font_masks[] = { " 16x16.png", ".redir", NULL };
|
||||
static const char *numbers_masks[] = { " 5x3.png", ".redir", NULL };
|
||||
static const char *bganimations_masks[] = { ".", ".redir", NULL };
|
||||
static const char *blank_mask[] = { "", NULL };
|
||||
const char **asset_masks = NULL;
|
||||
if( sAssetCategory == "graphics" ) asset_masks = graphic_masks;
|
||||
else if( sAssetCategory == "sounds" ) asset_masks = sound_masks;
|
||||
@@ -146,8 +144,15 @@ try_element_again:
|
||||
else if( sAssetCategory == "numbers" ) asset_masks = numbers_masks;
|
||||
else if( sAssetCategory == "bganimations" ) asset_masks = bganimations_masks;
|
||||
else ASSERT(0); // Unknown theme asset category
|
||||
|
||||
/* If the theme asset name has an extension, don't add
|
||||
* a mask. This should only happen with redirs. */
|
||||
if(sFileName.find_last_of('.') != sFileName.npos)
|
||||
asset_masks = blank_mask;
|
||||
|
||||
int i;
|
||||
CString path;
|
||||
|
||||
for(i = 0; asset_masks[i]; ++i)
|
||||
{
|
||||
path = sCurrentThemeDir;
|
||||
@@ -204,11 +209,8 @@ try_element_again:
|
||||
/* backwards-compatibility hack */
|
||||
if( sAssetCategory == "fonts" )
|
||||
sNewFilePath.Replace(" 16x16.png", "");
|
||||
|
||||
return sNewFilePath;
|
||||
}
|
||||
|
||||
if( !DoesFileExist(sNewFilePath) )
|
||||
else if( !DoesFileExist(sNewFilePath) )
|
||||
{
|
||||
CString message = ssprintf(
|
||||
"The redirect '%s' points to the file '%s', which does not exist."
|
||||
@@ -222,8 +224,16 @@ try_element_again:
|
||||
RageException::Throw( "%s", message.GetString() );
|
||||
}
|
||||
|
||||
/* Search again. For example, themes/default/Fonts/foo might redir
|
||||
* to "Hello"; but "Hello" might be overridden in themes/hot pink/Fonts/Hello. */
|
||||
|
||||
return sNewFilePath;
|
||||
/* Strip off the path. */
|
||||
unsigned pos = sNewFilePath.find_last_of("/\\");
|
||||
if(pos != sNewFilePath.npos) sNewFilePath = sNewFilePath.substr(pos+1);
|
||||
sFileName = sNewFilePath;
|
||||
|
||||
/* XXX check for loops */
|
||||
goto try_element_again;
|
||||
}
|
||||
|
||||
/* If we're searching for a font, the return value should be the file
|
||||
|
||||
Reference in New Issue
Block a user