00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "OSDLFont.h"
00028
00029 #include "OSDLSurface.h"
00030 #include "OSDLPixel.h"
00031
00032
00033 #include <list>
00034
00035
00036 #ifdef OSDL_USES_CONFIG_H
00037 #include <OSDLConfig.h>
00038 #endif // OSDL_USES_CONFIG_H
00039
00040
00041 #if OSDL_ARCH_NINTENDO_DS
00042 #include "OSDLConfigForNintendoDS.h"
00043 #endif // OSDL_ARCH_NINTENDO_DS
00044
00045
00046
00047
00048
00049 #if OSDL_USES_SDL_TTF
00050
00051 #include "SDL_ttf.h"
00052
00053 #endif // OSDL_USES_SDL_TTF
00054
00055
00056 using std::list ;
00057 using std::pair ;
00058
00059 using std::string ;
00060
00061
00062 using namespace Ceylan ;
00063 using namespace Ceylan::Log ;
00064
00065 using namespace OSDL::Video ;
00066 using namespace OSDL::Video::Pixels ;
00067 using namespace OSDL::Video::TwoDimensional ;
00068
00069
00070
00071 string Text::Font::FontPathEnvironmentVariable = "FONT_PATH" ;
00072
00073
00074 Ceylan::System::FileLocator Text::Font::FontFileLocator(
00075 FontPathEnvironmentVariable ) ;
00076
00077
00078
00079
00080 FontException::FontException( const string & reason ) :
00081 VideoException( "FontException: " + reason )
00082 {
00083
00084 }
00085
00086
00087
00088 FontException::~FontException() throw()
00089 {
00090
00091 }
00092
00093
00094
00095
00096 using namespace OSDL::Video::TwoDimensional::Text ;
00097
00098
00099
00100
00101
00102
00103
00104
00105 #if OSDL_USES_SDL_TTF
00106
00107 const RenderingStyle Font::Normal = TTF_STYLE_NORMAL ;
00108 const RenderingStyle Font::Bold = TTF_STYLE_BOLD ;
00109 const RenderingStyle Font::Italic = TTF_STYLE_ITALIC ;
00110 const RenderingStyle Font::Underline = TTF_STYLE_UNDERLINE ;
00111
00112 #else // OSDL_USES_SDL_TTF
00113
00114
00115
00116
00117 const RenderingStyle Font::Normal = 0x00 ;
00118 const RenderingStyle Font::Bold = 0x01 ;
00119 const RenderingStyle Font::Italic = 0x02 ;
00120 const RenderingStyle Font::Underline = 0x04 ;
00121
00122 #endif // OSDL_USES_SDL_TTF
00123
00124
00125
00126
00127 const Ceylan::System::Size Font::DefaultGlyphCachedQuota = 4 * 1024 * 1024 ;
00128 const Ceylan::System::Size Font::DefaultWordCachedQuota = 6 * 1024 * 1024 ;
00129 const Ceylan::System::Size Font::DefaultTextCachedQuota = 8 * 1024 * 1024 ;
00130
00131 const Ceylan::Uint8 Font::DefaultSpaceBasedAlineaWidth = 6 ;
00132
00133
00134
00135
00136 Font::Font(
00137 bool convertToDisplay,
00138 RenderCache cacheSettings,
00139 AllowedCachePolicy cachePolicy,
00140 Ceylan::System::Size quota ) :
00141 _renderingStyle( Normal ),
00142 _convertToDisplay( convertToDisplay ),
00143 _cacheSettings( cacheSettings ),
00144 _glyphCache( 0 ),
00145 _textCache( 0 ),
00146 _backgroundColor( Pixels::Black ),
00147 _spaceWidth( 0 ),
00148 _alineaWidth( 0 )
00149 {
00150
00151
00152
00153
00154
00155
00156
00157
00158 switch( _cacheSettings )
00159 {
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175 case None:
00176
00177 #if OSDL_DEBUG_FONT
00178 LogPlug::debug( "Font created with no rendering cache." ) ;
00179 #endif // OSDL_DEBUG_FONT
00180
00181
00182 break ;
00183
00184
00185 case GlyphCached:
00186
00187 #if OSDL_DEBUG_FONT
00188 LogPlug::debug( "Font created with glyph rendering cache." ) ;
00189 #endif // OSDL_DEBUG_FONT
00190
00191 if ( quota == 0 )
00192 quota = DefaultGlyphCachedQuota ;
00193
00194 SmartResourceManager<CharColorQualityKey>::CachePolicy
00195 actualGlyphPolicy ;
00196
00197
00198
00199
00200
00201
00202 switch( cachePolicy )
00203 {
00204
00205 case NeverDrop:
00206 actualGlyphPolicy =
00207 SmartResourceManager<CharColorQualityKey>::NeverDrop ;
00208 break ;
00209
00210 case DropLessRequestedFirst:
00211 actualGlyphPolicy =
00212 SmartResourceManager<CharColorQualityKey>::DropLessRequestedFirst ;
00213 break ;
00214
00215 default:
00216 Ceylan::emergencyShutdown(
00217 "OSDL::Video::TwoDimensional::Font constructor "
00218 "with glych cache: forbidden cache settings" ) ;
00219
00220 break ;
00221
00222 }
00223
00224 _glyphCache = new SmartResourceManager<CharColorQualityKey>( quota,
00225 actualGlyphPolicy ) ;
00226 break ;
00227
00228
00229 case WordCached:
00230
00231 #if OSDL_DEBUG_FONT
00232 LogPlug::debug( "Font created with word rendering cache." ) ;
00233 #endif // OSDL_DEBUG_FONT
00234
00235 if ( quota == 0 )
00236 quota = DefaultWordCachedQuota ;
00237
00238 SmartResourceManager<StringColorQualityKey>::CachePolicy
00239 actualWordPolicy ;
00240
00241
00242
00243
00244
00245
00246 switch( cachePolicy )
00247 {
00248
00249 case NeverDrop:
00250 actualWordPolicy =
00251 SmartResourceManager<StringColorQualityKey>::NeverDrop ;
00252 break ;
00253
00254 case DropLessRequestedFirst:
00255 actualWordPolicy =
00256 SmartResourceManager<StringColorQualityKey>::DropLessRequestedFirst ;
00257 break ;
00258
00259 default:
00260 Ceylan::emergencyShutdown(
00261 "OSDL::Video::TwoDimensional::Font constructor "
00262 "with word cache: forbidden cache settings" ) ;
00263
00264 break ;
00265 }
00266
00267 _textCache = new SmartResourceManager<StringColorQualityKey>(
00268 quota, actualWordPolicy ) ;
00269 break ;
00270
00271
00272 case TextCached:
00273
00274 #if OSDL_DEBUG_FONT
00275 LogPlug::debug( "Font created with text rendering cache." ) ;
00276 #endif // OSDL_DEBUG_FONT
00277
00278 if ( quota == 0 )
00279 quota = DefaultTextCachedQuota ;
00280
00281 SmartResourceManager<StringColorQualityKey>::CachePolicy
00282 actualTextPolicy ;
00283
00284
00285
00286
00287
00288
00289 switch( cachePolicy )
00290 {
00291
00292 case NeverDrop:
00293 actualTextPolicy =
00294 SmartResourceManager<StringColorQualityKey>::NeverDrop ;
00295 break ;
00296
00297 case DropLessRequestedFirst:
00298 actualTextPolicy =
00299 SmartResourceManager<StringColorQualityKey>::DropLessRequestedFirst ;
00300 break ;
00301
00302 default:
00303 Ceylan::emergencyShutdown(
00304 "OSDL::Video::TwoDimensional::Font constructor "
00305 "with text cache: forbidden cache settings" ) ;
00306 break ;
00307
00308 }
00309
00310 _textCache = new SmartResourceManager<StringColorQualityKey>(
00311 quota, actualTextPolicy ) ;
00312 break ;
00313
00314
00315 default:
00316 Ceylan::emergencyShutdown(
00317 "OSDL::Video::TwoDimensional::Font constructor: "
00318 "unexpected cache settings" ) ;
00319 break ;
00320
00321 }
00322
00323
00324
00325 }
00326
00327
00328
00329 Font::~Font() throw()
00330 {
00331
00332 if ( _glyphCache != 0 )
00333 delete _glyphCache ;
00334
00335 if ( _textCache != 0 )
00336 delete _textCache ;
00337
00338 }
00339
00340
00341
00342 RenderingStyle Font::getRenderingStyle() const
00343 {
00344
00345 return _renderingStyle ;
00346
00347 }
00348
00349
00350
00351 void Font::setRenderingStyle( RenderingStyle newStyle )
00352 {
00353
00354 _renderingStyle = newStyle ;
00355
00356 }
00357
00358
00359
00360
00361 void Font::setBackgroundColor( Pixels::ColorDefinition newBackgroundColor )
00362 {
00363
00364 _backgroundColor = newBackgroundColor ;
00365
00366 }
00367
00368
00369
00370 OSDL::Video::Pixels::ColorDefinition Font::getBackgroundColor() const
00371 {
00372
00373 return _backgroundColor ;
00374
00375 }
00376
00377
00378
00379 Width Font::getAlineaWidth() const
00380 {
00381 return _alineaWidth ;
00382
00383 }
00384
00385
00386 void Font::setAlineaWidth( Width newAlineaWidth )
00387 {
00388
00389 _alineaWidth = newAlineaWidth ;
00390
00391 }
00392
00393
00394
00395 std::string Font::describeGlyphFor( Ceylan::Latin1Char character ) const
00396 {
00397
00398 list<string> res ;
00399
00400 res.push_back( "Advance is "
00401 + Ceylan::toString( getAdvance( character ) ) ) ;
00402
00403 res.push_back( "Width is " + Ceylan::toString( getWidth( character ) ) ) ;
00404
00405 res.push_back( "Width offset is "
00406 + Ceylan::toString( getWidthOffset( character ) ) ) ;
00407
00408 res.push_back( "Height above baseline is "
00409 + Ceylan::toString( getHeightAboveBaseline( character ) ) ) ;
00410
00411 return "Informations about the glyph corresponding to the character '"
00412 + Ceylan::toString( character ) + "': "
00413 + Ceylan::formatStringList( res ) ;
00414
00415 }
00416
00417
00418
00419 Width Font::getInterGlyphWidth() const
00420 {
00421
00422
00423 static Width inter = static_cast<Width>(
00424 Ceylan::Maths::Max<Ceylan::Float32>( 1, 0.1f * getWidth( 'a' ) ) ) ;
00425
00426 return inter ;
00427
00428 }
00429
00430
00431
00432 OSDL::Video::Surface & Font::renderLatin1Text( const std::string & text,
00433 RenderQuality quality, Pixels::ColorDefinition textColor )
00434 {
00435
00436
00437
00438 switch( _cacheSettings )
00439 {
00440
00441 case None:
00442 case GlyphCached:
00443
00444
00445
00446
00447
00448
00449
00450 return basicRenderLatin1Text( text, quality, textColor ) ;
00451 break ;
00452
00453
00454 case WordCached:
00455
00456 return renderLatin1TextWithWordCached( text, quality, textColor ) ;
00457 break ;
00458
00459
00460 case TextCached:
00461
00462 return renderLatin1TextWithTextCached( text, quality, textColor ) ;
00463 break ;
00464
00465
00466 default:
00467 Ceylan::emergencyShutdown(
00468 "OSDL::Video::TwoDimensional::Font::renderLatin1Text: "
00469 "unexpected cache settings" ) ;
00470 break ;
00471
00472 }
00473
00474
00475 throw FontException( "Font::renderLatin1Text: unexpected end of method" ) ;
00476
00477 }
00478
00479
00480
00481 void Font::blitLatin1Text( Surface & targetSurface, Coordinate x, Coordinate y,
00482 const std::string & text, RenderQuality quality,
00483 Pixels::ColorDefinition textColor )
00484 {
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495 if ( _cacheSettings == TextCached )
00496 {
00497
00498 StringColorQualityKey renderKey( text, textColor, quality ) ;
00499
00500 const Resource * res = _textCache->get( renderKey ) ;
00501
00502
00503 if ( res != 0 )
00504 {
00505
00506 const Surface * toReturn = dynamic_cast<const Surface *>( res ) ;
00507
00508 #if OSDL_DEBUG_FONT
00509
00510 LogPlug::debug( "Font::blitLatin1Text: cache hit, "
00511 "returning clone of prerendered text." ) ;
00512
00513 if ( toReturn == 0 )
00514 Ceylan::emergencyShutdown( "Font::blitLatin1Text: "
00515 "clone is not a Surface." ) ;
00516
00517 #endif // OSDL_DEBUG_FONT
00518
00519 toReturn->blitTo( targetSurface, x, y ) ;
00520
00521 return ;
00522
00523 }
00524
00525 }
00526
00527
00528
00529
00530
00531
00532
00533 Surface & res = renderLatin1Text( text, quality, textColor ) ;
00534
00535
00536
00537
00538 try
00539 {
00540 res.blitTo( targetSurface, x, y ) ;
00541 }
00542 catch( const VideoException & e )
00543 {
00544
00545 throw FontException( "Font::blitLatin1Text: blit failed: "
00546 + e.toString() ) ;
00547 }
00548
00549 delete & res ;
00550
00551 }
00552
00553
00554
00555 OSDL::Video::Surface & Font::renderLatin1MultiLineText(
00556 Length width, Length height, const std::string & text,
00557 TextIndex & renderIndex, Coordinate & lastOrdinateUsed,
00558 RenderQuality quality, Pixels::ColorDefinition textColor, bool justified )
00559 {
00560
00561
00562
00563
00564
00565
00566 ColorMask redMask, greenMask, blueMask ;
00567
00568 Pixels::getRecommendedColorMasks( redMask, greenMask, blueMask ) ;
00569
00570 Surface & res = * new Surface( Surface::Hardware | Surface::ColorkeyBlit,
00571 width, height, 32, redMask, greenMask, blueMask,
00572 0 ) ;
00573
00574
00575
00576
00577
00578
00579
00580
00581 Pixels::ColorDefinition colorKey ;
00582
00583 if ( Pixels::areEqual( textColor, Pixels::Black, false ) )
00584 {
00585
00586 colorKey = Pixels::White ;
00587 res.fill( colorKey ) ;
00588
00589 }
00590 else
00591 {
00592
00593 colorKey = Pixels::Black ;
00594
00595
00596
00597
00598
00599
00600 }
00601
00602 Length lineSkip = getLineSkip() ;
00603
00604
00605
00606
00607
00608
00609 LineNumber maxLines = height / lineSkip ;
00610
00611 if ( maxLines == 0 )
00612 throw FontException( "Font::renderLatin1MultiLineText: box height ("
00613 + Ceylan::toString( height )
00614 + ") is not enough even for one line of text, whose height is "
00615 + Ceylan::toString( lineSkip ) + "." ) ;
00616
00617 renderIndex = 0 ;
00618
00619 #if OSDL_DEBUG_FONT
00620
00621 LogPlug::debug( "Font::renderLatin1MultiLineText: "
00622 + Ceylan::toString( maxLines )
00623 + " line(s) available to render following text: '" + text + "'." ) ;
00624
00625 #endif // OSDL_DEBUG_FONT
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637 Height lineHeight = 0 ;
00638
00639
00640 list<string> words ;
00641
00642 string currentWord ;
00643
00644 Length currentWidth, storedWidth ;
00645
00646 Width wordWidth ;
00647 const Surface * wordSurface ;
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667 bool createTemporaryWordCache =
00668 ( _cacheSettings == GlyphCached || _cacheSettings == None ) ;
00669
00670 if ( createTemporaryWordCache )
00671 {
00672
00673 #if OSDL_DEBUG_FONT
00674
00675 if ( _textCache != 0 )
00676 throw FontException( "Font::renderLatin1MultiLineText: "
00677 "unable to create temporary word cache "
00678 "since already existing." ) ;
00679
00680 LogPlug::debug( "Font::renderLatin1MultiLineText: "
00681 "creating a temporary word cache" ) ;
00682
00683 #endif // OSDL_DEBUG_FONT
00684
00685 _textCache = new SmartResourceManager<StringColorQualityKey>(
00686 DefaultTextCachedQuota,
00687 SmartResourceManager<StringColorQualityKey>::DropLessRequestedFirst ) ;
00688
00689 }
00690
00691
00692
00693
00694
00695
00696
00697 list<string> paragraphs = Ceylan::splitIntoParagraphs( text ) ;
00698
00699 words = Ceylan::splitIntoWords( paragraphs.front() ) ;
00700 paragraphs.pop_front() ;
00701
00702 currentWidth = _alineaWidth ;
00703
00704 list<string> wordsOnTheLine ;
00705
00706 Width totalWordWidth ;
00707
00708 bool lineFull ;
00709
00710
00711 for ( TextIndex currentLine = 0; currentLine < maxLines; currentLine++ )
00712 {
00713
00714
00715 storedWidth = currentWidth ;
00716
00717
00718
00719
00720
00721
00722 totalWordWidth = 0 ;
00723
00724 lineFull = false ;
00725 wordsOnTheLine.clear() ;
00726
00727 while ( ! words.empty() && ! lineFull )
00728 {
00729
00730 currentWord = words.front() ;
00731
00732
00733
00734 if ( currentWord.empty() )
00735 {
00736
00737 wordSurface = 0 ;
00738 wordWidth = 0 ;
00739
00740 }
00741 else
00742 {
00743
00744 wordSurface = & getConstLatin1WordFromCache( currentWord,
00745 quality, textColor ) ;
00746 wordWidth = wordSurface->getWidth() ;
00747
00748
00749
00750
00751
00752
00753
00754
00755 if ( wordWidth > width )
00756 LogPlug::error( "Font::renderLatin1MultiLineText: "
00757 "the rendering of word '" + currentWord
00758 + "' cannot fit in one line." ) ;
00759
00760 }
00761
00762 if ( currentWidth + wordWidth <= width )
00763 {
00764
00765
00766 renderIndex +=
00767 static_cast<Text::TextIndex>( currentWord.size() )
00768 + 1 ;
00769
00770 totalWordWidth += wordWidth ;
00771
00772 if ( justified )
00773 wordsOnTheLine.push_back( currentWord ) ;
00774 else
00775 if ( wordSurface != 0 )
00776 wordSurface->blitTo( res, currentWidth, lineHeight ) ;
00777
00778 currentWidth += wordWidth + _spaceWidth ;
00779 words.pop_front() ;
00780 }
00781 else
00782 {
00783
00784
00785 lineFull = true ;
00786 }
00787
00788 }
00789
00790
00791
00792 System::Size wordCount = wordsOnTheLine.size() ;
00793 currentWidth = storedWidth ;
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804 if ( justified && ! words.empty() && wordCount > 1 )
00805 {
00806
00807 for ( list<string>::const_iterator it = wordsOnTheLine.begin();
00808 it != wordsOnTheLine.end(); it++ )
00809 {
00810
00811 if ( (*it ).empty() )
00812 {
00813 wordWidth = 0 ;
00814 }
00815 else
00816 {
00817
00818 wordSurface = & getConstLatin1WordFromCache( (*it),
00819 quality, textColor ) ;
00820
00821 wordSurface->blitTo( res, currentWidth, lineHeight ) ;
00822
00823 wordWidth = wordSurface->getWidth() ;
00824
00825 }
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858 wordCount-- ;
00859
00860 currentWidth += wordWidth +
00861 static_cast<Width>( Maths::Round(
00862 static_cast<Ceylan::Float32>(
00863 width - currentWidth - totalWordWidth )
00864 / wordCount ) ) ;
00865
00866 totalWordWidth -= wordWidth ;
00867
00868 }
00869
00870 }
00871 else
00872 {
00873
00874
00875
00876 for ( list<string>::const_iterator it = wordsOnTheLine.begin();
00877 it != wordsOnTheLine.end(); it++ )
00878 {
00879
00880 if ( ! (*it).empty() )
00881 {
00882
00883 wordSurface = & getConstLatin1WordFromCache( (*it),
00884 quality, textColor ) ;
00885 wordSurface->blitTo( res, currentWidth, lineHeight ) ;
00886 currentWidth += wordSurface->getWidth() + _spaceWidth ;
00887
00888 }
00889
00890 }
00891
00892 }
00893
00894 lineHeight += lineSkip ;
00895
00896
00897 if ( words.empty() )
00898 {
00899
00900 if ( paragraphs.empty() )
00901 break ;
00902 words = Ceylan::splitIntoWords( paragraphs.front() ) ;
00903 paragraphs.pop_front() ;
00904
00905
00906 currentLine++ ;
00907 lineHeight += lineSkip ;
00908 currentWidth = _alineaWidth ;
00909
00910 }
00911 else
00912 {
00913 currentWidth = 0 ;
00914 }
00915
00916 }
00917
00918
00919 if ( createTemporaryWordCache )
00920 {
00921
00922
00923 #if OSDL_DEBUG_FONT
00924
00925 LogPlug::debug( "Font::renderLatin1MultiLineText: "
00926 "deleting temporary word cache: " + _textCache->toString() ) ;
00927
00928 #endif // OSDL_DEBUG_FONT
00929
00930 delete _textCache ;
00931 _textCache = 0 ;
00932
00933 }
00934
00935
00936
00937 lastOrdinateUsed = lineHeight ;
00938
00939
00940
00941
00942 #if OSDL_DEBUG_FONT
00943
00944 if ( renderIndex == text.size() )
00945 LogPlug::debug(
00946 "Font::renderLatin1MultiLineText: full text fit in box." ) ;
00947 else
00948 LogPlug::debug( "Font::renderLatin1MultiLineText: only "
00949 + Ceylan::toString( renderIndex ) + " characters out of "
00950 + Ceylan::toString( text.size() )
00951 + " characters of the full text could be rendered in the box." ) ;
00952
00953 #endif // OSDL_DEBUG_FONT
00954
00955
00956
00957
00958
00959
00960
00961 res.setColorKey( Surface::ColorkeyBlit | Surface::RLEColorkeyBlit,
00962 convertColorDefinitionToPixelColor( res.getPixelFormat(),
00963 colorKey ) ) ;
00964
00965
00966 if ( _convertToDisplay )
00967 {
00968
00969
00970
00971
00972
00973
00974 res.convertToDisplay( false ) ;
00975 }
00976
00977 return res ;
00978
00979 }
00980
00981
00982
00983 void Font::blitLatin1MultiLineText( Surface & targetSurface,
00984 const UprightRectangle & clientArea, const std::string & text,
00985 TextIndex & renderIndex, RenderQuality quality,
00986 Pixels::ColorDefinition textColor, bool justified )
00987 {
00988
00989 #if OSDL_DEBUG_FONT
00990
00991 LogPlug::debug( "Font::blitLatin1MultiLineText: rendering multiline text '"
00992 + text + "' on location " + clientArea.toString() + " of target "
00993 + targetSurface.toString( Ceylan::low ) + "." ) ;
00994
00995 #endif // OSDL_DEBUG_FONT
00996
00997 blitLatin1MultiLineText( targetSurface, clientArea.getUpperLeftAbscissa(),
00998 clientArea.getUpperLeftOrdinate(), clientArea.getWidth(),
00999 clientArea.getHeight(), text, renderIndex, quality,
01000 textColor, justified ) ;
01001
01002 }
01003
01004
01005
01006 void Font::blitLatin1MultiLineText( Surface & targetSurface,
01007 Coordinate x, Coordinate y, Length width, Length height,
01008 const std::string & text, TextIndex & renderIndex,
01009 RenderQuality quality, Pixels::ColorDefinition textColor,
01010 bool justified )
01011 {
01012
01013
01014 Coordinate lastOrdinateUsed ;
01015
01016
01017
01018
01019
01020
01021 Surface * res = & renderLatin1MultiLineText( width, height,
01022 text, renderIndex, lastOrdinateUsed, quality, textColor, justified ) ;
01023
01024 res->blitTo( targetSurface, x, y ) ;
01025
01026 delete res ;
01027
01028 }
01029
01030
01031
01032 const string Font::toString( Ceylan::VerbosityLevels level ) const
01033 {
01034
01035 string res = "Rendering style: " ;
01036
01037 if ( _renderingStyle == Normal )
01038 res += "normal" ;
01039 else
01040 {
01041 std::list<string> listRes ;
01042
01043 if ( _renderingStyle & Bold )
01044 listRes.push_back( "bold" ) ;
01045
01046 if ( _renderingStyle & Italic )
01047 listRes.push_back( "italic" ) ;
01048
01049 if ( _renderingStyle & Underline )
01050 listRes.push_back( "underline" ) ;
01051
01052 res += Ceylan::join( listRes, ", " ) ;
01053
01054 }
01055
01056 res += ". Renderings (and caches if activated) are " ;
01057
01058 if ( ! _convertToDisplay )
01059 res += "not " ;
01060
01061 res += "automatically converted to display. " ;
01062
01063 switch( _cacheSettings )
01064 {
01065
01066 case None:
01067 res += "No render cache used" ;
01068 break ;
01069
01070 case GlyphCached:
01071 res += "Glyph renderings are cached" ;
01072 break ;
01073
01074 case WordCached:
01075 res += "Word renderings are cached" ;
01076 break ;
01077
01078 case TextCached:
01079 res += "Text renderings are cached" ;
01080 break ;
01081
01082 default:
01083 res += "Unknown policy for render cache (abnormal)" ;
01084 break ;
01085
01086 }
01087
01088
01089 if ( level == Ceylan::low )
01090 return res ;
01091
01092
01093
01094 switch( _cacheSettings )
01095 {
01096
01097 case None:
01098 break ;
01099
01100 case GlyphCached:
01101 res += ". Glyph cache state is: "
01102 + _glyphCache->toString( level ) ;
01103 break ;
01104
01105 case WordCached:
01106 res += ". Word cache state is: " + _textCache->toString( level ) ;
01107 break ;
01108
01109 case TextCached:
01110 res += ". Text cache state is: " + _textCache->toString( level ) ;
01111 break ;
01112
01113 default:
01114 break ;
01115
01116 }
01117
01118 return res ;
01119
01120 }
01121
01122
01123
01124 string Font::InterpretRenderingStyle( RenderingStyle style )
01125 {
01126
01127 if ( style == Normal )
01128 return "normal" ;
01129
01130 std::list<string> res ;
01131
01132 if ( style & Bold )
01133 res.push_back( "bold" ) ;
01134
01135 if ( style & Italic )
01136 res.push_back( "italic" ) ;
01137
01138 if ( style & Underline )
01139 res.push_back( "underline" ) ;
01140
01141 return Ceylan::join( res, ", " ) ;
01142
01143 }
01144
01145
01146 OSDL::Video::Surface & Font::renderLatin1TextWithWordCached(
01147 const string & text, RenderQuality quality,
01148 Pixels::ColorDefinition textColor )
01149 {
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160 list<string> words = Ceylan::split( text, ' ' ) ;
01161
01162
01163 Length currentWidth = 0 ;
01164
01165 #if OSDL_DEBUG_FONT
01166
01167 LogPlug::debug( "Font::renderLatin1TextWithWordCached: will render '"
01168 + text + "', space width is " + Ceylan::toString( _spaceWidth ) ) ;
01169
01170 #endif // OSDL_DEBUG_FONT
01171
01172 const Surface * wordRendered ;
01173
01174
01175
01176
01177
01178
01179 for ( list<string>::const_iterator it = words.begin();
01180 it != words.end(); it++ )
01181 {
01182
01183 if ( (*it).empty() )
01184 {
01185
01186 #if OSDL_DEBUG_FONT
01187
01188 LogPlug::debug(
01189 "Font::renderLatin1TextWithWordCached: jumping a space." ) ;
01190
01191 #endif // OSDL_DEBUG_FONT
01192
01193 currentWidth += _spaceWidth ;
01194 continue ;
01195 }
01196
01197 #if OSDL_DEBUG_FONT
01198
01199 LogPlug::debug( "Font::renderLatin1TextWithWordCached: examining '"
01200 + (*it) + "'." ) ;
01201
01202 #endif // OSDL_DEBUG_FONT
01203
01204
01205
01206
01207
01208
01209 wordRendered = & getConstLatin1WordFromCache( (*it), quality,
01210 textColor ) ;
01211
01212 currentWidth += wordRendered->getWidth() + _spaceWidth ;
01213
01214 }
01215
01216
01217
01218
01219 ColorMask redMask, greenMask, blueMask ;
01220 Pixels::getRecommendedColorMasks( redMask, greenMask, blueMask ) ;
01221
01222 Surface & res = * new Surface( Surface::Hardware | Surface::ColorkeyBlit,
01223 currentWidth, getLineSkip() - getDescent(), 32,
01224 redMask, greenMask, blueMask, 0 ) ;
01225
01226
01227 Pixels::ColorDefinition colorKey ;
01228
01229 if ( Pixels::areEqual( textColor, Pixels::Black, false ) )
01230 {
01231
01232 colorKey = Pixels::White ;
01233 res.fill( colorKey ) ;
01234
01235 }
01236 else
01237 {
01238
01239 colorKey = Pixels::Black ;
01240
01241
01242
01243
01244
01245
01246 }
01247
01248 currentWidth = 0 ;
01249
01250
01251
01252
01253
01254
01255
01256
01257
01258
01259 for ( list<string>::const_iterator it = words.begin();
01260 it != words.end(); it++ )
01261 {
01262
01263 if ( (*it).empty() )
01264 {
01265 currentWidth += _spaceWidth ;
01266 continue ;
01267 }
01268
01269 #if OSDL_DEBUG_FONT
01270
01271 LogPlug::debug( "Font::renderLatin1TextWithWordCached: blitting '"
01272 + (*it) + "'." ) ;
01273
01274 #endif // OSDL_DEBUG_FONT
01275
01276 wordRendered = & getConstLatin1WordFromCache( (*it),
01277 quality, textColor ) ;
01278 wordRendered->blitTo( res, currentWidth, 0 ) ;
01279 currentWidth += wordRendered->getWidth() + _spaceWidth ;
01280
01281 }
01282
01283
01284
01285 res.setColorKey( Surface::ColorkeyBlit | Surface::RLEColorkeyBlit,
01286 convertColorDefinitionToPixelColor( res.getPixelFormat(), colorKey ) ) ;
01287
01288
01289
01290
01291
01292
01293
01294
01295 if ( _convertToDisplay )
01296 {
01297
01298
01299
01300
01301
01302
01303 res.convertToDisplay( false ) ;
01304 }
01305
01306 return res ;
01307
01308 }
01309
01310
01311
01312 OSDL::Video::Surface & Font::renderLatin1TextWithTextCached(
01313 const string & text, RenderQuality quality,
01314 Pixels::ColorDefinition textColor )
01315 {
01316
01317 #if OSDL_DEBUG_FONT
01318
01319 LogPlug::trace( "Font::renderLatin1TextWithTextCached" ) ;
01320
01321 #endif // OSDL_DEBUG_FONT
01322
01323
01324
01325
01326
01327
01328
01329 StringColorQualityKey renderKey( text, textColor, quality ) ;
01330
01331 SmartResource * res = _textCache->getClone( renderKey ) ;
01332
01333
01334 if ( res != 0 )
01335 {
01336
01337 Surface * returned = dynamic_cast<Surface *>( res ) ;
01338
01339 #if OSDL_DEBUG_FONT
01340
01341 LogPlug::debug( "Font::renderLatin1TextWithTextCached: cache hit, "
01342 "returning clone of prerendered text." ) ;
01343
01344 if ( returned == 0 )
01345 Ceylan::emergencyShutdown( "Font::renderLatin1TextWithTextCached: "
01346 "clone is not a Surface." ) ;
01347
01348 #endif // OSDL_DEBUG_FONT
01349
01350 return * returned ;
01351
01352 }
01353
01354 #if OSDL_DEBUG_FONT
01355 LogPlug::debug( "Font::renderLatin1TextWithTextCached: "
01356 "cache miss, creating new text rendering." ) ;
01357 #endif // OSDL_DEBUG_FONT
01358
01359
01360 Surface & newSurface = basicRenderLatin1Text( text, quality, textColor ) ;
01361
01362
01363 _textCache->scanForAddition( renderKey, newSurface ) ;
01364
01365 return newSurface ;
01366
01367 }
01368
01369
01370
01371 void Font::blitLatin1Word( Surface & targetSurface, Coordinate x, Coordinate y,
01372 const std::string & word, RenderQuality quality,
01373 Pixels::ColorDefinition wordColor )
01374 {
01375
01376
01377
01378
01379
01380
01381
01382
01383
01384
01385
01386
01387
01388
01389
01390
01391
01392
01393 #ifdef OSDL_WORD_LOOKUP_IN_TEXT_CACHE
01394 if ( _cacheSettings == WordCached || _cacheSettings == TextCached )
01395 #else // OSDL_WORD_LOOKUP_IN_TEXT_CACHE
01396 if ( _cacheSettings == WordCached )
01397 #endif // OSDL_WORD_LOOKUP_IN_TEXT_CACHE
01398 {
01399
01400 getConstLatin1WordFromCache( word, quality, wordColor ).blitTo(
01401 targetSurface, x, y ) ;
01402
01403 }
01404 else
01405 {
01406
01407 basicRenderLatin1Text( word, quality, wordColor ).blitTo(
01408 targetSurface, x, y ) ;
01409 }
01410
01411 }
01412
01413
01414
01415
01416
01417
01418
01419
01420
01421
01422
01423
01424
01425
01426
01427
01428
01429
01430
01431
01432
01433
01434
01435
01436
01437
01438
01439 const OSDL::Video::Surface & Font::getConstLatin1WordFromCache(
01440 const std::string & word, RenderQuality quality,
01441 Pixels::ColorDefinition wordColor )
01442 {
01443
01444
01445
01446 StringColorQualityKey renderKey( word, wordColor, quality ) ;
01447
01448 const Resource * inCache = _textCache->get( renderKey ) ;
01449
01450 if ( inCache != 0 )
01451 {
01452
01453
01454 const Surface * wordSurface = dynamic_cast<const Surface *>( inCache ) ;
01455
01456 #if OSDL_DEBUG_FONT
01457
01458 LogPlug::debug( "Font::getConstLatin1WordFromCache: "
01459 "cache hit for '" + word
01460 + "', returning 'const' prerendered word." ) ;
01461
01462 if ( wordSurface == 0 )
01463 Ceylan::emergencyShutdown( "Font::getConstLatin1WordFromCache: "
01464 "cache did not return a Surface." ) ;
01465
01466 #endif // OSDL_DEBUG_FONT
01467
01468 return * wordSurface ;
01469
01470 }
01471
01472 #if OSDL_DEBUG_FONT
01473
01474 LogPlug::debug( "Font::getConstLatin1WordFromCache: "
01475 "cache miss for '" + word
01476 + "', rendering it and submitting it to cache." ) ;
01477
01478 #endif // OSDL_DEBUG_FONT
01479
01480
01481 Surface & wordSurface = basicRenderLatin1Text( word, quality, wordColor ) ;
01482
01483 try
01484 {
01485 _textCache->takeOwnershipOf( renderKey, wordSurface ) ;
01486 }
01487 catch( const ResourceManagerException & e )
01488 {
01489
01490
01491
01492
01493
01494
01495 throw FontException( "Font::getConstLatin1WordFromCache: "
01496 "cache submitting failed (abnormal): " + e.toString() ) ;
01497
01498 }
01499
01500
01501 return wordSurface ;
01502
01503 }
01504
01505
01506
01507 OSDL::Video::Surface & Font::basicRenderLatin1Text( const std::string & text,
01508 RenderQuality quality, Pixels::ColorDefinition textColor )
01509 {
01510
01511 Length lineSkip = getLineSkip() ;
01512 Length ascent = getAscent() ;
01513
01514 System::Size textSize = text.size() ;
01515
01516
01517 #if OSDL_DEBUG_FONT
01518
01519 LogPlug::debug( "Font::basicRenderLatin1Text: rendering '" + text + "'." ) ;
01520
01521 LogPlug::debug( "Font::basicRenderLatin1Text: line skip is "
01522 + Ceylan::toString( lineSkip ) ) ;
01523
01524 LogPlug::debug( "Font::basicRenderLatin1Text: ascent is "
01525 + Ceylan::toString( ascent ) ) ;
01526
01527 LogPlug::debug( "Font::basicRenderLatin1Text: descent is "
01528 + Ceylan::toString( getDescent() ) ) ;
01529
01530 LogPlug::debug( "Font::basicRenderLatin1Text: height is "
01531 + Ceylan::toString( getHeight() ) ) ;
01532
01533 #endif // OSDL_DEBUG_FONT
01534
01535 Length * horizSteps = new Length[ textSize ] ;
01536
01537
01538
01539
01540
01541
01542
01543
01544
01545
01546
01547
01548
01549
01550
01551
01552
01553
01554 Length width = 0 ;
01555 Length maxWidth = 0 ;
01556 System::Size charCount = 0 ;
01557
01558 bool firstLetter = true ;
01559
01560 Ceylan::Latin1Char currentChar = 0 ;
01561 SignedLength currentOffset = 0 ;
01562 Length currentAdvance ;
01563
01564
01565
01566
01567
01568
01569 for ( string::const_iterator it = text.begin(); it != text.end(); it++ )
01570 {
01571
01572 currentChar = static_cast<Ceylan::Latin1Char>(*it) ;
01573 currentOffset = getWidthOffset( currentChar ) ;
01574 currentAdvance = getAdvance( currentChar ) ;
01575
01576
01577
01578
01579
01580
01581
01582 if ( firstLetter )
01583 {
01584
01585 firstLetter = false ;
01586
01587
01588 horizSteps[charCount] = 0 ;
01589
01590 }
01591 else
01592 {
01593
01594
01595
01596
01597
01598
01599 horizSteps[charCount] = width + currentOffset ;
01600
01601 }
01602
01603 charCount++ ;
01604
01605 #if OSDL_DEBUG_FONT
01606
01607 LogPlug::debug( "Font::basicRenderLatin1Text: adding "
01608 + Ceylan::toString( currentAdvance )
01609 + " width for char '" + Ceylan::toString( currentChar ) + "'" ) ;
01610
01611 #endif // OSDL_DEBUG_FONT
01612
01613
01614 width += currentAdvance ;
01615
01616
01617
01618
01619
01620
01621
01622
01623
01624
01625
01626 }
01627
01628
01629
01630
01631
01632
01633
01634
01635 maxWidth = horizSteps[ textSize - 1 ] + currentOffset
01636 + Ceylan::Maths::Max<Ceylan::Sint32>( getWidth( currentChar ),
01637 getAdvance( currentChar ) ) ;
01638
01639 #if OSDL_DEBUG_FONT
01640
01641 LogPlug::debug( "Font::basicRenderLatin1Text: text width will be "
01642 + Ceylan::toString( maxWidth )
01643 + ", height will be " + Ceylan::toString( lineSkip ) + "." ) ;
01644
01645 #endif // OSDL_DEBUG_FONT
01646
01647
01648
01649
01650
01651
01652
01653 ColorMask redMask, greenMask, blueMask ;
01654 Pixels::getRecommendedColorMasks( redMask, greenMask, blueMask ) ;
01655
01656 Surface * res ;
01657
01658 try
01659 {
01660 res = new Surface( Surface::Hardware | Surface::ColorkeyBlit,
01661 maxWidth, lineSkip - getDescent(), 32,
01662 redMask, greenMask, blueMask, 0 ) ;
01663 }
01664 catch( const VideoException & e )
01665 {
01666 delete [] horizSteps ;
01667 throw FontException(
01668 "Font::basicRenderLatin1Text: surface creation failed: "
01669 + e.toString() ) ;
01670 }
01671
01672
01673 Pixels::ColorDefinition colorKey ;
01674
01675 if ( Pixels::areEqual( textColor, Pixels::Black, false ) )
01676 {
01677 colorKey = Pixels::White ;
01678 res->fill( colorKey ) ;
01679 }
01680 else
01681 {
01682 colorKey = Pixels::Black ;
01683
01684
01685
01686
01687
01688 }
01689
01690
01691
01692 charCount = 0 ;
01693
01694 for ( string::const_iterator it = text.begin(); it != text.end(); it++ )
01695 {
01696
01697 currentChar = static_cast<Ceylan::Latin1Char>(*it) ;
01698
01699 #if OSDL_DEBUG_FONT
01700
01701 LogPlug::debug( "Font::basicRenderLatin1Text: rendering '"
01702 + Ceylan::toString( currentChar )
01703 + "' at width " + Ceylan::toString( horizSteps[charCount] )
01704 + ", at height "
01705 + Ceylan::toString( ascent - getHeightAboveBaseline( currentChar ) )
01706 ) ;
01707
01708 #endif // OSDL_DEBUG_FONT
01709
01710 blitLatin1Glyph( *res, horizSteps[charCount],
01711 ascent - getHeightAboveBaseline( currentChar ),
01712 currentChar, quality, textColor ) ;
01713
01714 #if OSDL_DEBUG_FONT
01715
01716 LogPlug::debug( "Font::basicRenderLatin1Text: rendered '"
01717 + Ceylan::toString( currentChar )
01718 + "' at width " + Ceylan::toString( horizSteps[charCount] )
01719 + ", at height "
01720 + Ceylan::toString( ascent - getHeightAboveBaseline( currentChar ) )
01721 ) ;
01722
01723 #endif // OSDL_DEBUG_FONT
01724
01725 charCount++ ;
01726
01727 }
01728
01729
01730 res->setColorKey( Surface::ColorkeyBlit | Surface::RLEColorkeyBlit,
01731 convertColorDefinitionToPixelColor( res->getPixelFormat(), colorKey )
01732 ) ;
01733
01734 if ( _convertToDisplay )
01735 {
01736
01737
01738
01739
01740
01741
01742 res->convertToDisplay( false ) ;
01743 }
01744
01745
01746
01747
01748
01749
01750
01751
01752 delete [] horizSteps ;
01753
01754 return *res ;
01755
01756 }