00001 #include "OSDLTrueTypeFont.h"
00002
00003 #include "OSDLSurface.h"
00004 #include "OSDLPixel.h"
00005
00006 #include "Ceylan.h"
00007
00008 #include "SDL_gfxPrimitives.h"
00009 #include "SDL.h"
00010
00011 #include <list>
00012
00013
00014
00015
00016 using namespace OSDL::Video::TwoDimensional ;
00017 using namespace OSDL::Video::TwoDimensional::Text ;
00018
00019 using namespace Ceylan ;
00020 using namespace Ceylan::Log ;
00021
00022 using std::string ;
00023
00024
00025 #ifdef OSDL_USES_CONFIG_H
00026 #include <OSDLConfig.h>
00027 #endif // OSDL_USES_CONFIG_H
00028
00029
00030 Ceylan::System::FileLocator Text::TrueTypeFont::TrueTypeFontFileLocator ;
00031
00032 string Text::TrueTypeFont::TrueTypeFontFileExtension = ".ttf" ;
00033
00034
00035 const Ceylan::Float32 Text::TrueTypeFont::SpaceWidthFactor = 1 ;
00036
00037
00038
00039 Ceylan::Uint32 TrueTypeFont::FontCounter = 0 ;
00040
00041
00042
00043 TrueTypeFont::TrueTypeFont(
00044 const std::string & fontFilename,
00045 PointSize pointSize,
00046 FontIndex index,
00047 bool convertToDisplay,
00048 RenderCache cacheSettings )
00049 throw( TextException ) :
00050 Font( convertToDisplay, cacheSettings ),
00051 _pointSize( pointSize ),
00052 _actualFont( 0 )
00053 {
00054
00055 string fontFullPath = fontFilename ;
00056
00057
00058 if ( ! System::File::ExistsAsFileOrSymbolicLink( fontFilename ) )
00059 {
00060
00061
00062 try
00063 {
00064
00065 fontFullPath = TrueTypeFont::TrueTypeFontFileLocator.find(
00066 fontFilename ) ;
00067
00068 }
00069 catch( const System::FileLocatorException & e )
00070 {
00071
00072
00073 try
00074 {
00075 fontFullPath = Font::FontFileLocator.find( fontFilename ) ;
00076 }
00077 catch( const System::FileLocatorException & ex )
00078 {
00079
00080
00081
00082 string currentDir ;
00083
00084 try
00085 {
00086 currentDir =
00087 System::Directory::GetCurrentWorkingDirectoryName() ;
00088 }
00089 catch( const System::Directory::DirectoryException & exc )
00090 {
00091 throw TextException(
00092 "TrueTypeFont constructor : unable to load '"
00093 + fontFilename
00094 + "', exception generation triggered another failure : "
00095 + exc.toString() + "." ) ;
00096 }
00097
00098 throw TextException( "TrueTypeFont constructor : '"
00099 + fontFilename
00100 + "' is not a regular file or a symbolic link "
00101 "relative to the current directory (" + currentDir
00102 + ") and cannot be found through TrueType font locator ("
00103 + TrueTypeFont::TrueTypeFontFileLocator.toString()
00104 + ") nor through general font locator based on "
00105 "font path environment variable ("
00106 + Font::FontPathEnvironmentVariable + ") : "
00107 + Font::FontFileLocator.toString() + "." ) ;
00108
00109 }
00110 }
00111 }
00112
00113
00114 if ( TTF_WasInit() == 0 )
00115 {
00116
00117 if ( TTF_Init()== -1 )
00118 throw TextException(
00119 "TrueTypeFont constructor : unable to init font library : "
00120 + DescribeLastError() ) ;
00121
00122 }
00123
00124 _actualFont = TTF_OpenFont( fontFullPath.c_str(), pointSize ) ;
00125
00126 if ( _actualFont == 0 )
00127 throw TextException( "TrueTypeFont constructor : unable to open '"
00128 + fontFullPath
00129 + "' with a point size of "
00130 + Ceylan::toString( pointSize ) + " dots per inch : "
00131 + DescribeLastError() ) ;
00132
00133 _spaceWidth = static_cast<Width>( SpaceWidthFactor * getWidth( ' ' ) ) ;
00134
00135
00136 _alineaWidth = DefaultSpaceBasedAlineaWidth * _spaceWidth ;
00137
00138 FontCounter++ ;
00139
00140 }
00141
00142
00143 TrueTypeFont::~TrueTypeFont() throw()
00144 {
00145
00146 if ( _actualFont != 0 )
00147 TTF_CloseFont( _actualFont ) ;
00148
00149 FontCounter-- ;
00150
00151 if ( FontCounter == 0 && TTF_WasInit() != 0 )
00152 TTF_Quit() ;
00153
00154 }
00155
00156
00157
00158 PointSize TrueTypeFont::getPointSize() const throw()
00159 {
00160
00161 return _pointSize ;
00162
00163 }
00164
00165
00166 RenderingStyle TrueTypeFont::getRenderingStyle() const throw()
00167 {
00168
00169 return TTF_GetFontStyle( _actualFont ) ;
00170
00171 }
00172
00173
00174 void TrueTypeFont::setRenderingStyle( RenderingStyle newStyle )
00175 throw( TextException )
00176 {
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187 if ( newStyle != getRenderingStyle() )
00188 TTF_SetFontStyle( _actualFont, newStyle ) ;
00189
00190 }
00191
00192
00193 Width TrueTypeFont::getWidth( Ceylan::Latin1Char character )
00194 const throw( TextException )
00195 {
00196
00197
00198
00199
00200
00201
00202
00203 if ( character == ' ' )
00204 return getAdvance( ' ' ) ;
00205
00206 int minX, maxX ;
00207
00208 if ( TTF_GlyphMetrics( _actualFont,
00209 Ceylan::UnicodeString::ConvertFromLatin1( character),
00210 & minX, & maxX, 0, 0, 0 ) != 0 )
00211 throw TextException( "TrueTypeFont::getWidth : "
00212 + DescribeLastError() ) ;
00213
00214 return static_cast<Width>( maxX - minX ) ;
00215
00216 }
00217
00218
00219 SignedWidth TrueTypeFont::getWidthOffset( Ceylan::Latin1Char character )
00220 const throw( TextException )
00221 {
00222
00223 int minX ;
00224
00225 if ( TTF_GlyphMetrics( _actualFont,
00226 Ceylan::UnicodeString::ConvertFromLatin1( character),
00227 & minX, 0, 0, 0, 0 ) != 0 )
00228 throw TextException( "TrueTypeFont::getWidthOffset : "
00229 + DescribeLastError() ) ;
00230
00231 return static_cast<SignedWidth>( minX ) ;
00232
00233 }
00234
00235
00236 SignedHeight TrueTypeFont::getHeightAboveBaseline(
00237 Ceylan::Latin1Char character ) const throw( TextException )
00238 {
00239
00240 int maxY ;
00241
00242 if ( TTF_GlyphMetrics( _actualFont,
00243 Ceylan::UnicodeString::ConvertFromLatin1( character),
00244 0, 0, 0, & maxY, 0 ) != 0 )
00245 throw TextException( "TrueTypeFont::getHeightAboveBaseline : "
00246 + DescribeLastError() ) ;
00247
00248 return static_cast<SignedHeight>( maxY ) ;
00249
00250 }
00251
00252
00253 OSDL::Video::SignedLength TrueTypeFont::getAdvance(
00254 Ceylan::Latin1Char character ) const throw( TextException )
00255 {
00256
00257 int advance ;
00258
00259 if ( TTF_GlyphMetrics( _actualFont,
00260 Ceylan::UnicodeString::ConvertFromLatin1( character),
00261 0, 0, 0, 0, & advance ) != 0 )
00262 throw TextException( "TrueTypeFont::getAdvance : "
00263 + DescribeLastError() ) ;
00264
00265 return static_cast<SignedLength>( advance ) ;
00266
00267 }
00268
00269
00270 Text::Height TrueTypeFont::getHeight() const throw()
00271 {
00272
00273 return TTF_FontHeight( _actualFont ) ;
00274
00275 }
00276
00277
00278 Text::SignedHeight TrueTypeFont::getAscent() const throw()
00279 {
00280
00281 return TTF_FontAscent( _actualFont ) ;
00282
00283 }
00284
00285
00286 Text::SignedHeight TrueTypeFont::getDescent() const throw()
00287 {
00288
00289 return TTF_FontDescent( _actualFont ) ;
00290
00291 }
00292
00293
00294 Text::Height TrueTypeFont::getLineSkip() const throw()
00295 {
00296
00297 return TTF_FontLineSkip( _actualFont ) ;
00298
00299 }
00300
00301
00302 Ceylan::Uint16 TrueTypeFont::getFacesCount() const throw()
00303 {
00304
00305 return TTF_FontFaces( _actualFont ) ;
00306
00307 }
00308
00309
00310 bool TrueTypeFont::isFixedWidth() const throw()
00311 {
00312
00313 return ( TTF_FontFaceIsFixedWidth( _actualFont ) > 0 ) ;
00314
00315 }
00316
00317
00318 string TrueTypeFont::getFaceFamilyName() const throw()
00319 {
00320
00321 return TTF_FontFaceFamilyName( _actualFont ) ;
00322
00323 }
00324
00325
00326 string TrueTypeFont::getFaceStyleName() const throw()
00327 {
00328
00329 return TTF_FontFaceStyleName( _actualFont ) ;
00330
00331 }
00332
00333
00334
00335
00336
00337
00338 UprightRectangle & TrueTypeFont::getBoundingBoxFor(
00339 Ceylan::Unicode glyph, SignedLength & advance )
00340 const throw( TextException )
00341 {
00342
00343 int minX, maxX, minY, maxY, intAdvance ;
00344
00345 if ( TTF_GlyphMetrics( _actualFont, glyph, & minX, & maxX,
00346 & minY, & maxY, & intAdvance ) != 0 )
00347 throw TextException( "TrueTypeFont::getClippingBoxFor (glyph) : "
00348 + DescribeLastError() ) ;
00349
00350 advance = static_cast<SignedLength>( intAdvance ) ;
00351
00352 return * new UprightRectangle(
00353 static_cast<Coordinate>( minX ),
00354 static_cast<Coordinate>( maxY ),
00355 static_cast<Length>( maxX - minX ),
00356 static_cast<Length>( maxY - minY ) ) ;
00357
00358 }
00359
00360
00361 UprightRectangle & TrueTypeFont::getBoundingBoxFor( const std::string & text )
00362 const throw( TextException )
00363 {
00364
00365 int width, height ;
00366
00367 if ( TTF_SizeText( _actualFont, text.c_str(), & width, & height ) != 0 )
00368 throw TextException(
00369 "TrueTypeFont::getBoundingBoxFor (Latin-1 string) : "
00370 + DescribeLastError() ) ;
00371
00372 return * new UprightRectangle( 0, 0, static_cast<Length>( width ),
00373 static_cast<Length>( height ) ) ;
00374
00375 }
00376
00377
00378 UprightRectangle & TrueTypeFont::getBoundingBoxForUTF8(
00379 const std::string & text ) const throw( TextException )
00380 {
00381
00382 int width, height ;
00383
00384 if ( TTF_SizeUTF8( _actualFont, text.c_str(), & width, & height ) != 0 )
00385 throw TextException(
00386 "TrueTypeFont::getBoundingBoxFor (UTF-8 string) : "
00387 + DescribeLastError() ) ;
00388
00389 return * new UprightRectangle( 0, 0, static_cast<Length>( width ),
00390 static_cast<Length>( height ) ) ;
00391
00392 }
00393
00394
00395 UprightRectangle & TrueTypeFont::getBoundingBoxForUnicode(
00396 const Ceylan::Unicode * text ) const throw( TextException )
00397 {
00398
00399 if ( text == 0 )
00400 throw TextException( "TrueTypeFont::getBoundingBoxForUnicode : "
00401 "null pointer for Unicode string." ) ;
00402
00403 int width, height ;
00404
00405 if ( TTF_SizeUNICODE( _actualFont, text, & width, & height ) != 0 )
00406 throw TextException(
00407 "TrueTypeFont::getBoundingBoxFor (Unicode string) : "
00408 + DescribeLastError() ) ;
00409
00410 return * new UprightRectangle( 0, 0, static_cast<Length>( width ),
00411 static_cast<Length>( height ) ) ;
00412
00413 }
00414
00415
00416
00417
00418
00419
00420 OSDL::Video::Surface & TrueTypeFont::renderLatin1Glyph(
00421 Ceylan::Latin1Char character,
00422 RenderQuality quality,
00423 Pixels::ColorDefinition glyphColor )
00424 throw( TextException )
00425 {
00426
00427 return renderUnicodeGlyph(
00428 Ceylan::UnicodeString::ConvertFromLatin1( character ),
00429 quality, glyphColor ) ;
00430
00431 }
00432
00433
00434 void TrueTypeFont::blitLatin1Glyph(
00435 Surface & targetSurface, Coordinate x, Coordinate y,
00436 Ceylan::Latin1Char character, RenderQuality quality,
00437 Pixels::ColorDefinition glyphColor ) throw( TextException )
00438 {
00439
00440
00441
00442 Surface & res = renderUnicodeGlyph(
00443 Ceylan::UnicodeString::ConvertFromLatin1( character ),
00444 quality, glyphColor ) ;
00445
00446 res.blitTo( targetSurface, x, y ) ;
00447
00448 delete & res ;
00449
00450 }
00451
00452
00453 OSDL::Video::Surface & TrueTypeFont::renderUnicodeGlyph(
00454 Ceylan::Unicode character,
00455 RenderQuality quality,
00456 Pixels::ColorDefinition glyphColor ) throw( TextException )
00457 {
00458
00459
00460
00461 if ( _cacheSettings == GlyphCached )
00462 {
00463
00464
00465
00466
00467
00468
00469
00470 CharColorQualityKey renderKey( character, glyphColor, quality ) ;
00471
00472 SmartResource * res = _glyphCache->getClone( renderKey ) ;
00473
00474 if ( res != 0 )
00475 {
00476
00477 Surface * returned = dynamic_cast<Surface *>( res ) ;
00478
00479 #if OSDL_DEBUG_FONT
00480
00481 LogPlug::debug( "TrueTypeFont::renderUnicodeGlyph : cache hit, "
00482 "returning clone of prerendered glyph." ) ;
00483
00484 if ( returned == 0 )
00485 Ceylan::emergencyShutdown( "TrueTypeFont::renderUnicodeGlyph : "
00486 "clone is not a Surface." ) ;
00487
00488 #endif // OSDL_DEBUG_FONT
00489
00490 return * returned ;
00491
00492 }
00493
00494 #if OSDL_DEBUG_FONT
00495
00496 LogPlug::debug( "TrueTypeFont::renderUnicodeGlyph : "
00497 "cache miss, creating new glyph rendering." ) ;
00498
00499 #endif // OSDL_DEBUG_FONT
00500
00501
00502 Surface & newSurface = basicRenderUnicodeGlyph( character, quality,
00503 glyphColor ) ;
00504
00505
00506 _glyphCache->scanForAddition( renderKey, newSurface ) ;
00507
00508
00509 return newSurface ;
00510
00511 }
00512
00513
00514
00515
00516
00517
00518 return basicRenderUnicodeGlyph( character, quality, glyphColor ) ;
00519
00520 }
00521
00522
00523
00524
00525 OSDL::Video::Surface & TrueTypeFont::renderLatin1Text(
00526 const std::string & text,
00527 RenderQuality quality, Pixels::ColorDefinition textColor )
00528 throw( TextException )
00529 {
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549 return Font::renderLatin1Text( text, quality, textColor ) ;
00550
00551
00552
00553
00554
00555
00556
00557
00558 SDL_Surface * textSurface ;
00559 Surface * res ;
00560
00561 switch( quality )
00562 {
00563
00564 case Solid:
00565 textSurface = TTF_RenderText_Solid( _actualFont,
00566 text.c_str(), textColor ) ;
00567 if ( textSurface == 0 )
00568 throw TextException(
00569 "TrueTypeFont::renderLatin1Text (solid) : "
00570 "unable to render text '" + text
00571 + "' : " + DescribeLastError() ) ;
00572 res = new Surface( * textSurface,
00573 Surface::BackBuffer ) ;
00574
00575 break ;
00576
00577
00578 case Shaded:
00579 textSurface = TTF_RenderText_Shaded( _actualFont,
00580 text.c_str(), textColor, _backgroundColor ) ;
00581 if ( textSurface == 0 )
00582 throw TextException(
00583 "TrueTypeFont::renderLatin1Text (shaded) : "
00584 "unable to render text '" + text
00585 + "' : " + DescribeLastError() ) ;
00586
00587
00588
00589
00590
00591
00592
00593 ColorMask redMask, greenMask, blueMask ;
00594 Pixels::getRecommendedColorMasks( redMask, greenMask, blueMask ) ;
00595
00596 res = new Surface( Surface::Hardware | Surface::ColorkeyBlit,
00597 textSurface->w, textSurface->h, 32,
00598 redMask, greenMask, blueMask, 0 ) ;
00599
00600
00601 Pixels::ColorDefinition colorKey ;
00602
00603 if ( Pixels::areEqual( textColor, Pixels::Black,
00604 false ) )
00605 {
00606 colorKey = Pixels::White ;
00607 res->fill( colorKey ) ;
00608 }
00609 else
00610 {
00611 colorKey = Pixels::Black ;
00612
00613
00614
00615
00616
00617 }
00618
00619 try
00620 {
00621 res->setColorKey(
00622 Surface::ColorkeyBlit | Surface::RLEColorkeyBlit,
00623 Pixels::convertColorDefinitionToPixelColor(
00624 res->getPixelFormat(), colorKey ) ) ;
00625 }
00626 catch( const Video::VideoException & e )
00627 {
00628 throw TextException(
00629 "TrueTypeFont::renderLatin1Text (shaded) : "
00630 "color keying failed : " + e.toString() ) ;
00631 }
00632 SDL_BlitSurface( textSurface, 0, & res->getSDLSurface(), 0 ) ;
00633 break ;
00634
00635
00636 case Blended:
00637 textSurface = TTF_RenderText_Blended( _actualFont,
00638 text.c_str(), textColor ) ;
00639 if ( textSurface == 0 )
00640 throw TextException(
00641 "TrueTypeFont::renderLatin1Text (blended) : "
00642 "unable to render text '" + text
00643 + "' : " + DescribeLastError() ) ;
00644
00645 res = new Surface( * textSurface,
00646 Surface::BackBuffer ) ;
00647
00648
00649 #ifdef OSDL_ADDS_COLOR_KEY
00650
00651
00652
00653
00654
00655
00656
00657
00658 Pixels::ColorDefinition colorKey ;
00659
00660 if ( Pixels::areEqual( textColor, Pixels::Black,
00661 false ) )
00662 {
00663 colorKey = Pixels::White ;
00664 res->fill( colorKey ) ;
00665 }
00666 else
00667 {
00668 colorKey = Pixels::Black ;
00669
00670
00671
00672
00673
00674
00675 }
00676
00677 try
00678 {
00679 res->setColorKey(
00680 Surface::ColorkeyBlit | Surface::RLEColorkeyBlit,
00681 Pixels::convertColorDefinitionToPixelColor(
00682 res->getPixelFormat(), colorKey ) ) ;
00683 }
00684 catch( const Video::VideoException & e )
00685 {
00686 throw TextException(
00687 "TrueTypeFont::renderLatin1Text (blended) : "
00688 "color keying failed : " + e.toString() ) ;
00689 }
00690
00691 #endif // OSDL_ADDS_COLOR_KEY
00692
00693 break ;
00694
00695
00696 default:
00697 throw TextException( "TrueTypeFont::renderLatin1Text : "
00698 "unknown quality requested : "
00699 + Ceylan::toString( quality ) + "." ) ;
00700 break ;
00701
00702 }
00703
00704
00705 if ( _convertToDisplay )
00706 {
00707
00708
00709
00710
00711
00712
00713
00714
00715 if ( quality == Blended )
00716 res->convertToDisplay( true ) ;
00717 else
00718 res->convertToDisplay( false ) ;
00719
00720 }
00721
00722 return * res ;
00723
00724 }
00725
00726
00727
00728
00729 OSDL::Video::Surface & TrueTypeFont::renderUTF8Text(
00730 const std::string & text,
00731 RenderQuality quality,
00732 Pixels::ColorDefinition textColor )
00733 throw( TextException )
00734 {
00735
00736 SDL_Surface * textSurface ;
00737 Surface * res ;
00738
00739 switch( quality )
00740 {
00741
00742
00743 case Solid:
00744 textSurface = TTF_RenderUTF8_Solid( _actualFont, text.c_str(),
00745 textColor ) ;
00746
00747 if ( textSurface == 0 )
00748 throw TextException( "TrueTypeFont::renderUTF8Text (solid) : "
00749 "unable to render text '" + text
00750 + "' : " + DescribeLastError() ) ;
00751
00752 res = new Surface( * textSurface,
00753 Surface::BackBuffer ) ;
00754 break ;
00755
00756
00757 case Shaded:
00758 textSurface = TTF_RenderUTF8_Shaded( _actualFont, text.c_str(),
00759 textColor, _backgroundColor ) ;
00760
00761 if ( textSurface == 0 )
00762 throw TextException( "TrueTypeFont::renderUTF8Text (shaded) : "
00763 "unable to render text '" + text
00764 + "' : " + DescribeLastError() ) ;
00765
00766
00767
00768
00769
00770
00771
00772 ColorMask redMask, greenMask, blueMask ;
00773 Pixels::getRecommendedColorMasks( redMask, greenMask, blueMask ) ;
00774
00775 res = new Surface( Surface::Hardware | Surface::ColorkeyBlit,
00776 textSurface->w, textSurface->h, 32,
00777 redMask, greenMask, blueMask, 0 ) ;
00778
00779
00780 Pixels::ColorDefinition colorKey ;
00781
00782 if ( Pixels::areEqual( textColor, Pixels::Black,
00783 false ) )
00784 {
00785
00786 colorKey = Pixels::White ;
00787 res->fill( colorKey ) ;
00788
00789 }
00790 else
00791 {
00792
00793 colorKey = Pixels::Black ;
00794
00795
00796
00797
00798
00799
00800 }
00801
00802 try
00803 {
00804
00805 res->setColorKey(
00806 Surface::ColorkeyBlit | Surface::RLEColorkeyBlit,
00807 Pixels::convertColorDefinitionToPixelColor(
00808 res->getPixelFormat(), colorKey ) ) ;
00809
00810 }
00811 catch( const Video::VideoException & e )
00812 {
00813 throw TextException( "TrueTypeFont::renderUTF8Text (shaded) : "
00814 "color keying failed : " + e.toString() ) ;
00815 }
00816
00817 SDL_BlitSurface( textSurface, 0, & res->getSDLSurface(), 0 ) ;
00818 break ;
00819
00820
00821 case Blended:
00822 textSurface = TTF_RenderUTF8_Blended( _actualFont, text.c_str(),
00823 textColor ) ;
00824
00825 if ( textSurface == 0 )
00826 throw TextException(
00827 "TrueTypeFont::renderUTF8Text (blended) : "
00828 "unable to render text '" + text
00829 + "' : " + DescribeLastError() ) ;
00830
00831 res = new Surface( * textSurface,
00832 Surface::BackBuffer ) ;
00833
00834
00835
00836 #ifdef OSDL_ADDS_COLOR_KEY
00837
00838
00839
00840
00841
00842
00843
00844
00845 Pixels::ColorDefinition colorKey ;
00846
00847 if ( Pixels::areEqual( textColor, Pixels::Black,
00848 false ) )
00849 {
00850
00851 colorKey = Pixels::White ;
00852 res->fill( colorKey ) ;
00853
00854 }
00855 else
00856 {
00857
00858 colorKey = Pixels::Black ;
00859
00860
00861
00862
00863
00864 }
00865
00866 try
00867 {
00868 res->setColorKey(
00869 Surface::ColorkeyBlit | Surface::RLEColorkeyBlit,
00870 Pixels::convertColorDefinitionToPixelColor(
00871 res->getPixelFormat(), colorKey ) ) ;
00872 }
00873 catch( const Video::VideoException & e )
00874 {
00875
00876 throw TextException( "TrueTypeFont::renderUTF8Text (blended) : "
00877 "color keying failed : " + e.toString() ) ;
00878
00879 }
00880
00881 #endif // OSDL_ADDS_COLOR_KEY
00882
00883 break ;
00884
00885
00886 default:
00887 throw TextException( "TrueTypeFont::renderUTF8Text : "
00888 "unknown quality requested : "
00889 + Ceylan::toString( quality ) + "." ) ;
00890 break ;
00891
00892 }
00893
00894
00895 if ( _convertToDisplay )
00896 {
00897
00898
00899
00900
00901
00902
00903
00904
00905 if ( quality == Blended )
00906 res->convertToDisplay( true ) ;
00907 else
00908 res->convertToDisplay( false ) ;
00909
00910 }
00911
00912 return * res ;
00913
00914 }
00915
00916
00917
00918 OSDL::Video::Surface & TrueTypeFont::renderUnicodeText(
00919 const Ceylan::Unicode * text,
00920 RenderQuality quality,
00921 Pixels::ColorDefinition textColor )
00922 throw( TextException )
00923 {
00924
00925 if ( text == 0 )
00926 throw TextException(
00927 "TrueTypeFont::renderUnicode : null pointer for Unicode string." ) ;
00928
00929 SDL_Surface * textSurface ;
00930 Surface * res ;
00931
00932 switch( quality )
00933 {
00934
00935 case Solid:
00936 textSurface = TTF_RenderUNICODE_Solid( _actualFont, text,
00937 textColor ) ;
00938
00939 if ( textSurface == 0 )
00940 throw TextException(
00941 "TrueTypeFont::renderUnicodeText (solid) : "
00942 "unable to render text : " + DescribeLastError() ) ;
00943 res = new Surface( * textSurface,
00944 Surface::BackBuffer ) ;
00945 break ;
00946
00947
00948 case Shaded:
00949 textSurface = TTF_RenderUNICODE_Shaded( _actualFont, text,
00950 textColor, _backgroundColor ) ;
00951
00952 if ( textSurface == 0 )
00953 throw TextException(
00954 "TrueTypeFont::renderUnicodeText (shaded) : "
00955 "unable to render text : " + DescribeLastError() ) ;
00956
00957
00958
00959
00960
00961
00962
00963 ColorMask redMask, greenMask, blueMask ;
00964 Pixels::getRecommendedColorMasks( redMask, greenMask, blueMask ) ;
00965
00966 res = new Surface( Surface::Hardware | Surface::ColorkeyBlit,
00967 textSurface->w, textSurface->h, 32,
00968 redMask, greenMask, blueMask, 0 ) ;
00969
00970
00971 Pixels::ColorDefinition colorKey ;
00972
00973 if ( Pixels::areEqual( textColor, Pixels::Black,
00974 false ) )
00975 {
00976
00977 colorKey = Pixels::White ;
00978 res->fill( colorKey ) ;
00979
00980 }
00981 else
00982 {
00983
00984 colorKey = Pixels::Black ;
00985
00986
00987
00988
00989
00990
00991 }
00992
00993 try
00994 {
00995 res->setColorKey(
00996 Surface::ColorkeyBlit | Surface::RLEColorkeyBlit,
00997 Pixels::convertColorDefinitionToPixelColor(
00998 res->getPixelFormat(), colorKey ) ) ;
00999 }
01000 catch( const Video::VideoException & e )
01001 {
01002 throw TextException(
01003 "TrueTypeFont::renderUnicodeText (shaded) : "
01004 "color keying failed : " + e.toString() ) ;
01005 }
01006 SDL_BlitSurface( textSurface, 0, & res->getSDLSurface(), 0 ) ;
01007 break ;
01008
01009
01010 case Blended:
01011 textSurface = TTF_RenderUNICODE_Blended( _actualFont, text,
01012 textColor ) ;
01013
01014 if ( textSurface == 0 )
01015 throw TextException(
01016 "TrueTypeFont::renderUnicodeText (blended) : "
01017 "unable to render text : " + DescribeLastError() ) ;
01018
01019 res = new Surface( * textSurface,
01020 Surface::BackBuffer ) ;
01021
01022
01023
01024 #ifdef OSDL_ADDS_COLOR_KEY
01025
01026
01027
01028
01029
01030
01031
01032
01033 Pixels::ColorDefinition colorKey ;
01034
01035 if ( Pixels::areEqual( textColor, Pixels::Black,
01036 false ) )
01037 {
01038
01039 colorKey = Pixels::White ;
01040 res->fill( colorKey ) ;
01041
01042 }
01043 else
01044 {
01045
01046 colorKey = Pixels::Black ;
01047
01048
01049
01050
01051
01052
01053 }
01054
01055
01056
01057
01058
01059
01060
01061 try
01062 {
01063
01064 res->setColorKey(
01065 Surface::ColorkeyBlit | Surface::RLEColorkeyBlit,
01066 Pixels::convertColorDefinitionToPixelColor(
01067 res->getPixelFormat(), colorKey ) ) ;
01068
01069 }
01070 catch( const Video::VideoException & e )
01071 {
01072 throw TextException(
01073 "TrueTypeFont::renderUnicodeText (blended) : "
01074 "color keying failed : " + e.toString() ) ;
01075 }
01076
01077 #endif // OSDL_ADDS_COLOR_KEY
01078
01079 break ;
01080
01081
01082 default:
01083 throw TextException( "TrueTypeFont::renderUnicodeText : "
01084 "unknown quality requested : "
01085 + Ceylan::toString( quality ) + "." ) ;
01086 break ;
01087
01088 }
01089
01090
01091 if ( _convertToDisplay )
01092 {
01093
01094
01095
01096
01097
01098
01099
01100
01101 if ( quality == Blended )
01102 res->convertToDisplay( true ) ;
01103 else
01104 res->convertToDisplay( false ) ;
01105
01106 }
01107
01108 return * res ;
01109
01110 }
01111
01112
01113
01114 const string TrueTypeFont::toString( Ceylan::VerbosityLevels level )
01115 const throw()
01116 {
01117
01118 string res = "Truetype font, whose point size is "
01119 + Ceylan::toString( _pointSize ) + " dots per inch" ;
01120
01121 if ( level == Ceylan::low )
01122 return res ;
01123
01124 Ceylan::Uint16 faceCount = getFacesCount() ;
01125
01126 res += ". This font has " ;
01127
01128 switch( faceCount )
01129 {
01130
01131 case 0:
01132 res += "no available face (abnormal)" ;
01133 break ;
01134
01135 case 1:
01136 res += "exactly one face" ;
01137 break ;
01138
01139 default:
01140 res += Ceylan::toString( faceCount ) + " faces" ;
01141 break ;
01142
01143 }
01144
01145 if ( isFixedWidth() )
01146 res +=", and is fixed width" ;
01147 else
01148 res +=", and is not fixed width" ;
01149
01150 res +=". The family name of the current face is '" + getFaceFamilyName()
01151 + "', and its style name is '" + getFaceStyleName() + "'" ;
01152
01153 if ( level == Ceylan::medium )
01154 return res ;
01155
01156 SDL_version compileVersion ;
01157
01158 TTF_VERSION( & compileVersion ) ;
01159
01160 const SDL_version * linkedVersion = TTF_Linked_Version() ;
01161
01162 res += ". The OSDL font module is compiled with SDL_ttf version "
01163 + Ceylan::toNumericalString( compileVersion.major ) + "."
01164 + Ceylan::toNumericalString( compileVersion.minor ) + "."
01165 + Ceylan::toNumericalString( compileVersion.patch )
01166 + ", linked with version "
01167 + Ceylan::toNumericalString( linkedVersion->major ) + "."
01168 + Ceylan::toNumericalString( linkedVersion->minor ) + "."
01169 + Ceylan::toNumericalString( linkedVersion->patch ) ;
01170 + ". Rendering style is "
01171 + InterpretRenderingStyle( TTF_GetFontStyle( _actualFont ) ) ;
01172
01173
01174 return res ;
01175
01176
01177 }
01178
01179
01180
01181
01182
01183
01184 Font::RenderQuality TrueTypeFont::GetObtainedQualityFor(
01185 Font::RenderQuality targetedQuality ) throw()
01186 {
01187
01188 return targetedQuality ;
01189
01190 }
01191
01192
01193 void TrueTypeFont::SetUnicodeSwapStatus( bool newStatus ) throw()
01194 {
01195
01196 if ( newStatus )
01197 TTF_ByteSwappedUNICODE( 1 ) ;
01198 else
01199 TTF_ByteSwappedUNICODE( 0 ) ;
01200
01201 }
01202
01203
01204 string TrueTypeFont::DescribeLastError() throw()
01205 {
01206
01207 return TTF_GetError() ;
01208
01209 }
01210
01211
01212 OSDL::Video::Surface & TrueTypeFont::basicRenderUnicodeGlyph(
01213 Ceylan::Unicode character, RenderQuality quality,
01214 Pixels::ColorDefinition glyphColor ) throw( TextException )
01215 {
01216
01217
01218
01219 SDL_Surface * textSurface ;
01220 Surface * res ;
01221
01222 switch( quality )
01223 {
01224
01225
01226 case Solid:
01227 textSurface = TTF_RenderGlyph_Solid( _actualFont, character,
01228 glyphColor ) ;
01229
01230 if ( textSurface == 0 )
01231 throw TextException(
01232 "TrueTypeFont::basicRenderUnicodeGlyph (solid) : "
01233 "unable to render character '"
01234 + Ceylan::toString( character )
01235 + "' : " + DescribeLastError() ) ;
01236
01237 res = new Surface( * textSurface,
01238 Surface::BackBuffer ) ;
01239
01240
01241 break ;
01242
01243
01244 case Shaded:
01245 textSurface = TTF_RenderGlyph_Shaded( _actualFont, character,
01246 glyphColor, _backgroundColor ) ;
01247
01248 if ( textSurface == 0 )
01249 throw TextException(
01250 "TrueTypeFont::basicRenderUnicodeGlyph (shaded) : "
01251 "unable to render character '"
01252 + Ceylan::toString( character )
01253 + "' : " + DescribeLastError() ) ;
01254
01255
01256
01257
01258
01259
01260
01261
01262 ColorMask redMask, greenMask, blueMask ;
01263 Pixels::getRecommendedColorMasks( redMask, greenMask, blueMask ) ;
01264
01265 res = new Surface( Surface::Hardware | Surface::ColorkeyBlit,
01266 textSurface->w, textSurface->h, 32,
01267 redMask, greenMask, blueMask, 0 ) ;
01268
01269
01270 Pixels::ColorDefinition colorKey ;
01271
01272 if ( Pixels::areEqual( glyphColor, Pixels::Black,
01273 false ) )
01274 {
01275
01276 colorKey = Pixels::White ;
01277 res->fill( colorKey ) ;
01278
01279 }
01280 else
01281 {
01282
01283 colorKey = Pixels::Black ;
01284
01285
01286
01287
01288
01289
01290
01291 }
01292
01293 try
01294 {
01295 res->setColorKey(
01296 Surface::ColorkeyBlit | Surface::RLEColorkeyBlit,
01297 Pixels::convertColorDefinitionToPixelColor(
01298 res->getPixelFormat(), colorKey ) ) ;
01299 }
01300 catch( const Video::VideoException & e )
01301 {
01302
01303 throw TextException(
01304 "TrueTypeFont::basicRenderUnicodeGlyph (shaded) : "
01305 "color keying failed : " + e.toString() ) ;
01306
01307 }
01308 SDL_BlitSurface( textSurface, 0, & res->getSDLSurface(), 0 ) ;
01309 break ;
01310
01311
01312 case Blended:
01313 textSurface = TTF_RenderGlyph_Blended( _actualFont, character,
01314 glyphColor ) ;
01315
01316 if ( textSurface == 0 )
01317 throw TextException(
01318 "TrueTypeFont::basicRenderUnicodeGlyph (blended) : "
01319 "unable to render character '"
01320 + Ceylan::toString( character )
01321 + "' : " + DescribeLastError() ) ;
01322
01323 res = new Surface( * textSurface,
01324 Surface::BackBuffer ) ;
01325
01326
01327
01328 break ;
01329
01330
01331 default:
01332 throw TextException( "TrueTypeFont::basicRenderUnicodeGlyph : "
01333 "unknown quality requested : "
01334 + Ceylan::toString( quality ) + "." ) ;
01335 break ;
01336
01337 }
01338
01339
01340 if ( _convertToDisplay )
01341 {
01342
01343
01344
01345
01346
01347
01348
01349
01350 if ( quality == Blended )
01351 res->convertToDisplay( true ) ;
01352 else
01353 res->convertToDisplay( false ) ;
01354
01355 }
01356
01357
01358
01359
01360 return * res ;
01361
01362 }
01363