10 #include "../../stdafx.h"
11 #include "../../debug.h"
13 #include "../../blitter/factory.hpp"
14 #include "../../fileio_func.h"
15 #include "../../fontdetection.h"
16 #include "../../string_func.h"
17 #include "../../strings_func.h"
18 #include "../../zoom_func.h"
22 #include "../../table/control_codes.h"
30 #include FT_FREETYPE_H
32 extern FT_Library _library;
37 FT_Error err = FT_Err_Cannot_Open_Resource;
40 UInt8 file_path[PATH_MAX];
49 CFAutoRelease<CFSetRef> mandatory_attribs(CFSetCreate(kCFAllocatorDefault,
const_cast<const void **
>(
reinterpret_cast<const void *
const *
>(&kCTFontNameAttribute)), 1, &kCFTypeSetCallBacks));
53 for (CFIndex i = 0; descs.get() !=
nullptr && i < CFArrayGetCount(descs.get()) && os_err != noErr; i++) {
54 CFAutoRelease<CTFontRef> font(CTFontCreateWithFontDescriptor((CTFontDescriptorRef)CFArrayGetValueAtIndex(descs.get(), i), 0.0,
nullptr));
56 if (CFURLGetFileSystemRepresentation(fontURL.get(),
true, file_path,
lengthof(file_path))) os_err = noErr;
59 if (os_err == noErr) {
60 DEBUG(freetype, 3,
"Font path for %s: %s", font_name, file_path);
61 err = FT_New_Face(_library, (
const char *)file_path, 0, face);
75 if (strcmp(language_isocode,
"zh_TW") == 0) {
78 }
else if (strcmp(language_isocode,
"zh_CN") == 0) {
84 char *sep = strchr(lang,
'_');
85 if (sep !=
nullptr) *sep =
'\0';
90 CFStringRef lang_codes[2];
91 lang_codes[0] = CFStringCreateWithCString(kCFAllocatorDefault, lang, kCFStringEncodingUTF8);
92 lang_codes[1] = CFSTR(
"en");
93 CFArrayRef lang_arr = CFArrayCreate(kCFAllocatorDefault, (
const void **)lang_codes,
lengthof(lang_codes), &kCFTypeArrayCallBacks);
94 CFAutoRelease<CFDictionaryRef> lang_attribs(CFDictionaryCreate(kCFAllocatorDefault,
const_cast<const void **
>(
reinterpret_cast<const void *
const *
>(&kCTFontLanguagesAttribute)), (
const void **)&lang_arr, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
97 CFRelease(lang_codes[0]);
100 CFAutoRelease<CFSetRef> mandatory_attribs(CFSetCreate(kCFAllocatorDefault,
const_cast<const void **
>(
reinterpret_cast<const void *
const *
>(&kCTFontLanguagesAttribute)), 1, &kCFTypeSetCallBacks));
101 CFAutoRelease<CFArrayRef> descs(CTFontDescriptorCreateMatchingFontDescriptors(lang_desc.get(), mandatory_attribs.get()));
104 for (
int tries = 0; tries < 2; tries++) {
105 for (CFIndex i = 0; descs.get() !=
nullptr && i < CFArrayGetCount(descs.get()); i++) {
106 CTFontDescriptorRef font = (CTFontDescriptorRef)CFArrayGetValueAtIndex(descs.get(), i);
110 CTFontSymbolicTraits symbolic_traits;
111 CFNumberGetValue((CFNumberRef)CFDictionaryGetValue(traits.get(), kCTFontSymbolicTrait), kCFNumberIntType, &symbolic_traits);
114 if ((symbolic_traits & kCTFontClassMaskTrait) == (CTFontStylisticClass)kCTFontSymbolicClass || (symbolic_traits & kCTFontVerticalTrait))
continue;
116 if (symbolic_traits & kCTFontBoldTrait)
continue;
118 if (((symbolic_traits & kCTFontMonoSpaceTrait) == kCTFontMonoSpaceTrait) != callback->
Monospace())
continue;
123 CFStringGetCString(font_name.get(), name,
lengthof(name), kCFStringEncodingUTF8);
128 if (tries == 0 && (symbolic_traits & kCTFontClassMaskTrait) != (CTFontStylisticClass)kCTFontSansSerifClass)
continue;
132 if (name[0] ==
'.' || strncmp(name,
"LastResort", 10) == 0)
continue;
137 DEBUG(freetype, 2,
"CT-Font for %s: %s", language_isocode, name);
158 this->SetFontSize(pixels);
172 void CoreTextFontCache::SetFontSize(
int pixels)
176 int scaled_height =
ScaleFontTrad(this->GetDefaultFontHeight(this->
fs));
177 pixels = scaled_height;
181 float min_size = 0.0f;
190 uint16_t lowestRecPPEM;
191 CFDataGetBytes(data.get(), CFRangeMake(46,
sizeof(lowestRecPPEM)), (UInt8 *)&lowestRecPPEM);
192 min_size = CFSwapInt16BigToHost(lowestRecPPEM);
195 CFNumberGetValue(size.get(), kCFNumberFloatType, &min_size);
208 this->
font.reset(CTFontCreateWithFontDescriptor(this->
font_desc.get(), pixels,
nullptr));
214 this->
ascender = (int)std::ceil(CTFontGetAscent(this->
font.get()));
215 this->
descender = -(int)std::ceil(CTFontGetDescent(this->
font.get()));
221 CFStringGetCString(
font_name.get(), name,
lengthof(name), kCFStringEncodingUTF8);
224 DEBUG(freetype, 2,
"Loaded font '%s' with size %d", this->
font_name.c_str(), pixels);
229 assert(IsPrintable(key));
231 if (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END) {
237 if (key >= 0x010000U) {
238 chars[0] = (UniChar)(((key - 0x010000U) >> 10) + 0xD800);
239 chars[1] = (UniChar)(((key - 0x010000U) & 0x3FF) + 0xDC00);
241 chars[0] = (UniChar)(key & 0xFFFF);
244 CGGlyph glyph[2] = {0, 0};
245 if (CTFontGetGlyphsForCharacters(this->
font.get(), chars, glyph, key >= 0x010000U ? 2 : 1)) {
252 const void *CoreTextFontCache::InternalGetFontTable(uint32 tag,
size_t &length)
255 if (!data)
return nullptr;
257 length = CFDataGetLength(data.get());
258 auto buf = MallocT<UInt8>(length);
260 CFDataGetBytes(data.get(), CFRangeMake(0, (CFIndex)length), buf);
264 const Sprite *CoreTextFontCache::InternalGetGlyph(
GlyphID key,
bool use_aa)
267 CGGlyph glyph = (CGGlyph)key;
268 CGRect bounds = CGRectNull;
270 bounds = CTFontGetOpticalBoundsForGlyphs(this->
font.get(), &glyph,
nullptr, 1, 0);
272 bounds = CTFontGetBoundingRectsForGlyphs(this->
font.get(), kCTFontOrientationDefault, &glyph,
nullptr, 1);
274 if (CGRectIsNull(bounds))
usererror(
"Unable to render font glyph");
276 uint bb_width = (uint)std::ceil(bounds.size.width) + 1;
277 uint bb_height = (uint)std::ceil(bounds.size.height);
280 uint width = std::max(1U, bb_width + (this->
fs ==
FS_NORMAL ? 1 : 0));
290 sprite.
width = width;
292 sprite.
x_offs = (int16)std::round(CGRectGetMinX(bounds));
293 sprite.
y_offs = this->
ascender - (int16)std::ceil(CGRectGetMaxY(bounds));
295 if (bounds.size.width > 0) {
299 int pitch =
Align(bb_width, 16);
300 byte *bmp = CallocT<byte>(bb_height * pitch);
303 CGContextSetAllowsAntialiasing(context.get(), use_aa);
304 CGContextSetAllowsFontSubpixelPositioning(context.get(), use_aa);
305 CGContextSetAllowsFontSubpixelQuantization(context.get(), !use_aa);
306 CGContextSetShouldSmoothFonts(context.get(),
false);
309 CGPoint pos{offset - bounds.origin.x, offset - bounds.origin.y};
310 CTFontDrawGlyphs(this->
font.get(), &glyph, &pos, 1, context.get());
314 for (uint y = 0; y < bb_height; y++) {
315 for (uint x = 0; x < bb_width; x++) {
316 if (bmp[y * pitch + x] > 0) {
317 sprite.
data[1 + x + (1 + y) * sprite.
width].
m = SHADOW_COLOUR;
318 sprite.
data[1 + x + (1 + y) * sprite.
width].
a = use_aa ? bmp[x + y * pitch] : 0xFF;
325 for (uint y = 0; y < bb_height; y++) {
326 for (uint x = 0; x < bb_width; x++) {
327 if (bmp[y * pitch + x] > 0) {
328 sprite.
data[x + y * sprite.
width].
m = FACE_COLOUR;
329 sprite.
data[x + y * sprite.
width].
a = use_aa ? bmp[x + y * pitch] : 0xFF;
335 GlyphEntry new_glyph;
337 new_glyph.
width = (byte)std::round(CTFontGetAdvancesForGlyphs(this->
font.get(), kCTFontOrientationDefault, &glyph,
nullptr, 1));
338 this->SetGlyphPtr(key, &new_glyph);
340 return new_glyph.sprite;
351 static const char *SIZE_TO_NAME[] = {
"medium",
"small",
"large",
"mono" };
355 default: NOT_REACHED();
366 if (
settings->os_handle !=
nullptr) {
367 font_ref.reset(
static_cast<CTFontDescriptorRef
>(
const_cast<void *
>(
settings->os_handle)));
368 CFRetain(font_ref.get());
378 path.reset(CFStringCreateWithCString(kCFAllocatorDefault,
settings->font, kCFStringEncodingUTF8));
382 if (!full_font.empty()) {
383 path.reset(CFStringCreateWithCString(kCFAllocatorDefault, full_font.c_str(), kCFStringEncodingUTF8));
389 CFAutoRelease<CFURLRef> url(CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path.get(), kCFURLPOSIXPathStyle,
false));
392 if (descs && CFArrayGetCount(descs.get()) > 0) {
393 font_ref.reset((CTFontDescriptorRef)CFArrayGetValueAtIndex(descs.get(), 0));
394 CFRetain(font_ref.get());
396 ShowInfoF(
"Unable to load file '%s' for %s font, using default OS font selection instead",
settings->font, SIZE_TO_NAME[fs]);
409 CFAutoRelease<CFSetRef> mandatory_attribs(CFSetCreate(kCFAllocatorDefault,
const_cast<const void **
>(
reinterpret_cast<const void *
const *
>(&kCTFontNameAttribute)), 1, &kCFTypeSetCallBacks));
410 CFAutoRelease<CFArrayRef> descs(CTFontDescriptorCreateMatchingFontDescriptors(name_desc.get(), mandatory_attribs.get()));
413 if (descs && CFArrayGetCount(descs.get()) > 0) {
414 font_ref.reset((CTFontDescriptorRef)CFArrayGetValueAtIndex(descs.get(), 0));
415 CFRetain(font_ref.get());
420 ShowInfoF(
"Unable to use '%s' for %s font, using sprite font instead",
settings->font, SIZE_TO_NAME[fs]);