10#include "../../stdafx.h"
11#include "../../debug.h"
13#include "../../core/math_func.hpp"
14#include "../../blitter/factory.hpp"
15#include "../../error_func.h"
16#include "../../fileio_func.h"
17#include "../../string_func.h"
18#include "../../strings_func.h"
19#include "../../zoom_func.h"
22#include "../../table/control_codes.h"
24#include "../../safeguards.h"
28 this->SetFontSize(pixels);
42void CoreTextFontCache::SetFontSize(
int pixels)
46 int scaled_height =
ScaleGUITrad(FontCache::GetDefaultFontHeight(this->
fs));
47 pixels = scaled_height;
51 float min_size = 0.0f;
60 uint16_t lowestRecPPEM;
61 CFDataGetBytes(data.get(), CFRangeMake(46,
sizeof(lowestRecPPEM)), (UInt8 *)&lowestRecPPEM);
62 min_size = CFSwapInt16BigToHost(lowestRecPPEM);
65 CFNumberGetValue(size.get(), kCFNumberFloatType, &min_size);
79 this->
font.reset(CTFontCreateWithFontDescriptor(this->
font_desc.get(), pixels,
nullptr));
84 this->
ascender = (int)std::ceil(CTFontGetAscent(this->
font.get()));
85 this->
descender = -(int)std::ceil(CTFontGetDescent(this->
font.get()));
94 Debug(fontcache, 2,
"Loaded font '{}' with size {}", this->
font_name, pixels);
99 assert(IsPrintable(key));
103 if (key >= 0x010000U) {
104 chars[0] = (UniChar)(((key - 0x010000U) >> 10) + 0xD800);
105 chars[1] = (UniChar)(((key - 0x010000U) & 0x3FF) + 0xDC00);
107 chars[0] = (UniChar)(key & 0xFFFF);
110 CGGlyph glyph[2] = {0, 0};
111 if (CTFontGetGlyphsForCharacters(this->
font.get(), chars, glyph, key >= 0x010000U ? 2 : 1)) {
115 if (allow_fallback && key >= SCC_SPRITE_START && key <= SCC_SPRITE_END) {
116 return this->
parent->MapCharToGlyph(key);
122const Sprite *CoreTextFontCache::InternalGetGlyph(
GlyphID key,
bool use_aa)
125 CGGlyph glyph = (CGGlyph)key;
126 CGRect bounds = CGRectNull;
128 bounds = CTFontGetOpticalBoundsForGlyphs(this->
font.get(), &glyph,
nullptr, 1, 0);
130 bounds = CTFontGetBoundingRectsForGlyphs(this->
font.get(), kCTFontOrientationDefault, &glyph,
nullptr, 1);
132 if (CGRectIsNull(bounds)) UserError(
"Unable to render font glyph");
134 uint bb_width = (uint)std::ceil(bounds.size.width) + 1;
135 uint bb_height = (uint)std::ceil(bounds.size.height);
139 uint width = std::max(1U, bb_width + shadow);
140 uint
height = std::max(1U, bb_height + shadow);
150 sprite.
width = width;
152 sprite.
x_offs = (int16_t)std::round(CGRectGetMinX(bounds));
153 sprite.
y_offs = this->
ascender - (int16_t)std::ceil(CGRectGetMaxY(bounds));
155 if (bounds.size.width > 0) {
159 int pitch =
Align(bb_width, 16);
161 const uint8_t *bmp =
static_cast<uint8_t *
>(CGBitmapContextGetData(context.get()));
163 CGContextSetAllowsAntialiasing(context.get(), use_aa);
164 CGContextSetAllowsFontSubpixelPositioning(context.get(), use_aa);
165 CGContextSetAllowsFontSubpixelQuantization(context.get(), !use_aa);
166 CGContextSetShouldSmoothFonts(context.get(),
false);
168 CGPoint pos{-bounds.origin.x, -bounds.origin.y};
169 CTFontDrawGlyphs(this->
font.get(), &glyph, &pos, 1, context.get());
173 for (uint y = 0; y < bb_height; y++) {
174 for (uint x = 0; x < bb_width; x++) {
175 if (bmp[y * pitch + x] > 0) {
176 sprite.
data[shadow + x + (shadow + y) * sprite.
width].
m = SHADOW_COLOUR;
177 sprite.
data[shadow + x + (shadow + y) * sprite.
width].
a = use_aa ? bmp[x + y * pitch] : 0xFF;
184 for (uint y = 0; y < bb_height; y++) {
185 for (uint x = 0; x < bb_width; x++) {
186 if (bmp[y * pitch + x] > 0) {
187 sprite.
data[x + y * sprite.
width].
m = FACE_COLOUR;
188 sprite.
data[x + y * sprite.
width].
a = use_aa ? bmp[x + y * pitch] : 0xFF;
197 GlyphEntry new_glyph;
198 new_glyph.
data = std::move(allocator.data);
199 new_glyph.width = (uint8_t)std::round(CTFontGetAdvancesForGlyphs(this->
font.get(), kCTFontOrientationDefault, &glyph,
nullptr, 1));
201 return this->SetGlyphPtr(key, std::move(new_glyph)).GetSprite();
221 if (font.empty())
return nullptr;
225 if (
settings->os_handle !=
nullptr) {
226 font_ref.reset(
static_cast<CTFontDescriptorRef
>(
const_cast<void *
>(
settings->os_handle)));
227 CFRetain(font_ref.get());
232 font_ref.reset(LoadFontFromFile(font));
233 if (!font_ref) ShowInfo(
"Unable to load file '{}' for {} font, using default OS font selection instead", font, FontSizeToName(fs));
244 CFAutoRelease<CFSetRef> mandatory_attribs(CFSetCreate(kCFAllocatorDefault,
const_cast<const void **
>(
reinterpret_cast<const void *
const *
>(&kCTFontNameAttribute)), 1, &kCFTypeSetCallBacks));
245 CFAutoRelease<CFArrayRef> descs(CTFontDescriptorCreateMatchingFontDescriptors(name_desc.get(), mandatory_attribs.get()));
248 if (descs && CFArrayGetCount(descs.get()) > 0) {
249 font_ref.reset((CTFontDescriptorRef)CFArrayGetValueAtIndex(descs.get(), 0));
250 CFRetain(font_ref.get());
255 ShowInfo(
"Unable to use '{}' for {} font, using sprite font instead", font, FontSizeToName(fs));
267 if (language_isocode ==
"zh_TW") {
270 }
else if (language_isocode ==
"zh_CN") {
275 lang = language_isocode.substr(0, language_isocode.find(
'_'));
280 CFStringRef lang_codes[2];
281 lang_codes[0] = CFStringCreateWithCString(kCFAllocatorDefault, lang.c_str(), kCFStringEncodingUTF8);
282 lang_codes[1] = CFSTR(
"en");
283 CFArrayRef lang_arr = CFArrayCreate(kCFAllocatorDefault, (
const void **)lang_codes,
lengthof(lang_codes), &kCFTypeArrayCallBacks);
284 CFAutoRelease<CFDictionaryRef> lang_attribs(CFDictionaryCreate(kCFAllocatorDefault,
const_cast<const void **
>(
reinterpret_cast<const void *
const *
>(&kCTFontLanguagesAttribute)), (
const void **)&lang_arr, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
287 CFRelease(lang_codes[0]);
290 CFAutoRelease<CFSetRef> mandatory_attribs(CFSetCreate(kCFAllocatorDefault,
const_cast<const void **
>(
reinterpret_cast<const void *
const *
>(&kCTFontLanguagesAttribute)), 1, &kCFTypeSetCallBacks));
291 CFAutoRelease<CFArrayRef> descs(CTFontDescriptorCreateMatchingFontDescriptors(lang_desc.get(), mandatory_attribs.get()));
294 for (
int tries = 0; tries < 2; tries++) {
295 for (CFIndex i = 0; descs.get() !=
nullptr && i < CFArrayGetCount(descs.get()); i++) {
296 CTFontDescriptorRef font = (CTFontDescriptorRef)CFArrayGetValueAtIndex(descs.get(), i);
300 CTFontSymbolicTraits symbolic_traits;
301 CFNumberGetValue((CFNumberRef)CFDictionaryGetValue(traits.get(), kCTFontSymbolicTrait), kCFNumberIntType, &symbolic_traits);
304 if ((symbolic_traits & kCTFontClassMaskTrait) == (CTFontStylisticClass)kCTFontSymbolicClass || (symbolic_traits & kCTFontVerticalTrait))
continue;
306 if (symbolic_traits & kCTFontBoldTrait)
continue;
308 if (((symbolic_traits & kCTFontMonoSpaceTrait) == kCTFontMonoSpaceTrait) != callback->
Monospace())
continue;
313 CFStringGetCString(font_name.get(), buffer, std::size(buffer), kCFStringEncodingUTF8);
318 if (tries == 0 && (symbolic_traits & kCTFontClassMaskTrait) != (CTFontStylisticClass)kCTFontSansSerifClass)
continue;
322 std::string_view name{buffer};
323 if (name.starts_with(
".") || name.starts_with(
"LastResort"))
continue;
328 Debug(fontcache, 2,
"CT-Font for {}: {}", language_isocode, name);
347 static CTFontDescriptorRef LoadFontFromFile(
const std::string &font_name)
357 path.reset(CFStringCreateWithCString(kCFAllocatorDefault, font_name.c_str(), kCFStringEncodingUTF8));
361 if (!full_font.empty()) {
362 path.reset(CFStringCreateWithCString(kCFAllocatorDefault, full_font.c_str(), kCFStringEncodingUTF8));
368 CFAutoRelease<CFURLRef> url(CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path.get(), kCFURLPOSIXPathStyle,
false));
371 if (descs && CFArrayGetCount(descs.get()) > 0) {
372 CTFontDescriptorRef font_ref = (CTFontDescriptorRef)CFArrayGetValueAtIndex(descs.get(), 0);
constexpr Timpl & Set()
Set all bits.
static Blitter * GetCurrentBlitter()
Get the current active blitter (always set by calling SelectBlitter).
std::unique_ptr< FontCache > LoadFont(FontSize fs, FontType fonttype) override
Loads the TrueType font.
CFAutoRelease< CTFontDescriptorRef > font_desc
Font descriptor excluding font size.
std::string font_name
Cached font name.
CFAutoRelease< CTFontRef > font
CoreText font handle.
void ClearFontCache() override
Reset cached glyphs.
GlyphID MapCharToGlyph(char32_t key, bool allow_fallback=true) override
Map a character into a glyph.
int height
The height of the font.
std::unique_ptr< FontCache > parent
The parent of this font cache.
const FontSize fs
The size of the font.
int descender
The descender value of the font.
int ascender
The ascender value of the font.
A searcher for missing glyphs.
bool FindMissingGlyphs()
Check whether there are glyphs missing in the current language.
virtual void SetFontNames(struct FontCacheSettings *settings, std::string_view font_name, const void *os_data=nullptr)=0
Set the right font names.
virtual bool Monospace()=0
Whether to search for a monospace font or not.
virtual Sprite * Encode(SpriteType sprite_type, const SpriteLoader::SpriteCollection &sprite, SpriteAllocator &allocator)=0
Convert a sprite from the loader to our own format.
Font cache for fonts that are based on a TrueType font.
static constexpr int MAX_GLYPH_DIM
Maximum glyph dimensions.
int used_size
Used font size.
int req_size
Requested font size.
void ClearFontCache() override
Reset cached glyphs.
static constexpr uint MAX_FONT_MIN_REC_SIZE
Upper limit for the recommended font size in case a font file contains nonsensical values.
SpriteAllocator that allocates memory via a unique_ptr array.
#define Debug(category, level, format_string,...)
Output a line of debugging information.
bool FileExists(std::string_view filename)
Test whether the given filename exists.
std::string FioFindFullPath(Subdirectory subdir, std::string_view filename)
Find a path to the filename in one of the search directories.
@ BASE_DIR
Base directory for all subdirectories.
fluid_settings_t * settings
FluidSynth settings handle.
Functions related to font handling on MacOS.
uint GetFontCacheFontSize(FontSize fs)
Get the scalable font size to use for a FontSize.
std::string GetFontCacheFontName(FontSize fs)
Get font to use for a given font size.
FontType
Different types of font that can be loaded.
@ TrueType
Scalable TrueType fonts.
FontCacheSubSetting * GetFontCacheSubSetting(FontSize fs)
Get the settings of a given font size.
uint32_t GlyphID
Glyphs are characters from a font.
@ Font
A sprite used for fonts.
FontSize
Available font sizes.
@ FS_SMALL
Index of the small font in the font tables.
@ FS_NORMAL
Index of the normal font in the font tables.
Functions related to MacOS support.
std::unique_ptr< typename std::remove_pointer< T >::type, CFDeleter< typename std::remove_pointer< T >::type > > CFAutoRelease
Specialisation of std::unique_ptr for CoreFoundation objects.
bool MacOSVersionIsAtLeast(long major, long minor, long bugfix)
Check if we are at least running on the specified version of Mac OS.
constexpr T Align(const T x, uint n)
Return the smallest multiple of n equal or greater than x.
@ Palette
Sprite has palette data.
#define lengthof(array)
Return the length of an fixed size array.
Settings for the four different fonts.
Settings for a single font.
Structure for passing information from the sprite loader to the blitter.
SpriteComponents colours
The colour components of the sprite with useful information.
void AllocateData(ZoomLevel zoom, size_t size)
Allocate the sprite data of this sprite.
uint16_t width
Width of the sprite.
int16_t x_offs
The x-offset of where the sprite will be drawn.
SpriteLoader::CommonPixel * data
The sprite itself.
uint16_t height
Height of the sprite.
int16_t y_offs
The y-offset of where the sprite will be drawn.
Data structure describing a sprite.
std::byte data[]
Sprite data.
static const int MAX_FONT_SIZE
Maximum font size.