Add a basic CoreText-based fonts collector backend

This commit is contained in:
Thomas Goyne 2015-10-28 12:44:22 -07:00
parent f8c3504898
commit 973f0b09fc
3 changed files with 115 additions and 1 deletions

View file

@ -59,7 +59,6 @@ src_OBJ := \
$(d)export_framerate.o \
$(d)fft.o \
$(d)font_file_lister.o \
$(d)font_file_lister_fontconfig.o \
$(d)frame_main.o \
$(d)gl_text.o \
$(d)gl_wrap.o \
@ -119,7 +118,10 @@ src_OBJ := \
$(TOP)lib/libuniversalchardet.a \
ifeq (yes, $(BUILD_DARWIN))
src_OBJ += $(d)font_file_lister_coretext.o
src_OBJ += $(subst .mm,.o,$(wildcard $(d)osx/*.mm))
else
src_OBJ += $(d)font_file_lister_fontconfig.o
endif
###############

View file

@ -63,7 +63,25 @@ public:
};
using FontFileLister = GdiFontFileLister;
#elif defined(__APPLE__)
struct CoreTextFontFileLister {
CoreTextFontFileLister(FontCollectorStatusCallback &) {}
/// @brief Get the path to the font with the given styles
/// @param facename Name of font face
/// @param bold ASS font weight
/// @param italic Italic?
/// @param characters Characters in this style
/// @return Path to the matching font file(s), or empty if not found
CollectionResult GetFontPaths(std::string const& facename, int bold, bool italic, std::vector<int> const& characters);
};
using FontFileLister = CoreTextFontFileLister;
#else
typedef struct _FcConfig FcConfig;
typedef struct _FcFontSet FcFontSet;

View file

@ -0,0 +1,94 @@
// Copyright (c) 2016, Thomas Goyne <plorkyeran@aegisub.org>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
//
// Aegisub Project http://www.aegisub.org/
#include "font_file_lister.h"
#include <AppKit/AppKit.h>
#include <CoreText/CoreText.h>
namespace {
void process_font(CollectionResult& ret, NSFontDescriptor *font, int bold, bool italic,
std::vector<int> const& characters) {
// For whatever reason there is no NSFontURLAttribute
NSURL *url = [font objectForKey:(__bridge NSString *)kCTFontURLAttribute];
if (!url)
return;
NSDictionary *attributes = [font objectForKey:NSFontTraitsAttribute];
double weight = [attributes[NSFontWeightTrait] doubleValue];
double slant = [attributes[NSFontSlantTrait] doubleValue];
if (italic != (slant > 0.03))
return;
if (bold == 0 && weight > 0)
return;
if (bold == 1 && weight < 0.4)
return;
NSCharacterSet *codepoints = [font objectForKey:NSFontCharacterSetAttribute];
for (int chr : characters) {
if (![codepoints longCharacterIsMember:chr]) {
ret.missing += chr;
}
}
ret.paths.push_back(url.absoluteString.UTF8String);
}
}
CollectionResult CoreTextFontFileLister::GetFontPaths(std::string const& facename,
int bold, bool italic,
std::vector<int> const& characters) {
CollectionResult ret;
@autoreleasepool {
NSString *name = @(facename.c_str() + (facename[0] == '@'));
NSArray *attrs = @[
[NSFontDescriptor fontDescriptorWithFontAttributes:@{NSFontFamilyAttribute: name}],
[NSFontDescriptor fontDescriptorWithFontAttributes:@{NSFontFaceAttribute: name}],
[NSFontDescriptor fontDescriptorWithFontAttributes:@{NSFontNameAttribute: name}]
];
auto font_collection = [NSFontCollection fontCollectionWithDescriptors:attrs];
for (NSFontDescriptor *desc in font_collection.matchingDescriptors) {
process_font(ret, desc, bold, italic, characters);
// If we didn't get any results, check for non-bold/italic variants
// and collect them with a warning
if (ret.paths.empty() && bold) {
process_font(ret, desc, 0, italic, characters);
if (!ret.paths.empty())
ret.fake_bold = true;
}
if (ret.paths.empty() && italic) {
process_font(ret, desc, bold, false, characters);
if (!ret.paths.empty())
ret.fake_italic = true;
}
if (ret.paths.empty() && bold && italic) {
process_font(ret, desc, 0, false, characters);
if (!ret.paths.empty()) {
ret.fake_bold = true;
ret.fake_italic = true;
}
}
}
}
return ret;
}