2012-11-22 21:29:51 +00:00
# include "sceFont.h"
2020-08-15 18:53:08 +00:00
# include "Common/TimeUtil.h"
2012-11-22 21:29:51 +00:00
2013-02-28 16:07:33 +00:00
# include <cmath>
2013-03-03 23:42:16 +00:00
# include <vector>
# include <map>
# include <algorithm>
2013-02-28 16:07:33 +00:00
2020-08-10 07:12:51 +00:00
# include "Common/Serialize/Serializer.h"
# include "Common/Serialize/SerializeFuncs.h"
# include "Common/Serialize/SerializeMap.h"
2013-12-29 22:28:31 +00:00
# include "Core/HLE/HLE.h"
2014-03-15 18:22:19 +00:00
# include "Core/HLE/FunctionWrappers.h"
2014-12-08 09:40:08 +00:00
# include "Core/HLE/sceFont.h"
# include "Core/HLE/sceKernel.h"
# include "Core/HLE/sceKernelThread.h"
2013-12-29 22:28:31 +00:00
# include "Core/MIPS/MIPS.h"
2013-02-22 19:05:07 +00:00
# include "Core/FileSystems/FileSystem.h"
2013-12-29 22:28:31 +00:00
# include "Core/FileSystems/MetaFileSystem.h"
2015-04-06 01:09:35 +00:00
# include "Core/MemMapHelpers.h"
2013-05-20 00:54:14 +00:00
# include "Core/Reporting.h"
2013-02-22 19:05:07 +00:00
# include "Core/System.h"
# include "Core/Font/PGF.h"
enum {
2014-03-03 16:16:53 +00:00
ERROR_FONT_OUT_OF_MEMORY = 0x80460001 ,
ERROR_FONT_INVALID_LIBID = 0x80460002 ,
ERROR_FONT_INVALID_PARAMETER = 0x80460003 ,
ERROR_FONT_HANDLER_OPEN_FAILED = 0x80460005 ,
ERROR_FONT_TOO_MANY_OPEN_FONTS = 0x80460009 ,
ERROR_FONT_INVALID_FONT_DATA = 0x8046000a ,
2013-02-22 19:05:07 +00:00
} ;
2021-08-08 00:44:40 +00:00
constexpr int MAX_FONT_REFS = 4 ;
2020-03-15 23:54:42 +00:00
// For the save states.
static bool useAllocCallbacks = true ;
2013-02-22 19:05:07 +00:00
// Actions
static int actionPostAllocCallback ;
static int actionPostOpenCallback ;
2020-03-15 15:05:28 +00:00
static int actionPostOpenAllocCallback ;
static int actionPostCharInfoAllocCallback ;
static int actionPostCharInfoFreeCallback ;
2013-02-22 19:05:07 +00:00
// Monster Hunter sequence:
// 36:46:998 c:\dev\ppsspp\core\hle\scefont.cpp:469 E[HLE]: sceFontNewLib 89ad4a0, 9fff5cc
// 36:46:998 c:\dev\ppsspp\core\hle\scefont.cpp:699 E[HLE]: UNIMPL sceFontGetNumFontList 1, 9fff5cc
// 36:46:998 c:\dev\ppsspp\core\hle\scefont.cpp:526 E[HLE]: sceFontFindOptimumFont 1, 9fff524, 9fff5cc
// 36:46:999 c:\dev\ppsspp\core\hle\scefont.cpp:490 E[HLE]: sceFontOpenFont 1, 1, 0, 9fff5cc
// 36:46:999 c:\dev\ppsspp\core\hle\scefont.cpp:542 E[HLE]: sceFontGetFontInfo 1, 997140c
2012-11-22 21:29:51 +00:00
2012-12-08 19:53:15 +00:00
typedef u32 FontLibraryHandle ;
typedef u32 FontHandle ;
2013-02-12 23:49:49 +00:00
struct FontNewLibParams {
2013-07-25 07:18:50 +00:00
u32_le userDataAddr ;
u32_le numFonts ;
u32_le cacheDataAddr ;
2012-12-08 19:53:15 +00:00
// Driver callbacks.
2013-07-25 07:18:50 +00:00
u32_le allocFuncAddr ;
u32_le freeFuncAddr ;
u32_le openFuncAddr ;
u32_le closeFuncAddr ;
u32_le readFuncAddr ;
u32_le seekFuncAddr ;
u32_le errorFuncAddr ;
u32_le ioFinishFuncAddr ;
2013-02-12 23:49:49 +00:00
} ;
2012-12-08 19:53:15 +00:00
2013-02-22 19:05:07 +00:00
struct FontRegistryEntry {
int hSize ;
int vSize ;
int hResolution ;
int vResolution ;
int extraAttributes ;
int weight ;
int familyCode ;
int style ;
int styleSub ;
int languageCode ;
int regionCode ;
int countryCode ;
const char * fileName ;
const char * fontName ;
int expireDate ;
int shadow_option ;
2020-03-15 15:05:28 +00:00
u32 fontFileSize ;
2020-07-22 15:47:29 +00:00
u32 stingySize ; // for the FONT_OPEN_INTERNAL_STINGY mode, from pspautotests.
2016-08-07 17:27:27 +00:00
bool ignoreIfMissing ;
2013-02-12 23:49:49 +00:00
} ;
2012-12-08 19:53:15 +00:00
2013-02-22 19:05:07 +00:00
static const FontRegistryEntry fontRegistry [ ] = {
2016-08-07 17:27:27 +00:00
// This was added for Chinese translations and is not normally loaded on a PSP.
2020-07-22 15:47:29 +00:00
{ 0x288 , 0x288 , 0x2000 , 0x2000 , 0 , 0 , FONT_FAMILY_SANS_SERIF , FONT_STYLE_DB , 0 , FONT_LANGUAGE_CHINESE , 0 , 1 , " zh_gb.pgf " , " FTT-NewRodin Pro DB " , 0 , 0 , 1581700 , 145844 , true } ,
{ 0x288 , 0x288 , 0x2000 , 0x2000 , 0 , 0 , FONT_FAMILY_SANS_SERIF , FONT_STYLE_DB , 0 , FONT_LANGUAGE_JAPANESE , 0 , 1 , " jpn0.pgf " , " FTT-NewRodin Pro DB " , 0 , 0 , 1581700 , 145844 } ,
{ 0x288 , 0x288 , 0x2000 , 0x2000 , 0 , 0 , FONT_FAMILY_SANS_SERIF , FONT_STYLE_REGULAR , 0 , FONT_LANGUAGE_LATIN , 0 , 1 , " ltn0.pgf " , " FTT-NewRodin Pro Latin " , 0 , 0 , 69108 , 16680 } ,
{ 0x288 , 0x288 , 0x2000 , 0x2000 , 0 , 0 , FONT_FAMILY_SERIF , FONT_STYLE_REGULAR , 0 , FONT_LANGUAGE_LATIN , 0 , 1 , " ltn1.pgf " , " FTT-Matisse Pro Latin " , 0 , 0 , 65124 , 16920 } ,
{ 0x288 , 0x288 , 0x2000 , 0x2000 , 0 , 0 , FONT_FAMILY_SANS_SERIF , FONT_STYLE_ITALIC , 0 , FONT_LANGUAGE_LATIN , 0 , 1 , " ltn2.pgf " , " FTT-NewRodin Pro Latin " , 0 , 0 , 72948 , 16872 } ,
{ 0x288 , 0x288 , 0x2000 , 0x2000 , 0 , 0 , FONT_FAMILY_SERIF , FONT_STYLE_ITALIC , 0 , FONT_LANGUAGE_LATIN , 0 , 1 , " ltn3.pgf " , " FTT-Matisse Pro Latin " , 0 , 0 , 67700 , 17112 } ,
{ 0x288 , 0x288 , 0x2000 , 0x2000 , 0 , 0 , FONT_FAMILY_SANS_SERIF , FONT_STYLE_BOLD , 0 , FONT_LANGUAGE_LATIN , 0 , 1 , " ltn4.pgf " , " FTT-NewRodin Pro Latin " , 0 , 0 , 72828 , 16648 } ,
{ 0x288 , 0x288 , 0x2000 , 0x2000 , 0 , 0 , FONT_FAMILY_SERIF , FONT_STYLE_BOLD , 0 , FONT_LANGUAGE_LATIN , 0 , 1 , " ltn5.pgf " , " FTT-Matisse Pro Latin " , 0 , 0 , 68220 , 16928 } ,
{ 0x288 , 0x288 , 0x2000 , 0x2000 , 0 , 0 , FONT_FAMILY_SANS_SERIF , FONT_STYLE_BOLD_ITALIC , 0 , FONT_LANGUAGE_LATIN , 0 , 1 , " ltn6.pgf " , " FTT-NewRodin Pro Latin " , 0 , 0 , 77032 , 16792 } ,
{ 0x288 , 0x288 , 0x2000 , 0x2000 , 0 , 0 , FONT_FAMILY_SERIF , FONT_STYLE_BOLD_ITALIC , 0 , FONT_LANGUAGE_LATIN , 0 , 1 , " ltn7.pgf " , " FTT-Matisse Pro Latin " , 0 , 0 , 71144 , 17160 } ,
{ 0x1c0 , 0x1c0 , 0x2000 , 0x2000 , 0 , 0 , FONT_FAMILY_SANS_SERIF , FONT_STYLE_REGULAR , 0 , FONT_LANGUAGE_LATIN , 0 , 1 , " ltn8.pgf " , " FTT-NewRodin Pro Latin " , 0 , 0 , 41000 , 16192 } ,
{ 0x1c0 , 0x1c0 , 0x2000 , 0x2000 , 0 , 0 , FONT_FAMILY_SERIF , FONT_STYLE_REGULAR , 0 , FONT_LANGUAGE_LATIN , 0 , 1 , " ltn9.pgf " , " FTT-Matisse Pro Latin " , 0 , 0 , 40164 , 16476 } ,
{ 0x1c0 , 0x1c0 , 0x2000 , 0x2000 , 0 , 0 , FONT_FAMILY_SANS_SERIF , FONT_STYLE_ITALIC , 0 , FONT_LANGUAGE_LATIN , 0 , 1 , " ltn10.pgf " , " FTT-NewRodin Pro Latin " , 0 , 0 , 42692 , 16300 } ,
{ 0x1c0 , 0x1c0 , 0x2000 , 0x2000 , 0 , 0 , FONT_FAMILY_SERIF , FONT_STYLE_ITALIC , 0 , FONT_LANGUAGE_LATIN , 0 , 1 , " ltn11.pgf " , " FTT-Matisse Pro Latin " , 0 , 0 , 41488 , 16656 } ,
{ 0x1c0 , 0x1c0 , 0x2000 , 0x2000 , 0 , 0 , FONT_FAMILY_SANS_SERIF , FONT_STYLE_BOLD , 0 , FONT_LANGUAGE_LATIN , 0 , 1 , " ltn12.pgf " , " FTT-NewRodin Pro Latin " , 0 , 0 , 43136 , 16176 } ,
{ 0x1c0 , 0x1c0 , 0x2000 , 0x2000 , 0 , 0 , FONT_FAMILY_SERIF , FONT_STYLE_BOLD , 0 , FONT_LANGUAGE_LATIN , 0 , 1 , " ltn13.pgf " , " FTT-Matisse Pro Latin " , 0 , 0 , 41772 , 16436 } ,
{ 0x1c0 , 0x1c0 , 0x2000 , 0x2000 , 0 , 0 , FONT_FAMILY_SANS_SERIF , FONT_STYLE_BOLD_ITALIC , 0 , FONT_LANGUAGE_LATIN , 0 , 1 , " ltn14.pgf " , " FTT-NewRodin Pro Latin " , 0 , 0 , 45184 , 16272 } ,
{ 0x1c0 , 0x1c0 , 0x2000 , 0x2000 , 0 , 0 , FONT_FAMILY_SERIF , FONT_STYLE_BOLD_ITALIC , 0 , FONT_LANGUAGE_LATIN , 0 , 1 , " ltn15.pgf " , " FTT-Matisse Pro Latin " , 0 , 0 , 43044 , 16704 } ,
{ 0x288 , 0x288 , 0x2000 , 0x2000 , 0 , 0 , FONT_FAMILY_SANS_SERIF , FONT_STYLE_REGULAR , 0 , FONT_LANGUAGE_KOREAN , 0 , 3 , " kr0.pgf " , " AsiaNHH(512Johab) " , 0 , 0 , 394192 , 51856 } ,
2013-02-12 23:49:49 +00:00
} ;
2012-12-08 19:53:15 +00:00
2013-02-22 19:05:07 +00:00
static const float pointDPI = 72.f ;
2013-03-03 23:57:05 +00:00
class LoadedFont ;
2013-02-22 19:05:07 +00:00
class FontLib ;
2013-03-03 23:57:05 +00:00
class Font ;
int GetInternalFontIndex ( Font * font ) ;
// These should not need to be state saved.
static std : : vector < Font * > internalFonts ;
// However, these we must save - but we could take a shortcut
// for LoadedFonts that point to internal fonts.
static std : : map < u32 , LoadedFont * > fontMap ;
static std : : map < u32 , u32 > fontLibMap ;
// We keep this list to avoid ptr references, even before alloc is called.
static std : : vector < FontLib * > fontLibList ;
2013-02-22 19:05:07 +00:00
2013-05-05 19:34:28 +00:00
enum MatchQuality {
2014-02-25 16:16:10 +00:00
MATCH_UNKNOWN ,
2013-05-05 19:34:28 +00:00
MATCH_NONE ,
MATCH_GOOD ,
} ;
2014-02-23 07:04:46 +00:00
enum FontOpenMode {
2014-03-03 16:16:53 +00:00
FONT_OPEN_INTERNAL_STINGY = 0 ,
FONT_OPEN_INTERNAL_FULL = 1 ,
2014-02-23 07:04:46 +00:00
// Calls open/seek/read/close handlers to read the file partially.
FONT_OPEN_USERFILE_HANDLERS = 2 ,
// Reads directly from filesystem.
2014-03-03 16:16:53 +00:00
FONT_OPEN_USERFILE_FULL = 3 ,
FONT_OPEN_USERBUFFER = 4 ,
2014-02-23 07:04:46 +00:00
} ;
2013-02-22 19:05:07 +00:00
// TODO: Merge this class with PGF? That'd make it harder to support .bwfon
// fonts though, unless that's added directly to PGF.
class Font {
public :
2013-03-03 23:57:05 +00:00
// For savestates only.
Font ( ) {
}
2013-02-22 19:05:07 +00:00
Font ( const u8 * data , size_t dataSize ) {
2013-12-08 20:02:37 +00:00
Init ( data , dataSize ) ;
2013-02-22 19:05:07 +00:00
}
Font ( const u8 * data , size_t dataSize , const FontRegistryEntry & entry ) {
2013-12-08 20:02:37 +00:00
Init ( data , dataSize , entry ) ;
}
2014-02-23 04:35:58 +00:00
Font ( const std : : vector < u8 > & data ) {
2013-12-08 20:02:37 +00:00
Init ( & data [ 0 ] , data . size ( ) ) ;
}
2014-02-23 04:35:58 +00:00
Font ( const std : : vector < u8 > & data , const FontRegistryEntry & entry ) {
2013-12-08 20:02:37 +00:00
Init ( & data [ 0 ] , data . size ( ) , entry ) ;
2013-02-22 19:05:07 +00:00
}
const PGFFontStyle & GetFontStyle ( ) const { return style_ ; }
2014-03-01 10:17:11 +00:00
MatchQuality MatchesStyle ( const PGFFontStyle & style ) const {
2013-05-05 19:34:28 +00:00
// If no field matches, it doesn't match.
2014-02-25 16:16:10 +00:00
MatchQuality match = MATCH_UNKNOWN ;
2013-05-05 19:34:28 +00:00
# define CHECK_FIELD(f, m) \
2013-05-06 00:46:16 +00:00
if ( style . f ! = 0 ) { \
if ( style . f ! = style_ . f ) { \
2013-05-05 19:34:28 +00:00
return MATCH_NONE ; \
} \
if ( match < m ) { \
match = m ; \
} \
}
# define CHECK_FIELD_STR(f, m) \
2013-05-06 00:46:16 +00:00
if ( style . f [ 0 ] ! = ' \0 ' ) { \
if ( strcmp ( style . f , style_ . f ) ! = 0 ) { \
2013-05-05 19:34:28 +00:00
return MATCH_NONE ; \
} \
if ( match < m ) { \
match = m ; \
} \
}
CHECK_FIELD ( fontFamily , MATCH_GOOD ) ;
CHECK_FIELD ( fontStyle , MATCH_GOOD ) ;
CHECK_FIELD ( fontLanguage , MATCH_GOOD ) ;
CHECK_FIELD ( fontCountry , MATCH_GOOD ) ;
CHECK_FIELD_STR ( fontName , MATCH_GOOD ) ;
CHECK_FIELD_STR ( fontFileName , MATCH_GOOD ) ;
# undef CHECK_FIELD_STR
# undef CHECK_FIELD
return match ;
2013-02-22 19:05:07 +00:00
}
PGF * GetPGF ( ) { return & pgf_ ; }
2014-02-23 04:35:58 +00:00
const PGF * GetPGF ( ) const { return & pgf_ ; }
2020-03-15 15:05:28 +00:00
u32 getSize ( ) const { return dataSize_ ; }
2020-07-22 15:47:29 +00:00
u32 getStingySize ( ) const { return stingySize_ ; }
2014-02-23 04:35:58 +00:00
bool IsValid ( ) const { return valid_ ; }
2013-02-22 19:05:07 +00:00
2013-03-03 23:57:05 +00:00
void DoState ( PointerWrap & p ) {
2014-02-23 04:35:58 +00:00
auto s = p . Section ( " Font " , 1 , 2 ) ;
2013-09-15 03:23:03 +00:00
if ( ! s )
return ;
2020-08-10 04:20:42 +00:00
Do ( p , pgf_ ) ;
Do ( p , style_ ) ;
2014-02-23 04:35:58 +00:00
if ( s < 2 ) {
valid_ = true ;
} else {
2020-08-10 04:20:42 +00:00
Do ( p , valid_ ) ;
2014-02-23 04:35:58 +00:00
}
2013-03-03 23:57:05 +00:00
}
2013-02-22 19:05:07 +00:00
private :
2013-12-08 20:02:37 +00:00
void Init ( const u8 * data , size_t dataSize ) {
2014-02-23 04:35:58 +00:00
valid_ = pgf_ . ReadPtr ( data , dataSize ) ;
2014-03-01 09:30:25 +00:00
memset ( & style_ , 0 , sizeof ( style_ ) ) ;
2013-12-08 20:02:37 +00:00
style_ . fontH = ( float ) pgf_ . header . hSize / 64.0f ;
style_ . fontV = ( float ) pgf_ . header . vSize / 64.0f ;
style_ . fontHRes = ( float ) pgf_ . header . hResolution / 64.0f ;
style_ . fontVRes = ( float ) pgf_ . header . vResolution / 64.0f ;
2020-03-15 15:05:28 +00:00
this - > dataSize_ = ( u32 ) dataSize ;
2020-07-22 15:47:29 +00:00
this - > stingySize_ = 0 ; // Unused
2013-12-08 20:02:37 +00:00
}
void Init ( const u8 * data , size_t dataSize , const FontRegistryEntry & entry ) {
2014-02-23 04:35:58 +00:00
valid_ = pgf_ . ReadPtr ( data , dataSize ) ;
2013-12-08 20:02:37 +00:00
style_ . fontH = entry . hSize / 64.f ;
style_ . fontV = entry . vSize / 64.f ;
style_ . fontHRes = entry . hResolution / 64.f ;
style_ . fontVRes = entry . vResolution / 64.f ;
style_ . fontWeight = ( float ) entry . weight ;
style_ . fontFamily = ( u16 ) entry . familyCode ;
style_ . fontStyle = ( u16 ) entry . style ;
style_ . fontStyleSub = ( u16 ) entry . styleSub ;
style_ . fontLanguage = ( u16 ) entry . languageCode ;
style_ . fontRegion = ( u16 ) entry . regionCode ;
style_ . fontCountry = ( u16 ) entry . countryCode ;
strncpy ( style_ . fontName , entry . fontName , sizeof ( style_ . fontName ) ) ;
strncpy ( style_ . fontFileName , entry . fileName , sizeof ( style_ . fontFileName ) ) ;
style_ . fontAttributes = entry . extraAttributes ;
style_ . fontExpire = entry . expireDate ;
2020-03-15 15:05:28 +00:00
this - > dataSize_ = entry . fontFileSize ;
2020-07-22 15:47:29 +00:00
this - > stingySize_ = entry . stingySize ;
2013-12-08 20:02:37 +00:00
}
2013-02-22 19:05:07 +00:00
PGF pgf_ ;
PGFFontStyle style_ ;
2014-02-23 04:35:58 +00:00
bool valid_ ;
2020-03-15 15:05:28 +00:00
u32 dataSize_ ;
2020-07-22 15:47:29 +00:00
u32 stingySize_ ;
2013-02-22 19:05:07 +00:00
DISALLOW_COPY_AND_ASSIGN ( Font ) ;
2013-02-12 23:49:49 +00:00
} ;
2012-12-08 19:53:15 +00:00
2013-02-22 19:05:07 +00:00
class LoadedFont {
public :
2013-03-03 23:57:05 +00:00
// For savestates only.
2013-03-21 06:37:18 +00:00
LoadedFont ( ) : font_ ( NULL ) {
2013-03-03 23:57:05 +00:00
}
2014-03-30 19:55:40 +00:00
LoadedFont ( Font * font , FontOpenMode mode , u32 fontLibID , u32 handle )
2014-07-16 14:49:48 +00:00
: fontLibID_ ( fontLibID ) , font_ ( font ) , handle_ ( handle ) , mode_ ( mode ) , open_ ( true ) { }
2014-03-30 19:55:40 +00:00
~ LoadedFont ( ) {
switch ( mode_ ) {
case FONT_OPEN_USERBUFFER :
case FONT_OPEN_USERFILE_FULL :
case FONT_OPEN_USERFILE_HANDLERS :
// For these types, it's our responsibility to delete.
delete font_ ;
font_ = NULL ;
break ;
default :
// Otherwise, it's an internal font, we keep those.
break ;
}
}
2013-02-22 19:05:07 +00:00
2014-03-01 07:04:34 +00:00
const Font * GetFont ( ) const { return font_ ; }
const PGF * GetPGF ( ) const { return font_ - > GetPGF ( ) ; }
const FontLib * GetFontLib ( ) const { return fontLibList [ fontLibID_ ] ; }
2014-02-23 19:48:31 +00:00
FontLib * GetFontLib ( ) { return fontLibList [ fontLibID_ ] ; }
2013-02-22 19:05:07 +00:00
u32 Handle ( ) const { return handle_ ; }
2014-03-01 07:04:34 +00:00
bool GetCharInfo ( int charCode , PGFCharInfo * charInfo , int glyphType = FONT_PGF_CHARGLYPH ) const ;
void DrawCharacter ( const GlyphImage * image , int clipX , int clipY , int clipWidth , int clipHeight , int charCode , int glyphType ) const ;
2014-02-23 19:48:31 +00:00
bool IsOpen ( ) const { return open_ ; }
2013-02-22 19:05:07 +00:00
void Close ( ) {
2014-02-23 19:48:31 +00:00
open_ = false ;
2013-02-22 19:05:07 +00:00
// We keep the rest around until deleted, as some queries are allowed
// on closed fonts (which is rather strange).
}
2013-03-03 23:57:05 +00:00
void DoState ( PointerWrap & p ) {
2014-03-30 19:55:40 +00:00
auto s = p . Section ( " LoadedFont " , 1 , 3 ) ;
2013-09-15 03:23:03 +00:00
if ( ! s )
return ;
2013-03-03 23:57:05 +00:00
int numInternalFonts = ( int ) internalFonts . size ( ) ;
2020-08-10 04:20:42 +00:00
Do ( p , numInternalFonts ) ;
2013-03-03 23:57:05 +00:00
if ( numInternalFonts ! = ( int ) internalFonts . size ( ) ) {
2013-09-07 20:02:55 +00:00
ERROR_LOG ( SCEFONT , " Unable to load state: different internal font count. " ) ;
2014-03-23 20:03:33 +00:00
p . SetError ( p . ERROR_FAILURE ) ;
2013-03-03 23:57:05 +00:00
return ;
}
2020-08-10 04:20:42 +00:00
Do ( p , fontLibID_ ) ;
2013-03-03 23:57:05 +00:00
int internalFont = GetInternalFontIndex ( font_ ) ;
2020-08-10 04:20:42 +00:00
Do ( p , internalFont ) ;
2013-03-03 23:57:05 +00:00
if ( internalFont = = - 1 ) {
2020-08-10 04:20:42 +00:00
Do ( p , font_ ) ;
2013-03-03 23:57:05 +00:00
} else if ( p . mode = = p . MODE_READ ) {
font_ = internalFonts [ internalFont ] ;
}
2020-08-10 04:20:42 +00:00
Do ( p , handle_ ) ;
2014-02-23 19:48:31 +00:00
if ( s > = 2 ) {
2020-08-10 04:20:42 +00:00
Do ( p , open_ ) ;
2014-02-23 19:48:31 +00:00
} else {
open_ = fontLibID_ ! = ( u32 ) - 1 ;
}
2014-03-30 19:55:40 +00:00
if ( s > = 3 ) {
2020-08-10 04:20:42 +00:00
Do ( p , mode_ ) ;
2014-03-30 19:55:40 +00:00
} else {
mode_ = FONT_OPEN_INTERNAL_FULL ;
}
2013-03-03 23:57:05 +00:00
}
2013-02-22 19:05:07 +00:00
private :
2013-03-03 23:57:05 +00:00
u32 fontLibID_ ;
2013-02-22 19:05:07 +00:00
Font * font_ ;
u32 handle_ ;
2014-03-30 19:55:40 +00:00
FontOpenMode mode_ ;
2014-02-23 19:48:31 +00:00
bool open_ ;
2013-02-22 19:05:07 +00:00
DISALLOW_COPY_AND_ASSIGN ( LoadedFont ) ;
2013-02-12 23:49:49 +00:00
} ;
2012-12-08 19:53:15 +00:00
2020-03-15 15:33:40 +00:00
class PostAllocCallback : public PSPAction {
2013-02-22 19:05:07 +00:00
public :
PostAllocCallback ( ) { }
2020-03-15 15:33:40 +00:00
static PSPAction * Create ( ) { return new PostAllocCallback ( ) ; }
2014-12-08 20:14:35 +00:00
void DoState ( PointerWrap & p ) override {
2014-02-22 21:37:45 +00:00
auto s = p . Section ( " PostAllocCallback " , 1 , 2 ) ;
2013-09-15 03:23:03 +00:00
if ( ! s )
return ;
2020-08-10 04:20:42 +00:00
Do ( p , fontLibID_ ) ;
2014-02-22 21:37:45 +00:00
if ( s > = 2 ) {
2020-08-10 04:20:42 +00:00
Do ( p , errorCodePtr_ ) ;
2020-06-30 02:40:54 +00:00
} else {
errorCodePtr_ = 0 ;
2014-02-22 21:37:45 +00:00
}
2013-09-15 03:23:03 +00:00
}
2014-12-08 20:14:35 +00:00
void run ( MipsCall & call ) override ;
2014-02-22 21:37:45 +00:00
void SetFontLib ( u32 fontLibID , u32 errorCodePtr ) { fontLibID_ = fontLibID ; errorCodePtr_ = errorCodePtr ; }
2013-02-22 19:05:07 +00:00
private :
2013-03-03 23:42:16 +00:00
u32 fontLibID_ ;
2014-02-22 21:37:45 +00:00
u32 errorCodePtr_ ;
2013-02-12 23:49:49 +00:00
} ;
2012-12-08 19:53:15 +00:00
2020-03-15 15:33:40 +00:00
class PostOpenCallback : public PSPAction {
2013-02-22 19:05:07 +00:00
public :
PostOpenCallback ( ) { }
2020-03-15 15:33:40 +00:00
static PSPAction * Create ( ) { return new PostOpenCallback ( ) ; }
2014-12-08 20:14:35 +00:00
void DoState ( PointerWrap & p ) override {
2013-09-15 03:23:03 +00:00
auto s = p . Section ( " PostOpenCallback " , 1 ) ;
if ( ! s )
return ;
2020-08-10 04:20:42 +00:00
Do ( p , fontLibID_ ) ;
2013-09-15 03:23:03 +00:00
}
2014-12-08 20:14:35 +00:00
void run ( MipsCall & call ) override ;
2013-03-03 23:42:16 +00:00
void SetFontLib ( u32 fontLibID ) { fontLibID_ = fontLibID ; }
2013-02-22 19:05:07 +00:00
private :
2013-03-03 23:42:16 +00:00
u32 fontLibID_ ;
2013-02-12 23:49:49 +00:00
} ;
2012-12-08 19:53:15 +00:00
2020-03-16 01:36:23 +00:00
class PostOpenAllocCallback : public PSPAction {
2020-03-15 15:05:28 +00:00
public :
PostOpenAllocCallback ( ) { }
2020-03-16 01:36:23 +00:00
static PSPAction * Create ( ) { return new PostOpenAllocCallback ( ) ; }
2020-03-15 15:05:28 +00:00
void DoState ( PointerWrap & p ) override {
auto s = p . Section ( " PostOpenAllocCallback " , 1 ) ;
if ( ! s )
return ;
2020-08-10 04:20:42 +00:00
Do ( p , fontLibID_ ) ;
Do ( p , fontHandle_ ) ;
Do ( p , fontIndex_ ) ;
2020-03-15 15:05:28 +00:00
}
void run ( MipsCall & call ) override ;
void SetFontLib ( u32 fontLibID ) { fontLibID_ = fontLibID ; }
void SetFont ( u32 handle , int index ) { fontHandle_ = handle ; fontIndex_ = index ; }
private :
u32 fontLibID_ ;
u32 fontHandle_ ;
int fontIndex_ ;
} ;
2020-03-16 01:36:23 +00:00
class PostCharInfoAllocCallback : public PSPAction {
2020-03-15 15:05:28 +00:00
public :
PostCharInfoAllocCallback ( ) { }
2020-03-16 01:36:23 +00:00
static PSPAction * Create ( ) { return new PostCharInfoAllocCallback ( ) ; }
2020-03-15 15:05:28 +00:00
void DoState ( PointerWrap & p ) override {
auto s = p . Section ( " PostCharInfoAllocCallback " , 1 ) ;
if ( ! s )
return ;
2020-08-10 04:20:42 +00:00
Do ( p , fontLibID_ ) ;
2020-03-15 15:05:28 +00:00
}
void run ( MipsCall & call ) override ;
void SetFontLib ( u32 fontLibID ) { fontLibID_ = fontLibID ; }
private :
u32 fontLibID_ ;
} ;
2020-03-16 01:36:23 +00:00
class PostCharInfoFreeCallback : public PSPAction {
2020-03-15 15:05:28 +00:00
public :
PostCharInfoFreeCallback ( ) { }
2020-03-16 01:36:23 +00:00
static PSPAction * Create ( ) { return new PostCharInfoFreeCallback ( ) ; }
2020-03-15 15:05:28 +00:00
void DoState ( PointerWrap & p ) override {
auto s = p . Section ( " PostCharInfoFreeCallback " , 1 ) ;
if ( ! s )
return ;
2020-08-10 04:20:42 +00:00
Do ( p , fontLibID_ ) ;
Do ( p , charInfo_ ) ;
2020-03-15 15:05:28 +00:00
}
void run ( MipsCall & call ) override ;
void SetFontLib ( u32 fontLibID ) { fontLibID_ = fontLibID ; }
void SetCharInfo ( PSPPointer < PGFCharInfo > charInfo ) { charInfo_ = charInfo ; }
private :
u32 fontLibID_ ;
PSPPointer < PGFCharInfo > charInfo_ ;
} ;
2014-02-22 22:01:05 +00:00
struct NativeFontLib {
FontNewLibParams params ;
// TODO
u32_le fontInfo1 ;
u32_le fontInfo2 ;
2014-02-23 04:35:58 +00:00
u16_le unk1 ;
u16_le unk2 ;
2014-02-22 22:01:05 +00:00
float_le hRes ;
float_le vRes ;
u32_le internalFontCount ;
u32_le internalFontInfo ;
2014-03-01 05:20:06 +00:00
u16_le altCharCode ;
2014-02-22 22:01:05 +00:00
u16_le unk5 ;
} ;
2014-03-01 07:04:34 +00:00
struct FontImageRect {
s16_le width ;
s16_le height ;
} ;
2013-02-22 19:05:07 +00:00
// A "fontLib" is a container of loaded fonts.
// One can open either "internal" fonts or custom fonts into a fontlib.
class FontLib {
public :
2013-03-03 23:42:16 +00:00
FontLib ( ) {
// For save states only.
}
2020-03-15 15:05:28 +00:00
FontLib ( u32 paramPtr , u32 errorCodePtr ) : fontHRes_ ( 128.0f ) , fontVRes_ ( 128.0f ) , altCharCode_ ( 0x5F ) , charInfoBitmapAddress_ ( 0 ) {
2014-03-01 05:29:41 +00:00
nfl_ = 0 ;
2013-02-22 19:05:07 +00:00
Memory : : ReadStruct ( paramPtr , & params_ ) ;
2014-02-22 20:48:54 +00:00
if ( params_ . numFonts > 9 ) {
params_ . numFonts = 9 ;
}
2014-02-22 21:00:03 +00:00
// Technically, this should be four separate allocations.
u32 allocSize = 0x4C + params_ . numFonts * 0x4C + params_ . numFonts * 0x230 + ( u32 ) internalFonts . size ( ) * 0xA8 ;
2013-05-11 05:06:50 +00:00
PostAllocCallback * action = ( PostAllocCallback * ) __KernelCreateAction ( actionPostAllocCallback ) ;
2014-02-22 21:37:45 +00:00
action - > SetFontLib ( GetListID ( ) , errorCodePtr ) ;
2013-03-03 13:29:03 +00:00
2020-03-21 23:09:23 +00:00
u32 args [ 2 ] = { userDataAddr ( ) , allocSize } ;
hleEnqueueCall ( allocFuncAddr ( ) , 2 , args , action ) ;
2013-02-22 19:05:07 +00:00
}
2013-03-03 23:42:16 +00:00
u32 GetListID ( ) {
return ( u32 ) ( std : : find ( fontLibList . begin ( ) , fontLibList . end ( ) , this ) - fontLibList . begin ( ) ) ;
}
2013-02-22 19:05:07 +00:00
void Done ( ) {
2013-02-26 23:59:30 +00:00
for ( size_t i = 0 ; i < fonts_ . size ( ) ; i + + ) {
2021-08-08 00:35:37 +00:00
if ( fontRefCount_ [ i ] > 0 ) {
CloseFont ( fontMap [ fonts_ [ i ] ] , true ) ;
2013-02-26 23:59:30 +00:00
delete fontMap [ fonts_ [ i ] ] ;
fontMap . erase ( fonts_ [ i ] ) ;
}
}
2020-03-21 23:09:23 +00:00
u32 args [ 2 ] = { userDataAddr ( ) , ( u32 ) handle_ } ;
2013-11-17 07:11:13 +00:00
// TODO: The return value of this is leaking.
2019-03-11 11:55:09 +00:00
if ( handle_ ) { // Avoid calling free-callback on double-free
2020-03-21 19:36:09 +00:00
if ( coreState ! = CORE_POWERDOWN ) {
2020-03-21 23:09:23 +00:00
hleEnqueueCall ( freeFuncAddr ( ) , 2 , args ) ;
2020-03-21 19:36:09 +00:00
}
2019-03-11 11:55:09 +00:00
}
2013-02-26 23:59:30 +00:00
handle_ = 0 ;
fonts_ . clear ( ) ;
2021-08-08 00:35:37 +00:00
fontRefCount_ . clear ( ) ;
2020-03-15 15:05:28 +00:00
openAllocatedAddresses_ . clear ( ) ;
2013-02-22 19:05:07 +00:00
}
void AllocDone ( u32 allocatedAddr ) {
handle_ = allocatedAddr ;
fonts_ . resize ( params_ . numFonts ) ;
2021-08-08 00:35:37 +00:00
fontRefCount_ . resize ( params_ . numFonts ) ;
2020-03-15 15:05:28 +00:00
openAllocatedAddresses_ . resize ( params_ . numFonts ) ;
2013-02-22 19:05:07 +00:00
for ( size_t i = 0 ; i < fonts_ . size ( ) ; i + + ) {
2014-02-22 22:01:05 +00:00
u32 addr = allocatedAddr + 0x4C + ( u32 ) i * 0x4C ;
2021-08-08 00:35:37 +00:00
fontRefCount_ [ i ] = 0 ;
2013-02-22 19:05:07 +00:00
fonts_ [ i ] = addr ;
}
2014-02-22 22:01:05 +00:00
// Let's write out the native struct to make tests easier.
// It's possible games may depend on this staying in ram, e.g. copying it, we may move to that.
2014-03-01 05:29:41 +00:00
nfl_ = allocatedAddr ;
nfl_ - > params = params_ ;
nfl_ - > fontInfo1 = allocatedAddr + 0x4C ;
nfl_ - > fontInfo2 = allocatedAddr + 0x4C + params_ . numFonts * 0x4C ;
nfl_ - > unk1 = 0 ;
nfl_ - > unk2 = 0 ;
nfl_ - > hRes = fontHRes_ ;
nfl_ - > vRes = fontVRes_ ;
nfl_ - > internalFontCount = ( u32 ) internalFonts . size ( ) ;
nfl_ - > internalFontInfo = allocatedAddr + 0x4C + params_ . numFonts * 0x4C + params_ . numFonts * 0x230 ;
nfl_ - > altCharCode = altCharCode_ ;
2013-02-22 19:05:07 +00:00
}
u32 handle ( ) const { return handle_ ; }
int numFonts ( ) const { return params_ . numFonts ; }
2020-03-15 15:05:28 +00:00
u32_le userDataAddr ( ) const { return params_ . userDataAddr ; }
u32_le allocFuncAddr ( ) const { return params_ . allocFuncAddr ; }
u32_le freeFuncAddr ( ) const { return params_ . freeFuncAddr ; }
2013-02-22 19:05:07 +00:00
void SetResolution ( float hres , float vres ) {
fontHRes_ = hres ;
fontVRes_ = vres ;
2014-03-01 05:29:41 +00:00
if ( nfl_ . IsValid ( ) ) {
nfl_ - > hRes = hres ;
nfl_ - > vRes = vres ;
}
2013-02-22 19:05:07 +00:00
}
float FontHRes ( ) const { return fontHRes_ ; }
float FontVRes ( ) const { return fontVRes_ ; }
2014-03-01 05:29:41 +00:00
void SetAltCharCode ( int charCode ) {
altCharCode_ = charCode ;
if ( nfl_ . IsValid ( ) )
nfl_ - > altCharCode = charCode ;
}
2013-02-22 19:05:07 +00:00
2014-12-03 20:16:11 +00:00
int GetFontHandle ( int index ) const {
2013-02-22 19:05:07 +00:00
return fonts_ [ index ] ;
}
2021-08-08 00:36:29 +00:00
int GetFontRefCount ( Font * font ) const {
int foundFontIndex = FindExistingIndex ( font ) ;
if ( foundFontIndex > = 0 )
return fontRefCount_ . at ( foundFontIndex ) ;
return 0 ;
}
2014-03-30 19:55:40 +00:00
// For FONT_OPEN_USER* modes, the font will automatically be freed.
2014-02-23 07:04:46 +00:00
LoadedFont * OpenFont ( Font * font , FontOpenMode mode , int & error ) {
// TODO: Do something with mode, possibly save it where the PSP does in the struct.
// Maybe needed in Font, though? Handlers seem... difficult to emulate.
2021-08-08 00:35:37 +00:00
// First, check if the font is already open. We need to refcount, see font/open test.
int foundFontIndex = FindExistingIndex ( font ) ;
if ( foundFontIndex < 0 )
foundFontIndex = FindFreeIndex ( ) ;
2021-08-08 00:44:40 +00:00
if ( foundFontIndex < 0 | | fontRefCount_ [ foundFontIndex ] > = MAX_FONT_REFS ) {
2014-02-23 04:35:58 +00:00
error = ERROR_FONT_TOO_MANY_OPEN_FONTS ;
2021-09-13 15:29:45 +00:00
hleLogError ( SCEFONT , 0 , " Too many fonts opened in FontLib " ) ;
2021-08-08 00:35:37 +00:00
return nullptr ;
2014-02-23 04:35:58 +00:00
}
if ( ! font - > IsValid ( ) ) {
error = ERROR_FONT_INVALID_FONT_DATA ;
2021-09-13 15:29:45 +00:00
hleLogError ( SCEFONT , 0 , " Invalid font data " ) ;
2021-08-08 00:35:37 +00:00
return nullptr ;
2013-02-22 19:05:07 +00:00
}
2014-03-30 19:55:40 +00:00
2021-08-08 00:35:37 +00:00
LoadedFont * loadedFont = nullptr ;
if ( fontRefCount_ [ foundFontIndex ] = = 0 ) {
loadedFont = new LoadedFont ( font , mode , GetListID ( ) , fonts_ [ foundFontIndex ] ) ;
auto prevFont = fontMap . find ( loadedFont - > Handle ( ) ) ;
if ( prevFont ! = fontMap . end ( ) ) {
// Before replacing it and forgetting about it, let's free it.
delete prevFont - > second ;
}
fontMap [ loadedFont - > Handle ( ) ] = loadedFont ;
} else {
loadedFont = fontMap [ fonts_ [ foundFontIndex ] ] ;
2014-03-30 19:55:40 +00:00
}
2021-08-08 00:35:37 +00:00
fontRefCount_ [ foundFontIndex ] + + ;
2020-03-15 15:05:28 +00:00
2021-08-08 00:35:37 +00:00
// Only need to allocate the first time.
if ( ! useAllocCallbacks | | fontRefCount_ [ foundFontIndex ] > 1 )
2020-03-15 23:54:42 +00:00
return loadedFont ;
2020-03-15 15:05:28 +00:00
u32 allocSize = 12 ;
if ( mode = = FONT_OPEN_INTERNAL_STINGY ) {
2020-07-22 15:47:29 +00:00
allocSize = loadedFont - > GetFont ( ) - > getStingySize ( ) ;
2020-03-15 15:05:28 +00:00
} else if ( mode = = FONT_OPEN_INTERNAL_FULL ) {
allocSize + = loadedFont - > GetFont ( ) - > getSize ( ) ;
}
PostOpenAllocCallback * action = ( PostOpenAllocCallback * ) __KernelCreateAction ( actionPostOpenAllocCallback ) ;
action - > SetFontLib ( GetListID ( ) ) ;
2021-08-08 00:35:37 +00:00
action - > SetFont ( loadedFont - > Handle ( ) , foundFontIndex ) ;
2020-03-15 15:05:28 +00:00
2020-03-21 23:09:23 +00:00
u32 args [ 2 ] = { userDataAddr ( ) , allocSize } ;
hleEnqueueCall ( allocFuncAddr ( ) , 2 , args , action ) ;
2020-03-15 15:05:28 +00:00
2013-02-22 19:05:07 +00:00
return loadedFont ;
}
2021-08-08 00:35:37 +00:00
void CloseFont ( LoadedFont * font , bool releaseAll ) {
bool allowClose = true ;
2013-02-22 19:05:07 +00:00
for ( size_t i = 0 ; i < fonts_ . size ( ) ; i + + ) {
2021-08-08 00:35:37 +00:00
if ( fonts_ [ i ] = = font - > Handle ( ) & & fontRefCount_ [ i ] > 0 ) {
if ( releaseAll )
fontRefCount_ [ i ] = 0 ;
else
fontRefCount_ [ i ] - - ;
allowClose = fontRefCount_ [ i ] = = 0 ;
bool deallocate = allowClose & & openAllocatedAddresses_ [ i ] ! = 0 ;
if ( deallocate & & coreState ! = CORE_POWERDOWN ) {
2020-03-15 15:05:28 +00:00
u32 args [ 2 ] = { userDataAddr ( ) , openAllocatedAddresses_ [ i ] } ;
2020-03-21 23:09:23 +00:00
hleEnqueueCall ( freeFuncAddr ( ) , 2 , args ) ;
2020-03-15 15:05:28 +00:00
openAllocatedAddresses_ [ i ] = 0 ;
}
break ;
2013-02-22 19:05:07 +00:00
}
}
2020-03-15 23:46:13 +00:00
flushFont ( ) ;
2021-08-08 00:35:37 +00:00
if ( allowClose )
font - > Close ( ) ;
2013-02-22 19:05:07 +00:00
}
2020-03-15 15:05:28 +00:00
void flushFont ( ) {
2020-03-21 19:36:09 +00:00
if ( charInfoBitmapAddress_ ! = 0 & & coreState ! = CORE_POWERDOWN ) {
2020-03-15 15:05:28 +00:00
u32 args [ 2 ] = { userDataAddr ( ) , charInfoBitmapAddress_ } ;
2020-03-21 23:09:23 +00:00
hleEnqueueCall ( freeFuncAddr ( ) , 2 , args ) ;
2020-03-15 15:05:28 +00:00
charInfoBitmapAddress_ = 0 ;
}
}
2013-02-22 19:05:07 +00:00
void DoState ( PointerWrap & p ) {
2020-03-15 15:05:28 +00:00
auto s = p . Section ( " FontLib " , 1 , 3 ) ;
2013-09-15 03:23:03 +00:00
if ( ! s )
return ;
2020-08-10 04:20:42 +00:00
Do ( p , fonts_ ) ;
2021-08-08 00:35:37 +00:00
Do ( p , fontRefCount_ ) ;
2020-08-10 04:20:42 +00:00
Do ( p , params_ ) ;
Do ( p , fontHRes_ ) ;
Do ( p , fontVRes_ ) ;
Do ( p , fileFontHandle_ ) ;
Do ( p , handle_ ) ;
Do ( p , altCharCode_ ) ;
2014-03-01 05:29:41 +00:00
if ( s > = 2 ) {
2020-08-10 04:20:42 +00:00
Do ( p , nfl_ ) ;
2014-03-01 05:29:41 +00:00
} else {
nfl_ = 0 ;
}
2020-03-15 15:05:28 +00:00
if ( s > = 3 ) {
2020-08-10 04:20:42 +00:00
Do ( p , openAllocatedAddresses_ ) ;
Do ( p , charInfoBitmapAddress_ ) ;
2020-03-15 15:05:28 +00:00
} else {
openAllocatedAddresses_ . resize ( params_ . numFonts ) ;
charInfoBitmapAddress_ = 0 ;
}
2013-02-22 19:05:07 +00:00
}
void SetFileFontHandle ( u32 handle ) {
fileFontHandle_ = handle ;
}
u32 GetAltCharCode ( ) const { return altCharCode_ ; }
2020-03-15 15:05:28 +00:00
u32 GetOpenAllocatedAddress ( int index ) const {
if ( index < numFonts ( ) )
2020-03-16 01:36:23 +00:00
return openAllocatedAddresses_ [ index ] ;
return 0 ;
2020-03-15 15:05:28 +00:00
}
void SetOpenAllocatedAddress ( int index , u32 addr ) {
if ( index < numFonts ( ) )
openAllocatedAddresses_ [ index ] = addr ;
}
u32 GetCharInfoBitmapAddress ( ) const { return charInfoBitmapAddress_ ; }
void SetCharInfoBitmapAddress ( u32 addr ) { charInfoBitmapAddress_ = addr ; }
2013-02-22 19:05:07 +00:00
private :
2021-08-08 00:35:37 +00:00
int FindExistingIndex ( Font * font ) const {
// TODO: Should this also match for memory fonts, or only internal fonts?
for ( auto it : fontMap ) {
if ( it . second - > GetFont ( ) ! = font | | it . second - > GetFontLib ( ) ! = this )
continue ;
for ( size_t i = 0 ; i < fonts_ . size ( ) ; i + + ) {
if ( fonts_ [ i ] = = it . first ) {
return ( int ) i ;
}
}
}
return - 1 ;
}
int FindFreeIndex ( ) const {
for ( size_t i = 0 ; i < fonts_ . size ( ) ; i + + ) {
if ( fontRefCount_ [ i ] = = 0 ) {
return ( int ) i ;
}
}
return - 1 ;
}
2013-02-26 23:59:30 +00:00
std : : vector < u32 > fonts_ ;
2021-08-08 00:35:37 +00:00
std : : vector < u32 > fontRefCount_ ;
2013-02-22 19:05:07 +00:00
FontNewLibParams params_ ;
float fontHRes_ ;
float fontVRes_ ;
int fileFontHandle_ ;
int handle_ ;
int altCharCode_ ;
2020-03-15 15:05:28 +00:00
std : : vector < u32 > openAllocatedAddresses_ ;
u32 charInfoBitmapAddress_ ;
2014-03-01 05:29:41 +00:00
PSPPointer < NativeFontLib > nfl_ ;
2013-03-03 13:29:03 +00:00
2013-02-22 19:05:07 +00:00
DISALLOW_COPY_AND_ASSIGN ( FontLib ) ;
2013-02-12 23:49:49 +00:00
} ;
2012-12-08 19:53:15 +00:00
2013-02-22 19:05:07 +00:00
void PostAllocCallback : : run ( MipsCall & call ) {
2013-09-07 20:02:55 +00:00
INFO_LOG ( SCEFONT , " Entering PostAllocCallback::run " ) ;
2013-05-11 05:06:50 +00:00
u32 v0 = currentMIPS - > r [ MIPS_REG_V0 ] ;
2014-02-22 21:37:45 +00:00
if ( v0 = = 0 ) {
// TODO: Who deletes fontLib?
2020-06-30 02:40:54 +00:00
if ( errorCodePtr_ )
Memory : : Write_U32 ( ERROR_FONT_OUT_OF_MEMORY , errorCodePtr_ ) ;
2014-02-22 21:37:45 +00:00
call . setReturnValue ( 0 ) ;
} else {
FontLib * fontLib = fontLibList [ fontLibID_ ] ;
fontLib - > AllocDone ( v0 ) ;
fontLibMap [ fontLib - > handle ( ) ] = fontLibID_ ;
2020-03-21 23:09:23 +00:00
// This is the same as v0 above.
2014-02-22 21:37:45 +00:00
call . setReturnValue ( fontLib - > handle ( ) ) ;
}
2013-09-07 20:02:55 +00:00
INFO_LOG ( SCEFONT , " Leaving PostAllocCallback::run " ) ;
2013-02-22 19:05:07 +00:00
}
void PostOpenCallback : : run ( MipsCall & call ) {
2013-03-03 23:42:16 +00:00
FontLib * fontLib = fontLibList [ fontLibID_ ] ;
2013-05-11 05:06:50 +00:00
u32 v0 = currentMIPS - > r [ MIPS_REG_V0 ] ;
fontLib - > SetFileFontHandle ( v0 ) ;
2013-02-22 19:05:07 +00:00
}
2020-03-15 15:05:28 +00:00
void PostOpenAllocCallback : : run ( MipsCall & call ) {
FontLib * fontLib = fontLibList [ fontLibID_ ] ;
u32 v0 = currentMIPS - > r [ MIPS_REG_V0 ] ;
fontLib - > SetOpenAllocatedAddress ( fontIndex_ , v0 ) ;
}
void PostCharInfoAllocCallback : : run ( MipsCall & call ) {
FontLib * fontLib = fontLibList [ fontLibID_ ] ;
u32 v0 = currentMIPS - > r [ MIPS_REG_V0 ] ;
if ( v0 = = 0 ) {
call . setReturnValue ( ERROR_FONT_OUT_OF_MEMORY ) ; // From JPCSP, if alloc size is 0, still this error value?
} else {
fontLib - > SetCharInfoBitmapAddress ( v0 ) ;
}
}
void PostCharInfoFreeCallback : : run ( MipsCall & call ) {
FontLib * fontLib = fontLibList [ fontLibID_ ] ;
fontLib - > SetCharInfoBitmapAddress ( 0 ) ;
u32 allocSize = charInfo_ - > bitmapWidth * charInfo_ - > bitmapHeight ;
PostCharInfoAllocCallback * action = ( PostCharInfoAllocCallback * ) __KernelCreateAction ( actionPostCharInfoAllocCallback ) ;
action - > SetFontLib ( fontLibID_ ) ;
u32 args [ 2 ] = { fontLib - > userDataAddr ( ) , allocSize } ;
2020-03-21 23:09:23 +00:00
hleEnqueueCall ( fontLib - > allocFuncAddr ( ) , 2 , args , action ) ;
2020-03-15 15:05:28 +00:00
}
2014-03-01 07:04:34 +00:00
inline bool LoadedFont : : GetCharInfo ( int charCode , PGFCharInfo * charInfo , int glyphType ) const {
auto fontLib = GetFontLib ( ) ;
int altCharCode = fontLib = = NULL ? - 1 : fontLib - > GetAltCharCode ( ) ;
return GetPGF ( ) - > GetCharInfo ( charCode , charInfo , altCharCode , glyphType ) ;
}
inline void LoadedFont : : DrawCharacter ( const GlyphImage * image , int clipX , int clipY , int clipWidth , int clipHeight , int charCode , int glyphType ) const {
auto fontLib = GetFontLib ( ) ;
int altCharCode = fontLib = = NULL ? - 1 : fontLib - > GetAltCharCode ( ) ;
GetPGF ( ) - > DrawCharacter ( image , clipX , clipY , clipWidth , clipHeight , charCode , altCharCode , glyphType ) ;
}
2014-12-08 09:40:08 +00:00
static FontLib * GetFontLib ( u32 handle ) {
2013-02-22 19:05:07 +00:00
if ( fontLibMap . find ( handle ) ! = fontLibMap . end ( ) ) {
2013-03-03 23:42:16 +00:00
return fontLibList [ fontLibMap [ handle ] ] ;
2013-02-22 19:05:07 +00:00
}
2021-09-13 15:29:45 +00:00
return nullptr ;
2013-02-22 19:05:07 +00:00
}
2014-12-08 09:40:08 +00:00
static LoadedFont * GetLoadedFont ( u32 handle , bool allowClosed ) {
2013-02-22 19:05:07 +00:00
auto iter = fontMap . find ( handle ) ;
if ( iter ! = fontMap . end ( ) ) {
if ( iter - > second - > IsOpen ( ) | | allowClosed ) {
return fontMap [ handle ] ;
} else {
2013-09-07 20:02:55 +00:00
ERROR_LOG ( SCEFONT , " Font exists but is closed, which was not allowed in this call. " ) ;
2013-02-22 19:05:07 +00:00
return 0 ;
}
} else {
2013-09-07 20:02:55 +00:00
ERROR_LOG ( SCEFONT , " No font with handle %08x " , handle ) ;
2013-02-22 19:05:07 +00:00
return 0 ;
}
}
2014-12-08 09:40:08 +00:00
static void __LoadInternalFonts ( ) {
2013-03-06 21:24:30 +00:00
if ( internalFonts . size ( ) ) {
// Fonts already loaded.
return ;
}
2013-10-12 23:13:11 +00:00
const std : : string fontPath = " flash0:/font/ " ;
const std : : string fontOverridePath = " ms0:/PSP/flash0/font/ " ;
2014-02-12 09:49:02 +00:00
const std : : string userfontPath = " disc0:/PSP_GAME/USRDIR/ " ;
2013-02-28 14:36:57 +00:00
if ( ! pspFileSystem . GetFileInfo ( fontPath ) . exists ) {
pspFileSystem . MkDir ( fontPath ) ;
}
2016-08-05 22:52:48 +00:00
if ( ( pspFileSystem . GetFileInfo ( " disc0:/PSP_GAME/USRDIR/zh_gb.pgf " ) . exists ) & & ( pspFileSystem . GetFileInfo ( " disc0:/PSP_GAME/USRDIR/oldfont.prx " ) . exists ) ) {
2016-08-05 11:58:31 +00:00
for ( size_t i = 0 ; i < ARRAY_SIZE ( fontRegistry ) ; i + + ) {
const FontRegistryEntry & entry = fontRegistry [ i ] ;
std : : string fontFilename = userfontPath + entry . fileName ;
PSPFileInfo info = pspFileSystem . GetFileInfo ( fontFilename ) ;
DEBUG_LOG ( SCEFONT , " Loading internal font %s (%i bytes) " , fontFilename . c_str ( ) , ( int ) info . size ) ;
std : : vector < u8 > buffer ;
if ( pspFileSystem . ReadEntireFile ( fontFilename , buffer ) < 0 ) {
ERROR_LOG ( SCEFONT , " Failed opening font " ) ;
continue ;
}
internalFonts . push_back ( new Font ( buffer , entry ) ) ;
DEBUG_LOG ( SCEFONT , " Loaded font %s " , fontFilename . c_str ( ) ) ;
return ;
}
}
2013-02-22 19:05:07 +00:00
for ( size_t i = 0 ; i < ARRAY_SIZE ( fontRegistry ) ; i + + ) {
const FontRegistryEntry & entry = fontRegistry [ i ] ;
2016-08-05 11:58:31 +00:00
std : : string fontFilename = userfontPath + entry . fileName ;
2013-02-22 19:05:07 +00:00
PSPFileInfo info = pspFileSystem . GetFileInfo ( fontFilename ) ;
2013-10-12 23:13:11 +00:00
if ( ! info . exists ) {
2014-02-12 09:49:02 +00:00
// No user font, let's try override path.
fontFilename = fontOverridePath + entry . fileName ;
info = pspFileSystem . GetFileInfo ( fontFilename ) ;
}
if ( ! info . exists ) {
// No override, let's use the default path.
2013-10-12 23:13:11 +00:00
fontFilename = fontPath + entry . fileName ;
info = pspFileSystem . GetFileInfo ( fontFilename ) ;
}
2013-02-22 19:05:07 +00:00
if ( info . exists ) {
2014-06-09 17:40:05 +00:00
DEBUG_LOG ( SCEFONT , " Loading internal font %s (%i bytes) " , fontFilename . c_str ( ) , ( int ) info . size ) ;
2013-12-08 20:02:37 +00:00
std : : vector < u8 > buffer ;
if ( pspFileSystem . ReadEntireFile ( fontFilename , buffer ) < 0 ) {
2013-09-07 20:02:55 +00:00
ERROR_LOG ( SCEFONT , " Failed opening font " ) ;
2013-02-26 23:59:30 +00:00
continue ;
}
2013-02-22 19:05:07 +00:00
2013-12-08 20:02:37 +00:00
internalFonts . push_back ( new Font ( buffer , entry ) ) ;
2013-02-22 19:05:07 +00:00
2013-12-08 20:02:37 +00:00
DEBUG_LOG ( SCEFONT , " Loaded font %s " , fontFilename . c_str ( ) ) ;
2016-08-07 17:27:27 +00:00
} else if ( ! entry . ignoreIfMissing ) {
2013-12-08 20:02:37 +00:00
WARN_LOG ( SCEFONT , " Font file not found: %s " , fontFilename . c_str ( ) ) ;
2013-02-22 19:05:07 +00:00
}
}
}
int GetInternalFontIndex ( Font * font ) {
for ( size_t i = 0 ; i < internalFonts . size ( ) ; i + + ) {
if ( internalFonts [ i ] = = font )
2013-04-06 03:29:20 +00:00
return ( int ) i ;
2013-02-22 19:05:07 +00:00
}
2013-03-03 23:57:05 +00:00
return - 1 ;
2013-02-22 19:05:07 +00:00
}
void __FontInit ( ) {
2020-03-16 02:54:46 +00:00
useAllocCallbacks = true ;
2013-02-22 19:05:07 +00:00
actionPostAllocCallback = __KernelRegisterActionType ( PostAllocCallback : : Create ) ;
actionPostOpenCallback = __KernelRegisterActionType ( PostOpenCallback : : Create ) ;
2020-03-15 15:05:28 +00:00
actionPostOpenAllocCallback = __KernelRegisterActionType ( PostOpenAllocCallback : : Create ) ;
actionPostCharInfoAllocCallback = __KernelRegisterActionType ( PostCharInfoAllocCallback : : Create ) ;
actionPostCharInfoFreeCallback = __KernelRegisterActionType ( PostCharInfoFreeCallback : : Create ) ;
2013-02-22 19:05:07 +00:00
}
void __FontShutdown ( ) {
for ( auto iter = fontMap . begin ( ) ; iter ! = fontMap . end ( ) ; iter + + ) {
2013-02-28 16:33:30 +00:00
FontLib * fontLib = iter - > second - > GetFontLib ( ) ;
if ( fontLib )
2021-08-08 00:35:37 +00:00
fontLib - > CloseFont ( iter - > second , true ) ;
2014-03-30 19:55:40 +00:00
delete iter - > second ;
2013-02-22 19:05:07 +00:00
}
fontMap . clear ( ) ;
2013-03-03 23:42:16 +00:00
for ( auto iter = fontLibList . begin ( ) ; iter ! = fontLibList . end ( ) ; iter + + ) {
delete * iter ;
2013-02-22 19:05:07 +00:00
}
2013-03-03 23:42:16 +00:00
fontLibList . clear ( ) ;
2013-02-22 19:05:07 +00:00
fontLibMap . clear ( ) ;
for ( auto iter = internalFonts . begin ( ) ; iter ! = internalFonts . end ( ) ; + + iter ) {
delete * iter ;
}
internalFonts . clear ( ) ;
2012-12-28 07:00:04 +00:00
}
2013-02-22 19:05:07 +00:00
void __FontDoState ( PointerWrap & p ) {
2020-03-15 23:54:42 +00:00
auto s = p . Section ( " sceFont " , 1 , 2 ) ;
2013-09-15 03:23:03 +00:00
if ( ! s )
return ;
2013-03-06 22:42:55 +00:00
__LoadInternalFonts ( ) ;
2020-08-10 04:20:42 +00:00
Do ( p , fontLibList ) ;
Do ( p , fontLibMap ) ;
Do ( p , fontMap ) ;
2013-02-22 19:05:07 +00:00
2020-08-10 04:20:42 +00:00
Do ( p , actionPostAllocCallback ) ;
2013-02-22 19:05:07 +00:00
__KernelRestoreActionType ( actionPostAllocCallback , PostAllocCallback : : Create ) ;
2020-08-10 04:20:42 +00:00
Do ( p , actionPostOpenCallback ) ;
2020-03-21 23:09:23 +00:00
__KernelRestoreActionType ( actionPostOpenCallback , PostOpenCallback : : Create ) ;
2020-03-15 23:54:42 +00:00
if ( s > = 2 ) {
2020-08-10 04:20:42 +00:00
Do ( p , actionPostOpenAllocCallback ) ;
2020-03-15 23:54:42 +00:00
__KernelRestoreActionType ( actionPostOpenAllocCallback , PostOpenAllocCallback : : Create ) ;
2020-08-10 04:20:42 +00:00
Do ( p , actionPostCharInfoAllocCallback ) ;
2020-03-15 23:54:42 +00:00
__KernelRestoreActionType ( actionPostCharInfoAllocCallback , PostCharInfoAllocCallback : : Create ) ;
2020-08-10 04:20:42 +00:00
Do ( p , actionPostCharInfoFreeCallback ) ;
2020-03-15 23:54:42 +00:00
__KernelRestoreActionType ( actionPostCharInfoFreeCallback , PostCharInfoFreeCallback : : Create ) ;
} else {
useAllocCallbacks = false ;
}
2012-12-28 07:00:04 +00:00
}
2014-12-08 09:40:08 +00:00
static u32 sceFontNewLib ( u32 paramPtr , u32 errorCodePtr ) {
2013-03-06 21:24:30 +00:00
// Lazy load internal fonts, only when font library first inited.
__LoadInternalFonts ( ) ;
2012-12-08 19:53:15 +00:00
2014-02-22 20:48:54 +00:00
auto params = PSPPointer < FontNewLibParams > : : Create ( paramPtr ) ;
2021-02-19 06:25:24 +00:00
auto errorCode = PSPPointer < s32_le > : : Create ( errorCodePtr ) ;
2014-02-22 20:48:54 +00:00
if ( ! params . IsValid ( ) | | ! errorCode . IsValid ( ) ) {
ERROR_LOG_REPORT ( SCEFONT , " sceFontNewLib(%08x, %08x): invalid addresses " , paramPtr , errorCodePtr ) ;
// The PSP would crash in this situation, not a real error code.
return SCE_KERNEL_ERROR_ILLEGAL_ADDR ;
}
if ( ! Memory : : IsValidAddress ( params - > allocFuncAddr ) | | ! Memory : : IsValidAddress ( params - > freeFuncAddr ) ) {
ERROR_LOG_REPORT ( SCEFONT , " sceFontNewLib(%08x, %08x): missing alloc func " , paramPtr , errorCodePtr ) ;
* errorCode = ERROR_FONT_INVALID_PARAMETER ;
return 0 ;
2012-12-08 19:53:15 +00:00
}
2014-02-22 20:48:54 +00:00
INFO_LOG ( SCEFONT , " sceFontNewLib(%08x, %08x) " , paramPtr , errorCodePtr ) ;
* errorCode = 0 ;
2014-02-22 21:37:45 +00:00
FontLib * newLib = new FontLib ( paramPtr , errorCodePtr ) ;
2014-02-22 20:48:54 +00:00
fontLibList . push_back ( newLib ) ;
// The game should never see this value, the return value is replaced
// by the action. Except if we disable the alloc, in this case we return
// the handle correctly here.
2014-09-27 06:44:04 +00:00
return hleDelayResult ( newLib - > handle ( ) , " new fontlib " , 30000 ) ;
2012-12-08 19:53:15 +00:00
}
2014-12-08 09:40:08 +00:00
static int sceFontDoneLib ( u32 fontLibHandle ) {
2013-02-22 19:05:07 +00:00
FontLib * fl = GetFontLib ( fontLibHandle ) ;
if ( fl ) {
fl - > Done ( ) ;
2021-09-13 15:29:45 +00:00
return hleLogSuccessInfoI ( SCEFONT , 0 ) ;
2013-02-22 19:05:07 +00:00
}
2021-09-13 15:29:45 +00:00
return hleLogWarning ( SCEFONT , 0 , " invalid font lib " ) ;
2012-12-08 19:53:15 +00:00
}
2013-02-22 19:05:07 +00:00
// Open internal font into a FontLib
2014-12-08 09:40:08 +00:00
static u32 sceFontOpen ( u32 libHandle , u32 index , u32 mode , u32 errorCodePtr ) {
2021-02-19 06:25:24 +00:00
auto errorCode = PSPPointer < s32_le > : : Create ( errorCodePtr ) ;
2014-02-23 04:35:58 +00:00
if ( ! errorCode . IsValid ( ) ) {
2013-05-06 04:29:41 +00:00
// Would crash on the PSP.
2021-09-13 15:29:45 +00:00
return hleLogError ( SCEFONT , - 1 , " invalid error address " ) ;
2013-02-22 19:05:07 +00:00
}
2012-12-08 19:53:15 +00:00
2013-02-22 19:05:07 +00:00
FontLib * fontLib = GetFontLib ( libHandle ) ;
2021-09-13 15:29:45 +00:00
if ( ! fontLib ) {
2014-02-23 04:35:58 +00:00
* errorCode = ERROR_FONT_INVALID_LIBID ;
2021-09-13 15:29:45 +00:00
return hleLogDebug ( SCEFONT , 0 , " invalid font lib " ) ;
2013-05-06 04:29:41 +00:00
}
2013-03-02 21:50:38 +00:00
if ( index > = internalFonts . size ( ) ) {
2014-02-23 04:35:58 +00:00
* errorCode = ERROR_FONT_INVALID_PARAMETER ;
2021-09-13 15:29:45 +00:00
return hleLogDebug ( SCEFONT , 0 , " invalid font index " ) ;
2013-02-22 19:05:07 +00:00
}
2021-08-08 00:54:39 +00:00
FontOpenMode openMode = mode ! = 1 ? FONT_OPEN_INTERNAL_STINGY : FONT_OPEN_INTERNAL_FULL ;
2014-02-23 07:04:46 +00:00
LoadedFont * font = fontLib - > OpenFont ( internalFonts [ index ] , openMode , * errorCode ) ;
2013-02-22 19:05:07 +00:00
if ( font ) {
2014-02-23 04:35:58 +00:00
* errorCode = 0 ;
2021-08-08 00:36:29 +00:00
// Delay only on the first open.
if ( fontLib - > GetFontRefCount ( internalFonts [ index ] ) = = 1 )
2021-09-13 15:29:45 +00:00
return hleDelayResult ( hleLogSuccessX ( SCEFONT , font - > Handle ( ) ) , " font open " , 10000 ) ;
return hleLogSuccessX ( SCEFONT , font - > Handle ( ) ) ;
2012-12-08 19:53:15 +00:00
}
2021-08-08 00:36:29 +00:00
return 0 ;
2012-12-08 19:53:15 +00:00
}
2013-02-22 19:05:07 +00:00
// Open a user font in RAM into a FontLib
2021-09-13 15:29:45 +00:00
static u32 sceFontOpenUserMemory ( u32 libHandle , u32 memoryFontPtr , u32 memoryFontLength , u32 errorCodePtr ) {
2021-02-19 06:25:24 +00:00
auto errorCode = PSPPointer < s32_le > : : Create ( errorCodePtr ) ;
2014-02-23 04:35:58 +00:00
if ( ! errorCode . IsValid ( ) ) {
2021-09-13 15:29:45 +00:00
return hleReportError ( SCEFONT , - 1 , " invalid error address " ) ;
2014-02-23 04:35:58 +00:00
}
2021-09-13 15:29:45 +00:00
if ( ! Memory : : IsValidAddress ( memoryFontPtr ) ) {
2014-02-23 04:35:58 +00:00
* errorCode = ERROR_FONT_INVALID_PARAMETER ;
2021-09-13 15:29:45 +00:00
return hleReportError ( SCEFONT , 0 , " invalid address " ) ;
2013-02-22 19:05:07 +00:00
}
FontLib * fontLib = GetFontLib ( libHandle ) ;
if ( ! fontLib ) {
2014-09-27 06:44:36 +00:00
* errorCode = ERROR_FONT_INVALID_LIBID ;
2021-09-13 15:29:45 +00:00
return hleReportError ( SCEFONT , 0 , " invalid font lib " ) ;
2014-09-27 06:44:36 +00:00
}
if ( memoryFontLength = = 0 ) {
2014-02-23 04:35:58 +00:00
* errorCode = ERROR_FONT_INVALID_PARAMETER ;
2021-09-13 15:29:45 +00:00
return hleReportError ( SCEFONT , 0 , " invalid size " ) ;
2013-02-22 19:05:07 +00:00
}
2021-09-13 15:29:45 +00:00
const u8 * fontData = Memory : : GetPointer ( memoryFontPtr ) ;
2014-03-30 02:38:54 +00:00
// Games are able to overstate the size of a font. Let's avoid crashing when we memcpy() it.
// Unsigned 0xFFFFFFFF is treated as max, but that's impossible, so let's clamp to 64MB.
if ( memoryFontLength > 0x03FFFFFF )
memoryFontLength = 0x03FFFFFF ;
2021-09-13 15:29:45 +00:00
while ( ! Memory : : IsValidAddress ( memoryFontPtr + memoryFontLength - 1 ) ) {
2014-03-30 02:38:54 +00:00
- - memoryFontLength ;
}
2014-02-23 04:35:58 +00:00
Font * f = new Font ( fontData , memoryFontLength ) ;
2014-02-23 07:04:46 +00:00
LoadedFont * font = fontLib - > OpenFont ( f , FONT_OPEN_USERBUFFER , * errorCode ) ;
2013-02-22 19:05:07 +00:00
if ( font ) {
2014-02-23 04:35:58 +00:00
* errorCode = 0 ;
2021-09-13 15:29:45 +00:00
return hleLogSuccessX ( SCEFONT , font - > Handle ( ) ) ;
2012-12-12 16:40:53 +00:00
}
2021-09-13 15:29:45 +00:00
delete f ;
return 0 ;
2012-12-08 19:53:15 +00:00
}
2013-02-22 19:05:07 +00:00
// Open a user font in a file into a FontLib
2014-12-08 09:40:08 +00:00
static u32 sceFontOpenUserFile ( u32 libHandle , const char * fileName , u32 mode , u32 errorCodePtr ) {
2021-02-19 06:25:24 +00:00
auto errorCode = PSPPointer < s32_le > : : Create ( errorCodePtr ) ;
2014-02-23 04:35:58 +00:00
if ( ! errorCode . IsValid ( ) ) {
2021-09-13 15:29:45 +00:00
return hleReportError ( SCEFONT , ERROR_FONT_INVALID_PARAMETER , " invalid error address " ) ;
2014-02-23 04:35:58 +00:00
}
2013-02-22 19:05:07 +00:00
2021-09-13 15:29:45 +00:00
if ( ! fileName ) {
2014-02-23 04:35:58 +00:00
* errorCode = ERROR_FONT_INVALID_PARAMETER ;
2021-09-13 15:29:45 +00:00
return hleReportError ( SCEFONT , 0 , " invalid filename " ) ;
2013-02-22 19:05:07 +00:00
}
FontLib * fontLib = GetFontLib ( libHandle ) ;
if ( ! fontLib ) {
2014-02-23 04:35:58 +00:00
* errorCode = ERROR_FONT_INVALID_LIBID ;
2021-09-13 15:29:45 +00:00
return hleReportError ( SCEFONT , 0 , " invalid font lib " ) ;
2013-02-22 19:05:07 +00:00
}
2014-02-23 04:35:58 +00:00
// TODO: Technically, we only do this if mode = 1. Mode 0 uses the handlers.
if ( mode ! = 1 ) {
WARN_LOG_REPORT ( SCEFONT , " Loading file directly instead of using handlers: %s " , fileName ) ;
}
2021-09-13 15:29:45 +00:00
std : : vector < u8 > buffer ;
if ( pspFileSystem . ReadEntireFile ( fileName , buffer ) ! = 0 ) {
2014-02-23 04:35:58 +00:00
* errorCode = ERROR_FONT_HANDLER_OPEN_FAILED ;
2021-09-13 15:29:45 +00:00
return hleLogError ( SCEFONT , 0 , " file does not exist " ) ;
2014-02-23 04:35:58 +00:00
}
Font * f = new Font ( buffer ) ;
2014-02-23 07:04:46 +00:00
FontOpenMode openMode = mode = = 0 ? FONT_OPEN_USERFILE_HANDLERS : FONT_OPEN_USERFILE_FULL ;
LoadedFont * font = fontLib - > OpenFont ( f , openMode , * errorCode ) ;
2013-02-22 19:05:07 +00:00
if ( font ) {
2014-02-23 04:35:58 +00:00
* errorCode = 0 ;
2021-09-13 15:29:45 +00:00
return hleLogSuccessInfoX ( SCEFONT , font - > Handle ( ) ) ;
2012-12-12 16:40:53 +00:00
}
2021-09-13 15:29:45 +00:00
delete f ;
// Message was already logged.
return 0 ;
2012-12-08 19:53:15 +00:00
}
2014-12-08 09:40:08 +00:00
static int sceFontClose ( u32 fontHandle ) {
2013-02-22 19:05:07 +00:00
LoadedFont * font = GetLoadedFont ( fontHandle , false ) ;
2020-03-15 15:05:28 +00:00
if ( font ) {
2014-03-16 00:23:08 +00:00
DEBUG_LOG ( SCEFONT , " sceFontClose(%x) " , fontHandle ) ;
2013-02-28 16:03:52 +00:00
FontLib * fontLib = font - > GetFontLib ( ) ;
2020-03-18 08:58:07 +00:00
if ( fontLib ) {
2021-08-08 00:35:37 +00:00
fontLib - > CloseFont ( font , false ) ;
2020-03-18 08:58:07 +00:00
}
2020-03-15 15:05:28 +00:00
} else
2013-09-07 20:02:55 +00:00
ERROR_LOG ( SCEFONT , " sceFontClose(%x) - font not open? " , fontHandle ) ;
2012-12-08 19:53:15 +00:00
return 0 ;
}
2014-12-08 09:40:08 +00:00
static int sceFontFindOptimumFont ( u32 libHandle , u32 fontStylePtr , u32 errorCodePtr ) {
2021-02-19 06:25:24 +00:00
auto errorCode = PSPPointer < s32_le > : : Create ( errorCodePtr ) ;
2014-02-25 07:42:22 +00:00
if ( ! errorCode . IsValid ( ) ) {
2014-02-25 08:43:24 +00:00
ERROR_LOG_REPORT ( SCEFONT , " sceFontFindOptimumFont(%08x, %08x, %08x): invalid error address " , libHandle , fontStylePtr , errorCodePtr ) ;
2014-02-25 07:42:22 +00:00
return SCE_KERNEL_ERROR_INVALID_ARGUMENT ;
}
FontLib * fontLib = GetFontLib ( libHandle ) ;
if ( ! fontLib ) {
ERROR_LOG_REPORT ( SCEFONT , " sceFontFindOptimumFont(%08x, %08x, %08x): invalid font lib " , libHandle , fontStylePtr , errorCodePtr ) ;
* errorCode = ERROR_FONT_INVALID_LIBID ;
return 0 ;
}
if ( ! Memory : : IsValidAddress ( fontStylePtr ) ) {
ERROR_LOG_REPORT ( SCEFONT , " sceFontFindOptimumFont(%08x, %08x, %08x): invalid style address " , libHandle , fontStylePtr , errorCodePtr ) ;
// Yes, actually. Must've been a typo in the library.
* errorCode = ERROR_FONT_INVALID_LIBID ;
2013-02-22 19:05:07 +00:00
return 0 ;
2014-02-25 07:42:22 +00:00
}
2014-03-16 00:23:08 +00:00
DEBUG_LOG ( SCEFONT , " sceFontFindOptimumFont(%08x, %08x, %08x) " , libHandle , fontStylePtr , errorCodePtr ) ;
2013-02-22 19:05:07 +00:00
2014-02-27 08:28:57 +00:00
auto requestedStyle = PSPPointer < const PGFFontStyle > : : Create ( fontStylePtr ) ;
2013-02-22 19:05:07 +00:00
2014-02-25 16:16:10 +00:00
// Find the first nearest match for H/V, OR the last exact match for others.
2021-02-19 06:25:24 +00:00
float hRes = requestedStyle - > fontHRes > 0.0f ? ( float ) requestedStyle - > fontHRes : fontLib - > FontHRes ( ) ;
float vRes = requestedStyle - > fontVRes > 0.0f ? ( float ) requestedStyle - > fontVRes : fontLib - > FontVRes ( ) ;
2013-02-22 19:05:07 +00:00
Font * optimumFont = 0 ;
2014-03-01 10:17:11 +00:00
Font * nearestFont = 0 ;
2014-02-25 16:16:10 +00:00
float nearestDist = std : : numeric_limits < float > : : infinity ( ) ;
2013-02-22 19:05:07 +00:00
for ( size_t i = 0 ; i < internalFonts . size ( ) ; i + + ) {
2014-03-01 10:17:11 +00:00
MatchQuality q = internalFonts [ i ] - > MatchesStyle ( * requestedStyle ) ;
2013-05-05 19:34:28 +00:00
if ( q ! = MATCH_NONE ) {
2014-02-25 16:16:10 +00:00
auto matchStyle = internalFonts [ i ] - > GetFontStyle ( ) ;
if ( requestedStyle - > fontH > 0.0f ) {
2015-03-29 03:46:37 +00:00
float hDist = fabs ( matchStyle . fontHRes * matchStyle . fontH - hRes * requestedStyle - > fontH ) ;
2014-02-25 16:16:10 +00:00
if ( hDist < nearestDist ) {
nearestDist = hDist ;
2014-03-01 10:17:11 +00:00
nearestFont = internalFonts [ i ] ;
2014-02-25 16:16:10 +00:00
}
}
if ( requestedStyle - > fontV > 0.0f ) {
// Appears to be a bug? It seems to match H instead of V.
2015-03-29 03:46:37 +00:00
float vDist = fabs ( matchStyle . fontVRes * matchStyle . fontV - vRes * requestedStyle - > fontH ) ;
2014-02-25 16:16:10 +00:00
if ( vDist < nearestDist ) {
nearestDist = vDist ;
2014-03-01 10:17:11 +00:00
nearestFont = internalFonts [ i ] ;
2014-02-25 16:16:10 +00:00
}
2013-05-05 19:34:28 +00:00
}
2013-02-22 19:05:07 +00:00
}
2014-02-25 16:16:10 +00:00
if ( q = = MATCH_GOOD ) {
optimumFont = internalFonts [ i ] ;
}
2013-02-22 19:05:07 +00:00
}
2014-03-01 10:17:11 +00:00
if ( nearestFont ) {
optimumFont = nearestFont ;
}
2013-02-22 19:05:07 +00:00
if ( optimumFont ) {
2014-02-25 07:42:22 +00:00
* errorCode = 0 ;
2013-02-22 19:05:07 +00:00
return GetInternalFontIndex ( optimumFont ) ;
} else {
2014-02-25 07:42:22 +00:00
* errorCode = 0 ;
2013-02-22 19:05:07 +00:00
return 0 ;
2012-12-08 19:53:15 +00:00
}
}
2013-02-22 19:05:07 +00:00
// Returns the font index, not handle
2014-12-08 09:40:08 +00:00
static int sceFontFindFont ( u32 libHandle , u32 fontStylePtr , u32 errorCodePtr ) {
2021-02-19 06:25:24 +00:00
auto errorCode = PSPPointer < s32_le > : : Create ( errorCodePtr ) ;
2014-02-25 08:43:24 +00:00
if ( ! errorCode . IsValid ( ) ) {
ERROR_LOG_REPORT ( SCEFONT , " sceFontFindFont(%x, %x, %x): invalid error address " , libHandle , fontStylePtr , errorCodePtr ) ;
return SCE_KERNEL_ERROR_INVALID_ARGUMENT ;
}
FontLib * fontLib = GetFontLib ( libHandle ) ;
if ( ! fontLib ) {
ERROR_LOG_REPORT ( SCEFONT , " sceFontFindFont(%08x, %08x, %08x): invalid font lib " , libHandle , fontStylePtr , errorCodePtr ) ;
* errorCode = ERROR_FONT_INVALID_LIBID ;
2013-02-22 19:05:07 +00:00
return 0 ;
}
2014-02-25 08:43:24 +00:00
if ( ! Memory : : IsValidAddress ( fontStylePtr ) ) {
ERROR_LOG_REPORT ( SCEFONT , " sceFontFindFont(%08x, %08x, %08x): invalid style address " , libHandle , fontStylePtr , errorCodePtr ) ;
* errorCode = ERROR_FONT_INVALID_PARAMETER ;
return 0 ;
}
2014-03-16 00:23:08 +00:00
DEBUG_LOG ( SCEFONT , " sceFontFindFont(%x, %x, %x) " , libHandle , fontStylePtr , errorCodePtr ) ;
2014-02-25 08:43:24 +00:00
2014-02-27 08:28:57 +00:00
auto requestedStyle = PSPPointer < const PGFFontStyle > : : Create ( fontStylePtr ) ;
2013-02-22 19:05:07 +00:00
2014-02-25 16:16:10 +00:00
// Find the closest exact match for the fields specified.
2021-02-19 06:25:24 +00:00
float hRes = requestedStyle - > fontHRes > 0.0f ? ( float ) requestedStyle - > fontHRes : fontLib - > FontHRes ( ) ;
2013-02-22 19:05:07 +00:00
for ( size_t i = 0 ; i < internalFonts . size ( ) ; i + + ) {
2014-03-01 10:17:11 +00:00
if ( internalFonts [ i ] - > MatchesStyle ( * requestedStyle ) ! = MATCH_NONE ) {
2014-02-25 16:16:10 +00:00
auto matchStyle = internalFonts [ i ] - > GetFontStyle ( ) ;
if ( requestedStyle - > fontH > 0.0f ) {
2015-03-29 03:46:37 +00:00
float hDist = fabs ( matchStyle . fontHRes * matchStyle . fontH - hRes * requestedStyle - > fontH ) ;
2014-02-25 16:16:10 +00:00
if ( hDist > 0.001f ) {
continue ;
}
} else if ( requestedStyle - > fontV > 0.0f ) {
// V seems to be ignored, unless H isn't specified.
// If V is specified alone, the match always fails.
continue ;
}
2014-02-25 08:43:24 +00:00
* errorCode = 0 ;
2013-04-06 03:29:20 +00:00
return ( int ) i ;
2013-02-22 19:05:07 +00:00
}
}
2014-02-25 08:43:24 +00:00
* errorCode = 0 ;
2013-02-22 19:05:07 +00:00
return - 1 ;
2012-12-08 19:53:15 +00:00
}
2014-12-08 09:40:08 +00:00
static int sceFontGetFontInfo ( u32 fontHandle , u32 fontInfoPtr ) {
2013-05-06 03:58:52 +00:00
if ( ! Memory : : IsValidAddress ( fontInfoPtr ) ) {
2013-09-07 20:02:55 +00:00
ERROR_LOG ( SCEFONT , " sceFontGetFontInfo(%x, %x): bad fontInfo pointer " , fontHandle , fontInfoPtr ) ;
2013-05-06 03:58:52 +00:00
return ERROR_FONT_INVALID_PARAMETER ;
}
2013-02-28 15:04:40 +00:00
LoadedFont * font = GetLoadedFont ( fontHandle , true ) ;
2013-05-06 03:58:52 +00:00
if ( ! font ) {
2013-09-07 20:02:55 +00:00
ERROR_LOG_REPORT ( SCEFONT , " sceFontGetFontInfo(%x, %x): bad font " , fontHandle , fontInfoPtr ) ;
2013-05-06 03:58:52 +00:00
return ERROR_FONT_INVALID_PARAMETER ;
}
2013-09-07 20:02:55 +00:00
DEBUG_LOG ( SCEFONT , " sceFontGetFontInfo(%x, %x) " , fontHandle , fontInfoPtr ) ;
2014-02-27 08:28:57 +00:00
auto fi = PSPPointer < PGFFontInfo > : : Create ( fontInfoPtr ) ;
2013-05-06 04:02:13 +00:00
font - > GetPGF ( ) - > GetFontInfo ( fi ) ;
2013-05-06 03:58:52 +00:00
fi - > fontStyle = font - > GetFont ( ) - > GetFontStyle ( ) ;
2012-12-09 20:37:33 +00:00
2012-12-08 19:53:15 +00:00
return 0 ;
}
2014-03-01 09:30:43 +00:00
// It says FontInfo but it means Style - this is like sceFontGetFontList().
2014-12-08 09:40:08 +00:00
static int sceFontGetFontInfoByIndexNumber ( u32 libHandle , u32 fontInfoPtr , u32 index ) {
2014-03-01 09:30:43 +00:00
auto fontStyle = PSPPointer < PGFFontStyle > : : Create ( fontInfoPtr ) ;
2013-02-22 19:05:07 +00:00
FontLib * fl = GetFontLib ( libHandle ) ;
2014-03-01 09:30:43 +00:00
if ( ! fl | | fl - > handle ( ) = = 0 ) {
2014-03-01 09:47:35 +00:00
ERROR_LOG_REPORT ( SCEFONT , " sceFontGetFontInfoByIndexNumber(%08x, %08x, %i): invalid font lib " , libHandle , fontInfoPtr , index ) ;
2014-03-01 09:30:43 +00:00
return ! fl ? ERROR_FONT_INVALID_LIBID : ERROR_FONT_INVALID_PARAMETER ;
}
if ( index > = internalFonts . size ( ) ) {
2014-03-01 09:47:35 +00:00
ERROR_LOG_REPORT ( SCEFONT , " sceFontGetFontInfoByIndexNumber(%08x, %08x, %i): invalid font index " , libHandle , fontInfoPtr , index ) ;
2014-03-01 09:30:43 +00:00
return ERROR_FONT_INVALID_PARAMETER ;
}
if ( ! fontStyle . IsValid ( ) ) {
2014-03-01 09:47:35 +00:00
ERROR_LOG_REPORT ( SCEFONT , " sceFontGetFontInfoByIndexNumber(%08x, %08x, %i): invalid info pointer " , libHandle , fontInfoPtr , index ) ;
2014-03-01 09:30:43 +00:00
return ERROR_FONT_INVALID_PARAMETER ;
}
2014-03-01 09:47:35 +00:00
DEBUG_LOG ( SCEFONT , " sceFontGetFontInfoByIndexNumber(%08x, %08x, %i) " , libHandle , fontInfoPtr , index ) ;
2014-03-01 09:30:43 +00:00
auto font = internalFonts [ index ] ;
* fontStyle = font - > GetFontStyle ( ) ;
return 0 ;
2013-02-22 19:05:07 +00:00
}
2012-12-09 20:37:33 +00:00
2014-12-08 09:40:08 +00:00
static int sceFontGetCharInfo ( u32 fontHandle , u32 charCode , u32 charInfoPtr ) {
2015-11-01 13:11:31 +00:00
charCode & = 0xffff ;
2013-05-06 03:58:52 +00:00
if ( ! Memory : : IsValidAddress ( charInfoPtr ) ) {
2013-09-07 20:02:55 +00:00
ERROR_LOG ( SCEFONT , " sceFontGetCharInfo(%08x, %i, %08x): bad charInfo pointer " , fontHandle , charCode , charInfoPtr ) ;
2013-05-06 03:58:52 +00:00
return ERROR_FONT_INVALID_PARAMETER ;
}
2014-02-23 19:48:31 +00:00
LoadedFont * font = GetLoadedFont ( fontHandle , true ) ;
2013-05-06 03:58:52 +00:00
if ( ! font ) {
// The PSP crashes, but we assume it'd work like sceFontGetFontInfo(), and not touch charInfo.
2013-09-07 20:02:55 +00:00
ERROR_LOG_REPORT ( SCEFONT , " sceFontGetCharInfo(%08x, %i, %08x): bad font " , fontHandle , charCode , charInfoPtr ) ;
2013-05-06 03:58:52 +00:00
return ERROR_FONT_INVALID_PARAMETER ;
2013-02-22 19:05:07 +00:00
}
2013-05-06 03:58:52 +00:00
2013-09-07 20:02:55 +00:00
DEBUG_LOG ( SCEFONT , " sceFontGetCharInfo(%08x, %i, %08x) " , fontHandle , charCode , charInfoPtr ) ;
2014-02-27 08:28:57 +00:00
auto charInfo = PSPPointer < PGFCharInfo > : : Create ( charInfoPtr ) ;
2014-03-01 07:04:34 +00:00
font - > GetCharInfo ( charCode , charInfo ) ;
2013-05-06 03:58:52 +00:00
2020-03-15 23:54:42 +00:00
if ( ! useAllocCallbacks )
return 0 ;
2020-03-15 15:05:28 +00:00
u32 allocSize = charInfo - > bitmapWidth * charInfo - > bitmapHeight ;
2021-09-13 15:29:45 +00:00
if ( font - > GetFontLib ( ) & & ( charInfo - > sfp26AdvanceH ! = 0 | | charInfo - > sfp26AdvanceV ! = 0 ) ) {
2020-03-15 15:05:28 +00:00
if ( font - > GetFontLib ( ) - > GetCharInfoBitmapAddress ( ) ! = 0 ) {
PostCharInfoFreeCallback * action = ( PostCharInfoFreeCallback * ) __KernelCreateAction ( actionPostCharInfoFreeCallback ) ;
action - > SetFontLib ( font - > GetFontLib ( ) - > GetListID ( ) ) ;
action - > SetCharInfo ( charInfo ) ;
u32 args [ 2 ] = { font - > GetFontLib ( ) - > userDataAddr ( ) , font - > GetFontLib ( ) - > GetCharInfoBitmapAddress ( ) } ;
2020-03-21 23:09:23 +00:00
hleEnqueueCall ( font - > GetFontLib ( ) - > freeFuncAddr ( ) , 2 , args , action ) ;
2020-03-15 15:05:28 +00:00
} else {
PostCharInfoAllocCallback * action = ( PostCharInfoAllocCallback * ) __KernelCreateAction ( actionPostCharInfoAllocCallback ) ;
action - > SetFontLib ( font - > GetFontLib ( ) - > GetListID ( ) ) ;
u32 args [ 2 ] = { font - > GetFontLib ( ) - > userDataAddr ( ) , allocSize } ;
2020-03-21 23:09:23 +00:00
hleEnqueueCall ( font - > GetFontLib ( ) - > allocFuncAddr ( ) , 2 , args , action ) ;
2020-03-15 15:05:28 +00:00
}
}
2013-02-22 19:05:07 +00:00
return 0 ;
2012-12-08 19:53:15 +00:00
}
2014-12-08 09:40:08 +00:00
static int sceFontGetShadowInfo ( u32 fontHandle , u32 charCode , u32 charInfoPtr ) {
2015-11-01 13:11:31 +00:00
charCode & = 0xffff ;
2014-03-01 08:18:19 +00:00
if ( ! Memory : : IsValidAddress ( charInfoPtr ) ) {
ERROR_LOG ( SCEFONT , " sceFontGetShadowInfo(%08x, %i, %08x): bad charInfo pointer " , fontHandle , charCode , charInfoPtr ) ;
return ERROR_FONT_INVALID_PARAMETER ;
}
LoadedFont * font = GetLoadedFont ( fontHandle , true ) ;
if ( ! font ) {
ERROR_LOG_REPORT ( SCEFONT , " sceFontGetShadowInfo(%08x, %i, %08x): bad font " , fontHandle , charCode , charInfoPtr ) ;
return ERROR_FONT_INVALID_PARAMETER ;
}
DEBUG_LOG ( SCEFONT , " sceFontGetShadowInfo(%08x, %i, %08x) " , fontHandle , charCode , charInfoPtr ) ;
auto charInfo = PSPPointer < PGFCharInfo > : : Create ( charInfoPtr ) ;
font - > GetCharInfo ( charCode , charInfo , FONT_PGF_SHADOWGLYPH ) ;
2013-02-22 19:05:07 +00:00
return 0 ;
}
2012-12-09 20:37:33 +00:00
2014-12-08 09:40:08 +00:00
static int sceFontGetCharImageRect ( u32 fontHandle , u32 charCode , u32 charRectPtr ) {
2015-11-01 13:11:31 +00:00
charCode & = 0xffff ;
2014-03-01 07:04:34 +00:00
auto charRect = PSPPointer < FontImageRect > : : Create ( charRectPtr ) ;
LoadedFont * font = GetLoadedFont ( fontHandle , true ) ;
if ( ! font ) {
ERROR_LOG_REPORT ( SCEFONT , " sceFontGetCharImageRect(%08x, %i, %08x): bad font " , fontHandle , charCode , charRectPtr ) ;
return ERROR_FONT_INVALID_PARAMETER ;
}
if ( ! charRect . IsValid ( ) ) {
ERROR_LOG_REPORT ( SCEFONT , " sceFontGetCharImageRect(%08x, %i, %08x): invalid rect pointer " , fontHandle , charCode , charRectPtr ) ;
return ERROR_FONT_INVALID_PARAMETER ;
}
2013-09-07 20:02:55 +00:00
DEBUG_LOG ( SCEFONT , " sceFontGetCharImageRect(%08x, %i, %08x) " , fontHandle , charCode , charRectPtr ) ;
2013-02-22 19:05:07 +00:00
PGFCharInfo charInfo ;
2014-03-01 07:04:34 +00:00
font - > GetCharInfo ( charCode , & charInfo ) ;
charRect - > width = charInfo . bitmapWidth ;
charRect - > height = charInfo . bitmapHeight ;
2012-12-08 19:53:15 +00:00
return 0 ;
}
2014-12-08 09:40:08 +00:00
static int sceFontGetShadowImageRect ( u32 fontHandle , u32 charCode , u32 charRectPtr ) {
2015-11-01 13:11:31 +00:00
charCode & = 0xffff ;
2014-03-01 07:04:34 +00:00
auto charRect = PSPPointer < FontImageRect > : : Create ( charRectPtr ) ;
LoadedFont * font = GetLoadedFont ( fontHandle , true ) ;
if ( ! font ) {
ERROR_LOG_REPORT ( SCEFONT , " sceFontGetShadowImageRect(%08x, %i, %08x): bad font " , fontHandle , charCode , charRectPtr ) ;
return ERROR_FONT_INVALID_PARAMETER ;
}
if ( ! charRect . IsValid ( ) ) {
ERROR_LOG_REPORT ( SCEFONT , " sceFontGetShadowImageRect(%08x, %i, %08x): invalid rect pointer " , fontHandle , charCode , charRectPtr ) ;
return ERROR_FONT_INVALID_PARAMETER ;
}
DEBUG_LOG ( SCEFONT , " sceFontGetShadowImageRect(%08x, %i, %08x) " , fontHandle , charCode , charRectPtr ) ;
PGFCharInfo charInfo ;
font - > GetCharInfo ( charCode , & charInfo , FONT_PGF_SHADOWGLYPH ) ;
charRect - > width = charInfo . bitmapWidth ;
charRect - > height = charInfo . bitmapHeight ;
2013-02-04 19:22:16 +00:00
return 0 ;
}
2014-12-08 09:40:08 +00:00
static int sceFontGetCharGlyphImage ( u32 fontHandle , u32 charCode , u32 glyphImagePtr ) {
2015-11-01 13:11:31 +00:00
charCode & = 0xffff ;
2013-05-06 04:21:58 +00:00
if ( ! Memory : : IsValidAddress ( glyphImagePtr ) ) {
2013-09-07 20:02:55 +00:00
ERROR_LOG ( SCEFONT , " sceFontGetCharGlyphImage(%x, %x, %x): bad glyphImage pointer " , fontHandle , charCode , glyphImagePtr ) ;
2013-05-06 04:21:58 +00:00
return ERROR_FONT_INVALID_PARAMETER ;
}
2014-02-23 19:48:31 +00:00
LoadedFont * font = GetLoadedFont ( fontHandle , true ) ;
2013-02-28 14:50:14 +00:00
if ( ! font ) {
2013-09-07 20:02:55 +00:00
ERROR_LOG_REPORT ( SCEFONT , " sceFontGetCharGlyphImage(%x, %x, %x): bad font " , fontHandle , charCode , glyphImagePtr ) ;
2013-05-06 04:21:58 +00:00
return ERROR_FONT_INVALID_PARAMETER ;
2013-02-28 14:50:14 +00:00
}
2013-05-06 04:21:58 +00:00
2013-09-07 20:02:55 +00:00
DEBUG_LOG ( SCEFONT , " sceFontGetCharGlyphImage(%x, %x, %x) " , fontHandle , charCode , glyphImagePtr ) ;
2014-02-27 08:28:57 +00:00
auto glyph = PSPPointer < const GlyphImage > : : Create ( glyphImagePtr ) ;
2014-03-01 07:04:34 +00:00
font - > DrawCharacter ( glyph , - 1 , - 1 , - 1 , - 1 , charCode , FONT_PGF_CHARGLYPH ) ;
2013-02-22 19:05:07 +00:00
return 0 ;
}
2014-12-08 09:40:08 +00:00
static int sceFontGetCharGlyphImage_Clip ( u32 fontHandle , u32 charCode , u32 glyphImagePtr , int clipXPos , int clipYPos , int clipWidth , int clipHeight ) {
2015-11-01 13:11:31 +00:00
charCode & = 0xffff ;
2013-05-06 04:21:58 +00:00
if ( ! Memory : : IsValidAddress ( glyphImagePtr ) ) {
2013-09-07 20:02:55 +00:00
ERROR_LOG ( SCEFONT , " sceFontGetCharGlyphImage_Clip(%08x, %i, %08x, %i, %i, %i, %i): bad glyphImage pointer " , fontHandle , charCode , glyphImagePtr , clipXPos , clipYPos , clipWidth , clipHeight ) ;
2013-05-06 04:21:58 +00:00
return ERROR_FONT_INVALID_PARAMETER ;
}
2014-02-23 19:48:31 +00:00
LoadedFont * font = GetLoadedFont ( fontHandle , true ) ;
2013-02-22 19:05:07 +00:00
if ( ! font ) {
2013-09-07 20:02:55 +00:00
ERROR_LOG_REPORT ( SCEFONT , " sceFontGetCharGlyphImage_Clip(%08x, %i, %08x, %i, %i, %i, %i): bad font " , fontHandle , charCode , glyphImagePtr , clipXPos , clipYPos , clipWidth , clipHeight ) ;
2013-05-06 04:21:58 +00:00
return ERROR_FONT_INVALID_PARAMETER ;
2013-02-22 19:05:07 +00:00
}
2013-05-06 04:21:58 +00:00
2014-02-27 08:19:40 +00:00
DEBUG_LOG ( SCEFONT , " sceFontGetCharGlyphImage_Clip(%08x, %i, %08x, %i, %i, %i, %i) " , fontHandle , charCode , glyphImagePtr , clipXPos , clipYPos , clipWidth , clipHeight ) ;
2014-02-27 08:28:57 +00:00
auto glyph = PSPPointer < const GlyphImage > : : Create ( glyphImagePtr ) ;
2014-03-01 07:04:34 +00:00
font - > DrawCharacter ( glyph , clipXPos , clipYPos , clipWidth , clipHeight , charCode , FONT_PGF_CHARGLYPH ) ;
2012-12-08 19:53:15 +00:00
return 0 ;
}
2014-12-08 09:40:08 +00:00
static int sceFontSetAltCharacterCode ( u32 fontLibHandle , u32 charCode ) {
2015-11-01 13:11:31 +00:00
charCode & = 0xffff ;
2013-02-22 19:05:07 +00:00
FontLib * fl = GetFontLib ( fontLibHandle ) ;
2014-03-01 05:20:06 +00:00
if ( ! fl ) {
ERROR_LOG_REPORT ( SCEFONT , " sceFontSetAltCharacterCode(%08x, %08x): invalid font lib " , fontLibHandle , charCode ) ;
return ERROR_FONT_INVALID_LIBID ;
2013-02-22 19:05:07 +00:00
}
2014-03-01 05:20:06 +00:00
INFO_LOG ( SCEFONT , " sceFontSetAltCharacterCode(%08x, %08x) " , fontLibHandle , charCode ) ;
fl - > SetAltCharCode ( charCode & 0xFFFF ) ;
2012-12-08 19:53:15 +00:00
return 0 ;
}
2014-12-08 09:40:08 +00:00
static int sceFontFlush ( u32 fontHandle ) {
2013-09-07 20:02:55 +00:00
INFO_LOG ( SCEFONT , " sceFontFlush(%i) " , fontHandle ) ;
2020-03-15 15:05:28 +00:00
LoadedFont * font = GetLoadedFont ( fontHandle , true ) ;
if ( ! font ) {
ERROR_LOG_REPORT ( SCEFONT , " sceFontFlush(%08x): bad font " , fontHandle ) ;
return ERROR_FONT_INVALID_PARAMETER ;
}
2021-09-13 15:29:45 +00:00
if ( font - > GetFontLib ( ) )
font - > GetFontLib ( ) - > flushFont ( ) ;
2020-03-15 15:05:28 +00:00
2013-02-04 19:22:16 +00:00
return 0 ;
}
2013-02-22 19:05:07 +00:00
// One would think that this should loop through the fonts loaded in the fontLibHandle,
// but it seems not.
2014-12-08 09:40:08 +00:00
static int sceFontGetFontList ( u32 fontLibHandle , u32 fontStylePtr , int numFonts ) {
2014-03-01 09:47:35 +00:00
auto fontStyles = PSPPointer < PGFFontStyle > : : Create ( fontStylePtr ) ;
FontLib * fl = GetFontLib ( fontLibHandle ) ;
if ( ! fl ) {
ERROR_LOG_REPORT ( SCEFONT , " sceFontGetFontList(%08x, %08x, %i): invalid font lib " , fontLibHandle , fontStylePtr , numFonts ) ;
return ERROR_FONT_INVALID_LIBID ;
2013-02-22 19:05:07 +00:00
}
2014-03-01 09:47:35 +00:00
if ( ! fontStyles . IsValid ( ) ) {
ERROR_LOG_REPORT ( SCEFONT , " sceFontGetFontList(%08x, %08x, %i): invalid style pointer " , fontLibHandle , fontStylePtr , numFonts ) ;
return ERROR_FONT_INVALID_PARAMETER ;
}
DEBUG_LOG ( SCEFONT , " sceFontGetFontList(%08x, %08x, %i) " , fontLibHandle , fontStylePtr , numFonts ) ;
if ( fl - > handle ( ) ! = 0 ) {
numFonts = std : : min ( numFonts , ( int ) internalFonts . size ( ) ) ;
for ( int i = 0 ; i < numFonts ; i + + )
fontStyles [ i ] = internalFonts [ i ] - > GetFontStyle ( ) ;
}
return hleDelayResult ( 0 , " font list read " , 100 ) ;
2013-02-04 19:22:16 +00:00
}
2014-12-08 09:40:08 +00:00
static int sceFontGetNumFontList ( u32 fontLibHandle , u32 errorCodePtr ) {
2021-02-19 06:25:24 +00:00
auto errorCode = PSPPointer < s32_le > : : Create ( errorCodePtr ) ;
2014-03-01 09:54:15 +00:00
if ( ! errorCode . IsValid ( ) ) {
ERROR_LOG_REPORT ( SCEFONT , " sceFontGetNumFontList(%08x, %08x): invalid error address " , fontLibHandle , errorCodePtr ) ;
return ERROR_FONT_INVALID_PARAMETER ;
}
FontLib * fl = GetFontLib ( fontLibHandle ) ;
if ( ! fl ) {
ERROR_LOG_REPORT ( SCEFONT , " sceFontGetNumFontList(%08x, %08x): invalid font lib " , fontLibHandle , errorCodePtr ) ;
* errorCode = ERROR_FONT_INVALID_LIBID ;
return 0 ;
}
DEBUG_LOG ( SCEFONT , " sceFontGetNumFontList(%08x, %08x) " , fontLibHandle , errorCodePtr ) ;
* errorCode = 0 ;
return fl - > handle ( ) = = 0 ? 0 : ( int ) internalFonts . size ( ) ;
2013-02-22 19:05:07 +00:00
}
2012-12-17 23:57:40 +00:00
2014-12-08 09:40:08 +00:00
static int sceFontSetResolution ( u32 fontLibHandle , float hRes , float vRes ) {
2013-02-22 19:05:07 +00:00
FontLib * fl = GetFontLib ( fontLibHandle ) ;
2014-03-01 05:52:34 +00:00
if ( ! fl ) {
ERROR_LOG_REPORT ( SCEFONT , " sceFontSetResolution(%08x, %f, %f): invalid font lib " , fontLibHandle , hRes , vRes ) ;
return ERROR_FONT_INVALID_LIBID ;
2013-02-22 19:05:07 +00:00
}
2014-03-01 05:52:34 +00:00
if ( hRes < = 0.0f | | vRes < = 0.0f ) {
ERROR_LOG_REPORT ( SCEFONT , " sceFontSetResolution(%08x, %f, %f): negative value " , fontLibHandle , hRes , vRes ) ;
return ERROR_FONT_INVALID_PARAMETER ;
}
INFO_LOG ( SCEFONT , " sceFontSetResolution(%08x, %f, %f) " , fontLibHandle , hRes , vRes ) ;
fl - > SetResolution ( hRes , vRes ) ;
2013-02-22 19:05:07 +00:00
return 0 ;
}
2012-12-17 21:21:09 +00:00
2014-12-08 09:40:08 +00:00
static float sceFontPixelToPointH ( int fontLibHandle , float fontPixelsH , u32 errorCodePtr ) {
2021-02-19 06:25:24 +00:00
auto errorCode = PSPPointer < s32_le > : : Create ( errorCodePtr ) ;
2014-03-01 06:05:37 +00:00
if ( ! errorCode . IsValid ( ) ) {
ERROR_LOG_REPORT ( SCEFONT , " sceFontPixelToPointH(%08x, %f, %08x): invalid error address " , fontLibHandle , fontPixelsH , errorCodePtr ) ;
return 0.0f ;
}
2013-02-22 19:05:07 +00:00
FontLib * fl = GetFontLib ( fontLibHandle ) ;
2014-03-01 06:05:37 +00:00
if ( ! fl ) {
ERROR_LOG_REPORT ( SCEFONT , " sceFontPixelToPointH(%08x, %f, %08x): invalid font lib " , fontLibHandle , fontPixelsH , errorCodePtr ) ;
* errorCode = ERROR_FONT_INVALID_LIBID ;
return 0.0f ;
2013-02-22 19:05:07 +00:00
}
2014-03-01 06:05:37 +00:00
DEBUG_LOG ( SCEFONT , " sceFontPixelToPointH(%08x, %f, %08x) " , fontLibHandle , fontPixelsH , errorCodePtr ) ;
* errorCode = 0 ;
return fontPixelsH * pointDPI / fl - > FontHRes ( ) ;
2013-02-22 19:05:07 +00:00
}
2012-12-17 21:21:09 +00:00
2014-12-08 09:40:08 +00:00
static float sceFontPixelToPointV ( int fontLibHandle , float fontPixelsV , u32 errorCodePtr ) {
2021-02-19 06:25:24 +00:00
auto errorCode = PSPPointer < s32_le > : : Create ( errorCodePtr ) ;
2014-03-01 06:05:37 +00:00
if ( ! errorCode . IsValid ( ) ) {
ERROR_LOG_REPORT ( SCEFONT , " sceFontPixelToPointV(%08x, %f, %08x): invalid error address " , fontLibHandle , fontPixelsV , errorCodePtr ) ;
return 0.0f ;
}
2013-02-22 19:05:07 +00:00
FontLib * fl = GetFontLib ( fontLibHandle ) ;
2014-03-01 06:05:37 +00:00
if ( ! fl ) {
ERROR_LOG_REPORT ( SCEFONT , " sceFontPixelToPointV(%08x, %f, %08x): invalid font lib " , fontLibHandle , fontPixelsV , errorCodePtr ) ;
* errorCode = ERROR_FONT_INVALID_LIBID ;
return 0.0f ;
2013-02-12 23:49:49 +00:00
}
2014-03-01 06:05:37 +00:00
DEBUG_LOG ( SCEFONT , " sceFontPixelToPointV(%08x, %f, %08x) " , fontLibHandle , fontPixelsV , errorCodePtr ) ;
* errorCode = 0 ;
return fontPixelsV * pointDPI / fl - > FontVRes ( ) ;
2013-02-12 23:49:49 +00:00
}
2014-12-08 09:40:08 +00:00
static float sceFontPointToPixelH ( int fontLibHandle , float fontPointsH , u32 errorCodePtr ) {
2021-02-19 06:25:24 +00:00
auto errorCode = PSPPointer < s32_le > : : Create ( errorCodePtr ) ;
2014-03-01 06:05:37 +00:00
if ( ! errorCode . IsValid ( ) ) {
ERROR_LOG_REPORT ( SCEFONT , " sceFontPointToPixelH(%08x, %f, %08x): invalid error address " , fontLibHandle , fontPointsH , errorCodePtr ) ;
return 0.0f ;
}
2013-02-22 19:05:07 +00:00
FontLib * fl = GetFontLib ( fontLibHandle ) ;
2014-03-01 06:05:37 +00:00
if ( ! fl ) {
ERROR_LOG_REPORT ( SCEFONT , " sceFontPointToPixelH(%08x, %f, %08x): invalid font lib " , fontLibHandle , fontPointsH , errorCodePtr ) ;
* errorCode = ERROR_FONT_INVALID_LIBID ;
return 0.0f ;
2012-12-22 12:25:03 +00:00
}
2014-03-01 06:05:37 +00:00
DEBUG_LOG ( SCEFONT , " sceFontPointToPixelH(%08x, %f, %08x) " , fontLibHandle , fontPointsH , errorCodePtr ) ;
* errorCode = 0 ;
return fontPointsH * fl - > FontHRes ( ) / pointDPI ;
2013-02-12 23:49:49 +00:00
}
2014-12-08 09:40:08 +00:00
static float sceFontPointToPixelV ( int fontLibHandle , float fontPointsV , u32 errorCodePtr ) {
2021-02-19 06:25:24 +00:00
auto errorCode = PSPPointer < s32_le > : : Create ( errorCodePtr ) ;
2014-03-01 06:05:37 +00:00
if ( ! errorCode . IsValid ( ) ) {
ERROR_LOG_REPORT ( SCEFONT , " sceFontPointToPixelV(%08x, %f, %08x): invalid error address " , fontLibHandle , fontPointsV , errorCodePtr ) ;
return 0.0f ;
}
2013-02-22 19:05:07 +00:00
FontLib * fl = GetFontLib ( fontLibHandle ) ;
2014-03-01 06:05:37 +00:00
if ( ! fl ) {
ERROR_LOG_REPORT ( SCEFONT , " sceFontPointToPixelV(%08x, %f, %08x): invalid font lib " , fontLibHandle , fontPointsV , errorCodePtr ) ;
* errorCode = ERROR_FONT_INVALID_LIBID ;
return 0.0f ;
2013-02-22 19:05:07 +00:00
}
2014-03-01 06:05:37 +00:00
DEBUG_LOG ( SCEFONT , " sceFontPointToPixelV(%08x, %f, %08x) " , fontLibHandle , fontPointsV , errorCodePtr ) ;
* errorCode = 0 ;
return fontPointsV * fl - > FontVRes ( ) / pointDPI ;
2012-12-17 23:57:40 +00:00
}
2012-11-22 21:29:51 +00:00
2014-12-08 09:40:08 +00:00
static int sceFontCalcMemorySize ( ) {
2013-09-07 20:02:55 +00:00
ERROR_LOG_REPORT ( SCEFONT , " UNIMPL sceFontCalcMemorySize() " ) ;
2013-02-12 23:49:49 +00:00
return 0 ;
}
2014-12-08 09:40:08 +00:00
static int sceFontGetShadowGlyphImage ( u32 fontHandle , u32 charCode , u32 glyphImagePtr ) {
2015-11-01 13:11:31 +00:00
charCode & = 0xffff ;
2014-03-01 04:57:18 +00:00
if ( ! Memory : : IsValidAddress ( glyphImagePtr ) ) {
ERROR_LOG ( SCEFONT , " sceFontGetShadowGlyphImage(%x, %x, %x): bad glyphImage pointer " , fontHandle , charCode , glyphImagePtr ) ;
return ERROR_FONT_INVALID_PARAMETER ;
}
LoadedFont * font = GetLoadedFont ( fontHandle , true ) ;
if ( ! font ) {
ERROR_LOG_REPORT ( SCEFONT , " sceFontGetShadowGlyphImage(%x, %x, %x): bad font " , fontHandle , charCode , glyphImagePtr ) ;
return ERROR_FONT_INVALID_PARAMETER ;
}
DEBUG_LOG ( SCEFONT , " sceFontGetShadowGlyphImage(%x, %x, %x) " , fontHandle , charCode , glyphImagePtr ) ;
auto glyph = PSPPointer < const GlyphImage > : : Create ( glyphImagePtr ) ;
2014-03-01 07:04:34 +00:00
font - > DrawCharacter ( glyph , - 1 , - 1 , - 1 , - 1 , charCode , FONT_PGF_SHADOWGLYPH ) ;
2013-02-22 19:05:07 +00:00
return 0 ;
}
2013-02-12 23:49:49 +00:00
2014-12-08 09:40:08 +00:00
static int sceFontGetShadowGlyphImage_Clip ( u32 fontHandle , u32 charCode , u32 glyphImagePtr , int clipXPos , int clipYPos , int clipWidth , int clipHeight ) {
2015-11-01 13:11:31 +00:00
charCode & = 0xffff ;
2014-03-01 04:57:18 +00:00
if ( ! Memory : : IsValidAddress ( glyphImagePtr ) ) {
ERROR_LOG ( SCEFONT , " sceFontGetShadowGlyphImage_Clip(%08x, %i, %08x, %i, %i, %i, %i): bad glyphImage pointer " , fontHandle , charCode , glyphImagePtr , clipXPos , clipYPos , clipWidth , clipHeight ) ;
return ERROR_FONT_INVALID_PARAMETER ;
}
LoadedFont * font = GetLoadedFont ( fontHandle , true ) ;
if ( ! font ) {
ERROR_LOG_REPORT ( SCEFONT , " sceFontGetShadowGlyphImage_Clip(%08x, %i, %08x, %i, %i, %i, %i): bad font " , fontHandle , charCode , glyphImagePtr , clipXPos , clipYPos , clipWidth , clipHeight ) ;
return ERROR_FONT_INVALID_PARAMETER ;
}
DEBUG_LOG ( SCEFONT , " sceFontGetShadowGlyphImage_Clip(%08x, %i, %08x, %i, %i, %i, %i) " , fontHandle , charCode , glyphImagePtr , clipXPos , clipYPos , clipWidth , clipHeight ) ;
auto glyph = PSPPointer < const GlyphImage > : : Create ( glyphImagePtr ) ;
2014-03-01 07:04:34 +00:00
font - > DrawCharacter ( glyph , clipXPos , clipYPos , clipWidth , clipHeight , charCode , FONT_PGF_SHADOWGLYPH ) ;
2013-02-22 19:05:07 +00:00
return 0 ;
}
2013-02-12 23:49:49 +00:00
2015-03-05 09:36:03 +00:00
// sceLibFont is a user level library so it can touch the stack. Some games appear to rely a bit of stack
// being wiped - although in reality, it won't be wiped with just zeroes..
2013-02-22 19:05:07 +00:00
const HLEFunction sceLibFont [ ] = {
2015-03-22 23:57:56 +00:00
{ 0X67F17ED7 , & WrapU_UU < sceFontNewLib > , " sceFontNewLib " , ' x ' , " xx " , HLE_CLEAR_STACK_BYTES , 0x5A0 } ,
{ 0X574B6FBC , & WrapI_U < sceFontDoneLib > , " sceFontDoneLib " , ' i ' , " x " , HLE_CLEAR_STACK_BYTES , 0x2C } ,
{ 0X48293280 , & WrapI_UFF < sceFontSetResolution > , " sceFontSetResolution " , ' i ' , " xff " } ,
{ 0X27F6E642 , & WrapI_UU < sceFontGetNumFontList > , " sceFontGetNumFontList " , ' i ' , " xx " } ,
{ 0XBC75D85B , & WrapI_UUI < sceFontGetFontList > , " sceFontGetFontList " , ' i ' , " xxi " , HLE_CLEAR_STACK_BYTES , 0x31C } ,
{ 0X099EF33C , & WrapI_UUU < sceFontFindOptimumFont > , " sceFontFindOptimumFont " , ' i ' , " xxx " , HLE_CLEAR_STACK_BYTES , 0xF0 } ,
{ 0X681E61A7 , & WrapI_UUU < sceFontFindFont > , " sceFontFindFont " , ' i ' , " xxx " , HLE_CLEAR_STACK_BYTES , 0x40 } ,
{ 0X2F67356A , & WrapI_V < sceFontCalcMemorySize > , " sceFontCalcMemorySize " , ' i ' , " " } ,
{ 0X5333322D , & WrapI_UUU < sceFontGetFontInfoByIndexNumber > , " sceFontGetFontInfoByIndexNumber " , ' i ' , " xxx " , HLE_CLEAR_STACK_BYTES , 0x20 } ,
2021-09-13 15:29:45 +00:00
{ 0XA834319D , & WrapU_UUUU < sceFontOpen > , " sceFontOpen " , ' x ' , " xxxp " , HLE_CLEAR_STACK_BYTES , 0x460 } ,
{ 0X57FCB733 , & WrapU_UCUU < sceFontOpenUserFile > , " sceFontOpenUserFile " , ' x ' , " xsxp " } ,
{ 0XBB8E7FE6 , & WrapU_UUUU < sceFontOpenUserMemory > , " sceFontOpenUserMemory " , ' x ' , " xxxp " , HLE_CLEAR_STACK_BYTES , 0x440 /*from JPCSP*/ } ,
2015-03-22 23:57:56 +00:00
{ 0X3AEA8CB6 , & WrapI_U < sceFontClose > , " sceFontClose " , ' i ' , " x " , HLE_CLEAR_STACK_BYTES , 0x54 } ,
{ 0X0DA7535E , & WrapI_UU < sceFontGetFontInfo > , " sceFontGetFontInfo " , ' i ' , " xx " } ,
{ 0XDCC80C2F , & WrapI_UUU < sceFontGetCharInfo > , " sceFontGetCharInfo " , ' i ' , " xxx " , HLE_CLEAR_STACK_BYTES , 0x110 } ,
{ 0XAA3DE7B5 , & WrapI_UUU < sceFontGetShadowInfo > , " sceFontGetShadowInfo " , ' i ' , " xxx " , HLE_CLEAR_STACK_BYTES , 0x150 } ,
{ 0X5C3E4A9E , & WrapI_UUU < sceFontGetCharImageRect > , " sceFontGetCharImageRect " , ' i ' , " xxx " , HLE_CLEAR_STACK_BYTES , 0x120 } ,
{ 0X48B06520 , & WrapI_UUU < sceFontGetShadowImageRect > , " sceFontGetShadowImageRect " , ' i ' , " xxx " , HLE_CLEAR_STACK_BYTES , 0x150 } ,
{ 0X980F4895 , & WrapI_UUU < sceFontGetCharGlyphImage > , " sceFontGetCharGlyphImage " , ' i ' , " xxx " , HLE_CLEAR_STACK_BYTES , 0x120 } ,
{ 0XCA1E6945 , & WrapI_UUUIIII < sceFontGetCharGlyphImage_Clip > , " sceFontGetCharGlyphImage_Clip " , ' i ' , " xxxiiii " , HLE_CLEAR_STACK_BYTES , 0x130 } ,
{ 0X74B21701 , & WrapF_IFU < sceFontPixelToPointH > , " sceFontPixelToPointH " , ' f ' , " ifx " , HLE_CLEAR_STACK_BYTES , 0x10 } ,
{ 0XF8F0752E , & WrapF_IFU < sceFontPixelToPointV > , " sceFontPixelToPointV " , ' f ' , " ifx " , HLE_CLEAR_STACK_BYTES , 0x10 } ,
{ 0X472694CD , & WrapF_IFU < sceFontPointToPixelH > , " sceFontPointToPixelH " , ' f ' , " ifx " } ,
{ 0X3C4B7E82 , & WrapF_IFU < sceFontPointToPixelV > , " sceFontPointToPixelV " , ' f ' , " ifx " } ,
{ 0XEE232411 , & WrapI_UU < sceFontSetAltCharacterCode > , " sceFontSetAltCharacterCode " , ' i ' , " xx " } ,
{ 0X568BE516 , & WrapI_UUU < sceFontGetShadowGlyphImage > , " sceFontGetShadowGlyphImage " , ' i ' , " xxx " , HLE_CLEAR_STACK_BYTES , 0x160 } ,
{ 0X5DCF6858 , & WrapI_UUUIIII < sceFontGetShadowGlyphImage_Clip > , " sceFontGetShadowGlyphImage_Clip " , ' i ' , " xxxiiii " , HLE_CLEAR_STACK_BYTES , 0x170 } ,
{ 0X02D7F94B , & WrapI_U < sceFontFlush > , " sceFontFlush " , ' i ' , " x " } ,
2012-11-22 21:29:51 +00:00
} ;
2013-02-22 19:05:07 +00:00
void Register_sceFont ( ) {
2012-11-22 21:29:51 +00:00
RegisterModule ( " sceLibFont " , ARRAY_SIZE ( sceLibFont ) , sceLibFont ) ;
}
2014-08-15 14:42:08 +00:00
void Register_sceLibFttt ( ) {
2014-08-15 15:30:51 +00:00
RegisterModule ( " sceLibFttt " , ARRAY_SIZE ( sceLibFont ) , sceLibFont ) ;
2014-08-15 14:42:08 +00:00
}