mirror of https://github.com/OpenTTD/OpenTTD
Compare commits
4 Commits
29c854a9f6
...
1a8a4c5782
Author | SHA1 | Date |
---|---|---|
|
1a8a4c5782 | |
|
ae917cb8c6 | |
|
d5e0fa7a73 | |
|
b32f46f36e |
|
@ -187,7 +187,6 @@ add_files(
|
||||||
fios_gui.cpp
|
fios_gui.cpp
|
||||||
fontcache.cpp
|
fontcache.cpp
|
||||||
fontcache.h
|
fontcache.h
|
||||||
fontdetection.h
|
|
||||||
framerate_gui.cpp
|
framerate_gui.cpp
|
||||||
framerate_type.h
|
framerate_type.h
|
||||||
gamelog.cpp
|
gamelog.cpp
|
||||||
|
|
|
@ -2369,7 +2369,7 @@ static bool ConFont(std::span<std::string_view> argv)
|
||||||
FontCacheSubSetting *setting = GetFontCacheSubSetting(fs);
|
FontCacheSubSetting *setting = GetFontCacheSubSetting(fs);
|
||||||
/* Make sure all non sprite fonts are loaded. */
|
/* Make sure all non sprite fonts are loaded. */
|
||||||
if (!setting->font.empty() && !fc->HasParent()) {
|
if (!setting->font.empty() && !fc->HasParent()) {
|
||||||
InitFontCache(fs);
|
FontCache::LoadFontCaches(fs);
|
||||||
fc = FontCache::Get(fs);
|
fc = FontCache::Get(fs);
|
||||||
}
|
}
|
||||||
IConsolePrint(CC_DEFAULT, "{} font:", FontSizeToName(fs));
|
IConsolePrint(CC_DEFAULT, "{} font:", FontSizeToName(fs));
|
||||||
|
|
|
@ -9,10 +9,8 @@
|
||||||
|
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "fontcache.h"
|
#include "fontcache.h"
|
||||||
#include "fontdetection.h"
|
|
||||||
#include "blitter/factory.hpp"
|
#include "blitter/factory.hpp"
|
||||||
#include "gfx_layout.h"
|
#include "gfx_layout.h"
|
||||||
#include "fontcache/spritefontcache.h"
|
|
||||||
#include "openttd.h"
|
#include "openttd.h"
|
||||||
#include "settings_func.h"
|
#include "settings_func.h"
|
||||||
#include "strings_func.h"
|
#include "strings_func.h"
|
||||||
|
@ -30,22 +28,38 @@
|
||||||
FontCacheSettings _fcsettings;
|
FontCacheSettings _fcsettings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new font cache.
|
* Try loading a font with any fontcache factory.
|
||||||
* @param fs The size of the font.
|
* @param fs Font size to load.
|
||||||
|
* @param fonttype Font type requested.
|
||||||
|
* @return FontCache of the font if loaded, or nullptr.
|
||||||
*/
|
*/
|
||||||
FontCache::FontCache(FontSize fs) : parent(FontCache::Get(fs)), fs(fs)
|
/* static */ std::unique_ptr<FontCache> FontProviderManager::LoadFont(FontSize fs, FontType fonttype)
|
||||||
{
|
{
|
||||||
assert(this->parent == nullptr || this->fs == this->parent->fs);
|
for (auto &provider : FontProviderManager::GetProviders()) {
|
||||||
FontCache::caches[this->fs] = this;
|
auto fc = provider->LoadFont(fs, fonttype);
|
||||||
Layouter::ResetFontCache(this->fs);
|
if (fc != nullptr) return fc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Clean everything up. */
|
/**
|
||||||
FontCache::~FontCache()
|
* We would like to have a fallback font as the current one
|
||||||
|
* doesn't contain all characters we need.
|
||||||
|
* This function must set all fonts of settings.
|
||||||
|
* @param settings the settings to overwrite the fontname of.
|
||||||
|
* @param language_isocode the language, e.g. en_GB.
|
||||||
|
* @param callback The function to call to check for missing glyphs.
|
||||||
|
* @return true if a font has been set, false otherwise.
|
||||||
|
*/
|
||||||
|
/* static */ bool FontProviderManager::FindFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, MissingGlyphSearcher *callback)
|
||||||
{
|
{
|
||||||
assert(this->parent == nullptr || this->fs == this->parent->fs);
|
for (auto &provider : FontProviderManager::GetProviders()) {
|
||||||
FontCache::caches[this->fs] = this->parent;
|
if (provider->FindFallbackFont(settings, language_isocode, callback)) {
|
||||||
Layouter::ResetFontCache(this->fs);
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int FontCache::GetDefaultFontHeight(FontSize fs)
|
int FontCache::GetDefaultFontHeight(FontSize fs)
|
||||||
|
@ -80,12 +94,16 @@ int GetCharacterHeight(FontSize size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* static */ FontCache *FontCache::caches[FS_END];
|
/* static */ std::array<std::unique_ptr<FontCache>, FS_END> FontCache::caches{};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise font caches with the base sprite font cache for all sizes.
|
||||||
|
*/
|
||||||
/* static */ void FontCache::InitializeFontCaches()
|
/* static */ void FontCache::InitializeFontCaches()
|
||||||
{
|
{
|
||||||
for (FontSize fs = FS_BEGIN; fs != FS_END; fs++) {
|
for (FontSize fs = FS_BEGIN; fs != FS_END; fs++) {
|
||||||
if (FontCache::caches[fs] == nullptr) new SpriteFontCache(fs); /* FontCache inserts itself into to the cache. */
|
if (FontCache::Get(fs) != nullptr) continue;
|
||||||
|
FontCache::Register(FontProviderManager::LoadFont(fs, FontType::Sprite));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,7 +144,7 @@ void SetFont(FontSize fontsize, const std::string &font, uint size)
|
||||||
CheckForMissingGlyphs();
|
CheckForMissingGlyphs();
|
||||||
_fcsettings = std::move(backup);
|
_fcsettings = std::move(backup);
|
||||||
} else {
|
} else {
|
||||||
InitFontCache(fontsize);
|
FontCache::LoadFontCaches(fontsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadStringWidthTable(fontsize);
|
LoadStringWidthTable(fontsize);
|
||||||
|
@ -136,15 +154,6 @@ void SetFont(FontSize fontsize, const std::string &font, uint size)
|
||||||
if (_save_config) SaveToConfig();
|
if (_save_config) SaveToConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_FREETYPE
|
|
||||||
extern void LoadFreeTypeFont(FontSize fs);
|
|
||||||
extern void UninitFreeType();
|
|
||||||
#elif defined(_WIN32)
|
|
||||||
extern void LoadWin32Font(FontSize fs);
|
|
||||||
#elif defined(WITH_COCOA)
|
|
||||||
extern void LoadCoreTextFont(FontSize fs);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test if a font setting uses the default font.
|
* Test if a font setting uses the default font.
|
||||||
* @return true iff the font is not configured and no fallback font data is present.
|
* @return true iff the font is not configured and no fallback font data is present.
|
||||||
|
@ -211,43 +220,55 @@ std::string GetFontCacheFontName(FontSize fs)
|
||||||
return GetDefaultTruetypeFontFile(fs);
|
return GetDefaultTruetypeFontFile(fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a FontCache for its font size.
|
||||||
|
* @param fc FontCache to register.
|
||||||
|
*/
|
||||||
|
/* static */ void FontCache::Register(std::unique_ptr<FontCache> &&fc)
|
||||||
|
{
|
||||||
|
if (fc == nullptr) return;
|
||||||
|
|
||||||
|
FontSize fs = fc->fs;
|
||||||
|
|
||||||
|
fc->parent = std::move(FontCache::caches[fs]);
|
||||||
|
FontCache::caches[fs] = std::move(fc);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* (Re)initialize the font cache related things, i.e. load the non-sprite fonts.
|
* (Re)initialize the font cache related things, i.e. load the non-sprite fonts.
|
||||||
* @param fontsizes Font sizes to be initialised.
|
* @param fontsizes Font sizes to be initialised.
|
||||||
*/
|
*/
|
||||||
void InitFontCache(FontSizes fontsizes)
|
/* static */ void FontCache::LoadFontCaches(FontSizes fontsizes)
|
||||||
{
|
{
|
||||||
FontCache::InitializeFontCaches();
|
FontCache::InitializeFontCaches();
|
||||||
|
|
||||||
for (FontSize fs : fontsizes) {
|
for (FontSize fs : fontsizes) {
|
||||||
FontCache *fc = FontCache::Get(fs);
|
Layouter::ResetFontCache(fs);
|
||||||
if (fc->HasParent()) delete fc;
|
|
||||||
|
|
||||||
#ifdef WITH_FREETYPE
|
/* Unload everything except the sprite font cache. */
|
||||||
LoadFreeTypeFont(fs);
|
while (FontCache::Get(fs)->HasParent()) {
|
||||||
#elif defined(_WIN32)
|
FontCache::caches[fs] = std::move(FontCache::caches[fs]->parent);
|
||||||
LoadWin32Font(fs);
|
}
|
||||||
#elif defined(WITH_COCOA)
|
|
||||||
LoadCoreTextFont(fs);
|
FontCache::Register(FontProviderManager::LoadFont(fs, FontType::TrueType));
|
||||||
#endif
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear cached information for the specified font caches.
|
||||||
|
* @param fontsizes Font sizes to clear.
|
||||||
|
*/
|
||||||
|
/* static */ void FontCache::ClearFontCaches(FontSizes fontsizes)
|
||||||
|
{
|
||||||
|
for (FontSize fs : fontsizes) {
|
||||||
|
FontCache::Get(fs)->ClearFontCache();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Free everything allocated w.r.t. fonts.
|
* Free everything allocated w.r.t. fonts.
|
||||||
*/
|
*/
|
||||||
void UninitFontCache()
|
/* static */ void FontCache::UninitializeFontCaches()
|
||||||
{
|
{
|
||||||
for (FontSize fs = FS_BEGIN; fs < FS_END; fs++) {
|
std::ranges::generate(FontCache::caches, []() { return nullptr; });
|
||||||
while (FontCache::Get(fs) != nullptr) delete FontCache::Get(fs);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef WITH_FREETYPE
|
|
||||||
UninitFreeType();
|
|
||||||
#endif /* WITH_FREETYPE */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(_WIN32) && !defined(__APPLE__) && !defined(WITH_FONTCONFIG) && !defined(WITH_COCOA)
|
|
||||||
|
|
||||||
bool SetFallbackFont(FontCacheSettings *, const std::string &, MissingGlyphSearcher *) { return false; }
|
|
||||||
#endif /* !defined(_WIN32) && !defined(__APPLE__) && !defined(WITH_FONTCONFIG) && !defined(WITH_COCOA) */
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#ifndef FONTCACHE_H
|
#ifndef FONTCACHE_H
|
||||||
#define FONTCACHE_H
|
#define FONTCACHE_H
|
||||||
|
|
||||||
|
#include "provider_manager.h"
|
||||||
#include "string_type.h"
|
#include "string_type.h"
|
||||||
#include "spritecache.h"
|
#include "spritecache.h"
|
||||||
|
|
||||||
|
@ -20,18 +21,23 @@ static const GlyphID SPRITE_GLYPH = 1U << 30;
|
||||||
/** Font cache for basic fonts. */
|
/** Font cache for basic fonts. */
|
||||||
class FontCache {
|
class FontCache {
|
||||||
protected:
|
protected:
|
||||||
static FontCache *caches[FS_END]; ///< All the font caches.
|
static std::array<std::unique_ptr<FontCache>, FS_END> caches; ///< All the font caches.
|
||||||
FontCache *parent; ///< The parent of this font cache.
|
std::unique_ptr<FontCache>parent; ///< The parent of this font cache.
|
||||||
const FontSize fs; ///< The size of the font.
|
const FontSize fs; ///< The size of the font.
|
||||||
int height = 0; ///< The height of the font.
|
int height = 0; ///< The height of the font.
|
||||||
int ascender = 0; ///< The ascender value of the font.
|
int ascender = 0; ///< The ascender value of the font.
|
||||||
int descender = 0; ///< The descender value of the font.
|
int descender = 0; ///< The descender value of the font.
|
||||||
|
|
||||||
|
FontCache(FontSize fs) : fs(fs) {}
|
||||||
|
static void Register(std::unique_ptr<FontCache> &&fc);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FontCache(FontSize fs);
|
virtual ~FontCache() {}
|
||||||
virtual ~FontCache();
|
|
||||||
|
|
||||||
static void InitializeFontCaches();
|
static void InitializeFontCaches();
|
||||||
|
static void UninitializeFontCaches();
|
||||||
|
static void LoadFontCaches(FontSizes fontsizes);
|
||||||
|
static void ClearFontCaches(FontSizes fontsizes);
|
||||||
|
|
||||||
/** Default unscaled font heights. */
|
/** Default unscaled font heights. */
|
||||||
static const int DEFAULT_FONT_HEIGHT[FS_END];
|
static const int DEFAULT_FONT_HEIGHT[FS_END];
|
||||||
|
@ -124,7 +130,7 @@ public:
|
||||||
static inline FontCache *Get(FontSize fs)
|
static inline FontCache *Get(FontSize fs)
|
||||||
{
|
{
|
||||||
assert(fs < FS_END);
|
assert(fs < FS_END);
|
||||||
return FontCache::caches[fs];
|
return FontCache::caches[fs].get();
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string GetName(FontSize fs);
|
static std::string GetName(FontSize fs);
|
||||||
|
@ -143,13 +149,6 @@ public:
|
||||||
virtual bool IsBuiltInFont() = 0;
|
virtual bool IsBuiltInFont() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void ClearFontCache(FontSizes fontsizes)
|
|
||||||
{
|
|
||||||
for (FontSize fs : fontsizes) {
|
|
||||||
FontCache::Get(fs)->ClearFontCache();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the Sprite for a glyph */
|
/** Get the Sprite for a glyph */
|
||||||
inline const Sprite *GetGlyph(FontSize size, char32_t key)
|
inline const Sprite *GetGlyph(FontSize size, char32_t key)
|
||||||
{
|
{
|
||||||
|
@ -207,12 +206,39 @@ inline FontCacheSubSetting *GetFontCacheSubSetting(FontSize fs)
|
||||||
|
|
||||||
uint GetFontCacheFontSize(FontSize fs);
|
uint GetFontCacheFontSize(FontSize fs);
|
||||||
std::string GetFontCacheFontName(FontSize fs);
|
std::string GetFontCacheFontName(FontSize fs);
|
||||||
void InitFontCache(FontSizes fontsizes);
|
|
||||||
void UninitFontCache();
|
|
||||||
|
|
||||||
bool GetFontAAState();
|
bool GetFontAAState();
|
||||||
void SetFont(FontSize fontsize, const std::string &font, uint size);
|
void SetFont(FontSize fontsize, const std::string &font, uint size);
|
||||||
|
|
||||||
|
/** Different types of font that can be loaded. */
|
||||||
|
enum class FontType : uint8_t {
|
||||||
|
Sprite, ///< Bitmap sprites from GRF files.
|
||||||
|
TrueType, ///< Scalable TrueType fonts.
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Factory for FontCaches. */
|
||||||
|
class FontCacheFactory : public BaseProvider<FontCacheFactory> {
|
||||||
|
public:
|
||||||
|
FontCacheFactory(std::string_view name, std::string_view description) : BaseProvider<FontCacheFactory>(name, description)
|
||||||
|
{
|
||||||
|
ProviderManager<FontCacheFactory>::Register(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~FontCacheFactory()
|
||||||
|
{
|
||||||
|
ProviderManager<FontCacheFactory>::Unregister(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::unique_ptr<FontCache> LoadFont(FontSize fs, FontType fonttype) = 0;
|
||||||
|
virtual bool FindFallbackFont(struct FontCacheSettings *settings, const std::string &language_isocode, class MissingGlyphSearcher *callback) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FontProviderManager : ProviderManager<FontCacheFactory> {
|
||||||
|
public:
|
||||||
|
static std::unique_ptr<FontCache> LoadFont(FontSize fs, FontType fonttype);
|
||||||
|
static bool FindFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, MissingGlyphSearcher *callback);
|
||||||
|
};
|
||||||
|
|
||||||
/* Implemented in spritefontcache.cpp */
|
/* Implemented in spritefontcache.cpp */
|
||||||
void InitializeUnicodeGlyphMap();
|
void InitializeUnicodeGlyphMap();
|
||||||
void SetUnicodeGlyph(FontSize size, char32_t key, SpriteID sprite);
|
void SetUnicodeGlyph(FontSize size, char32_t key, SpriteID sprite);
|
||||||
|
|
|
@ -8,14 +8,14 @@
|
||||||
/** @file freetypefontcache.cpp FreeType font cache implementation. */
|
/** @file freetypefontcache.cpp FreeType font cache implementation. */
|
||||||
|
|
||||||
#include "../stdafx.h"
|
#include "../stdafx.h"
|
||||||
|
|
||||||
#include "../debug.h"
|
#include "../debug.h"
|
||||||
#include "../fontcache.h"
|
#include "../fontcache.h"
|
||||||
#include "../fontdetection.h"
|
|
||||||
#include "../blitter/factory.hpp"
|
#include "../blitter/factory.hpp"
|
||||||
#include "../core/math_func.hpp"
|
|
||||||
#include "../zoom_func.h"
|
#include "../zoom_func.h"
|
||||||
#include "../fileio_func.h"
|
#include "../fileio_func.h"
|
||||||
#include "../error_func.h"
|
#include "../error_func.h"
|
||||||
|
#include "../../os/unix/font_unix.h"
|
||||||
#include "truetypefontcache.h"
|
#include "truetypefontcache.h"
|
||||||
|
|
||||||
#include "../table/control_codes.h"
|
#include "../table/control_codes.h"
|
||||||
|
@ -46,9 +46,6 @@ public:
|
||||||
const void *GetOSHandle() override { return &face; }
|
const void *GetOSHandle() override { return &face; }
|
||||||
};
|
};
|
||||||
|
|
||||||
FT_Library _ft_library = nullptr;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new FreeTypeFontCache.
|
* Create a new FreeTypeFontCache.
|
||||||
* @param fs The font size that is going to be cached.
|
* @param fs The font size that is going to be cached.
|
||||||
|
@ -113,93 +110,6 @@ void FreeTypeFontCache::SetFontSize(int pixels)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static FT_Error LoadFont(FontSize fs, FT_Face face, std::string_view font_name, uint size)
|
|
||||||
{
|
|
||||||
Debug(fontcache, 2, "Requested '{}', using '{} {}'", font_name, face->family_name, face->style_name);
|
|
||||||
|
|
||||||
/* Attempt to select the unicode character map */
|
|
||||||
FT_Error error = FT_Select_Charmap(face, ft_encoding_unicode);
|
|
||||||
if (error == FT_Err_Ok) goto found_face; // Success
|
|
||||||
|
|
||||||
if (error == FT_Err_Invalid_CharMap_Handle) {
|
|
||||||
/* Try to pick a different character map instead. We default to
|
|
||||||
* the first map, but platform_id 0 encoding_id 0 should also
|
|
||||||
* be unicode (strange system...) */
|
|
||||||
FT_CharMap found = face->charmaps[0];
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < face->num_charmaps; i++) {
|
|
||||||
FT_CharMap charmap = face->charmaps[i];
|
|
||||||
if (charmap->platform_id == 0 && charmap->encoding_id == 0) {
|
|
||||||
found = charmap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found != nullptr) {
|
|
||||||
error = FT_Set_Charmap(face, found);
|
|
||||||
if (error == FT_Err_Ok) goto found_face;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FT_Done_Face(face);
|
|
||||||
return error;
|
|
||||||
|
|
||||||
found_face:
|
|
||||||
new FreeTypeFontCache(fs, face, size);
|
|
||||||
return FT_Err_Ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads the freetype font.
|
|
||||||
* First type to load the fontname as if it were a path. If that fails,
|
|
||||||
* try to resolve the filename of the font using fontconfig, where the
|
|
||||||
* format is 'font family name' or 'font family name, font style'.
|
|
||||||
* @param fs The font size to load.
|
|
||||||
*/
|
|
||||||
void LoadFreeTypeFont(FontSize fs)
|
|
||||||
{
|
|
||||||
FontCacheSubSetting *settings = GetFontCacheSubSetting(fs);
|
|
||||||
|
|
||||||
std::string font = GetFontCacheFontName(fs);
|
|
||||||
if (font.empty()) return;
|
|
||||||
|
|
||||||
if (_ft_library == nullptr) {
|
|
||||||
if (FT_Init_FreeType(&_ft_library) != FT_Err_Ok) {
|
|
||||||
ShowInfo("Unable to initialize FreeType, using sprite fonts instead");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Debug(fontcache, 2, "Initialized");
|
|
||||||
}
|
|
||||||
|
|
||||||
FT_Face face = nullptr;
|
|
||||||
|
|
||||||
/* If font is an absolute path to a ttf, try loading that first. */
|
|
||||||
int32_t index = 0;
|
|
||||||
if (settings->os_handle != nullptr) index = *static_cast<const int32_t *>(settings->os_handle);
|
|
||||||
FT_Error error = FT_New_Face(_ft_library, font.c_str(), index, &face);
|
|
||||||
|
|
||||||
if (error != FT_Err_Ok) {
|
|
||||||
/* Check if font is a relative filename in one of our search-paths. */
|
|
||||||
std::string full_font = FioFindFullPath(BASE_DIR, font);
|
|
||||||
if (!full_font.empty()) {
|
|
||||||
error = FT_New_Face(_ft_library, full_font.c_str(), 0, &face);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Try loading based on font face name (OS-wide fonts). */
|
|
||||||
if (error != FT_Err_Ok) error = GetFontByFaceName(font, &face);
|
|
||||||
|
|
||||||
if (error == FT_Err_Ok) {
|
|
||||||
error = LoadFont(fs, face, font, GetFontCacheFontSize(fs));
|
|
||||||
if (error != FT_Err_Ok) {
|
|
||||||
ShowInfo("Unable to use '{}' for {} font, FreeType reported error 0x{:X}, using sprite font instead", font, FontSizeToName(fs), error);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
FT_Done_Face(face);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Free everything that was allocated for this font cache.
|
* Free everything that was allocated for this font cache.
|
||||||
*/
|
*/
|
||||||
|
@ -296,19 +206,116 @@ GlyphID FreeTypeFontCache::MapCharToGlyph(char32_t key, bool allow_fallback)
|
||||||
return glyph;
|
return glyph;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
FT_Library _ft_library = nullptr;
|
||||||
* Free everything allocated w.r.t. freetype.
|
|
||||||
*/
|
|
||||||
void UninitFreeType()
|
|
||||||
{
|
|
||||||
FT_Done_FreeType(_ft_library);
|
|
||||||
_ft_library = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if !defined(WITH_FONTCONFIG)
|
class FreeTypeFontCacheFactory : public FontCacheFactory {
|
||||||
|
public:
|
||||||
|
FreeTypeFontCacheFactory() : FontCacheFactory("freetype", "FreeType font provider") {}
|
||||||
|
|
||||||
FT_Error GetFontByFaceName(std::string_view font_name, FT_Face *face) { return FT_Err_Cannot_Open_Resource; }
|
virtual ~FreeTypeFontCacheFactory()
|
||||||
|
{
|
||||||
|
FT_Done_FreeType(_ft_library);
|
||||||
|
_ft_library = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* !defined(WITH_FONTCONFIG) */
|
/**
|
||||||
|
* Loads the freetype font.
|
||||||
|
* First type to load the fontname as if it were a path. If that fails,
|
||||||
|
* try to resolve the filename of the font using fontconfig, where the
|
||||||
|
* format is 'font family name' or 'font family name, font style'.
|
||||||
|
* @param fs The font size to load.
|
||||||
|
*/
|
||||||
|
std::unique_ptr<FontCache> LoadFont(FontSize fs, FontType fonttype) override
|
||||||
|
{
|
||||||
|
if (fonttype != FontType::TrueType) return nullptr;
|
||||||
|
|
||||||
|
FontCacheSubSetting *settings = GetFontCacheSubSetting(fs);
|
||||||
|
|
||||||
|
std::string font = GetFontCacheFontName(fs);
|
||||||
|
if (font.empty()) return nullptr;
|
||||||
|
|
||||||
|
if (_ft_library == nullptr) {
|
||||||
|
if (FT_Init_FreeType(&_ft_library) != FT_Err_Ok) {
|
||||||
|
ShowInfo("Unable to initialize FreeType, using sprite fonts instead");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug(fontcache, 2, "Initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
FT_Face face = nullptr;
|
||||||
|
|
||||||
|
/* If font is an absolute path to a ttf, try loading that first. */
|
||||||
|
int32_t index = 0;
|
||||||
|
if (settings->os_handle != nullptr) index = *static_cast<const int32_t *>(settings->os_handle);
|
||||||
|
FT_Error error = FT_New_Face(_ft_library, font.c_str(), index, &face);
|
||||||
|
|
||||||
|
if (error != FT_Err_Ok) {
|
||||||
|
/* Check if font is a relative filename in one of our search-paths. */
|
||||||
|
std::string full_font = FioFindFullPath(BASE_DIR, font);
|
||||||
|
if (!full_font.empty()) {
|
||||||
|
error = FT_New_Face(_ft_library, full_font.c_str(), 0, &face);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef WITH_FONTCONFIG
|
||||||
|
/* Try loading based on font face name (OS-wide fonts). */
|
||||||
|
if (error != FT_Err_Ok) error = GetFontByFaceName(font, &face);
|
||||||
|
#endif /* WITH_FONTCONFIG */
|
||||||
|
|
||||||
|
if (error != FT_Err_Ok) {
|
||||||
|
FT_Done_Face(face);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return LoadFont(fs, face, font, GetFontCacheFontSize(fs));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FindFallbackFont(struct FontCacheSettings *settings, const std::string &language_isocode, class MissingGlyphSearcher *callback) override
|
||||||
|
{
|
||||||
|
#ifdef WITH_FONTCONFIG
|
||||||
|
if (FontConfigFindFallbackFont(settings, language_isocode, callback)) return true;
|
||||||
|
#endif /* WITH_FONTCONFIG */
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static std::unique_ptr<FontCache> LoadFont(FontSize fs, FT_Face face, std::string_view font_name, uint size)
|
||||||
|
{
|
||||||
|
Debug(fontcache, 2, "Requested '{}', using '{} {}'", font_name, face->family_name, face->style_name);
|
||||||
|
|
||||||
|
/* Attempt to select the unicode character map */
|
||||||
|
FT_Error error = FT_Select_Charmap(face, ft_encoding_unicode);
|
||||||
|
if (error == FT_Err_Invalid_CharMap_Handle) {
|
||||||
|
/* Try to pick a different character map instead. We default to
|
||||||
|
* the first map, but platform_id 0 encoding_id 0 should also
|
||||||
|
* be unicode (strange system...) */
|
||||||
|
FT_CharMap found = face->charmaps[0];
|
||||||
|
|
||||||
|
for (int i = 0; i < face->num_charmaps; ++i) {
|
||||||
|
FT_CharMap charmap = face->charmaps[i];
|
||||||
|
if (charmap->platform_id == 0 && charmap->encoding_id == 0) {
|
||||||
|
found = charmap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found != nullptr) {
|
||||||
|
error = FT_Set_Charmap(face, found);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error != FT_Err_Ok) {
|
||||||
|
FT_Done_Face(face);
|
||||||
|
|
||||||
|
ShowInfo("Unable to use '{}' for {} font, FreeType reported error 0x{:X}, using sprite font instead", font_name, FontSizeToName(fs), error);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_unique<FreeTypeFontCache>(fs, face, size);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static FreeTypeFontCacheFactory s_freetype_fontcache_factory;
|
||||||
|
|
||||||
#endif /* WITH_FREETYPE */
|
#endif /* WITH_FREETYPE */
|
||||||
|
|
|
@ -151,3 +151,22 @@ bool SpriteFontCache::GetDrawGlyphShadow()
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SpriteFontCacheFactory : public FontCacheFactory {
|
||||||
|
public:
|
||||||
|
SpriteFontCacheFactory() : FontCacheFactory("sprite", "Sprite font provider") {}
|
||||||
|
|
||||||
|
std::unique_ptr<FontCache> LoadFont(FontSize fs, FontType fonttype) override
|
||||||
|
{
|
||||||
|
if (fonttype != FontType::Sprite) return nullptr;
|
||||||
|
|
||||||
|
return std::make_unique<SpriteFontCache>(fs);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FindFallbackFont(struct FontCacheSettings *, const std::string &, class MissingGlyphSearcher *) override
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static SpriteFontCacheFactory s_sprite_fontcache_factory;
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
/*
|
|
||||||
* This file is part of OpenTTD.
|
|
||||||
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
|
||||||
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @file fontdetection.h Functions related to detecting/finding the right font. */
|
|
||||||
|
|
||||||
#ifndef FONTDETECTION_H
|
|
||||||
#define FONTDETECTION_H
|
|
||||||
|
|
||||||
#include "fontcache.h"
|
|
||||||
|
|
||||||
#ifdef WITH_FREETYPE
|
|
||||||
|
|
||||||
#include <ft2build.h>
|
|
||||||
#include FT_FREETYPE_H
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load a freetype font face with the given font name.
|
|
||||||
* @param font_name The name of the font to load.
|
|
||||||
* @param face The face that has been found.
|
|
||||||
* @return The error we encountered.
|
|
||||||
*/
|
|
||||||
FT_Error GetFontByFaceName(std::string_view font_name, FT_Face *face);
|
|
||||||
|
|
||||||
#endif /* WITH_FREETYPE */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* We would like to have a fallback font as the current one
|
|
||||||
* doesn't contain all characters we need.
|
|
||||||
* This function must set all fonts of settings.
|
|
||||||
* @param settings the settings to overwrite the fontname of.
|
|
||||||
* @param language_isocode the language, e.g. en_GB.
|
|
||||||
* @param callback The function to call to check for missing glyphs.
|
|
||||||
* @return true if a font has been set, false otherwise.
|
|
||||||
*/
|
|
||||||
bool SetFallbackFont(struct FontCacheSettings *settings, const std::string &language_isocode, class MissingGlyphSearcher *callback);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1253,7 +1253,7 @@ static void GfxMainBlitter(const Sprite *sprite, int x, int y, BlitterMode mode,
|
||||||
*/
|
*/
|
||||||
void LoadStringWidthTable(FontSizes fontsizes)
|
void LoadStringWidthTable(FontSizes fontsizes)
|
||||||
{
|
{
|
||||||
ClearFontCache(fontsizes);
|
FontCache::ClearFontCaches(fontsizes);
|
||||||
|
|
||||||
for (FontSize fs : fontsizes) {
|
for (FontSize fs : fontsizes) {
|
||||||
for (uint i = 0; i != 224; i++) {
|
for (uint i = 0; i != 224; i++) {
|
||||||
|
@ -1820,7 +1820,7 @@ bool AdjustGUIZoom(bool automatic)
|
||||||
if (old_font_zoom != _font_zoom) {
|
if (old_font_zoom != _font_zoom) {
|
||||||
GfxClearFontSpriteCache();
|
GfxClearFontSpriteCache();
|
||||||
}
|
}
|
||||||
ClearFontCache(FONTSIZES_ALL);
|
FontCache::ClearFontCaches(FONTSIZES_ALL);
|
||||||
LoadStringWidthTable();
|
LoadStringWidthTable();
|
||||||
|
|
||||||
SetupWidgetDimensions();
|
SetupWidgetDimensions();
|
||||||
|
|
|
@ -245,7 +245,7 @@ static void RealChangeBlitter(std::string_view repl_blitter)
|
||||||
|
|
||||||
/* Clear caches that might have sprites for another blitter. */
|
/* Clear caches that might have sprites for another blitter. */
|
||||||
VideoDriver::GetInstance()->ClearSystemSprites();
|
VideoDriver::GetInstance()->ClearSystemSprites();
|
||||||
ClearFontCache(FONTSIZES_ALL);
|
FontCache::ClearFontCaches(FONTSIZES_ALL);
|
||||||
GfxClearSpriteCache();
|
GfxClearSpriteCache();
|
||||||
ReInitAllWindows(false);
|
ReInitAllWindows(false);
|
||||||
}
|
}
|
||||||
|
@ -326,7 +326,7 @@ void CheckBlitter()
|
||||||
{
|
{
|
||||||
if (!SwitchNewGRFBlitter()) return;
|
if (!SwitchNewGRFBlitter()) return;
|
||||||
|
|
||||||
ClearFontCache(FONTSIZES_ALL);
|
FontCache::ClearFontCaches(FONTSIZES_ALL);
|
||||||
GfxClearSpriteCache();
|
GfxClearSpriteCache();
|
||||||
ReInitAllWindows(false);
|
ReInitAllWindows(false);
|
||||||
}
|
}
|
||||||
|
@ -338,7 +338,7 @@ void GfxLoadSprites()
|
||||||
|
|
||||||
SwitchNewGRFBlitter();
|
SwitchNewGRFBlitter();
|
||||||
VideoDriver::GetInstance()->ClearSystemSprites();
|
VideoDriver::GetInstance()->ClearSystemSprites();
|
||||||
ClearFontCache(FONTSIZES_ALL);
|
FontCache::ClearFontCaches(FONTSIZES_ALL);
|
||||||
GfxInitSpriteMem();
|
GfxInitSpriteMem();
|
||||||
LoadSpriteTables();
|
LoadSpriteTables();
|
||||||
GfxInitPalettes();
|
GfxInitPalettes();
|
||||||
|
|
|
@ -267,6 +267,7 @@ STR_UNITS_YEARS :{NUM}{NBSP}năm
|
||||||
STR_UNITS_PERIODS :{NUM}{NBSP}kỳ
|
STR_UNITS_PERIODS :{NUM}{NBSP}kỳ
|
||||||
|
|
||||||
STR_LIST_SEPARATOR :,{SPACE}
|
STR_LIST_SEPARATOR :,{SPACE}
|
||||||
|
STR_TRUNCATION_ELLIPSIS :...
|
||||||
|
|
||||||
# Common window strings
|
# Common window strings
|
||||||
STR_LIST_FILTER_TITLE :{BLACK}Lọc:
|
STR_LIST_FILTER_TITLE :{BLACK}Lọc:
|
||||||
|
@ -285,7 +286,7 @@ STR_TOOLTIP_CLOSE_WINDOW :{BLACK}Đóng c
|
||||||
STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS :{BLACK}Tiêu đề cửa sổ - kéo nó để di chuyển cửa số
|
STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS :{BLACK}Tiêu đề cửa sổ - kéo nó để di chuyển cửa số
|
||||||
STR_TOOLTIP_SHADE :{BLACK}Thu gọn cửa sổ - Chỉ hiển thị thanh tiêu đề
|
STR_TOOLTIP_SHADE :{BLACK}Thu gọn cửa sổ - Chỉ hiển thị thanh tiêu đề
|
||||||
STR_TOOLTIP_DEBUG :{BLACK}Hiện thông tin debug của NewGRF
|
STR_TOOLTIP_DEBUG :{BLACK}Hiện thông tin debug của NewGRF
|
||||||
STR_TOOLTIP_DEFSIZE :{BLACK}Chuyển cửa sổ về kích thước mặc định. Ctrl+Click để lưu kích thước hiện tại làm mặc định
|
STR_TOOLTIP_DEFSIZE :{BLACK}Chuyển cửa sổ về kích thước mặc định. Ctrl+Click để lưu kích thước hiện tại làm mặc định. Ctri+Click kép để thiết lập lại mặc định cũ.
|
||||||
STR_TOOLTIP_STICKY :{BLACK}Đánh dấu không-thể-đóng khi bấm nút "Đóng Tất Cả Cửa Sổ". Ctrl+Click để lưu thành trạng thái mặc định
|
STR_TOOLTIP_STICKY :{BLACK}Đánh dấu không-thể-đóng khi bấm nút "Đóng Tất Cả Cửa Sổ". Ctrl+Click để lưu thành trạng thái mặc định
|
||||||
STR_TOOLTIP_RESIZE :{BLACK}Click và kéo để thay đổi kích thước cửa sổ
|
STR_TOOLTIP_RESIZE :{BLACK}Click và kéo để thay đổi kích thước cửa sổ
|
||||||
STR_TOOLTIP_TOGGLE_LARGE_SMALL_WINDOW :{BLACK}Bật kích cỡ cửa sổ lớn/nhỏ
|
STR_TOOLTIP_TOGGLE_LARGE_SMALL_WINDOW :{BLACK}Bật kích cỡ cửa sổ lớn/nhỏ
|
||||||
|
@ -451,6 +452,12 @@ STR_SETTINGS_MENU_SANDBOX_OPTIONS :Tuỳ chọn Sa
|
||||||
STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS :Thiết lập hiệu ứng trong suốt
|
STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS :Thiết lập hiệu ứng trong suốt
|
||||||
STR_SETTINGS_MENU_TOWN_NAMES_DISPLAYED :Hiển thị tên thị trấn
|
STR_SETTINGS_MENU_TOWN_NAMES_DISPLAYED :Hiển thị tên thị trấn
|
||||||
STR_SETTINGS_MENU_STATION_NAMES_DISPLAYED :Hiển thị tên nhà ga
|
STR_SETTINGS_MENU_STATION_NAMES_DISPLAYED :Hiển thị tên nhà ga
|
||||||
|
STR_SETTINGS_MENU_STATION_NAMES_TRAIN :Ga tàu
|
||||||
|
STR_SETTINGS_MENU_STATION_NAMES_LORRY :Trạm xe tải
|
||||||
|
STR_SETTINGS_MENU_STATION_NAMES_BUS :Trạm xe buýt
|
||||||
|
STR_SETTINGS_MENU_STATION_NAMES_SHIP :Cảng
|
||||||
|
STR_SETTINGS_MENU_STATION_NAMES_PLANE :Sân bay
|
||||||
|
STR_SETTINGS_MENU_STATION_NAMES_GHOST :Trạm ma
|
||||||
STR_SETTINGS_MENU_WAYPOINTS_DISPLAYED :Hiển thị tên điểm mốc
|
STR_SETTINGS_MENU_WAYPOINTS_DISPLAYED :Hiển thị tên điểm mốc
|
||||||
STR_SETTINGS_MENU_SIGNS_DISPLAYED :Hiển thị ký hiệu
|
STR_SETTINGS_MENU_SIGNS_DISPLAYED :Hiển thị ký hiệu
|
||||||
STR_SETTINGS_MENU_SHOW_COMPETITOR_SIGNS :Hiển thị biển hiệu và tên của đối thủ
|
STR_SETTINGS_MENU_SHOW_COMPETITOR_SIGNS :Hiển thị biển hiệu và tên của đối thủ
|
||||||
|
@ -627,8 +634,11 @@ STR_GRAPH_CARGO_TOOLTIP_DISABLE_ALL :{BLACK}Không h
|
||||||
STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO :{BLACK}Bật/tắt đồ thị cho hàng hóa này
|
STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO :{BLACK}Bật/tắt đồ thị cho hàng hóa này
|
||||||
STR_GRAPH_CARGO_PAYMENT_CARGO :{TINY_FONT}{BLACK}{STRING}
|
STR_GRAPH_CARGO_PAYMENT_CARGO :{TINY_FONT}{BLACK}{STRING}
|
||||||
|
|
||||||
|
STR_GRAPH_INDUSTRY_CAPTION :{WHITE}{INDUSTRY} - Lịch sử hàng hóa
|
||||||
STR_GRAPH_INDUSTRY_RANGE_PRODUCED :Đã cung cấp
|
STR_GRAPH_INDUSTRY_RANGE_PRODUCED :Đã cung cấp
|
||||||
STR_GRAPH_INDUSTRY_RANGE_TRANSPORTED :Đã vận chuyển
|
STR_GRAPH_INDUSTRY_RANGE_TRANSPORTED :Đã vận chuyển
|
||||||
|
STR_GRAPH_INDUSTRY_RANGE_DELIVERED :Đã giao
|
||||||
|
STR_GRAPH_INDUSTRY_RANGE_WAITING :Đang chờ...
|
||||||
|
|
||||||
STR_GRAPH_PERFORMANCE_DETAIL_TOOLTIP :{BLACK}Hiện chi tiết đánh giá chỉ số năng suất
|
STR_GRAPH_PERFORMANCE_DETAIL_TOOLTIP :{BLACK}Hiện chi tiết đánh giá chỉ số năng suất
|
||||||
|
|
||||||
|
@ -830,7 +840,7 @@ STR_STATUSBAR_INFINITE_MONEY :{WHITE}(tiền
|
||||||
# News message history
|
# News message history
|
||||||
STR_MESSAGE_HISTORY :{WHITE}Lịch Sử Thông Điệp
|
STR_MESSAGE_HISTORY :{WHITE}Lịch Sử Thông Điệp
|
||||||
STR_MESSAGE_HISTORY_TOOLTIP :{BLACK}Danh sách những tin tức gần đây
|
STR_MESSAGE_HISTORY_TOOLTIP :{BLACK}Danh sách những tin tức gần đây
|
||||||
STR_MESSAGE_NEWS_FORMAT :{STRING} - {STRING}
|
STR_MESSAGE_NEWS_FORMAT :{STRING} - {STRING}
|
||||||
|
|
||||||
STR_NEWS_MESSAGE_CAPTION :{WHITE}Thông Điệp
|
STR_NEWS_MESSAGE_CAPTION :{WHITE}Thông Điệp
|
||||||
|
|
||||||
|
@ -958,11 +968,14 @@ STR_GAME_OPTIONS_TAB_SOUND :Âm thanh
|
||||||
STR_GAME_OPTIONS_TAB_SOUND_TOOLTIP :Lựa chọn thiết lập cho âm thanh và nhạc
|
STR_GAME_OPTIONS_TAB_SOUND_TOOLTIP :Lựa chọn thiết lập cho âm thanh và nhạc
|
||||||
STR_GAME_OPTIONS_TAB_SOCIAL :Xã hội
|
STR_GAME_OPTIONS_TAB_SOCIAL :Xã hội
|
||||||
STR_GAME_OPTIONS_TAB_SOCIAL_TOOLTIP :Chọn thiết lập các tích hợp xã hội
|
STR_GAME_OPTIONS_TAB_SOCIAL_TOOLTIP :Chọn thiết lập các tích hợp xã hội
|
||||||
|
STR_GAME_OPTIONS_TAB_ADVANCED :Tùy chọn nâng cao
|
||||||
|
STR_GAME_OPTIONS_TAB_ADVANCED_TOOLTIP :Thay đổi tùy chọn nâng cao
|
||||||
|
|
||||||
STR_GAME_OPTIONS_VOLUME :Âm lượng
|
STR_GAME_OPTIONS_VOLUME :Âm lượng
|
||||||
STR_GAME_OPTIONS_SFX_VOLUME :Hiệu ứng âm thanh
|
STR_GAME_OPTIONS_SFX_VOLUME :Hiệu ứng âm thanh
|
||||||
STR_GAME_OPTIONS_MUSIC_VOLUME :Âm nhạc
|
STR_GAME_OPTIONS_MUSIC_VOLUME :Âm nhạc
|
||||||
|
|
||||||
|
STR_GAME_OPTIONS_SETTING :{STRING}: {ORANGE}{STRING}
|
||||||
|
|
||||||
STR_GAME_OPTIONS_VOLUME_MARK :{NUM}%
|
STR_GAME_OPTIONS_VOLUME_MARK :{NUM}%
|
||||||
|
|
||||||
|
@ -1016,6 +1029,7 @@ STR_GAME_OPTIONS_CURRENCY_IDR :Rupiah Indonesi
|
||||||
STR_GAME_OPTIONS_CURRENCY_MYR :Ringgit Malaysia
|
STR_GAME_OPTIONS_CURRENCY_MYR :Ringgit Malaysia
|
||||||
STR_GAME_OPTIONS_CURRENCY_LVL :Lát-vi-a Lats
|
STR_GAME_OPTIONS_CURRENCY_LVL :Lát-vi-a Lats
|
||||||
STR_GAME_OPTIONS_CURRENCY_PTE :Escudo Bồ Đào Nha
|
STR_GAME_OPTIONS_CURRENCY_PTE :Escudo Bồ Đào Nha
|
||||||
|
STR_GAME_OPTIONS_CURRENCY_UAH :Hryvnia Ukraina
|
||||||
|
|
||||||
STR_GAME_OPTIONS_AUTOSAVE_FRAME :Lưu tự động
|
STR_GAME_OPTIONS_AUTOSAVE_FRAME :Lưu tự động
|
||||||
STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_TOOLTIP :Lựa chọn khoảng thời gian tự động lưu
|
STR_GAME_OPTIONS_AUTOSAVE_DROPDOWN_TOOLTIP :Lựa chọn khoảng thời gian tự động lưu
|
||||||
|
@ -1049,6 +1063,7 @@ STR_GAME_OPTIONS_VIDEO_VSYNC_TOOLTIP :Đánh dấu v
|
||||||
|
|
||||||
STR_GAME_OPTIONS_VIDEO_DRIVER_INFO :Trình điều khiển hiện tại: {STRING}
|
STR_GAME_OPTIONS_VIDEO_DRIVER_INFO :Trình điều khiển hiện tại: {STRING}
|
||||||
|
|
||||||
|
STR_GAME_OPTIONS_INTERFACE :Giao diện
|
||||||
|
|
||||||
STR_GAME_OPTIONS_GUI_SCALE_FRAME :Kích thước giao diện
|
STR_GAME_OPTIONS_GUI_SCALE_FRAME :Kích thước giao diện
|
||||||
STR_GAME_OPTIONS_GUI_SCALE_TOOLTIP :Kéo thanh trượt để điều chỉnh kích thước giao diện. Giữ Ctrl để điều chỉnh liên tục
|
STR_GAME_OPTIONS_GUI_SCALE_TOOLTIP :Kéo thanh trượt để điều chỉnh kích thước giao diện. Giữ Ctrl để điều chỉnh liên tục
|
||||||
|
@ -1073,6 +1088,7 @@ STR_GAME_OPTIONS_PARTICIPATE_SURVEY_LINK_TOOLTIP :Sẽ mở trìn
|
||||||
STR_GAME_OPTIONS_PARTICIPATE_SURVEY_PREVIEW :Xem trước kết quả khảo sát
|
STR_GAME_OPTIONS_PARTICIPATE_SURVEY_PREVIEW :Xem trước kết quả khảo sát
|
||||||
STR_GAME_OPTIONS_PARTICIPATE_SURVEY_PREVIEW_TOOLTIP :Hiển thị kết quả khảo sát ở ván chơi hiện tại
|
STR_GAME_OPTIONS_PARTICIPATE_SURVEY_PREVIEW_TOOLTIP :Hiển thị kết quả khảo sát ở ván chơi hiện tại
|
||||||
|
|
||||||
|
STR_GAME_OPTIONS_DISPLAY :Hiển thị
|
||||||
|
|
||||||
STR_GAME_OPTIONS_REFRESH_RATE :Tần số quét màn hình
|
STR_GAME_OPTIONS_REFRESH_RATE :Tần số quét màn hình
|
||||||
STR_GAME_OPTIONS_REFRESH_RATE_TOOLTIP :Chọn tần số quét màn hình
|
STR_GAME_OPTIONS_REFRESH_RATE_TOOLTIP :Chọn tần số quét màn hình
|
||||||
|
@ -1094,7 +1110,7 @@ STR_GAME_OPTIONS_BASE_MUSIC_DESCRIPTION_TOOLTIP :Thông tin thê
|
||||||
STR_GAME_OPTIONS_ONLINE_CONTENT :Tải Nội Dung
|
STR_GAME_OPTIONS_ONLINE_CONTENT :Tải Nội Dung
|
||||||
STR_GAME_OPTIONS_ONLINE_CONTENT_TOOLTIP :Kiểm tra những nội dung mới & cập nhật để tải về
|
STR_GAME_OPTIONS_ONLINE_CONTENT_TOOLTIP :Kiểm tra những nội dung mới & cập nhật để tải về
|
||||||
|
|
||||||
STR_GAME_OPTIONS_SOCIAL_PLUGINS_NONE :{LTBLUE}(không có plugins được cài đặt để tích hợp vào nền tảng xã hội)
|
STR_GAME_OPTIONS_SOCIAL_PLUGINS_NONE :(không có plugins được cài đặt để tích hợp vào nền tảng xã hội)
|
||||||
|
|
||||||
STR_GAME_OPTIONS_SOCIAL_PLUGIN_TITLE :{STRING} ({STRING})
|
STR_GAME_OPTIONS_SOCIAL_PLUGIN_TITLE :{STRING} ({STRING})
|
||||||
STR_GAME_OPTIONS_SOCIAL_PLUGIN_PLATFORM :Nền tảng:
|
STR_GAME_OPTIONS_SOCIAL_PLUGIN_PLATFORM :Nền tảng:
|
||||||
|
@ -1288,6 +1304,9 @@ STR_CONFIG_SETTING_INTEREST_RATE_HELPTEXT :Lãi xuất vay
|
||||||
STR_CONFIG_SETTING_RUNNING_COSTS :Chi phí hoạt động: {STRING}
|
STR_CONFIG_SETTING_RUNNING_COSTS :Chi phí hoạt động: {STRING}
|
||||||
STR_CONFIG_SETTING_RUNNING_COSTS_HELPTEXT :Thiết lập mức độ tính chi phí bảo trì và vận hành đối với phương tiện và hạ tầng giao thông
|
STR_CONFIG_SETTING_RUNNING_COSTS_HELPTEXT :Thiết lập mức độ tính chi phí bảo trì và vận hành đối với phương tiện và hạ tầng giao thông
|
||||||
###length 3
|
###length 3
|
||||||
|
STR_CONFIG_SETTING_RUNNING_COSTS_LOW :Thấp
|
||||||
|
STR_CONFIG_SETTING_RUNNING_COSTS_MEDIUM :Trung bình
|
||||||
|
STR_CONFIG_SETTING_RUNNING_COSTS_HIGH :Cao
|
||||||
|
|
||||||
STR_CONFIG_SETTING_CONSTRUCTION_SPEED :Tốc độ xây dựng: {STRING}
|
STR_CONFIG_SETTING_CONSTRUCTION_SPEED :Tốc độ xây dựng: {STRING}
|
||||||
STR_CONFIG_SETTING_CONSTRUCTION_SPEED_HELPTEXT :Giới hạn hành động xây dựng của AI
|
STR_CONFIG_SETTING_CONSTRUCTION_SPEED_HELPTEXT :Giới hạn hành động xây dựng của AI
|
||||||
|
@ -1310,6 +1329,9 @@ STR_CONFIG_SETTING_SUBSIDY_DURATION_DISABLED :Không có tr
|
||||||
STR_CONFIG_SETTING_CONSTRUCTION_COSTS :Chi phí xây dựng: {STRING}
|
STR_CONFIG_SETTING_CONSTRUCTION_COSTS :Chi phí xây dựng: {STRING}
|
||||||
STR_CONFIG_SETTING_CONSTRUCTION_COSTS_HELPTEXT :Thiết lập mức độ xây dựng và chi phí mua sắm
|
STR_CONFIG_SETTING_CONSTRUCTION_COSTS_HELPTEXT :Thiết lập mức độ xây dựng và chi phí mua sắm
|
||||||
###length 3
|
###length 3
|
||||||
|
STR_CONFIG_SETTING_CONSTRUCTION_COSTS_LOW :Thấp
|
||||||
|
STR_CONFIG_SETTING_CONSTRUCTION_COSTS_MEDIUM :Trung bình
|
||||||
|
STR_CONFIG_SETTING_CONSTRUCTION_COSTS_HIGH :Cao
|
||||||
|
|
||||||
STR_CONFIG_SETTING_RECESSIONS :Suy thoái: {STRING}
|
STR_CONFIG_SETTING_RECESSIONS :Suy thoái: {STRING}
|
||||||
STR_CONFIG_SETTING_RECESSIONS_HELPTEXT :Nếu bật, thì các đợt suy thoái sẽ xảy ra vài năm một lần. Trong suy thoái tất cả sản xuất sẽ giảm mạnh (và sẽ trở lại như cũ sau khi suy thoái kết thúc)
|
STR_CONFIG_SETTING_RECESSIONS_HELPTEXT :Nếu bật, thì các đợt suy thoái sẽ xảy ra vài năm một lần. Trong suy thoái tất cả sản xuất sẽ giảm mạnh (và sẽ trở lại như cũ sau khi suy thoái kết thúc)
|
||||||
|
@ -1979,8 +2001,12 @@ STR_CONFIG_SETTING_TOWN_FOUNDING_FORBIDDEN :không cho phé
|
||||||
STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED :cho phép
|
STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED :cho phép
|
||||||
STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED_CUSTOM_LAYOUT :cho phép, tùy chọn bố trí đô thị
|
STR_CONFIG_SETTING_TOWN_FOUNDING_ALLOWED_CUSTOM_LAYOUT :cho phép, tùy chọn bố trí đô thị
|
||||||
|
|
||||||
|
STR_CONFIG_SETTING_HOUSE_PLACER :Đật từng ngôi nhà: {STRING}
|
||||||
STR_CONFIG_SETTING_HOUSE_PLACER_HELPTEXT :Bật tùy chọn này cho phép người chơi đặt nhà cửa bằng tay
|
STR_CONFIG_SETTING_HOUSE_PLACER_HELPTEXT :Bật tùy chọn này cho phép người chơi đặt nhà cửa bằng tay
|
||||||
###length 3
|
###length 3
|
||||||
|
STR_CONFIG_SETTING_HOUSE_PLACER_FORBIDDEN :Không cho phép
|
||||||
|
STR_CONFIG_SETTING_HOUSE_PLACER_ALLOWED :Cho phép
|
||||||
|
STR_CONFIG_SETTING_HOUSE_PLACER_FULLY_CONSTRUCTED :Cho phép, đã hoàn thành thi công
|
||||||
|
|
||||||
STR_CONFIG_SETTING_TOWN_CARGOGENMODE :Nhu cầu vận chuyển hàng đô thị: {STRING}
|
STR_CONFIG_SETTING_TOWN_CARGOGENMODE :Nhu cầu vận chuyển hàng đô thị: {STRING}
|
||||||
STR_CONFIG_SETTING_TOWN_CARGOGENMODE_HELPTEXT :Lượng hàng hoá cần vận chuyển ở trong đô thị, tỉ lệ với tổng dân số của độ thị.{}Tăng tỉ lệ bình phương: một đô thị to gấp 2 sẽ tăng 4 lần số hành khách.{}Tăng tỉ lệ thuận: một đô thị tăng gấp 2 sẽ tăng gấp 2 lần số hành khách
|
STR_CONFIG_SETTING_TOWN_CARGOGENMODE_HELPTEXT :Lượng hàng hoá cần vận chuyển ở trong đô thị, tỉ lệ với tổng dân số của độ thị.{}Tăng tỉ lệ bình phương: một đô thị to gấp 2 sẽ tăng 4 lần số hành khách.{}Tăng tỉ lệ thuận: một đô thị tăng gấp 2 sẽ tăng gấp 2 lần số hành khách
|
||||||
|
@ -2009,7 +2035,7 @@ STR_CONFIG_SETTING_SOFT_LIMIT :Giới hạn s
|
||||||
STR_CONFIG_SETTING_SOFT_LIMIT_HELPTEXT :Số lượng cửa sổ chưa neo (tối đa) trước khi tự động đóng để nhường chỗ khi mở cửa sổ mới
|
STR_CONFIG_SETTING_SOFT_LIMIT_HELPTEXT :Số lượng cửa sổ chưa neo (tối đa) trước khi tự động đóng để nhường chỗ khi mở cửa sổ mới
|
||||||
STR_CONFIG_SETTING_SOFT_LIMIT_VALUE :{COMMA}
|
STR_CONFIG_SETTING_SOFT_LIMIT_VALUE :{COMMA}
|
||||||
###setting-zero-is-special
|
###setting-zero-is-special
|
||||||
STR_CONFIG_SETTING_SOFT_LIMIT_DISABLED :tắt
|
STR_CONFIG_SETTING_SOFT_LIMIT_DISABLED :Tắt
|
||||||
|
|
||||||
STR_CONFIG_SETTING_ZOOM_MIN :Độ phóng to tối đa: {STRING}
|
STR_CONFIG_SETTING_ZOOM_MIN :Độ phóng to tối đa: {STRING}
|
||||||
STR_CONFIG_SETTING_ZOOM_MIN_HELPTEXT :Độ phóng to tối đa của cửa sổ. Độ càng cao thì yêu cầu bộ nhớ càng nhiều
|
STR_CONFIG_SETTING_ZOOM_MIN_HELPTEXT :Độ phóng to tối đa của cửa sổ. Độ càng cao thì yêu cầu bộ nhớ càng nhiều
|
||||||
|
@ -2061,9 +2087,9 @@ STR_CONFIG_SETTING_DISTRIBUTION_ARMOURED_HELPTEXT :Loại hàng h
|
||||||
STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT :Chế độ phân phối đối với các loại hàng hóa mặc định: {STRING}
|
STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT :Chế độ phân phối đối với các loại hàng hóa mặc định: {STRING}
|
||||||
STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT_HELPTEXT :"Không đối xứng" có nghĩa là số lượng hàng hóa tùy ý có thể được gửi theo một trong hai hướng. "Thủ công" có nghĩa là những loại hàng hóa đó sẽ không được phân phối tự động
|
STR_CONFIG_SETTING_DISTRIBUTION_DEFAULT_HELPTEXT :"Không đối xứng" có nghĩa là số lượng hàng hóa tùy ý có thể được gửi theo một trong hai hướng. "Thủ công" có nghĩa là những loại hàng hóa đó sẽ không được phân phối tự động
|
||||||
###length 3
|
###length 3
|
||||||
STR_CONFIG_SETTING_DISTRIBUTION_MANUAL :bằng tay
|
STR_CONFIG_SETTING_DISTRIBUTION_MANUAL :Bằng tay
|
||||||
STR_CONFIG_SETTING_DISTRIBUTION_ASYMMETRIC :bất đối xứng
|
STR_CONFIG_SETTING_DISTRIBUTION_ASYMMETRIC :Bất đối xứng
|
||||||
STR_CONFIG_SETTING_DISTRIBUTION_SYMMETRIC :đối xứng
|
STR_CONFIG_SETTING_DISTRIBUTION_SYMMETRIC :Đối xứng
|
||||||
|
|
||||||
STR_CONFIG_SETTING_LINKGRAPH_ACCURACY :Độ chính xác phân phối: {STRING}
|
STR_CONFIG_SETTING_LINKGRAPH_ACCURACY :Độ chính xác phân phối: {STRING}
|
||||||
STR_CONFIG_SETTING_LINKGRAPH_ACCURACY_HELPTEXT :Mức chính xác tính toán đồ thị, nếu giá trị càng cao càng tốn CPU và trò chơi có thể chậm phản ứng, tuy nhiên giá trị thấp sẽ khiến việc phân phối sẽ giảm sự chính xác và bạn sẽ thấy sự khác biệt là hàng hóa không gửi đến chỗ cần đến
|
STR_CONFIG_SETTING_LINKGRAPH_ACCURACY_HELPTEXT :Mức chính xác tính toán đồ thị, nếu giá trị càng cao càng tốn CPU và trò chơi có thể chậm phản ứng, tuy nhiên giá trị thấp sẽ khiến việc phân phối sẽ giảm sự chính xác và bạn sẽ thấy sự khác biệt là hàng hóa không gửi đến chỗ cần đến
|
||||||
|
@ -2124,7 +2150,7 @@ STR_CONFIG_SETTING_LOCALISATION_UNITS_HEIGHT_SI :SI (m)
|
||||||
STR_CONFIG_SETTING_LOCALISATION :Tiêu Chuẩn Đo Lường
|
STR_CONFIG_SETTING_LOCALISATION :Tiêu Chuẩn Đo Lường
|
||||||
STR_CONFIG_SETTING_GRAPHICS :Đồ họa
|
STR_CONFIG_SETTING_GRAPHICS :Đồ họa
|
||||||
STR_CONFIG_SETTING_SOUND :Âm thanh
|
STR_CONFIG_SETTING_SOUND :Âm thanh
|
||||||
STR_CONFIG_SETTING_INTERFACE :Giao Diện
|
STR_CONFIG_SETTING_INTERFACE :Giao diện
|
||||||
STR_CONFIG_SETTING_INTERFACE_GENERAL :Tổng quát
|
STR_CONFIG_SETTING_INTERFACE_GENERAL :Tổng quát
|
||||||
STR_CONFIG_SETTING_INTERFACE_VIEWPORTS :Vùng nhìn
|
STR_CONFIG_SETTING_INTERFACE_VIEWPORTS :Vùng nhìn
|
||||||
STR_CONFIG_SETTING_INTERFACE_CONSTRUCTION :Xây Dựng
|
STR_CONFIG_SETTING_INTERFACE_CONSTRUCTION :Xây Dựng
|
||||||
|
@ -2178,6 +2204,8 @@ STR_VIDEO_DRIVER_ERROR_NO_HARDWARE_ACCELERATION :{WHITE}... khô
|
||||||
STR_VIDEO_DRIVER_ERROR_HARDWARE_ACCELERATION_CRASH :{WHITE}... trình điều khiển GPU đã làm trò chơi bị lỗi. Tăng tốc phần cứng đã được tắt
|
STR_VIDEO_DRIVER_ERROR_HARDWARE_ACCELERATION_CRASH :{WHITE}... trình điều khiển GPU đã làm trò chơi bị lỗi. Tăng tốc phần cứng đã được tắt
|
||||||
|
|
||||||
# Intro window
|
# Intro window
|
||||||
|
STR_INTRO_CAPTION :{WHITE}OpenTTD
|
||||||
|
STR_INTRO_VERSION :OpenTTD {REV}
|
||||||
|
|
||||||
STR_INTRO_NEW_GAME :{BLACK}Màn Chơi Mới
|
STR_INTRO_NEW_GAME :{BLACK}Màn Chơi Mới
|
||||||
STR_INTRO_LOAD_GAME :{BLACK}Nạp Ván Chơi
|
STR_INTRO_LOAD_GAME :{BLACK}Nạp Ván Chơi
|
||||||
|
@ -2311,16 +2339,19 @@ STR_FACE_SIMPLE_TOOLTIP :{BLACK}Trình c
|
||||||
STR_FACE_LOAD :{BLACK}Nạp
|
STR_FACE_LOAD :{BLACK}Nạp
|
||||||
STR_FACE_LOAD_TOOLTIP :{BLACK}Chọn vẻ mặt ưa thích
|
STR_FACE_LOAD_TOOLTIP :{BLACK}Chọn vẻ mặt ưa thích
|
||||||
STR_FACE_LOAD_DONE :{WHITE}Vẻ mặt ưa thích đã được nạp từ file thiết lập của OpenTTD.
|
STR_FACE_LOAD_DONE :{WHITE}Vẻ mặt ưa thích đã được nạp từ file thiết lập của OpenTTD.
|
||||||
STR_FACE_FACECODE :{BLACK}Khuôn mặt thứ.
|
STR_FACE_FACECODE :{BLACK}Mã số khuôn mặt
|
||||||
STR_FACE_FACECODE_TOOLTIP :{BLACK}Xem và/hoặc sửa số vẻ mặt của chủ tịch công ty
|
STR_FACE_FACECODE_TOOLTIP :{BLACK}Xem và/hoặc sửa mã số gương mặt của chủ tịch công ty
|
||||||
STR_FACE_FACECODE_CAPTION :{WHITE}Xem và/hoặc chọn số bộ mặt người chơi
|
STR_FACE_FACECODE_CAPTION :{WHITE}Xem và/hoặc chọn mã số gương mặt người chơi
|
||||||
STR_FACE_FACECODE_SET :{WHITE}Mã số gương mặt mới được thiết lập.
|
STR_FACE_FACECODE_SET :{WHITE}Gương mặt người chơi mới được thiết lập.
|
||||||
STR_FACE_FACECODE_ERR :{WHITE}Không thể thiết lập mã số gương mặt - mã số phải trong khoảng từ 0 đến 4,294,967,295!
|
STR_FACE_FACECODE_ERR :{WHITE}Không thể thiết lập mã số gương mặt - Nhãn và mã số phải hợp lệ
|
||||||
STR_FACE_SAVE :{BLACK}Lưu
|
STR_FACE_SAVE :{BLACK}Lưu
|
||||||
STR_FACE_SAVE_TOOLTIP :{BLACK}Lưu gương mặt yêu thích
|
STR_FACE_SAVE_TOOLTIP :{BLACK}Lưu gương mặt yêu thích
|
||||||
STR_FACE_SAVE_DONE :{WHITE}Gương mặt yêu thích này sẽ được lưu lại trong tập tin cấu hình OpenTTD .
|
STR_FACE_SAVE_DONE :{WHITE}Gương mặt yêu thích này sẽ được lưu lại trong tập tin cấu hình OpenTTD .
|
||||||
|
STR_FACE_SETTING_TOGGLE :{STRING} {ORANGE}{STRING}
|
||||||
|
STR_FACE_SETTING_NUMERIC :{STRING} {ORANGE}{NUM} / {NUM}
|
||||||
STR_FACE_YES :Đồng ý
|
STR_FACE_YES :Đồng ý
|
||||||
STR_FACE_NO :Không
|
STR_FACE_NO :Không
|
||||||
|
STR_FACE_STYLE :Kiểu:
|
||||||
STR_FACE_HAIR :Tóc:
|
STR_FACE_HAIR :Tóc:
|
||||||
STR_FACE_EYEBROWS :Lông mày:
|
STR_FACE_EYEBROWS :Lông mày:
|
||||||
STR_FACE_EYECOLOUR :Màu mắt:
|
STR_FACE_EYECOLOUR :Màu mắt:
|
||||||
|
@ -2607,7 +2638,7 @@ STR_NETWORK_MESSAGE_CLIENT_LEFT :*** {STRING} r
|
||||||
STR_NETWORK_MESSAGE_NAME_CHANGE :*** {STRING} đã đổi tên thành {STRING}
|
STR_NETWORK_MESSAGE_NAME_CHANGE :*** {STRING} đã đổi tên thành {STRING}
|
||||||
STR_NETWORK_MESSAGE_GIVE_MONEY :*** {STRING} tặng {CURRENCY_LONG} cho {STRING}
|
STR_NETWORK_MESSAGE_GIVE_MONEY :*** {STRING} tặng {CURRENCY_LONG} cho {STRING}
|
||||||
STR_NETWORK_MESSAGE_SERVER_SHUTDOWN :{WHITE}Server kết thúc phiên
|
STR_NETWORK_MESSAGE_SERVER_SHUTDOWN :{WHITE}Server kết thúc phiên
|
||||||
STR_NETWORK_MESSAGE_SERVER_REBOOT :{WHITE}Server khởi động lại...{}Xin chờ...
|
STR_NETWORK_MESSAGE_SERVER_REBOOT :{WHITE}Server khởi động lại...{}{}Xin chờ...
|
||||||
STR_NETWORK_MESSAGE_KICKED :*** {STRING} đã bị đá khỏi ván chơi. Lý do: ({STRING})
|
STR_NETWORK_MESSAGE_KICKED :*** {STRING} đã bị đá khỏi ván chơi. Lý do: ({STRING})
|
||||||
|
|
||||||
STR_NETWORK_ERROR_COORDINATOR_REGISTRATION_FAILED :{WHITE}Đăng ký server thất bại
|
STR_NETWORK_ERROR_COORDINATOR_REGISTRATION_FAILED :{WHITE}Đăng ký server thất bại
|
||||||
|
@ -2793,6 +2824,10 @@ STR_PICKER_MODE_USED_TOOLTIP :Bật/tắt hi
|
||||||
STR_PICKER_MODE_SAVED :Đã lưu
|
STR_PICKER_MODE_SAVED :Đã lưu
|
||||||
STR_PICKER_MODE_SAVED_TOOLTIP :Bật/tắt hiển thị những hạng mục được lưu
|
STR_PICKER_MODE_SAVED_TOOLTIP :Bật/tắt hiển thị những hạng mục được lưu
|
||||||
|
|
||||||
|
STR_PICKER_PREVIEW_SHRINK :-
|
||||||
|
STR_PICKER_PREVIEW_SHRINK_TOOLTIP :Giảm chiều cao của ảnh xem trước. Ctrl+Click để giảm đến mức tối thiểu
|
||||||
|
STR_PICKER_PREVIEW_EXPAND :+
|
||||||
|
STR_PICKER_PREVIEW_EXPAND_TOOLTIP :Tăng chiều cao của ảnh xem trước. Ctrl+Click để tăng đến mức tối đa
|
||||||
|
|
||||||
STR_PICKER_STATION_CLASS_TOOLTIP :Chọn loại ga bến cần hiển thị
|
STR_PICKER_STATION_CLASS_TOOLTIP :Chọn loại ga bến cần hiển thị
|
||||||
STR_PICKER_STATION_TYPE_TOOLTIP :Chọn loại ga bến để xây. Ctrl+Click để thêm hoặc bớt vào danh sách lưu
|
STR_PICKER_STATION_TYPE_TOOLTIP :Chọn loại ga bến để xây. Ctrl+Click để thêm hoặc bớt vào danh sách lưu
|
||||||
|
@ -2816,6 +2851,7 @@ STR_HOUSE_PICKER_YEARS_FROM :{BLACK}Năm: {O
|
||||||
STR_HOUSE_PICKER_YEARS_UNTIL :{BLACK}Năm: {ORANGE}Đến {NUM}
|
STR_HOUSE_PICKER_YEARS_UNTIL :{BLACK}Năm: {ORANGE}Đến {NUM}
|
||||||
STR_HOUSE_PICKER_SIZE :{BLACK}Kích thước: {ORANGE}{NUM}x{NUM} ô
|
STR_HOUSE_PICKER_SIZE :{BLACK}Kích thước: {ORANGE}{NUM}x{NUM} ô
|
||||||
STR_HOUSE_PICKER_CARGO_ACCEPTED :{BLACK}Hàng hóa được chấp nhận: {ORANGE}
|
STR_HOUSE_PICKER_CARGO_ACCEPTED :{BLACK}Hàng hóa được chấp nhận: {ORANGE}
|
||||||
|
STR_HOUSE_PICKER_CARGO_PRODUCED :{BLACK}Hàng hóa cung cấp: {ORANGE}{CARGO_LIST}
|
||||||
|
|
||||||
STR_HOUSE_PICKER_CLASS_ZONE1 :Ngoài rìa
|
STR_HOUSE_PICKER_CLASS_ZONE1 :Ngoài rìa
|
||||||
STR_HOUSE_PICKER_CLASS_ZONE2 :Ngoại ô
|
STR_HOUSE_PICKER_CLASS_ZONE2 :Ngoại ô
|
||||||
|
@ -2824,6 +2860,7 @@ STR_HOUSE_PICKER_CLASS_ZONE4 :Phía trong ngo
|
||||||
STR_HOUSE_PICKER_CLASS_ZONE5 :Nội thành
|
STR_HOUSE_PICKER_CLASS_ZONE5 :Nội thành
|
||||||
|
|
||||||
STR_HOUSE_PICKER_PROTECT_TITLE :Ngăn chặn nâng cấp
|
STR_HOUSE_PICKER_PROTECT_TITLE :Ngăn chặn nâng cấp
|
||||||
|
STR_HOUSE_PICKER_PROTECT_TOOLTIP :Chọn nếu ngôi nhà này có được bảo vệ khỏi việc bị thay thế hay không khi thị trấn phát triển
|
||||||
STR_HOUSE_PICKER_PROTECT_OFF :Tắt
|
STR_HOUSE_PICKER_PROTECT_OFF :Tắt
|
||||||
STR_HOUSE_PICKER_PROTECT_ON :Bật
|
STR_HOUSE_PICKER_PROTECT_ON :Bật
|
||||||
|
|
||||||
|
@ -3031,6 +3068,11 @@ STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP :{BLACK}Chọn q
|
||||||
STR_FOUND_TOWN_CITY :{BLACK}Đô thị
|
STR_FOUND_TOWN_CITY :{BLACK}Đô thị
|
||||||
STR_FOUND_TOWN_CITY_TOOLTIP :{BLACK}Thành phố phát triển nhanh hơn thị trấn{}Tuỳ thuộc thiết lập, chúng lớn hơn khi khai sinh
|
STR_FOUND_TOWN_CITY_TOOLTIP :{BLACK}Thành phố phát triển nhanh hơn thị trấn{}Tuỳ thuộc thiết lập, chúng lớn hơn khi khai sinh
|
||||||
|
|
||||||
|
STR_FOUND_TOWN_EXPAND_MODE :{YELLOW}Mở rộng thị trấn:
|
||||||
|
STR_FOUND_TOWN_EXPAND_BUILDINGS :Công trình
|
||||||
|
STR_FOUND_TOWN_EXPAND_BUILDINGS_TOOLTIP :Tăng số công trình của thị trấn
|
||||||
|
STR_FOUND_TOWN_EXPAND_ROADS :Đường sá
|
||||||
|
STR_FOUND_TOWN_EXPAND_ROADS_TOOLTIP :Tăng số đường sá của thị trấn
|
||||||
|
|
||||||
STR_FOUND_TOWN_ROAD_LAYOUT :{YELLOW}Quy hoạch đường đô thị:
|
STR_FOUND_TOWN_ROAD_LAYOUT :{YELLOW}Quy hoạch đường đô thị:
|
||||||
STR_FOUND_TOWN_SELECT_LAYOUT_TOOLTIP :{BLACK}Chọn để quy hoạch đường bộ trong đô thị
|
STR_FOUND_TOWN_SELECT_LAYOUT_TOOLTIP :{BLACK}Chọn để quy hoạch đường bộ trong đô thị
|
||||||
|
@ -3103,6 +3145,8 @@ STR_LANG_AREA_INFORMATION_TRAM_TYPE :{BLACK}Kiểu x
|
||||||
STR_LANG_AREA_INFORMATION_RAIL_SPEED_LIMIT :{BLACK}Giới hạn tốc độ đường ray: {LTBLUE}{VELOCITY}
|
STR_LANG_AREA_INFORMATION_RAIL_SPEED_LIMIT :{BLACK}Giới hạn tốc độ đường ray: {LTBLUE}{VELOCITY}
|
||||||
STR_LANG_AREA_INFORMATION_ROAD_SPEED_LIMIT :{BLACK}Hạn chế tốc độ đường bộ: {LTBLUE}{VELOCITY}
|
STR_LANG_AREA_INFORMATION_ROAD_SPEED_LIMIT :{BLACK}Hạn chế tốc độ đường bộ: {LTBLUE}{VELOCITY}
|
||||||
STR_LANG_AREA_INFORMATION_TRAM_SPEED_LIMIT :{BLACK}Tốc độ xe điện giới hạn: {LTBLUE}{VELOCITY}
|
STR_LANG_AREA_INFORMATION_TRAM_SPEED_LIMIT :{BLACK}Tốc độ xe điện giới hạn: {LTBLUE}{VELOCITY}
|
||||||
|
STR_LAND_AREA_INFORMATION_TOWN_CAN_UPGRADE :{BLACK}Nâng cấp thị trấn: {LTBLUE}Có thể
|
||||||
|
STR_LAND_AREA_INFORMATION_TOWN_CANNOT_UPGRADE :{BLACK}Nâng cấp thị trấn: {LTBLUE}Không thể
|
||||||
|
|
||||||
# Description of land area of different tiles
|
# Description of land area of different tiles
|
||||||
STR_LAI_CLEAR_DESCRIPTION_ROCKS :Đá
|
STR_LAI_CLEAR_DESCRIPTION_ROCKS :Đá
|
||||||
|
@ -3111,6 +3155,9 @@ STR_LAI_CLEAR_DESCRIPTION_BARE_LAND :Đất trống
|
||||||
STR_LAI_CLEAR_DESCRIPTION_GRASS :Bãi cỏ
|
STR_LAI_CLEAR_DESCRIPTION_GRASS :Bãi cỏ
|
||||||
STR_LAI_CLEAR_DESCRIPTION_FIELDS :Cánh đồng
|
STR_LAI_CLEAR_DESCRIPTION_FIELDS :Cánh đồng
|
||||||
STR_LAI_CLEAR_DESCRIPTION_DESERT :Hoang mạc
|
STR_LAI_CLEAR_DESCRIPTION_DESERT :Hoang mạc
|
||||||
|
STR_LAI_CLEAR_DESCRIPTION_SNOWY_ROCKS :Đá có tuyết phủ
|
||||||
|
STR_LAI_CLEAR_DESCRIPTION_SNOWY_ROUGH_LAND :Đất gồ ghề có tuyết phủ
|
||||||
|
STR_LAI_CLEAR_DESCRIPTION_SNOWY_GRASS :Cỏ có tuyết phủ
|
||||||
|
|
||||||
STR_LAI_RAIL_DESCRIPTION_TRACK :Đường ray
|
STR_LAI_RAIL_DESCRIPTION_TRACK :Đường ray
|
||||||
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS :Đường ray với đèn hiệu khóa
|
STR_LAI_RAIL_DESCRIPTION_TRACK_WITH_NORMAL_SIGNALS :Đường ray với đèn hiệu khóa
|
||||||
|
@ -3579,17 +3626,17 @@ STR_NEWGRF_LIST_COMPATIBLE :{YELLOW}Đã t
|
||||||
STR_NEWGRF_LIST_MISSING :{RED}Thiếu files
|
STR_NEWGRF_LIST_MISSING :{RED}Thiếu files
|
||||||
|
|
||||||
# NewGRF 'it's broken' warnings
|
# NewGRF 'it's broken' warnings
|
||||||
STR_NEWGRF_BROKEN :{WHITE}Hoạt động của NewGRF '{0:STRING}' có thể gây mất đồng bộ hoặc bị treo.
|
STR_NEWGRF_BROKEN :{WHITE}Hoạt động của NewGRF '{PUSH_COLOUR}{0:STRING}{POP_COLOUR}' có thể gây mất đồng bộ hoặc bị treo.
|
||||||
STR_NEWGRF_BROKEN_POWERED_WAGON :{WHITE}Trạng thái đầu kéo '{1:ENGINE}' được thay đổi khi không ở trong xưởng sửa chữa.
|
STR_NEWGRF_BROKEN_POWERED_WAGON :{WHITE}Trạng thái đầu kéo '{PUSH_COLOUR}{1:ENGINE}{POP_COLOUR}' được thay đổi khi không ở trong xưởng sửa chữa.
|
||||||
STR_NEWGRF_BROKEN_VEHICLE_LENGTH :{WHITE}Nó cắt ngắn độ dài của đoàn tàu '{1:ENGINE}' nếu không ở trong xưởng.
|
STR_NEWGRF_BROKEN_VEHICLE_LENGTH :{WHITE}Nó cắt ngắn độ dài của đoàn tàu '{PUSH_COLOUR}{1:ENGINE}{POP_COLOUR}' nếu không ở trong xưởng.
|
||||||
STR_NEWGRF_BROKEN_CAPACITY :{WHITE}Sức chứa của phương tiện bị thay đổi '{1:ENGINE}' khi không ở trong xưởng hoặc vì cải biến
|
STR_NEWGRF_BROKEN_CAPACITY :{WHITE}Sức chứa của phương tiện bị thay đổi '{PUSH_COLOUR}{1:ENGINE}{POP_COLOUR}' khi không ở trong xưởng hoặc vì cải biến
|
||||||
STR_BROKEN_VEHICLE_LENGTH :{WHITE}Đoàn tàu '{VEHICLE}' của '{COMPANY}' có độ dài không hợp lệ. Sự cố có thể có căn nguyên từ NewGRFs. Ván chơi có thể mất đồng bộ hoặc bị treo
|
STR_BROKEN_VEHICLE_LENGTH :{WHITE}Đoàn tàu '{VEHICLE}' của '{COMPANY}' có độ dài không hợp lệ. Sự cố có thể có căn nguyên từ NewGRFs. Ván chơi có thể mất đồng bộ hoặc bị treo
|
||||||
|
|
||||||
STR_NEWGRF_BUGGY :{WHITE}NewGRF '{0:STRING}' không hợp lệ.
|
STR_NEWGRF_BUGGY :{WHITE}NewGRF '{PUSH_COLOUR}{0:STRING}{POP_COLOUR}' không hợp lệ.
|
||||||
STR_NEWGRF_BUGGY_ARTICULATED_CARGO :{WHITE}Danh mục hàng hoá/cải biến được cho '{1:ENGINE}' khác với danh mục mua được sau khi đã có. Việc này khiến cho việc tự thay thế hay là tự cải biến không chính xác.
|
STR_NEWGRF_BUGGY_ARTICULATED_CARGO :{WHITE}Danh mục hàng hoá/cải biến được cho '{PUSH_COLOUR}{1:ENGINE}{POP_COLOUR}' khác với danh mục mua được sau khi đã có. Việc này khiến cho việc tự thay thế hay là tự cải biến không chính xác.
|
||||||
STR_NEWGRF_BUGGY_ENDLESS_PRODUCTION_CALLBACK :{WHITE}'{1:STRING}' gây ra một vòng lặp vô tận khi gọi hàm callback.
|
STR_NEWGRF_BUGGY_ENDLESS_PRODUCTION_CALLBACK :{WHITE}'{PUSH_COLOUR}{1:STRING}{POP_COLOUR}' gây ra một vòng lặp vô tận khi gọi hàm callback.
|
||||||
STR_NEWGRF_BUGGY_UNKNOWN_CALLBACK_RESULT :{WHITE}Hàm callback {1:HEX} gửi trả kết quả sai/không rõ {2:HEX}
|
STR_NEWGRF_BUGGY_UNKNOWN_CALLBACK_RESULT :{WHITE}Hàm callback {1:HEX} gửi trả kết quả sai/không rõ {2:HEX}
|
||||||
STR_NEWGRF_BUGGY_INVALID_CARGO_PRODUCTION_CALLBACK :{WHITE}'{1:STRING}' trả về loại hàng hoá sản xuất không hợp lệ khi gọi lại tại {2:HEX}
|
STR_NEWGRF_BUGGY_INVALID_CARGO_PRODUCTION_CALLBACK :{WHITE}'{PUSH_COLOUR}{1:STRING}{POP_COLOUR}' trả về loại hàng hoá sản xuất không hợp lệ khi gọi lại tại {2:HEX}
|
||||||
|
|
||||||
# 'User removed essential NewGRFs'-placeholders for stuff without specs
|
# 'User removed essential NewGRFs'-placeholders for stuff without specs
|
||||||
STR_NEWGRF_INVALID_CARGO :<sai kiểu hàng>
|
STR_NEWGRF_INVALID_CARGO :<sai kiểu hàng>
|
||||||
|
@ -3650,6 +3697,10 @@ STR_TOWN_VIEW_RENAME_TOOLTIP :{BLACK}Đổi t
|
||||||
|
|
||||||
STR_TOWN_VIEW_EXPAND_BUTTON :{BLACK}Mở rộng
|
STR_TOWN_VIEW_EXPAND_BUTTON :{BLACK}Mở rộng
|
||||||
STR_TOWN_VIEW_EXPAND_TOOLTIP :{BLACK}Tăng quy mô đô thị
|
STR_TOWN_VIEW_EXPAND_TOOLTIP :{BLACK}Tăng quy mô đô thị
|
||||||
|
STR_TOWN_VIEW_EXPAND_BUILDINGS_BUTTON :{BLACK}Mở rộng công trình
|
||||||
|
STR_TOWN_VIEW_EXPAND_BUILDINGS_TOOLTIP :{BLACK}Tăng số công trình của thị trấn
|
||||||
|
STR_TOWN_VIEW_EXPAND_ROADS_BUTTON :{BLACK}Mở rộng đường
|
||||||
|
STR_TOWN_VIEW_EXPAND_ROADS_TOOLTIP :{BLACK}Tăng số đường sá của thị trấn
|
||||||
STR_TOWN_VIEW_DELETE_BUTTON :{BLACK}Xoá
|
STR_TOWN_VIEW_DELETE_BUTTON :{BLACK}Xoá
|
||||||
STR_TOWN_VIEW_DELETE_TOOLTIP :{BLACK}Xoá bỏ đô thị này hoàn toàn
|
STR_TOWN_VIEW_DELETE_TOOLTIP :{BLACK}Xoá bỏ đô thị này hoàn toàn
|
||||||
|
|
||||||
|
@ -3975,6 +4026,8 @@ STR_INDUSTRY_VIEW_PRODUCTION_LAST_MONTH_TITLE :{BLACK}Sản l
|
||||||
STR_INDUSTRY_VIEW_PRODUCTION_LAST_MINUTE_TITLE :{BLACK}Sản lượng phút trước:
|
STR_INDUSTRY_VIEW_PRODUCTION_LAST_MINUTE_TITLE :{BLACK}Sản lượng phút trước:
|
||||||
STR_INDUSTRY_VIEW_TRANSPORTED :{YELLOW}{CARGO_LONG}{STRING}{BLACK} ({COMMA}% đã vận chuyển)
|
STR_INDUSTRY_VIEW_TRANSPORTED :{YELLOW}{CARGO_LONG}{STRING}{BLACK} ({COMMA}% đã vận chuyển)
|
||||||
STR_INDUSTRY_VIEW_LOCATION_TOOLTIP :{BLACK}Xem vị trí trung tâm của nhà máy. Ctrl+Click mở cửa sổ mới để xem
|
STR_INDUSTRY_VIEW_LOCATION_TOOLTIP :{BLACK}Xem vị trí trung tâm của nhà máy. Ctrl+Click mở cửa sổ mới để xem
|
||||||
|
STR_INDUSTRY_VIEW_CARGO_GRAPH :{BLACK}Đồ thị hàng hóa
|
||||||
|
STR_INDUSTRY_VIEW_CARGO_GRAPH_TOOLTIP :{BLACK}Xem đồ thị lịch sử kinh doanh hàng hóa
|
||||||
STR_INDUSTRY_VIEW_PRODUCTION_LEVEL :{BLACK}Mức sản lượng: {YELLOW}{COMMA}%
|
STR_INDUSTRY_VIEW_PRODUCTION_LEVEL :{BLACK}Mức sản lượng: {YELLOW}{COMMA}%
|
||||||
STR_INDUSTRY_VIEW_INDUSTRY_ANNOUNCED_CLOSURE :{YELLOW}Nhà máy này đã thông báo sắp đóng cửa!
|
STR_INDUSTRY_VIEW_INDUSTRY_ANNOUNCED_CLOSURE :{YELLOW}Nhà máy này đã thông báo sắp đóng cửa!
|
||||||
|
|
||||||
|
@ -4386,10 +4439,10 @@ STR_VEHICLE_VIEW_SHIP_ORDERS_TOOLTIP :{BLACK}Hiện l
|
||||||
STR_VEHICLE_VIEW_AIRCRAFT_ORDERS_TOOLTIP :{BLACK}Hiện lộ trình máy bay. Ctrl+Click để hiện lịch trình
|
STR_VEHICLE_VIEW_AIRCRAFT_ORDERS_TOOLTIP :{BLACK}Hiện lộ trình máy bay. Ctrl+Click để hiện lịch trình
|
||||||
|
|
||||||
###length VEHICLE_TYPES
|
###length VEHICLE_TYPES
|
||||||
STR_VEHICLE_VIEW_TRAIN_SHOW_DETAILS_TOOLTIP :{BLACK}Hiện chi tiết tàu hoả
|
STR_VEHICLE_VIEW_TRAIN_SHOW_DETAILS_TOOLTIP :{BLACK}Hiện chi tiết tàu hoả. Ctrl+Click vào để hiện nhóm của tàu hỏa
|
||||||
STR_VEHICLE_VIEW_ROAD_VEHICLE_SHOW_DETAILS_TOOLTIP :{BLACK}Hiện chi tiết xe
|
STR_VEHICLE_VIEW_ROAD_VEHICLE_SHOW_DETAILS_TOOLTIP :{BLACK}Hiện chi tiết xe. Ctrl+Click để hiện nhóm phương tiện
|
||||||
STR_VEHICLE_VIEW_SHIP_SHOW_DETAILS_TOOLTIP :{BLACK}Hiện chi tiết tàu thuỷ
|
STR_VEHICLE_VIEW_SHIP_SHOW_DETAILS_TOOLTIP :{BLACK}Hiện chi tiết tàu thuỷ. Ctrl+Click vào để hiện nhóm của tàu thủy
|
||||||
STR_VEHICLE_VIEW_AIRCRAFT_SHOW_DETAILS_TOOLTIP :{BLACK}Hiện chi tiết máy bay
|
STR_VEHICLE_VIEW_AIRCRAFT_SHOW_DETAILS_TOOLTIP :{BLACK}Hiện chi tiết máy bay. Ctrl+Click để hiện nhóm của máy bay
|
||||||
|
|
||||||
###length VEHICLE_TYPES
|
###length VEHICLE_TYPES
|
||||||
STR_VEHICLE_VIEW_TRAIN_STATUS_START_STOP_TOOLTIP :{BLACK}Tác động đến tàu hỏa hiện tại - bấm để dừng/chạy tàu hỏa
|
STR_VEHICLE_VIEW_TRAIN_STATUS_START_STOP_TOOLTIP :{BLACK}Tác động đến tàu hỏa hiện tại - bấm để dừng/chạy tàu hỏa
|
||||||
|
@ -4644,55 +4697,56 @@ STR_ORDER_ROAD_VEHICLE_DEPOT :Xưởng xe
|
||||||
STR_ORDER_SHIP_DEPOT :Xưởng tàu thuỷ
|
STR_ORDER_SHIP_DEPOT :Xưởng tàu thuỷ
|
||||||
###next-name-looks-similar
|
###next-name-looks-similar
|
||||||
|
|
||||||
|
STR_ORDER_GO_TO_NEAREST_HANGAR_FORMAT :{STRING} xưởng sân bay gần nhất
|
||||||
STR_ORDER_GO_TO_NEAREST_DEPOT_FORMAT :{STRING} gần {STRING} nhất
|
STR_ORDER_GO_TO_NEAREST_DEPOT_FORMAT :{STRING} gần {STRING} nhất
|
||||||
STR_ORDER_GO_TO_DEPOT_FORMAT :{STRING} {DEPOT}
|
STR_ORDER_GO_TO_DEPOT_FORMAT :{STRING} {DEPOT}
|
||||||
|
|
||||||
STR_ORDER_REFIT_ORDER :(Cải biến thành {STRING})
|
STR_ORDER_REFIT_ORDER :{SPACE}(Cải biến thành {STRING})
|
||||||
STR_ORDER_REFIT_STOP_ORDER :(Cải biến thành {STRING} và dừng)
|
STR_ORDER_REFIT_STOP_ORDER :{SPACE}(Cải biến thành {STRING} và dừng)
|
||||||
STR_ORDER_STOP_ORDER :(Dừng)
|
STR_ORDER_STOP_ORDER :{SPACE}(Dừng)
|
||||||
|
|
||||||
STR_ORDER_WAIT_TO_UNBUNCH :(Chờ để gỡ gộp)
|
STR_ORDER_WAIT_TO_UNBUNCH :{SPACE}(Chờ để gỡ gộp)
|
||||||
|
|
||||||
STR_ORDER_GO_TO_STATION :{STRING} {STATION}
|
STR_ORDER_GO_TO_STATION :{STRING} {STATION}
|
||||||
STR_ORDER_GO_TO_STATION_CAN_T_USE_STATION :{PUSH_COLOUR}{RED}(Không thể sử dụng trạm){POP_COLOUR} {STRING} {STATION}
|
STR_ORDER_GO_TO_STATION_CAN_T_USE_STATION :{PUSH_COLOUR}{RED}(Không thể sử dụng trạm){POP_COLOUR} {STRING} {STATION}
|
||||||
|
|
||||||
STR_ORDER_IMPLICIT :(Chạy ngầm)
|
STR_ORDER_IMPLICIT :{SPACE}(Chạy ngầm)
|
||||||
|
|
||||||
STR_ORDER_FULL_LOAD :(Bốc đầy hàng)
|
STR_ORDER_FULL_LOAD :{SPACE}(Bốc đầy hàng)
|
||||||
STR_ORDER_FULL_LOAD_ANY :(Bốc đủ bất kỳ hàng nào)
|
STR_ORDER_FULL_LOAD_ANY :{SPACE}(Bốc đủ bất kỳ hàng nào)
|
||||||
STR_ORDER_NO_LOAD :(Không bốc xếp)
|
STR_ORDER_NO_LOAD :{SPACE}(Không bốc xếp)
|
||||||
STR_ORDER_UNLOAD :(Dỡ và lấy hàng khác)
|
STR_ORDER_UNLOAD :{SPACE}(Dỡ và lấy hàng khác)
|
||||||
STR_ORDER_UNLOAD_FULL_LOAD :(Dỡ tất hàng và chờ bốc đầy hàng)
|
STR_ORDER_UNLOAD_FULL_LOAD :{SPACE}(Dỡ tất hàng và chờ bốc đầy hàng)
|
||||||
STR_ORDER_UNLOAD_FULL_LOAD_ANY :(Dỡ tất hàng và chờ bốc đủ bất kỳ hàng nào)
|
STR_ORDER_UNLOAD_FULL_LOAD_ANY :{SPACE}(Dỡ tất hàng và chờ bốc đủ bất kỳ hàng nào)
|
||||||
STR_ORDER_UNLOAD_NO_LOAD :(Dỡ tất hàng và để trống)
|
STR_ORDER_UNLOAD_NO_LOAD :{SPACE}(Dỡ tất hàng và để trống)
|
||||||
STR_ORDER_TRANSFER :(Trung chuyển hàng và lấy hàng khác)
|
STR_ORDER_TRANSFER :{SPACE}(Trung chuyển hàng và lấy hàng khác)
|
||||||
STR_ORDER_TRANSFER_FULL_LOAD :(Trung chuyển và chờ bốc đầy hàng)
|
STR_ORDER_TRANSFER_FULL_LOAD :{SPACE}(Trung chuyển và chờ bốc đầy hàng)
|
||||||
STR_ORDER_TRANSFER_FULL_LOAD_ANY :(Trung chuyển và chờ bốc đủ hàng bất kỳ)
|
STR_ORDER_TRANSFER_FULL_LOAD_ANY :{SPACE}(Trung chuyển và chờ bốc đủ hàng bất kỳ)
|
||||||
STR_ORDER_TRANSFER_NO_LOAD :(Trung chuyển và để trống)
|
STR_ORDER_TRANSFER_NO_LOAD :{SPACE}(Trung chuyển và để trống)
|
||||||
STR_ORDER_NO_UNLOAD :(Không dỡ và lấy hàng)
|
STR_ORDER_NO_UNLOAD :{SPACE}(Không dỡ và lấy hàng)
|
||||||
STR_ORDER_NO_UNLOAD_FULL_LOAD :(Không dỡ và chờ lấy thêm đầy hàng)
|
STR_ORDER_NO_UNLOAD_FULL_LOAD :{SPACE}(Không dỡ và chờ lấy thêm đầy hàng)
|
||||||
STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY :(Không dỡ và chờ lấy đủ hàng bất kỳ)
|
STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY :{SPACE}(Không dỡ và chờ lấy đủ hàng bất kỳ)
|
||||||
STR_ORDER_NO_UNLOAD_NO_LOAD :(Không bốc hàng và không dỡ hàng)
|
STR_ORDER_NO_UNLOAD_NO_LOAD :{SPACE}(Không bốc hàng và không dỡ hàng)
|
||||||
|
|
||||||
STR_ORDER_AUTO_REFIT :(Tự cải biến thành {STRING})
|
STR_ORDER_AUTO_REFIT :{SPACE}(Tự cải biến thành {STRING})
|
||||||
STR_ORDER_FULL_LOAD_REFIT :(Tự cải biến và chất đầy {STRING})
|
STR_ORDER_FULL_LOAD_REFIT :{SPACE}(Tự cải biến và chất đầy {STRING})
|
||||||
STR_ORDER_FULL_LOAD_ANY_REFIT :(Tự cải biến và chất đầy bất kỳ {STRING})
|
STR_ORDER_FULL_LOAD_ANY_REFIT :{SPACE}(Tự cải biến và chất đầy bất kỳ {STRING})
|
||||||
STR_ORDER_UNLOAD_REFIT :(Dỡ hàng và tự cải biến để lấy {STRING})
|
STR_ORDER_UNLOAD_REFIT :{SPACE}(Dỡ hàng và tự cải biến để lấy {STRING})
|
||||||
STR_ORDER_UNLOAD_FULL_LOAD_REFIT :(Dỡ hàng và tự cải biến đề bốc đầy {STRING})
|
STR_ORDER_UNLOAD_FULL_LOAD_REFIT :{SPACE}(Dỡ hàng và tự cải biến đề bốc đầy {STRING})
|
||||||
STR_ORDER_UNLOAD_FULL_LOAD_ANY_REFIT :(Dỡ hàng và tự cải biến để bốc đầy bất kỳ {STRING})
|
STR_ORDER_UNLOAD_FULL_LOAD_ANY_REFIT :{SPACE}(Dỡ hàng và tự cải biến để bốc đầy bất kỳ {STRING})
|
||||||
STR_ORDER_TRANSFER_REFIT :(Trung chuyển và tự cải biến để lấy {STRING})
|
STR_ORDER_TRANSFER_REFIT :{SPACE}(Trung chuyển và tự cải biến để lấy {STRING})
|
||||||
STR_ORDER_TRANSFER_FULL_LOAD_REFIT :(Trung chuyển và tự cải biến đề bốc đầy {STRING})
|
STR_ORDER_TRANSFER_FULL_LOAD_REFIT :{SPACE}(Trung chuyển và tự cải biến đề bốc đầy {STRING})
|
||||||
STR_ORDER_TRANSFER_FULL_LOAD_ANY_REFIT :(Trung chuyển và tự cải biến để bốc đầy bất kỳ {STRING})
|
STR_ORDER_TRANSFER_FULL_LOAD_ANY_REFIT :{SPACE}(Trung chuyển và tự cải biến để bốc đầy bất kỳ {STRING})
|
||||||
STR_ORDER_NO_UNLOAD_REFIT :(Không dỡ hàng và tự cái biến để lấy {STRING})
|
STR_ORDER_NO_UNLOAD_REFIT :{SPACE}(Không dỡ hàng và tự cái biến để lấy {STRING})
|
||||||
STR_ORDER_NO_UNLOAD_FULL_LOAD_REFIT :(Không dỡ hàng và tự cải biến để bốc đầy {STRING})
|
STR_ORDER_NO_UNLOAD_FULL_LOAD_REFIT :{SPACE}(Không dỡ hàng và tự cải biến để bốc đầy {STRING})
|
||||||
STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY_REFIT :(Không dỡ hàng và tự cải biến để bốc đầy bất kỳ {STRING})
|
STR_ORDER_NO_UNLOAD_FULL_LOAD_ANY_REFIT :{SPACE}(Không dỡ hàng và tự cải biến để bốc đầy bất kỳ {STRING})
|
||||||
|
|
||||||
STR_ORDER_AUTO_REFIT_ANY :hàng hóa sẵn có
|
STR_ORDER_AUTO_REFIT_ANY :hàng hóa sẵn có
|
||||||
|
|
||||||
###length 3
|
###length 3
|
||||||
STR_ORDER_STOP_LOCATION_NEAR_END :[đỗ ở đầu gần]
|
STR_ORDER_STOP_LOCATION_NEAR_END :{SPACE}[đỗ ở đầu gần]
|
||||||
STR_ORDER_STOP_LOCATION_MIDDLE :[đỗ ở giữa]
|
STR_ORDER_STOP_LOCATION_MIDDLE :{SPACE}[đỗ ở giữa]
|
||||||
STR_ORDER_STOP_LOCATION_FAR_END :[đỗ ở đầu xa]
|
STR_ORDER_STOP_LOCATION_FAR_END :{SPACE}[đỗ ở đầu xa]
|
||||||
|
|
||||||
STR_ORDER_OUT_OF_RANGE :{RED} (Điểm đến kế tiếp ngoài tầm xa)
|
STR_ORDER_OUT_OF_RANGE :{RED} (Điểm đến kế tiếp ngoài tầm xa)
|
||||||
|
|
||||||
|
@ -4712,14 +4766,15 @@ STR_TIMETABLE_TOOLTIP :{BLACK}Lịch t
|
||||||
STR_TIMETABLE_NO_TRAVEL :Không di chuyển
|
STR_TIMETABLE_NO_TRAVEL :Không di chuyển
|
||||||
STR_TIMETABLE_NOT_TIMETABLEABLE :Hành trình (tự động; tính thời gian theo lịch trình thủ công kế tiếp)
|
STR_TIMETABLE_NOT_TIMETABLEABLE :Hành trình (tự động; tính thời gian theo lịch trình thủ công kế tiếp)
|
||||||
STR_TIMETABLE_TRAVEL_NOT_TIMETABLED :Di chuyển (không bó buộc theo lịch trình)
|
STR_TIMETABLE_TRAVEL_NOT_TIMETABLED :Di chuyển (không bó buộc theo lịch trình)
|
||||||
|
STR_TIMETABLE_TRAVEL_NOT_TIMETABLED_SPEED :Hành trình với tốc độ tối đa là {VELOCITY} (chưa dựng lịch trình)
|
||||||
STR_TIMETABLE_TRAVEL_FOR :Di chuyển trong {STRING}
|
STR_TIMETABLE_TRAVEL_FOR :Di chuyển trong {STRING}
|
||||||
STR_TIMETABLE_TRAVEL_FOR_SPEED :Lộ trình {STRING} với tốc độ tối đa {VELOCITY}
|
STR_TIMETABLE_TRAVEL_FOR_SPEED :Lộ trình {STRING} với tốc độ tối đa {VELOCITY}
|
||||||
STR_TIMETABLE_TRAVEL_FOR_ESTIMATED :Lộ trình (cho {STRING}, chưa có lịch trình)
|
STR_TIMETABLE_TRAVEL_FOR_ESTIMATED :Lộ trình (cho {STRING}, chưa có lịch trình)
|
||||||
STR_TIMETABLE_TRAVEL_FOR_SPEED_ESTIMATED :Lộ trình (cho {STRING}, chưa có lịch trình) với tốc độ đối đa {VELOCITY}
|
STR_TIMETABLE_TRAVEL_FOR_SPEED_ESTIMATED :Lộ trình (cho {STRING}, chưa có lịch trình) với tốc độ đối đa {VELOCITY}
|
||||||
STR_TIMETABLE_STAY_FOR_ESTIMATED :(ở lại {STRING}, chưa có lịch trình)
|
STR_TIMETABLE_STAY_FOR_ESTIMATED :{SPACE}(ở lại {STRING}, chưa có lịch trình)
|
||||||
STR_TIMETABLE_AND_TRAVEL_FOR_ESTIMATED :(di chuyển đến {STRING}, chưa có lịch trình)
|
STR_TIMETABLE_AND_TRAVEL_FOR_ESTIMATED :{SPACE}(di chuyển đến {STRING}, chưa có lịch trình)
|
||||||
STR_TIMETABLE_STAY_FOR :và ở lại trong {STRING}
|
STR_TIMETABLE_STAY_FOR :{SPACE}và ở lại trong {STRING}
|
||||||
STR_TIMETABLE_AND_TRAVEL_FOR :và di chuyển trong {STRING}
|
STR_TIMETABLE_AND_TRAVEL_FOR :{SPACE}và di chuyển trong {STRING}
|
||||||
|
|
||||||
STR_TIMETABLE_APPROX_TIME :{BLACK}Lịch trình này sẽ mất khoảng {STRING} để hoàn thành
|
STR_TIMETABLE_APPROX_TIME :{BLACK}Lịch trình này sẽ mất khoảng {STRING} để hoàn thành
|
||||||
STR_TIMETABLE_TOTAL_TIME :{BLACK}Lịch trình này sẽ mất {STRING} để hoàn thành
|
STR_TIMETABLE_TOTAL_TIME :{BLACK}Lịch trình này sẽ mất {STRING} để hoàn thành
|
||||||
|
@ -4738,12 +4793,14 @@ STR_TIMETABLE_START_SECONDS_QUERY :Số giây cho
|
||||||
|
|
||||||
STR_TIMETABLE_CHANGE_TIME :{BLACK}Đổi thời gian
|
STR_TIMETABLE_CHANGE_TIME :{BLACK}Đổi thời gian
|
||||||
STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}Thay đổi thời lượng của điểm lộ trình được phép sử dụng. Ctrl+Click đặt thời gian cho mọi lộ trình
|
STR_TIMETABLE_WAIT_TIME_TOOLTIP :{BLACK}Thay đổi thời lượng của điểm lộ trình được phép sử dụng. Ctrl+Click đặt thời gian cho mọi lộ trình
|
||||||
|
STR_TIMETABLE_CHANGE_TIME_QUERY :Thay đổi thời gian
|
||||||
|
|
||||||
STR_TIMETABLE_CLEAR_TIME :{BLACK}Xoá thời gian
|
STR_TIMETABLE_CLEAR_TIME :{BLACK}Xoá thời gian
|
||||||
STR_TIMETABLE_CLEAR_TIME_TOOLTIP :{BLACK}Xóa thời lượng áp dụng cho điểm lộ trình. Ctrl+Click xoá tất cả thời gian cho mọi lộ trình
|
STR_TIMETABLE_CLEAR_TIME_TOOLTIP :{BLACK}Xóa thời lượng áp dụng cho điểm lộ trình. Ctrl+Click xoá tất cả thời gian cho mọi lộ trình
|
||||||
|
|
||||||
STR_TIMETABLE_CHANGE_SPEED :{BLACK}Thay Đổi Giới Hạn Tốc Độ
|
STR_TIMETABLE_CHANGE_SPEED :{BLACK}Thay Đổi Giới Hạn Tốc Độ
|
||||||
STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}Thay đổi tốc độ tối đa của lộ trình được chọn. Ctrl+Click đặt tốc độ cho mọi lộ trình
|
STR_TIMETABLE_CHANGE_SPEED_TOOLTIP :{BLACK}Thay đổi tốc độ tối đa của lộ trình được chọn. Ctrl+Click đặt tốc độ cho mọi lộ trình
|
||||||
|
STR_TIMETABLE_CHANGE_SPEED_QUERY :Thay đổi giới hạn tốc độ
|
||||||
|
|
||||||
STR_TIMETABLE_CLEAR_SPEED :{BLACK}Xóa Giới Hạn Tốc Độ
|
STR_TIMETABLE_CLEAR_SPEED :{BLACK}Xóa Giới Hạn Tốc Độ
|
||||||
STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Xóa tốc độ đối đa đối với lộ trình được chọn. Ctrl+Click xoá tốc độ cho mọi lộ trình
|
STR_TIMETABLE_CLEAR_SPEED_TOOLTIP :{BLACK}Xóa tốc độ đối đa đối với lộ trình được chọn. Ctrl+Click xoá tốc độ cho mọi lộ trình
|
||||||
|
@ -4907,7 +4964,7 @@ STR_GAME_SAVELOAD_NOT_AVAILABLE :<không có s
|
||||||
STR_WARNING_LOADGAME_REMOVED_TRAMS :{WHITE}Lưu ván chơi sẽ không có xe điện. Những công trình cho xe điện sẽ bị xoá bỏ
|
STR_WARNING_LOADGAME_REMOVED_TRAMS :{WHITE}Lưu ván chơi sẽ không có xe điện. Những công trình cho xe điện sẽ bị xoá bỏ
|
||||||
|
|
||||||
# Map generation messages
|
# Map generation messages
|
||||||
STR_ERROR_COULD_NOT_CREATE_TOWN :{WHITE}Sinh bản đồ bị ngưng...{}... không có nơi đặt đô thị
|
STR_ERROR_COULD_NOT_CREATE_TOWN :{WHITE}Sinh bản đồ bị ngưng...{}{}... không có nơi đặt đô thị
|
||||||
STR_ERROR_NO_TOWN_IN_SCENARIO :{WHITE}... không có đô thị nào ở màn chơi kịch bản này
|
STR_ERROR_NO_TOWN_IN_SCENARIO :{WHITE}... không có đô thị nào ở màn chơi kịch bản này
|
||||||
|
|
||||||
STR_ERROR_PNGMAP :{WHITE}Không thể nạp nền từ file PNG...
|
STR_ERROR_PNGMAP :{WHITE}Không thể nạp nền từ file PNG...
|
||||||
|
@ -4946,6 +5003,7 @@ STR_ERROR_FLAT_LAND_REQUIRED :{WHITE}Yêu c
|
||||||
STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Tạo dốc bị sai hướng
|
STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION :{WHITE}Tạo dốc bị sai hướng
|
||||||
STR_ERROR_CAN_T_DO_THIS :{WHITE}Không làm thế này được...
|
STR_ERROR_CAN_T_DO_THIS :{WHITE}Không làm thế này được...
|
||||||
STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}Cần giải toả nhà cửa trước
|
STR_ERROR_BUILDING_MUST_BE_DEMOLISHED :{WHITE}Cần giải toả nhà cửa trước
|
||||||
|
STR_ERROR_BUILDING_IS_PROTECTED :{WHITE}... công trình được bảo vệ
|
||||||
STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}Không thể dọn dẹp khu vực này...
|
STR_ERROR_CAN_T_CLEAR_THIS_AREA :{WHITE}Không thể dọn dẹp khu vực này...
|
||||||
STR_ERROR_SITE_UNSUITABLE :{WHITE}... điểm không phù hợp
|
STR_ERROR_SITE_UNSUITABLE :{WHITE}... điểm không phù hợp
|
||||||
STR_ERROR_ALREADY_BUILT :{WHITE}... đã xây rồi
|
STR_ERROR_ALREADY_BUILT :{WHITE}... đã xây rồi
|
||||||
|
@ -4998,7 +5056,7 @@ STR_ERROR_TOO_CLOSE_TO_ANOTHER_TOWN :{WHITE}... quá
|
||||||
STR_ERROR_TOO_MANY_TOWNS :{WHITE}... quá nhiều đô thị
|
STR_ERROR_TOO_MANY_TOWNS :{WHITE}... quá nhiều đô thị
|
||||||
STR_ERROR_NO_SPACE_FOR_TOWN :{WHITE}... không còn khoảng trống nào trên bản đồ
|
STR_ERROR_NO_SPACE_FOR_TOWN :{WHITE}... không còn khoảng trống nào trên bản đồ
|
||||||
STR_ERROR_ROAD_WORKS_IN_PROGRESS :{WHITE}Xây dựng cầu đường đang tiến hành
|
STR_ERROR_ROAD_WORKS_IN_PROGRESS :{WHITE}Xây dựng cầu đường đang tiến hành
|
||||||
STR_ERROR_TOWN_CAN_T_DELETE :{WHITE}Không thể xoá đo thị này...{}Có một ga, bến hoặc xưởng thuộc đô thị hoặc là 1 ô đất của đô thị không thể xoá được.
|
STR_ERROR_TOWN_CAN_T_DELETE :{WHITE}Không thể xoá đo thị này...{}{}Có một ga, bến hoặc xưởng thuộc đô thị hoặc là 1 ô đất của đô thị không thể xoá được.
|
||||||
STR_ERROR_STATUE_NO_SUITABLE_PLACE :{WHITE}... không có nơi nào hợp lý để dựng tượng đài ở trung tâm đô thị này
|
STR_ERROR_STATUE_NO_SUITABLE_PLACE :{WHITE}... không có nơi nào hợp lý để dựng tượng đài ở trung tâm đô thị này
|
||||||
STR_ERROR_CAN_T_BUILD_HOUSE :{WHITE}Không thể xây dựng nhà...
|
STR_ERROR_CAN_T_BUILD_HOUSE :{WHITE}Không thể xây dựng nhà...
|
||||||
|
|
||||||
|
@ -5825,6 +5883,7 @@ STR_CURRENCY_SHORT_GIGA :{NBSP}tỷ
|
||||||
STR_CURRENCY_SHORT_TERA :{NBSP}ktỷ
|
STR_CURRENCY_SHORT_TERA :{NBSP}ktỷ
|
||||||
|
|
||||||
STR_JUST_CARGO :{CARGO_LONG}
|
STR_JUST_CARGO :{CARGO_LONG}
|
||||||
|
STR_JUST_LEFT_ARROW :{LEFT_ARROW}
|
||||||
STR_JUST_RIGHT_ARROW :{RIGHT_ARROW}
|
STR_JUST_RIGHT_ARROW :{RIGHT_ARROW}
|
||||||
STR_JUST_CHECKMARK :{CHECKMARK}
|
STR_JUST_CHECKMARK :{CHECKMARK}
|
||||||
STR_JUST_COMMA :{COMMA}
|
STR_JUST_COMMA :{COMMA}
|
||||||
|
@ -5864,3 +5923,11 @@ STR_SHIP :{BLACK}{SHIP}
|
||||||
STR_TOOLBAR_RAILTYPE_VELOCITY :{STRING} ({VELOCITY})
|
STR_TOOLBAR_RAILTYPE_VELOCITY :{STRING} ({VELOCITY})
|
||||||
|
|
||||||
STR_BADGE_NAME_LIST :{STRING}: {GOLD}{STRING}
|
STR_BADGE_NAME_LIST :{STRING}: {GOLD}{STRING}
|
||||||
|
STR_BADGE_CONFIG_MENU_TOOLTIP :Mở thiết lập phù hiệu
|
||||||
|
STR_BADGE_CONFIG_RESET :Thiêt lập lại
|
||||||
|
STR_BADGE_CONFIG_ICONS :{WHITE}Ảnh phù hiệu
|
||||||
|
STR_BADGE_CONFIG_FILTERS :{WHITE}Bộ lọc phù hiệu
|
||||||
|
STR_BADGE_CONFIG_PREVIEW :Ảnh xem trước
|
||||||
|
STR_BADGE_CONFIG_NAME :Tên
|
||||||
|
STR_BADGE_FILTER_ANY_LABEL :Bất cứ {STRING} nào
|
||||||
|
STR_BADGE_FILTER_IS_LABEL :{STRING} là {STRING}
|
||||||
|
|
|
@ -315,7 +315,7 @@ static void ShutdownGame()
|
||||||
/* No NewGRFs were loaded when it was still bootstrapping. */
|
/* No NewGRFs were loaded when it was still bootstrapping. */
|
||||||
if (_game_mode != GM_BOOTSTRAP) ResetNewGRFData();
|
if (_game_mode != GM_BOOTSTRAP) ResetNewGRFData();
|
||||||
|
|
||||||
UninitFontCache();
|
FontCache::UninitializeFontCaches();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -700,7 +700,7 @@ int openttd_main(std::span<std::string_view> arguments)
|
||||||
InitializeLanguagePacks();
|
InitializeLanguagePacks();
|
||||||
|
|
||||||
/* Initialize the font cache */
|
/* Initialize the font cache */
|
||||||
InitFontCache(FONTSIZES_REQUIRED);
|
FontCache::LoadFontCaches(FONTSIZES_REQUIRED);
|
||||||
|
|
||||||
/* This must be done early, since functions use the SetWindowDirty* calls */
|
/* This must be done early, since functions use the SetWindowDirty* calls */
|
||||||
InitWindowSystem();
|
InitWindowSystem();
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
#include "../../blitter/factory.hpp"
|
#include "../../blitter/factory.hpp"
|
||||||
#include "../../error_func.h"
|
#include "../../error_func.h"
|
||||||
#include "../../fileio_func.h"
|
#include "../../fileio_func.h"
|
||||||
#include "../../fontdetection.h"
|
|
||||||
#include "../../string_func.h"
|
#include "../../string_func.h"
|
||||||
#include "../../strings_func.h"
|
#include "../../strings_func.h"
|
||||||
#include "../../zoom_func.h"
|
#include "../../zoom_func.h"
|
||||||
|
@ -24,91 +23,6 @@
|
||||||
|
|
||||||
#include "../../safeguards.h"
|
#include "../../safeguards.h"
|
||||||
|
|
||||||
bool SetFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, MissingGlyphSearcher *callback)
|
|
||||||
{
|
|
||||||
/* Determine fallback font using CoreText. This uses the language isocode
|
|
||||||
* to find a suitable font. CoreText is available from 10.5 onwards. */
|
|
||||||
std::string lang;
|
|
||||||
if (language_isocode == "zh_TW") {
|
|
||||||
/* Traditional Chinese */
|
|
||||||
lang = "zh-Hant";
|
|
||||||
} else if (language_isocode == "zh_CN") {
|
|
||||||
/* Simplified Chinese */
|
|
||||||
lang = "zh-Hans";
|
|
||||||
} else {
|
|
||||||
/* Just copy the first part of the isocode. */
|
|
||||||
lang = language_isocode.substr(0, language_isocode.find('_'));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create a font descriptor matching the wanted language and latin (english) glyphs.
|
|
||||||
* Can't use CFAutoRelease here for everything due to the way the dictionary has to be created. */
|
|
||||||
CFStringRef lang_codes[2];
|
|
||||||
lang_codes[0] = CFStringCreateWithCString(kCFAllocatorDefault, lang.c_str(), kCFStringEncodingUTF8);
|
|
||||||
lang_codes[1] = CFSTR("en");
|
|
||||||
CFArrayRef lang_arr = CFArrayCreate(kCFAllocatorDefault, (const void **)lang_codes, lengthof(lang_codes), &kCFTypeArrayCallBacks);
|
|
||||||
CFAutoRelease<CFDictionaryRef> lang_attribs(CFDictionaryCreate(kCFAllocatorDefault, const_cast<const void **>(reinterpret_cast<const void *const *>(&kCTFontLanguagesAttribute)), (const void **)&lang_arr, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
|
|
||||||
CFAutoRelease<CTFontDescriptorRef> lang_desc(CTFontDescriptorCreateWithAttributes(lang_attribs.get()));
|
|
||||||
CFRelease(lang_arr);
|
|
||||||
CFRelease(lang_codes[0]);
|
|
||||||
|
|
||||||
/* Get array of all font descriptors for the wanted language. */
|
|
||||||
CFAutoRelease<CFSetRef> mandatory_attribs(CFSetCreate(kCFAllocatorDefault, const_cast<const void **>(reinterpret_cast<const void *const *>(&kCTFontLanguagesAttribute)), 1, &kCFTypeSetCallBacks));
|
|
||||||
CFAutoRelease<CFArrayRef> descs(CTFontDescriptorCreateMatchingFontDescriptors(lang_desc.get(), mandatory_attribs.get()));
|
|
||||||
|
|
||||||
bool result = false;
|
|
||||||
for (int tries = 0; tries < 2; tries++) {
|
|
||||||
for (CFIndex i = 0; descs.get() != nullptr && i < CFArrayGetCount(descs.get()); i++) {
|
|
||||||
CTFontDescriptorRef font = (CTFontDescriptorRef)CFArrayGetValueAtIndex(descs.get(), i);
|
|
||||||
|
|
||||||
/* Get font traits. */
|
|
||||||
CFAutoRelease<CFDictionaryRef> traits((CFDictionaryRef)CTFontDescriptorCopyAttribute(font, kCTFontTraitsAttribute));
|
|
||||||
CTFontSymbolicTraits symbolic_traits;
|
|
||||||
CFNumberGetValue((CFNumberRef)CFDictionaryGetValue(traits.get(), kCTFontSymbolicTrait), kCFNumberIntType, &symbolic_traits);
|
|
||||||
|
|
||||||
/* Skip symbol fonts and vertical fonts. */
|
|
||||||
if ((symbolic_traits & kCTFontClassMaskTrait) == (CTFontStylisticClass)kCTFontSymbolicClass || (symbolic_traits & kCTFontVerticalTrait)) continue;
|
|
||||||
/* Skip bold fonts (especially Arial Bold, which looks worse than regular Arial). */
|
|
||||||
if (symbolic_traits & kCTFontBoldTrait) continue;
|
|
||||||
/* Select monospaced fonts if asked for. */
|
|
||||||
if (((symbolic_traits & kCTFontMonoSpaceTrait) == kCTFontMonoSpaceTrait) != callback->Monospace()) continue;
|
|
||||||
|
|
||||||
/* Get font name. */
|
|
||||||
char buffer[128];
|
|
||||||
CFAutoRelease<CFStringRef> font_name((CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontDisplayNameAttribute));
|
|
||||||
CFStringGetCString(font_name.get(), buffer, std::size(buffer), kCFStringEncodingUTF8);
|
|
||||||
|
|
||||||
/* Serif fonts usually look worse on-screen with only small
|
|
||||||
* font sizes. As such, we try for a sans-serif font first.
|
|
||||||
* If we can't find one in the first try, try all fonts. */
|
|
||||||
if (tries == 0 && (symbolic_traits & kCTFontClassMaskTrait) != (CTFontStylisticClass)kCTFontSansSerifClass) continue;
|
|
||||||
|
|
||||||
/* There are some special fonts starting with an '.' and the last
|
|
||||||
* resort font that aren't usable. Skip them. */
|
|
||||||
std::string_view name{buffer};
|
|
||||||
if (name.starts_with(".") || name.starts_with("LastResort")) continue;
|
|
||||||
|
|
||||||
/* Save result. */
|
|
||||||
callback->SetFontNames(settings, name);
|
|
||||||
if (!callback->FindMissingGlyphs()) {
|
|
||||||
Debug(fontcache, 2, "CT-Font for {}: {}", language_isocode, name);
|
|
||||||
result = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!result) {
|
|
||||||
/* For some OS versions, the font 'Arial Unicode MS' does not report all languages it
|
|
||||||
* supports. If we didn't find any other font, just try it, maybe we get lucky. */
|
|
||||||
callback->SetFontNames(settings, "Arial Unicode MS");
|
|
||||||
result = !callback->FindMissingGlyphs();
|
|
||||||
}
|
|
||||||
|
|
||||||
callback->FindMissingGlyphs();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
CoreTextFontCache::CoreTextFontCache(FontSize fs, CFAutoRelease<CTFontDescriptorRef> &&font, int pixels) : TrueTypeFontCache(fs, pixels), font_desc(std::move(font))
|
CoreTextFontCache::CoreTextFontCache(FontSize fs, CFAutoRelease<CTFontDescriptorRef> &&font, int pixels) : TrueTypeFontCache(fs, pixels), font_desc(std::move(font))
|
||||||
{
|
{
|
||||||
this->SetFontSize(pixels);
|
this->SetFontSize(pixels);
|
||||||
|
@ -287,88 +201,182 @@ const Sprite *CoreTextFontCache::InternalGetGlyph(GlyphID key, bool use_aa)
|
||||||
return this->SetGlyphPtr(key, std::move(new_glyph)).GetSprite();
|
return this->SetGlyphPtr(key, std::move(new_glyph)).GetSprite();
|
||||||
}
|
}
|
||||||
|
|
||||||
static CTFontDescriptorRef LoadFontFromFile(const std::string &font_name)
|
class CoreTextFontCacheFactory : public FontCacheFactory {
|
||||||
{
|
public:
|
||||||
if (!MacOSVersionIsAtLeast(10, 6, 0)) return nullptr;
|
CoreTextFontCacheFactory() : FontCacheFactory("coretext", "CoreText font loader") {}
|
||||||
|
|
||||||
/* Might be a font file name, try load it. Direct font loading is
|
/**
|
||||||
* only supported starting on OSX 10.6. */
|
* Loads the TrueType font.
|
||||||
CFAutoRelease<CFStringRef> path;
|
* If a CoreText font description is present, e.g. from the automatic font
|
||||||
|
* fallback search, use it. Otherwise, try to resolve it by font name.
|
||||||
|
* @param fs The font size to load.
|
||||||
|
*/
|
||||||
|
std::unique_ptr<FontCache> LoadFont(FontSize fs, FontType fonttype) override
|
||||||
|
{
|
||||||
|
if (fonttype != FontType::TrueType) return nullptr;
|
||||||
|
|
||||||
/* See if this is an absolute path. */
|
FontCacheSubSetting *settings = GetFontCacheSubSetting(fs);
|
||||||
if (FileExists(font_name)) {
|
|
||||||
path.reset(CFStringCreateWithCString(kCFAllocatorDefault, font_name.c_str(), kCFStringEncodingUTF8));
|
std::string font = GetFontCacheFontName(fs);
|
||||||
} else {
|
if (font.empty()) return nullptr;
|
||||||
/* Scan the search-paths to see if it can be found. */
|
|
||||||
std::string full_font = FioFindFullPath(BASE_DIR, font_name);
|
CFAutoRelease<CTFontDescriptorRef> font_ref;
|
||||||
if (!full_font.empty()) {
|
|
||||||
path.reset(CFStringCreateWithCString(kCFAllocatorDefault, full_font.c_str(), kCFStringEncodingUTF8));
|
if (settings->os_handle != nullptr) {
|
||||||
|
font_ref.reset(static_cast<CTFontDescriptorRef>(const_cast<void *>(settings->os_handle)));
|
||||||
|
CFRetain(font_ref.get()); // Increase ref count to match a later release.
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (path) {
|
if (!font_ref && MacOSVersionIsAtLeast(10, 6, 0)) {
|
||||||
/* Try getting a font descriptor to see if the system can use it. */
|
/* Might be a font file name, try load it. */
|
||||||
CFAutoRelease<CFURLRef> url(CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path.get(), kCFURLPOSIXPathStyle, false));
|
font_ref.reset(LoadFontFromFile(font));
|
||||||
CFAutoRelease<CFArrayRef> descs(CTFontManagerCreateFontDescriptorsFromURL(url.get()));
|
if (!font_ref) ShowInfo("Unable to load file '{}' for {} font, using default OS font selection instead", font, FontSizeToName(fs));
|
||||||
|
|
||||||
if (descs && CFArrayGetCount(descs.get()) > 0) {
|
|
||||||
CTFontDescriptorRef font_ref = (CTFontDescriptorRef)CFArrayGetValueAtIndex(descs.get(), 0);
|
|
||||||
CFRetain(font_ref);
|
|
||||||
return font_ref;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
if (!font_ref) {
|
||||||
}
|
CFAutoRelease<CFStringRef> name(CFStringCreateWithCString(kCFAllocatorDefault, font.c_str(), kCFStringEncodingUTF8));
|
||||||
|
|
||||||
/**
|
/* Simply creating the font using CTFontCreateWithNameAndSize will *always* return
|
||||||
* Loads the TrueType font.
|
* something, no matter the name. As such, we can't use it to check for existence.
|
||||||
* If a CoreText font description is present, e.g. from the automatic font
|
* We instead query the list of all font descriptors that match the given name which
|
||||||
* fallback search, use it. Otherwise, try to resolve it by font name.
|
* does not do this stupid name fallback. */
|
||||||
* @param fs The font size to load.
|
CFAutoRelease<CTFontDescriptorRef> name_desc(CTFontDescriptorCreateWithNameAndSize(name.get(), 0.0));
|
||||||
*/
|
CFAutoRelease<CFSetRef> mandatory_attribs(CFSetCreate(kCFAllocatorDefault, const_cast<const void **>(reinterpret_cast<const void * const *>(&kCTFontNameAttribute)), 1, &kCFTypeSetCallBacks));
|
||||||
void LoadCoreTextFont(FontSize fs)
|
CFAutoRelease<CFArrayRef> descs(CTFontDescriptorCreateMatchingFontDescriptors(name_desc.get(), mandatory_attribs.get()));
|
||||||
{
|
|
||||||
FontCacheSubSetting *settings = GetFontCacheSubSetting(fs);
|
|
||||||
|
|
||||||
std::string font = GetFontCacheFontName(fs);
|
/* Assume the first result is the one we want. */
|
||||||
if (font.empty()) return;
|
if (descs && CFArrayGetCount(descs.get()) > 0) {
|
||||||
|
font_ref.reset((CTFontDescriptorRef)CFArrayGetValueAtIndex(descs.get(), 0));
|
||||||
CFAutoRelease<CTFontDescriptorRef> font_ref;
|
CFRetain(font_ref.get());
|
||||||
|
}
|
||||||
if (settings->os_handle != nullptr) {
|
|
||||||
font_ref.reset(static_cast<CTFontDescriptorRef>(const_cast<void *>(settings->os_handle)));
|
|
||||||
CFRetain(font_ref.get()); // Increase ref count to match a later release.
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!font_ref && MacOSVersionIsAtLeast(10, 6, 0)) {
|
|
||||||
/* Might be a font file name, try load it. */
|
|
||||||
font_ref.reset(LoadFontFromFile(font));
|
|
||||||
if (!font_ref) ShowInfo("Unable to load file '{}' for {} font, using default OS font selection instead", font, FontSizeToName(fs));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!font_ref) {
|
|
||||||
CFAutoRelease<CFStringRef> name(CFStringCreateWithCString(kCFAllocatorDefault, font.c_str(), kCFStringEncodingUTF8));
|
|
||||||
|
|
||||||
/* Simply creating the font using CTFontCreateWithNameAndSize will *always* return
|
|
||||||
* something, no matter the name. As such, we can't use it to check for existence.
|
|
||||||
* We instead query the list of all font descriptors that match the given name which
|
|
||||||
* does not do this stupid name fallback. */
|
|
||||||
CFAutoRelease<CTFontDescriptorRef> name_desc(CTFontDescriptorCreateWithNameAndSize(name.get(), 0.0));
|
|
||||||
CFAutoRelease<CFSetRef> mandatory_attribs(CFSetCreate(kCFAllocatorDefault, const_cast<const void **>(reinterpret_cast<const void * const *>(&kCTFontNameAttribute)), 1, &kCFTypeSetCallBacks));
|
|
||||||
CFAutoRelease<CFArrayRef> descs(CTFontDescriptorCreateMatchingFontDescriptors(name_desc.get(), mandatory_attribs.get()));
|
|
||||||
|
|
||||||
/* Assume the first result is the one we want. */
|
|
||||||
if (descs && CFArrayGetCount(descs.get()) > 0) {
|
|
||||||
font_ref.reset((CTFontDescriptorRef)CFArrayGetValueAtIndex(descs.get(), 0));
|
|
||||||
CFRetain(font_ref.get());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!font_ref) {
|
||||||
|
ShowInfo("Unable to use '{}' for {} font, using sprite font instead", font, FontSizeToName(fs));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_unique<CoreTextFontCache>(fs, std::move(font_ref), GetFontCacheFontSize(fs));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!font_ref) {
|
bool FindFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, MissingGlyphSearcher *callback) override
|
||||||
ShowInfo("Unable to use '{}' for {} font, using sprite font instead", font, FontSizeToName(fs));
|
{
|
||||||
return;
|
/* Determine fallback font using CoreText. This uses the language isocode
|
||||||
|
* to find a suitable font. CoreText is available from 10.5 onwards. */
|
||||||
|
std::string lang;
|
||||||
|
if (language_isocode == "zh_TW") {
|
||||||
|
/* Traditional Chinese */
|
||||||
|
lang = "zh-Hant";
|
||||||
|
} else if (language_isocode == "zh_CN") {
|
||||||
|
/* Simplified Chinese */
|
||||||
|
lang = "zh-Hans";
|
||||||
|
} else {
|
||||||
|
/* Just copy the first part of the isocode. */
|
||||||
|
lang = language_isocode.substr(0, language_isocode.find('_'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a font descriptor matching the wanted language and latin (english) glyphs.
|
||||||
|
* Can't use CFAutoRelease here for everything due to the way the dictionary has to be created. */
|
||||||
|
CFStringRef lang_codes[2];
|
||||||
|
lang_codes[0] = CFStringCreateWithCString(kCFAllocatorDefault, lang.c_str(), kCFStringEncodingUTF8);
|
||||||
|
lang_codes[1] = CFSTR("en");
|
||||||
|
CFArrayRef lang_arr = CFArrayCreate(kCFAllocatorDefault, (const void **)lang_codes, lengthof(lang_codes), &kCFTypeArrayCallBacks);
|
||||||
|
CFAutoRelease<CFDictionaryRef> lang_attribs(CFDictionaryCreate(kCFAllocatorDefault, const_cast<const void **>(reinterpret_cast<const void *const *>(&kCTFontLanguagesAttribute)), (const void **)&lang_arr, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
|
||||||
|
CFAutoRelease<CTFontDescriptorRef> lang_desc(CTFontDescriptorCreateWithAttributes(lang_attribs.get()));
|
||||||
|
CFRelease(lang_arr);
|
||||||
|
CFRelease(lang_codes[0]);
|
||||||
|
|
||||||
|
/* Get array of all font descriptors for the wanted language. */
|
||||||
|
CFAutoRelease<CFSetRef> mandatory_attribs(CFSetCreate(kCFAllocatorDefault, const_cast<const void **>(reinterpret_cast<const void *const *>(&kCTFontLanguagesAttribute)), 1, &kCFTypeSetCallBacks));
|
||||||
|
CFAutoRelease<CFArrayRef> descs(CTFontDescriptorCreateMatchingFontDescriptors(lang_desc.get(), mandatory_attribs.get()));
|
||||||
|
|
||||||
|
bool result = false;
|
||||||
|
for (int tries = 0; tries < 2; tries++) {
|
||||||
|
for (CFIndex i = 0; descs.get() != nullptr && i < CFArrayGetCount(descs.get()); i++) {
|
||||||
|
CTFontDescriptorRef font = (CTFontDescriptorRef)CFArrayGetValueAtIndex(descs.get(), i);
|
||||||
|
|
||||||
|
/* Get font traits. */
|
||||||
|
CFAutoRelease<CFDictionaryRef> traits((CFDictionaryRef)CTFontDescriptorCopyAttribute(font, kCTFontTraitsAttribute));
|
||||||
|
CTFontSymbolicTraits symbolic_traits;
|
||||||
|
CFNumberGetValue((CFNumberRef)CFDictionaryGetValue(traits.get(), kCTFontSymbolicTrait), kCFNumberIntType, &symbolic_traits);
|
||||||
|
|
||||||
|
/* Skip symbol fonts and vertical fonts. */
|
||||||
|
if ((symbolic_traits & kCTFontClassMaskTrait) == (CTFontStylisticClass)kCTFontSymbolicClass || (symbolic_traits & kCTFontVerticalTrait)) continue;
|
||||||
|
/* Skip bold fonts (especially Arial Bold, which looks worse than regular Arial). */
|
||||||
|
if (symbolic_traits & kCTFontBoldTrait) continue;
|
||||||
|
/* Select monospaced fonts if asked for. */
|
||||||
|
if (((symbolic_traits & kCTFontMonoSpaceTrait) == kCTFontMonoSpaceTrait) != callback->Monospace()) continue;
|
||||||
|
|
||||||
|
/* Get font name. */
|
||||||
|
char buffer[128];
|
||||||
|
CFAutoRelease<CFStringRef> font_name((CFStringRef)CTFontDescriptorCopyAttribute(font, kCTFontDisplayNameAttribute));
|
||||||
|
CFStringGetCString(font_name.get(), buffer, std::size(buffer), kCFStringEncodingUTF8);
|
||||||
|
|
||||||
|
/* Serif fonts usually look worse on-screen with only small
|
||||||
|
* font sizes. As such, we try for a sans-serif font first.
|
||||||
|
* If we can't find one in the first try, try all fonts. */
|
||||||
|
if (tries == 0 && (symbolic_traits & kCTFontClassMaskTrait) != (CTFontStylisticClass)kCTFontSansSerifClass) continue;
|
||||||
|
|
||||||
|
/* There are some special fonts starting with an '.' and the last
|
||||||
|
* resort font that aren't usable. Skip them. */
|
||||||
|
std::string_view name{buffer};
|
||||||
|
if (name.starts_with(".") || name.starts_with("LastResort")) continue;
|
||||||
|
|
||||||
|
/* Save result. */
|
||||||
|
callback->SetFontNames(settings, name);
|
||||||
|
if (!callback->FindMissingGlyphs()) {
|
||||||
|
Debug(fontcache, 2, "CT-Font for {}: {}", language_isocode, name);
|
||||||
|
result = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
/* For some OS versions, the font 'Arial Unicode MS' does not report all languages it
|
||||||
|
* supports. If we didn't find any other font, just try it, maybe we get lucky. */
|
||||||
|
callback->SetFontNames(settings, "Arial Unicode MS");
|
||||||
|
result = !callback->FindMissingGlyphs();
|
||||||
|
}
|
||||||
|
|
||||||
|
callback->FindMissingGlyphs();
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
new CoreTextFontCache(fs, std::move(font_ref), GetFontCacheFontSize(fs));
|
private:
|
||||||
}
|
static CTFontDescriptorRef LoadFontFromFile(const std::string &font_name)
|
||||||
|
{
|
||||||
|
if (!MacOSVersionIsAtLeast(10, 6, 0)) return nullptr;
|
||||||
|
|
||||||
|
/* Might be a font file name, try load it. Direct font loading is
|
||||||
|
* only supported starting on OSX 10.6. */
|
||||||
|
CFAutoRelease<CFStringRef> path;
|
||||||
|
|
||||||
|
/* See if this is an absolute path. */
|
||||||
|
if (FileExists(font_name)) {
|
||||||
|
path.reset(CFStringCreateWithCString(kCFAllocatorDefault, font_name.c_str(), kCFStringEncodingUTF8));
|
||||||
|
} else {
|
||||||
|
/* Scan the search-paths to see if it can be found. */
|
||||||
|
std::string full_font = FioFindFullPath(BASE_DIR, font_name);
|
||||||
|
if (!full_font.empty()) {
|
||||||
|
path.reset(CFStringCreateWithCString(kCFAllocatorDefault, full_font.c_str(), kCFStringEncodingUTF8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path) {
|
||||||
|
/* Try getting a font descriptor to see if the system can use it. */
|
||||||
|
CFAutoRelease<CFURLRef> url(CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path.get(), kCFURLPOSIXPathStyle, false));
|
||||||
|
CFAutoRelease<CFArrayRef> descs(CTFontManagerCreateFontDescriptorsFromURL(url.get()));
|
||||||
|
|
||||||
|
if (descs && CFArrayGetCount(descs.get()) > 0) {
|
||||||
|
CTFontDescriptorRef font_ref = (CTFontDescriptorRef)CFArrayGetValueAtIndex(descs.get(), 0);
|
||||||
|
CFRetain(font_ref);
|
||||||
|
return font_ref;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static CoreTextFontCacheFactory s_coretext_fontcache_Factory;
|
||||||
|
|
|
@ -12,6 +12,7 @@ add_files(
|
||||||
|
|
||||||
add_files(
|
add_files(
|
||||||
font_unix.cpp
|
font_unix.cpp
|
||||||
|
font_unix.h
|
||||||
CONDITION Fontconfig_FOUND
|
CONDITION Fontconfig_FOUND
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -11,17 +11,17 @@
|
||||||
|
|
||||||
#include "../../misc/autorelease.hpp"
|
#include "../../misc/autorelease.hpp"
|
||||||
#include "../../debug.h"
|
#include "../../debug.h"
|
||||||
#include "../../fontdetection.h"
|
#include "../../fontcache.h"
|
||||||
#include "../../string_func.h"
|
#include "../../string_func.h"
|
||||||
#include "../../strings_func.h"
|
#include "../../strings_func.h"
|
||||||
|
#include "font_unix.h"
|
||||||
|
|
||||||
#include <fontconfig/fontconfig.h>
|
#include <fontconfig/fontconfig.h>
|
||||||
|
|
||||||
#include "../../safeguards.h"
|
|
||||||
|
|
||||||
#include <ft2build.h>
|
#include <ft2build.h>
|
||||||
#include FT_FREETYPE_H
|
#include FT_FREETYPE_H
|
||||||
|
|
||||||
|
#include "../../safeguards.h"
|
||||||
|
|
||||||
extern FT_Library _ft_library;
|
extern FT_Library _ft_library;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -61,6 +61,12 @@ static std::tuple<std::string, std::string> SplitFontFamilyAndStyle(std::string_
|
||||||
return { std::string(font_name.substr(0, separator)), std::string(font_name.substr(begin)) };
|
return { std::string(font_name.substr(0, separator)), std::string(font_name.substr(begin)) };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a freetype font face with the given font name.
|
||||||
|
* @param font_name The name of the font to load.
|
||||||
|
* @param face The face that has been found.
|
||||||
|
* @return The error we encountered.
|
||||||
|
*/
|
||||||
FT_Error GetFontByFaceName(std::string_view font_name, FT_Face *face)
|
FT_Error GetFontByFaceName(std::string_view font_name, FT_Face *face)
|
||||||
{
|
{
|
||||||
FT_Error err = FT_Err_Cannot_Open_Resource;
|
FT_Error err = FT_Err_Cannot_Open_Resource;
|
||||||
|
@ -117,7 +123,7 @@ FT_Error GetFontByFaceName(std::string_view font_name, FT_Face *face)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SetFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, MissingGlyphSearcher *callback)
|
bool FontConfigFindFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, MissingGlyphSearcher *callback)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
|
|
||||||
|
@ -182,6 +188,6 @@ bool SetFallbackFont(FontCacheSettings *settings, const std::string &language_is
|
||||||
if (best_font == nullptr) return false;
|
if (best_font == nullptr) return false;
|
||||||
|
|
||||||
callback->SetFontNames(settings, best_font, &best_index);
|
callback->SetFontNames(settings, best_font, &best_index);
|
||||||
InitFontCache(callback->Monospace() ? FontSizes{FS_MONO} : FONTSIZES_REQUIRED);
|
FontCache::LoadFontCaches(callback->Monospace() ? FontSizes{FS_MONO} : FONTSIZES_REQUIRED);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* This file is part of OpenTTD.
|
||||||
|
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||||
|
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file font_unix.h Functions related to detecting/finding the right font. */
|
||||||
|
|
||||||
|
#ifndef FONT_UNIX_H
|
||||||
|
#define FONT_UNIX_H
|
||||||
|
|
||||||
|
#ifdef WITH_FONTCONFIG
|
||||||
|
|
||||||
|
#include "../../fontcache.h"
|
||||||
|
|
||||||
|
#include <ft2build.h>
|
||||||
|
#include FT_FREETYPE_H
|
||||||
|
|
||||||
|
FT_Error GetFontByFaceName(std::string_view font_name, FT_Face *face);
|
||||||
|
|
||||||
|
bool FontConfigFindFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, MissingGlyphSearcher *callback);
|
||||||
|
|
||||||
|
#endif /* WITH_FONTCONFIG */
|
||||||
|
|
||||||
|
#endif /* FONT_UNIX_H */
|
|
@ -15,7 +15,6 @@
|
||||||
#include "../../fileio_func.h"
|
#include "../../fileio_func.h"
|
||||||
#include "../../fontcache.h"
|
#include "../../fontcache.h"
|
||||||
#include "../../fontcache/truetypefontcache.h"
|
#include "../../fontcache/truetypefontcache.h"
|
||||||
#include "../../fontdetection.h"
|
|
||||||
#include "../../library_loader.h"
|
#include "../../library_loader.h"
|
||||||
#include "../../string_func.h"
|
#include "../../string_func.h"
|
||||||
#include "../../strings_func.h"
|
#include "../../strings_func.h"
|
||||||
|
@ -85,32 +84,6 @@ static int CALLBACK EnumFontCallback(const ENUMLOGFONTEX *logfont, const NEWTEXT
|
||||||
return 0; // stop enumerating
|
return 0; // stop enumerating
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SetFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, MissingGlyphSearcher *callback)
|
|
||||||
{
|
|
||||||
Debug(fontcache, 1, "Trying fallback fonts");
|
|
||||||
EFCParam langInfo;
|
|
||||||
std::wstring lang = OTTD2FS(language_isocode.substr(0, language_isocode.find('_')));
|
|
||||||
if (GetLocaleInfoEx(lang.c_str(), LOCALE_FONTSIGNATURE, reinterpret_cast<LPWSTR>(&langInfo.locale), sizeof(langInfo.locale) / sizeof(wchar_t)) == 0) {
|
|
||||||
/* Invalid isocode or some other mysterious error, can't determine fallback font. */
|
|
||||||
Debug(fontcache, 1, "Can't get locale info for fallback font (isocode={})", language_isocode);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
langInfo.settings = settings;
|
|
||||||
langInfo.callback = callback;
|
|
||||||
|
|
||||||
LOGFONT font;
|
|
||||||
/* Enumerate all fonts. */
|
|
||||||
font.lfCharSet = DEFAULT_CHARSET;
|
|
||||||
font.lfFaceName[0] = '\0';
|
|
||||||
font.lfPitchAndFamily = 0;
|
|
||||||
|
|
||||||
HDC dc = GetDC(nullptr);
|
|
||||||
int ret = EnumFontFamiliesEx(dc, &font, (FONTENUMPROC)&EnumFontCallback, (LPARAM)&langInfo, 0);
|
|
||||||
ReleaseDC(nullptr, dc);
|
|
||||||
return ret == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new Win32FontCache.
|
* Create a new Win32FontCache.
|
||||||
* @param fs The font size that is going to be cached.
|
* @param fs The font size that is going to be cached.
|
||||||
|
@ -293,99 +266,134 @@ void Win32FontCache::ClearFontCache()
|
||||||
return allow_fallback && key >= SCC_SPRITE_START && key <= SCC_SPRITE_END ? this->parent->MapCharToGlyph(key) : 0;
|
return allow_fallback && key >= SCC_SPRITE_START && key <= SCC_SPRITE_END ? this->parent->MapCharToGlyph(key) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Win32FontCacheFactory : FontCacheFactory {
|
||||||
|
public:
|
||||||
|
Win32FontCacheFactory() : FontCacheFactory("win32", "Win32 font loader") {}
|
||||||
|
|
||||||
static bool TryLoadFontFromFile(const std::string &font_name, LOGFONT &logfont)
|
/**
|
||||||
{
|
* Loads the GDI font.
|
||||||
wchar_t fontPath[MAX_PATH] = {};
|
* If a GDI font description is present, e.g. from the automatic font
|
||||||
|
* fallback search, use it. Otherwise, try to resolve it by font name.
|
||||||
|
* @param fs The font size to load.
|
||||||
|
*/
|
||||||
|
std::unique_ptr<FontCache> LoadFont(FontSize fs, FontType fonttype) override
|
||||||
|
{
|
||||||
|
if (fonttype != FontType::TrueType) return nullptr;
|
||||||
|
|
||||||
/* See if this is an absolute path. */
|
FontCacheSubSetting *settings = GetFontCacheSubSetting(fs);
|
||||||
if (FileExists(font_name)) {
|
|
||||||
convert_to_fs(font_name, fontPath);
|
std::string font = GetFontCacheFontName(fs);
|
||||||
} else {
|
if (font.empty()) return nullptr;
|
||||||
/* Scan the search-paths to see if it can be found. */
|
|
||||||
std::string full_font = FioFindFullPath(BASE_DIR, font_name);
|
LOGFONT logfont{};
|
||||||
if (!full_font.empty()) {
|
logfont.lfPitchAndFamily = fs == FS_MONO ? FIXED_PITCH : VARIABLE_PITCH;
|
||||||
convert_to_fs(font_name, fontPath);
|
logfont.lfCharSet = DEFAULT_CHARSET;
|
||||||
|
logfont.lfOutPrecision = OUT_OUTLINE_PRECIS;
|
||||||
|
logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
|
||||||
|
|
||||||
|
if (settings->os_handle != nullptr) {
|
||||||
|
logfont = *(const LOGFONT *)settings->os_handle;
|
||||||
|
} else if (font.find('.') != std::string::npos) {
|
||||||
|
/* Might be a font file name, try load it. */
|
||||||
|
if (!TryLoadFontFromFile(font, logfont)) {
|
||||||
|
ShowInfo("Unable to load file '{}' for {} font, using default windows font selection instead", font, FontSizeToName(fs));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (logfont.lfFaceName[0] == 0) {
|
||||||
|
logfont.lfWeight = StrContainsIgnoreCase(font, " bold") ? FW_BOLD : FW_NORMAL; // Poor man's way to allow selecting bold fonts.
|
||||||
|
convert_to_fs(font, logfont.lfFaceName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return LoadWin32Font(fs, logfont, GetFontCacheFontSize(fs), font);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fontPath[0] != 0) {
|
bool FindFallbackFont(FontCacheSettings *settings, const std::string &language_isocode, MissingGlyphSearcher *callback) override
|
||||||
if (AddFontResourceEx(fontPath, FR_PRIVATE, 0) != 0) {
|
{
|
||||||
/* Try a nice little undocumented function first for getting the internal font name.
|
Debug(fontcache, 1, "Trying fallback fonts");
|
||||||
* Some documentation is found at: http://www.undocprint.org/winspool/getfontresourceinfo */
|
EFCParam langInfo;
|
||||||
static LibraryLoader _gdi32("gdi32.dll");
|
std::wstring lang = OTTD2FS(language_isocode.substr(0, language_isocode.find('_')));
|
||||||
typedef BOOL(WINAPI *PFNGETFONTRESOURCEINFO)(LPCTSTR, LPDWORD, LPVOID, DWORD);
|
if (GetLocaleInfoEx(lang.c_str(), LOCALE_FONTSIGNATURE, reinterpret_cast<LPWSTR>(&langInfo.locale), sizeof(langInfo.locale) / sizeof(wchar_t)) == 0) {
|
||||||
static PFNGETFONTRESOURCEINFO GetFontResourceInfo = _gdi32.GetFunction("GetFontResourceInfoW");
|
/* Invalid isocode or some other mysterious error, can't determine fallback font. */
|
||||||
|
Debug(fontcache, 1, "Can't get locale info for fallback font (isocode={})", language_isocode);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
langInfo.settings = settings;
|
||||||
|
langInfo.callback = callback;
|
||||||
|
|
||||||
if (GetFontResourceInfo != nullptr) {
|
LOGFONT font;
|
||||||
/* Try to query an array of LOGFONTs that describe the file. */
|
/* Enumerate all fonts. */
|
||||||
DWORD len = 0;
|
font.lfCharSet = DEFAULT_CHARSET;
|
||||||
if (GetFontResourceInfo(fontPath, &len, nullptr, 2) && len >= sizeof(LOGFONT)) {
|
font.lfFaceName[0] = '\0';
|
||||||
LOGFONT *buf = (LOGFONT *)new uint8_t[len];
|
font.lfPitchAndFamily = 0;
|
||||||
if (GetFontResourceInfo(fontPath, &len, buf, 2)) {
|
|
||||||
logfont = *buf; // Just use first entry.
|
HDC dc = GetDC(nullptr);
|
||||||
|
int ret = EnumFontFamiliesEx(dc, &font, (FONTENUMPROC)&EnumFontCallback, (LPARAM)&langInfo, 0);
|
||||||
|
ReleaseDC(nullptr, dc);
|
||||||
|
return ret == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static std::unique_ptr<FontCache> LoadWin32Font(FontSize fs, const LOGFONT &logfont, uint size, std::string_view font_name)
|
||||||
|
{
|
||||||
|
HFONT font = CreateFontIndirect(&logfont);
|
||||||
|
if (font == nullptr) {
|
||||||
|
ShowInfo("Unable to use '{}' for {} font, Win32 reported error 0x{:X}, using sprite font instead", font_name, FontSizeToName(fs), GetLastError());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
DeleteObject(font);
|
||||||
|
|
||||||
|
return std::make_unique<Win32FontCache>(fs, logfont, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool TryLoadFontFromFile(const std::string &font_name, LOGFONT &logfont)
|
||||||
|
{
|
||||||
|
wchar_t fontPath[MAX_PATH] = {};
|
||||||
|
|
||||||
|
/* See if this is an absolute path. */
|
||||||
|
if (FileExists(font_name)) {
|
||||||
|
convert_to_fs(font_name, fontPath);
|
||||||
|
} else {
|
||||||
|
/* Scan the search-paths to see if it can be found. */
|
||||||
|
std::string full_font = FioFindFullPath(BASE_DIR, font_name);
|
||||||
|
if (!full_font.empty()) {
|
||||||
|
convert_to_fs(font_name, fontPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fontPath[0] != 0) {
|
||||||
|
if (AddFontResourceEx(fontPath, FR_PRIVATE, 0) != 0) {
|
||||||
|
/* Try a nice little undocumented function first for getting the internal font name.
|
||||||
|
* Some documentation is found at: http://www.undocprint.org/winspool/getfontresourceinfo */
|
||||||
|
static LibraryLoader _gdi32("gdi32.dll");
|
||||||
|
typedef BOOL(WINAPI *PFNGETFONTRESOURCEINFO)(LPCTSTR, LPDWORD, LPVOID, DWORD);
|
||||||
|
static PFNGETFONTRESOURCEINFO GetFontResourceInfo = _gdi32.GetFunction("GetFontResourceInfoW");
|
||||||
|
|
||||||
|
if (GetFontResourceInfo != nullptr) {
|
||||||
|
/* Try to query an array of LOGFONTs that describe the file. */
|
||||||
|
DWORD len = 0;
|
||||||
|
if (GetFontResourceInfo(fontPath, &len, nullptr, 2) && len >= sizeof(LOGFONT)) {
|
||||||
|
LOGFONT *buf = (LOGFONT *)new uint8_t[len];
|
||||||
|
if (GetFontResourceInfo(fontPath, &len, buf, 2)) {
|
||||||
|
logfont = *buf; // Just use first entry.
|
||||||
|
}
|
||||||
|
delete[](uint8_t *)buf;
|
||||||
}
|
}
|
||||||
delete[](uint8_t *)buf;
|
}
|
||||||
|
|
||||||
|
/* No dice yet. Use the file name as the font face name, hoping it matches. */
|
||||||
|
if (logfont.lfFaceName[0] == 0) {
|
||||||
|
wchar_t fname[_MAX_FNAME];
|
||||||
|
_wsplitpath(fontPath, nullptr, nullptr, fname, nullptr);
|
||||||
|
|
||||||
|
wcsncpy_s(logfont.lfFaceName, lengthof(logfont.lfFaceName), fname, _TRUNCATE);
|
||||||
|
logfont.lfWeight = StrContainsIgnoreCase(font_name, " bold") || StrContainsIgnoreCase(font_name, "-bold") ? FW_BOLD : FW_NORMAL; // Poor man's way to allow selecting bold fonts.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* No dice yet. Use the file name as the font face name, hoping it matches. */
|
|
||||||
if (logfont.lfFaceName[0] == 0) {
|
|
||||||
wchar_t fname[_MAX_FNAME];
|
|
||||||
_wsplitpath(fontPath, nullptr, nullptr, fname, nullptr);
|
|
||||||
|
|
||||||
wcsncpy_s(logfont.lfFaceName, lengthof(logfont.lfFaceName), fname, _TRUNCATE);
|
|
||||||
logfont.lfWeight = StrContainsIgnoreCase(font_name, " bold") || StrContainsIgnoreCase(font_name, "-bold") ? FW_BOLD : FW_NORMAL; // Poor man's way to allow selecting bold fonts.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return logfont.lfFaceName[0] != 0;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return logfont.lfFaceName[0] != 0;
|
static Win32FontCacheFactory s_win32_fontcache_factory;
|
||||||
}
|
|
||||||
|
|
||||||
static void LoadWin32Font(FontSize fs, const LOGFONT &logfont, uint size, std::string_view font_name)
|
|
||||||
{
|
|
||||||
HFONT font = CreateFontIndirect(&logfont);
|
|
||||||
if (font == nullptr) {
|
|
||||||
ShowInfo("Unable to use '{}' for {} font, Win32 reported error 0x{:X}, using sprite font instead", font_name, FontSizeToName(fs), GetLastError());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
DeleteObject(font);
|
|
||||||
|
|
||||||
new Win32FontCache(fs, logfont, size);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Loads the GDI font.
|
|
||||||
* If a GDI font description is present, e.g. from the automatic font
|
|
||||||
* fallback search, use it. Otherwise, try to resolve it by font name.
|
|
||||||
* @param fs The font size to load.
|
|
||||||
*/
|
|
||||||
void LoadWin32Font(FontSize fs)
|
|
||||||
{
|
|
||||||
FontCacheSubSetting *settings = GetFontCacheSubSetting(fs);
|
|
||||||
|
|
||||||
std::string font = GetFontCacheFontName(fs);
|
|
||||||
if (font.empty()) return;
|
|
||||||
|
|
||||||
LOGFONT logfont{};
|
|
||||||
logfont.lfPitchAndFamily = fs == FS_MONO ? FIXED_PITCH : VARIABLE_PITCH;
|
|
||||||
logfont.lfCharSet = DEFAULT_CHARSET;
|
|
||||||
logfont.lfOutPrecision = OUT_OUTLINE_PRECIS;
|
|
||||||
logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
|
|
||||||
|
|
||||||
if (settings->os_handle != nullptr) {
|
|
||||||
logfont = *(const LOGFONT *)settings->os_handle;
|
|
||||||
} else if (font.find('.') != std::string::npos) {
|
|
||||||
/* Might be a font file name, try load it. */
|
|
||||||
if (!TryLoadFontFromFile(font, logfont)) {
|
|
||||||
ShowInfo("Unable to load file '{}' for {} font, using default windows font selection instead", font, FontSizeToName(fs));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (logfont.lfFaceName[0] == 0) {
|
|
||||||
logfont.lfWeight = StrContainsIgnoreCase(font, " bold") ? FW_BOLD : FW_NORMAL; // Poor man's way to allow selecting bold fonts.
|
|
||||||
convert_to_fs(font, logfont.lfFaceName);
|
|
||||||
}
|
|
||||||
|
|
||||||
LoadWin32Font(fs, logfont, GetFontCacheFontSize(fs), font);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1036,8 +1036,8 @@ struct GameOptionsWindow : Window {
|
||||||
this->SetWidgetDisabledState(WID_GO_GUI_FONT_AA, _fcsettings.prefer_sprite);
|
this->SetWidgetDisabledState(WID_GO_GUI_FONT_AA, _fcsettings.prefer_sprite);
|
||||||
this->SetDirty();
|
this->SetDirty();
|
||||||
|
|
||||||
InitFontCache(FONTSIZES_ALL);
|
FontCache::LoadFontCaches(FONTSIZES_ALL);
|
||||||
ClearFontCache(FONTSIZES_ALL);
|
FontCache::ClearFontCaches(FONTSIZES_ALL);
|
||||||
CheckForMissingGlyphs();
|
CheckForMissingGlyphs();
|
||||||
SetupWidgetDimensions();
|
SetupWidgetDimensions();
|
||||||
UpdateAllVirtCoords();
|
UpdateAllVirtCoords();
|
||||||
|
@ -1050,7 +1050,7 @@ struct GameOptionsWindow : Window {
|
||||||
this->SetWidgetLoweredState(WID_GO_GUI_FONT_AA, _fcsettings.global_aa);
|
this->SetWidgetLoweredState(WID_GO_GUI_FONT_AA, _fcsettings.global_aa);
|
||||||
MarkWholeScreenDirty();
|
MarkWholeScreenDirty();
|
||||||
|
|
||||||
ClearFontCache(FONTSIZES_ALL);
|
FontCache::ClearFontCaches(FONTSIZES_ALL);
|
||||||
break;
|
break;
|
||||||
#endif /* HAS_TRUETYPE_FONT */
|
#endif /* HAS_TRUETYPE_FONT */
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
#include "newgrf_text.h"
|
#include "newgrf_text.h"
|
||||||
#include "fileio_func.h"
|
#include "fileio_func.h"
|
||||||
#include "signs_base.h"
|
#include "signs_base.h"
|
||||||
#include "fontdetection.h"
|
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "error_func.h"
|
#include "error_func.h"
|
||||||
#include "strings_func.h"
|
#include "strings_func.h"
|
||||||
|
@ -2278,7 +2277,7 @@ std::string_view GetCurrentLanguageIsoCode()
|
||||||
*/
|
*/
|
||||||
bool MissingGlyphSearcher::FindMissingGlyphs()
|
bool MissingGlyphSearcher::FindMissingGlyphs()
|
||||||
{
|
{
|
||||||
InitFontCache(this->Monospace() ? FontSizes{FS_MONO} : FONTSIZES_REQUIRED);
|
FontCache::LoadFontCaches(this->Monospace() ? FontSizes{FS_MONO} : FONTSIZES_REQUIRED);
|
||||||
|
|
||||||
this->Reset();
|
this->Reset();
|
||||||
for (auto text = this->NextString(); text.has_value(); text = this->NextString()) {
|
for (auto text = this->NextString(); text.has_value(); text = this->NextString()) {
|
||||||
|
@ -2376,7 +2375,7 @@ void CheckForMissingGlyphs(bool base_font, MissingGlyphSearcher *searcher)
|
||||||
_fcsettings.mono.os_handle = nullptr;
|
_fcsettings.mono.os_handle = nullptr;
|
||||||
_fcsettings.medium.os_handle = nullptr;
|
_fcsettings.medium.os_handle = nullptr;
|
||||||
|
|
||||||
bad_font = !SetFallbackFont(&_fcsettings, _langpack.langpack->isocode, searcher);
|
bad_font = !FontProviderManager::FindFallbackFont(&_fcsettings, _langpack.langpack->isocode, searcher);
|
||||||
|
|
||||||
_fcsettings = std::move(backup);
|
_fcsettings = std::move(backup);
|
||||||
|
|
||||||
|
@ -2395,7 +2394,7 @@ void CheckForMissingGlyphs(bool base_font, MissingGlyphSearcher *searcher)
|
||||||
/* Our fallback font does miss characters too, so keep the
|
/* Our fallback font does miss characters too, so keep the
|
||||||
* user chosen font as that is more likely to be any good than
|
* user chosen font as that is more likely to be any good than
|
||||||
* the wild guess we made */
|
* the wild guess we made */
|
||||||
InitFontCache(searcher->Monospace() ? FontSizes{FS_MONO} : FONTSIZES_REQUIRED);
|
FontCache::LoadFontCaches(searcher->Monospace() ? FontSizes{FS_MONO} : FONTSIZES_REQUIRED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -32,7 +32,8 @@ public:
|
||||||
static void InitializeFontCaches()
|
static void InitializeFontCaches()
|
||||||
{
|
{
|
||||||
for (FontSize fs = FS_BEGIN; fs != FS_END; fs++) {
|
for (FontSize fs = FS_BEGIN; fs != FS_END; fs++) {
|
||||||
if (FontCache::caches[fs] == nullptr) new MockFontCache(fs); /* FontCache inserts itself into to the cache. */
|
if (FontCache::Get(fs) != nullptr) continue;
|
||||||
|
FontCache::Register(std::make_unique<MockFontCache>(fs));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue