From 50ab63b5732142785a8739b2b107bb3481263ffc Mon Sep 17 00:00:00 2001 From: Kyzentun Date: Fri, 27 Feb 2015 17:38:30 -0700 Subject: [PATCH] Changed asserts and exceptions in Font to non-fatal error messages. Changed BitmapText::CropToWidth to ask the font how many glyphs will fit instead of removing one glyph at a time. --- src/BitmapText.cpp | 22 +++-- src/BitmapText.h | 3 +- src/Font.cpp | 198 +++++++++++++++++++++++++++++++++------------ src/Font.h | 1 + 4 files changed, 165 insertions(+), 59 deletions(-) diff --git a/src/BitmapText.cpp b/src/BitmapText.cpp index 45600d06d6..1c6e2b9687 100644 --- a/src/BitmapText.cpp +++ b/src/BitmapText.cpp @@ -622,19 +622,27 @@ bool BitmapText::StringWillUseAlternate( const RString& sText, const RString& sA return true; } -void BitmapText::CropToWidth( int iMaxWidthInSourcePixels ) +void BitmapText::CropLineToWidth(size_t l, int width) { - iMaxWidthInSourcePixels = max( 0, iMaxWidthInSourcePixels ); - - for( unsigned l=0; l iMaxWidthInSourcePixels ) + int used_width= width; + wstring& line= m_wTextLines[l]; + int fit= m_pFont->GetGlyphsThatFit(line, &used_width); + if(fit < line.size()) { - m_wTextLines[l].erase( m_wTextLines[l].end()-1, m_wTextLines[l].end() ); - m_iLineWidths[l] = m_pFont->GetLineWidthInSourcePixels( m_wTextLines[l] ); + line.erase(line.begin()+fit, line.end()); } + m_iLineWidths[l]= used_width; } +} +void BitmapText::CropToWidth(int width) +{ + for(size_t l= 0; l < m_wTextLines.size(); ++l) + { + CropLineToWidth(l, width); + } BuildChars(); } diff --git a/src/BitmapText.h b/src/BitmapText.h index b4cb21205d..b64f98eef5 100644 --- a/src/BitmapText.h +++ b/src/BitmapText.h @@ -62,7 +62,8 @@ public: void SetMaxHeight( float fMaxHeight ); void SetMaxDimUseZoom(bool use); void SetWrapWidthPixels( int iWrapWidthPixels ); - void CropToWidth( int iWidthInSourcePixels ); + void CropLineToWidth(size_t l, int width); + void CropToWidth(int width); virtual bool EarlyAbortDraw() const; virtual void DrawPrimitives(); diff --git a/src/Font.cpp b/src/Font.cpp index e0c3841bbc..c7e7f547ce 100644 --- a/src/Font.cpp +++ b/src/Font.cpp @@ -26,7 +26,14 @@ void FontPage::Load( const FontPageSettings &cfg ) ID1.AdditionalTextureHints = cfg.m_sTextureHints; m_FontPageTextures.m_pTextureMain = TEXTUREMAN->LoadTexture( ID1 ); - ASSERT( m_FontPageTextures.m_pTextureMain != NULL ); + if(m_FontPageTextures.m_pTextureMain == NULL) + { + LuaHelpers::ReportScriptErrorFmt( + "Failed to load main texture %s for font page.", + m_sTexturePath.c_str()); + m_FontPageTextures.m_pTextureMain= TEXTUREMAN->LoadTexture( + TEXTUREMAN->GetDefaultTextureID()); + } RageTextureID ID2 = ID1; // "arial 20 16x16 [main].png" => "arial 20 16x16 [main-stroke].png" @@ -36,9 +43,35 @@ void FontPage::Load( const FontPageSettings &cfg ) 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()) ); + if(m_FontPageTextures.m_pTextureStroke == NULL) + { + LuaHelpers::ReportScriptErrorFmt( + "Failed to load stroke texture %s for font page.", + ID2.filename.c_str()); + m_FontPageTextures.m_pTextureStroke= + m_FontPageTextures.m_pTextureMain; + } + // If the source frame dimensions or number of frames don't match, set + // the stroke layer to be the same as the main layer so that the + // assumptions based on the frames are still safe. -Kyz + if(m_FontPageTextures.m_pTextureMain->GetSourceFrameWidth() != + m_FontPageTextures.m_pTextureStroke->GetSourceFrameWidth()) + { + LuaHelpers::ReportScriptErrorFmt( + "'%s' and '%s' must have the same frame widths", + ID1.filename.c_str(), ID2.filename.c_str()); + m_FontPageTextures.m_pTextureStroke= + m_FontPageTextures.m_pTextureMain; + } + if(m_FontPageTextures.m_pTextureMain->GetNumFrames() != + m_FontPageTextures.m_pTextureStroke->GetNumFrames()) + { + LuaHelpers::ReportScriptErrorFmt( + "'%s' and '%s' must have the same frame dimensions", + ID1.filename.c_str(), ID2.filename.c_str()); + m_FontPageTextures.m_pTextureStroke= + m_FontPageTextures.m_pTextureMain; + } } } @@ -220,6 +253,23 @@ int Font::GetLineHeightInSourcePixels( const wstring &szLine ) const return iLineHeight; } +// width is a pointer so that we can return the used width through it. +int Font::GetGlyphsThatFit(const wstring& line, int* width) const +{ + if(*width == 0) + { + *width= GetLineWidthInSourcePixels(line); + return line.size(); + } + int curr_width= 0; + unsigned int i= 0; + for(i= 0; i < line.size() && curr_width < *width; ++i) + { + curr_width+= GetGlyph(line[i]).m_iHadvance; + } + *width= curr_width; + return i; +} Font::Font(): m_iRefCount(1), path(""), m_apPages(), m_pDefault(NULL), m_iCharToGlyph(), m_bRightToLeft(false), @@ -246,8 +296,12 @@ void Font::Unload() void Font::Reload() { + if(path.empty()) + { + LuaHelpers::ReportScriptError("Cannot reload a font that has an empty path."); + return; + } Unload(); - ASSERT( !path.empty() ); Load( path, m_sChars ); } @@ -347,7 +401,13 @@ void Font::CapsOnly() void Font::SetDefaultGlyph( FontPage *pPage ) { ASSERT( pPage != NULL ); - ASSERT( !pPage->m_aGlyphs.empty() ); + if(pPage->m_aGlyphs.empty()) + { + LuaHelpers::ReportScriptErrorFmt( + "Attempted to set default glyphs for %s to a blank page.", + path.c_str()); + return; + } m_pDefault = pPage; } @@ -393,9 +453,9 @@ void Font::LoadFontPageSettings( FontPageSettings &cfg, IniFile &ini, const RStr char c = sChars[n]; cfg.CharToGlyphNo[c] = n; } - int iNumFramesWide, iNumFramesHigh; - RageTexture::GetFrameDimensionsFromFileName( sTexturePath, &iNumFramesWide, &iNumFramesHigh ); - int iNumFrames = iNumFramesWide * iNumFramesHigh; + int num_frames_wide, num_frames_high; + RageTexture::GetFrameDimensionsFromFileName( sTexturePath, &num_frames_wide, &num_frames_high ); + int iNumFrames = num_frames_wide * num_frames_high; // Deal with fonts generated by Bitmap Font Builder. ini.RenameKey("Char Widths", "main"); @@ -487,33 +547,41 @@ void Font::LoadFontPageSettings( FontPageSettings &cfg, IniFile &ini, const RStr */ vector asMatches; static Regex parse("^RANGE ([A-Z0-9\\-]+)( ?#([0-9A-F]+)-([0-9A-F]+))?$"); - bool bMatch = parse.Compare( sName, asMatches ); - + bool match = parse.Compare( sName, asMatches ); ASSERT( asMatches.size() == 4 ); // 4 parens - - if( !bMatch || asMatches[0].empty() ) - RageException::Throw( "Font definition \"%s\" has an invalid range \"%s\": parse error.", - ini.GetPath().c_str(), sName.c_str() ); - + if(!match || asMatches[0].empty()) + { + LuaHelpers::ReportScriptErrorFmt( + "Font definition \"%s\" has an invalid range \"%s\": parse error.", + ini.GetPath().c_str(), sName.c_str()); + continue; + } // We must have either 1 match (just the codeset) or 4 (the whole thing). - int iCount = -1; - int iFirst = 0; + int count = -1; + int first = 0; if( !asMatches[2].empty() ) { - sscanf( asMatches[2].c_str(), "%x", &iFirst ); - int iLast; - sscanf( asMatches[3].c_str(), "%x", &iLast ); - if( iLast < iFirst ) - RageException::Throw( "Font definition \"%s\" has an invalid range \"%s\": %i < %i.", - ini.GetPath().c_str(), sName.c_str(), iLast, iFirst ); - - iCount = iLast - iFirst + 1; + sscanf( asMatches[2].c_str(), "%x", &first ); + int last; + sscanf( asMatches[3].c_str(), "%x", &last ); + if(last < first) + { + LuaHelpers::ReportScriptErrorFmt( + "Font definition \"%s\" has an invalid range \"%s\": %i < %i.", + ini.GetPath().c_str(), sName.c_str(), last, first); + continue; + } + count = last - first + 1; } - RString sRet = cfg.MapRange( asMatches[0], iFirst, pValue->GetValue(), iCount ); - if( !sRet.empty() ) - RageException::Throw( "Font definition \"%s\" has an invalid range \"%s\": %s.", - ini.GetPath().c_str(), sName.c_str(), sRet.c_str() ); + RString error_string = cfg.MapRange( asMatches[0], first, pValue->GetValue(), count ); + if(!error_string.empty()) + { + LuaHelpers::ReportScriptErrorFmt( + "Font definition \"%s\" has an invalid range \"%s\": %s.", + ini.GetPath().c_str(), sName.c_str(), error_string.c_str()); + continue; + } continue; } @@ -526,26 +594,42 @@ void Font::LoadFontPageSettings( FontPageSettings &cfg, IniFile &ini, const RStr * * This lets us assign characters very compactly and readably. */ - RString sRowStr = sName.substr(5); - TrimLeft( sRowStr ); + RString row_str = sName.substr(5); + TrimLeft(row_str); - ASSERT( IsAnInt(sRowStr) ); - const int iRow = StringToInt( sRowStr ); - const int iFirstFrame = iRow * iNumFramesWide; + if(!IsAnInt(row_str)) + { + LuaHelpers::ReportScriptErrorFmt("Line name %s is not a number.", + row_str.c_str()); + continue; + } + const int row = StringToInt(row_str); + const int first_frame = row * num_frames_wide; - if( iRow > iNumFramesHigh ) - RageException::Throw( "The font definition \"%s\" tries to assign line %i, but the font is only %i characters high.", - ini.GetPath().c_str(), iFirstFrame, iNumFramesHigh ); + if(row > num_frames_high) + { + LuaHelpers::ReportScriptErrorFmt( + "The font definition \"%s\" tries to assign line %i, " + "but the font is only %i characters high.", + ini.GetPath().c_str(), first_frame, num_frames_high); + continue; + } // Decode the string. const wstring wdata( RStringToWstring(pValue->GetValue()) ); - if( int(wdata.size()) > iNumFramesWide ) - 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 ); + if(int(wdata.size()) > num_frames_wide) + { + LuaHelpers::ReportScriptErrorFmt( + "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(), row, wdata.c_str(), + num_frames_wide); + continue; + } for( unsigned i = 0; i < wdata.size(); ++i ) - cfg.CharToGlyphNo[wdata[i]] = iFirstFrame+i; + cfg.CharToGlyphNo[wdata[i]] = first_frame+i; } } } @@ -657,8 +741,13 @@ static vector LoadStack; */ void Font::Load( const RString &sIniPath, RString sChars ) { - ASSERT_M( !GetExtension(sIniPath).CompareNoCase("ini"), sIniPath ); - + if(GetExtension(sIniPath).CompareNoCase("ini")) + { + LuaHelpers::ReportScriptErrorFmt( + "%s is not an ini file. Fonts can only be loaded from ini files.", + sIniPath.c_str()); + return; + } //LOG->Trace( "Font: Loading new font '%s'",sIniPath.c_str()); // Check for recursion (recursive imports). @@ -667,8 +756,10 @@ void Font::Load( const RString &sIniPath, RString sChars ) if( LoadStack[i] == sIniPath ) { RString str = join("\n", LoadStack); - str += "\n" + sIniPath; - RageException::Throw( "Font import recursion detected\n%s", str.c_str() ); + str += "\nCurrent font: " + sIniPath; + LuaHelpers::ReportScriptErrorFmt( + "Font import recursion detected\n%s", str.c_str()); + return; } } LoadStack.push_back( sIniPath ); @@ -762,13 +853,18 @@ void Font::Load( const RString &sIniPath, RString sChars ) /* 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. */ - for( map::const_iterator it = pPage->m_iCharToGlyphNo.begin(); - it != pPage->m_iCharToGlyphNo.end(); ++it ) + for(map::iterator it = pPage->m_iCharToGlyphNo.begin(); + it != pPage->m_iCharToGlyphNo.end(); ++it) { if( it->second < pPage->m_FontPageTextures.m_pTextureMain->GetNumFrames() ) continue; /* OK */ - RageException::Throw( "The font \"%s\" maps \"%s\" to frame %i, but the font only has %i frames.", - sTexturePath.c_str(), WcharDisplayText(wchar_t(it->first)).c_str(), it->second, pPage->m_FontPageTextures.m_pTextureMain->GetNumFrames() ); + LuaHelpers::ReportScriptErrorFmt( + "The font \"%s\" maps \"%s\" to frame %i, " + "but the font only has %i frames.", + sTexturePath.c_str(), WcharDisplayText(wchar_t(it->first)).c_str(), + it->second, + pPage->m_FontPageTextures.m_pTextureMain->GetNumFrames()); + it->second= 0; } // LOG->Trace( "Adding page %s (%s) to %s; %i glyphs", @@ -786,7 +882,7 @@ void Font::Load( const RString &sIniPath, RString sChars ) CapsOnly(); if( m_iCharToGlyph.empty() ) - LOG->Warn( "Font %s has no characters", sIniPath.c_str() ); + LuaHelpers::ReportScriptErrorFmt("Font %s has no characters", sIniPath.c_str()); LoadStack.pop_back(); diff --git a/src/Font.h b/src/Font.h index d57a6b5eae..b24faff671 100644 --- a/src/Font.h +++ b/src/Font.h @@ -145,6 +145,7 @@ public: int GetLineWidthInSourcePixels( const wstring &szLine ) const; int GetLineHeightInSourcePixels( const wstring &szLine ) const; + int GetGlyphsThatFit(const wstring& line, int* width) const; bool FontCompleteForString( const wstring &str ) const;