Font/MRI: Improve handling of (default_)name attributes

More accurate behavior, such as Font objects properly inheriting
their name attributes, and centralization of code for picking
the first existing name from a passed string array.

Also centralizes initial default_name population in core.

Note: This currently breaks the mruby binding build.
This commit is contained in:
Jonas Kulla 2016-01-05 08:41:47 +01:00
parent 53b5b923d4
commit 5d776319b5
4 changed files with 175 additions and 129 deletions

View file

@ -184,7 +184,7 @@ _TTF_Font *SharedFontState::getFont(std::string family,
return font;
}
bool SharedFontState::fontPresent(std::string family)
bool SharedFontState::fontPresent(std::string family) const
{
/* Check for substitutions */
if (p->subs.contains(family))
@ -202,6 +202,26 @@ _TTF_Font *SharedFontState::openBundled(int size)
return TTF_OpenFontRW(ops, 1, size);
}
void pickExistingFontName(const std::vector<std::string> &names,
std::string &out,
const SharedFontState &sfs)
{
/* Note: In RMXP, a names array with no existing entry
* results in no text being drawn at all (same for "" and []);
* we can't replicate this in mkxp due to the default substitute. */
for (size_t i = 0; i < names.size(); ++i)
{
if (sfs.fontPresent(names[i]))
{
out = names[i];
return;
}
}
out = "";
}
struct FontPrivate
{
@ -229,15 +249,15 @@ struct FontPrivate
static Color defaultColorTmp;
static Color defaultOutColorTmp;
static std::vector<std::string> initialDefaultNames;
/* The actual font is opened as late as possible
* (when it is queried by a Bitmap), prior it is
* set to null */
TTF_Font *sdlFont;
FontPrivate(const char *name = 0,
int size = 0)
: name(name ? std::string(name) : defaultName),
size(size ? size : defaultSize),
FontPrivate(int size)
: size(size),
bold(defaultBold),
italic(defaultItalic),
outline(defaultOutline),
@ -290,6 +310,8 @@ Color *FontPrivate::defaultOutColor = &FontPrivate::defaultOutColorTmp;
Color FontPrivate::defaultColorTmp(255, 255, 255, 255);
Color FontPrivate::defaultOutColorTmp(0, 0, 0, 128);
std::vector<std::string> FontPrivate::initialDefaultNames;
bool Font::doesExist(const char *name)
{
if (!name)
@ -298,10 +320,15 @@ bool Font::doesExist(const char *name)
return shState->fontState().fontPresent(name);
}
Font::Font(const char *name,
Font::Font(const std::vector<std::string> *names,
int size)
{
p = new FontPrivate(name, size);
p = new FontPrivate(size ? size : FontPrivate::defaultSize);
if (names)
setName(*names);
else
p->name = FontPrivate::defaultName;
}
Font::Font(const Font &other)
@ -321,17 +348,9 @@ const Font &Font::operator=(const Font &o)
return o;
}
const char *Font::getName() const
void Font::setName(const std::vector<std::string> &names)
{
return p->name.c_str();
}
void Font::setName(const char *value)
{
if (p->name == value)
return;
p->name = value;
pickExistingFontName(names, p->name, shState->fontState());
p->sdlFont = 0;
}
@ -367,14 +386,15 @@ DEF_ATTR_SIMPLE_STATIC(Font, DefaultOutline, bool, FontPrivate::defaultOutli
DEF_ATTR_SIMPLE_STATIC(Font, DefaultColor, Color&, *FontPrivate::defaultColor)
DEF_ATTR_SIMPLE_STATIC(Font, DefaultOutColor, Color&, *FontPrivate::defaultOutColor)
const char *Font::getDefaultName()
void Font::setDefaultName(const std::vector<std::string> &names,
const SharedFontState &sfs)
{
return FontPrivate::defaultName.c_str();
pickExistingFontName(names, FontPrivate::defaultName, sfs);
}
void Font::setDefaultName(const char *value)
const std::vector<std::string> &Font::getInitialDefaultNames()
{
FontPrivate::defaultName = value;
return FontPrivate::initialDefaultNames;
}
void Font::initDynAttribs()
@ -393,8 +413,30 @@ void Font::initDefaultDynAttribs()
FontPrivate::defaultOutColor = new Color(FontPrivate::defaultOutColorTmp);
}
void Font::initDefaults()
void Font::initDefaults(const SharedFontState &sfs)
{
std::vector<std::string> &names = FontPrivate::initialDefaultNames;
switch (rgssVer)
{
case 1 :
// FIXME: Japanese version has "MS PGothic" instead
names.push_back("Arial");
break;
case 2 :
names.push_back("UmePlus Gothic");
names.push_back("MS Gothic");
names.push_back("Courier New");
break;
default:
case 3 :
names.push_back("VL Gothic");
}
setDefaultName(names, sfs);
FontPrivate::defaultOutline = (rgssVer >= 3 ? true : false);
FontPrivate::defaultShadow = (rgssVer == 2 ? true : false);
}

View file

@ -25,6 +25,9 @@
#include "etc.h"
#include "util.h"
#include <vector>
#include <string>
struct SDL_RWops;
struct _TTF_Font;
struct Config;
@ -47,7 +50,7 @@ public:
_TTF_Font *getFont(std::string family,
int size);
bool fontPresent(std::string family);
bool fontPresent(std::string family) const;
static _TTF_Font *openBundled(int size);
@ -55,22 +58,6 @@ private:
SharedFontStatePrivate *p;
};
/* Concerning Font::name/defaultName :
* In RGSS, this is not actually a string; any type of
* object is accepted, however anything but strings and
* arrays is ignored (and text drawing turns blank).
* Single strings are interpreted as font family names,
* and directly passed to the underlying C++ object;
* arrays however are searched for the first string
* object corresponding to a valid font family name,
* and rendering is done with that. In mkxp, we pass
* this first valid font family as the 'name' attribute
* back to the C++ object on assignment and object
* creation (in case Font.default_name is also an array).
* Invalid parameters (things other than strings or
* arrays not containing any valid family name) are
* passed back as "". */
struct FontPrivate;
class Font
@ -78,31 +65,43 @@ class Font
public:
static bool doesExist(const char *name);
Font(const char *name = 0,
Font(const std::vector<std::string> *names = 0,
int size = 0);
/* Clone constructor */
Font(const Font &other);
~Font();
const Font &operator=(const Font &o);
DECL_ATTR( Name, const char * )
DECL_ATTR( Size, int )
DECL_ATTR( Bold, bool )
DECL_ATTR( Italic, bool )
DECL_ATTR( Color, Color& )
DECL_ATTR( Shadow, bool )
DECL_ATTR( Outline, bool )
DECL_ATTR( OutColor, Color& )
DECL_ATTR( Size, int )
DECL_ATTR( Bold, bool )
DECL_ATTR( Italic, bool )
DECL_ATTR( Color, Color& )
DECL_ATTR( Shadow, bool )
DECL_ATTR( Outline, bool )
DECL_ATTR( OutColor, Color& )
DECL_ATTR_STATIC( DefaultName, const char* )
DECL_ATTR_STATIC( DefaultSize, int )
DECL_ATTR_STATIC( DefaultBold, bool )
DECL_ATTR_STATIC( DefaultItalic, bool )
DECL_ATTR_STATIC( DefaultColor, Color& )
DECL_ATTR_STATIC( DefaultShadow, bool )
DECL_ATTR_STATIC( DefaultOutline, bool )
DECL_ATTR_STATIC( DefaultOutColor, Color& )
DECL_ATTR_STATIC( DefaultSize, int )
DECL_ATTR_STATIC( DefaultBold, bool )
DECL_ATTR_STATIC( DefaultItalic, bool )
DECL_ATTR_STATIC( DefaultColor, Color& )
DECL_ATTR_STATIC( DefaultShadow, bool )
DECL_ATTR_STATIC( DefaultOutline, bool )
DECL_ATTR_STATIC( DefaultOutColor, Color& )
/* There is no point in providing getters for these,
* as the bindings will always return the stored native
* string/array object anyway. It's impossible to mirror
* in the C++ core.
* The core object picks the first existing name from the
* passed array and stores it internally (same for default). */
void setName(const std::vector<std::string> &names);
static void setDefaultName(const std::vector<std::string> &names,
const SharedFontState &sfs);
static const std::vector<std::string> &getInitialDefaultNames();
/* Assigns heap allocated objects to object properties;
* using this in pure C++ will cause memory leaks
@ -110,7 +109,7 @@ public:
void initDynAttribs();
static void initDefaultDynAttribs();
static void initDefaults();
static void initDefaults(const SharedFontState &sfs);
/* internal */
_TTF_Font *getSdlFont();

View file

@ -172,7 +172,6 @@ void SharedState::initInstance(RGSSThreadData *threadData)
* Font depends on SharedState existing */
rgssVersion = threadData->config.rgssVersion;
Font::initDefaults();
_globalIBO = new GlobalIBO();
_globalIBO->ensureSize(1);
@ -183,6 +182,7 @@ void SharedState::initInstance(RGSSThreadData *threadData)
try
{
SharedState::instance = new SharedState(threadData);
Font::initDefaults(instance->p->fontState);
defaultFont = new Font();
}
catch (const Exception &exc)