diff --git a/src/Makefile b/src/Makefile index 08f921681..4b1165313 100644 --- a/src/Makefile +++ b/src/Makefile @@ -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 ############### diff --git a/src/font_file_lister.h b/src/font_file_lister.h index 2af4c5a54..9c7cd51ad 100644 --- a/src/font_file_lister.h +++ b/src/font_file_lister.h @@ -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 const& characters); +}; + +using FontFileLister = CoreTextFontFileLister; + #else + typedef struct _FcConfig FcConfig; typedef struct _FcFontSet FcFontSet; diff --git a/src/font_file_lister_coretext.mm b/src/font_file_lister_coretext.mm new file mode 100644 index 000000000..dbe6589d2 --- /dev/null +++ b/src/font_file_lister_coretext.mm @@ -0,0 +1,94 @@ +// Copyright (c) 2016, Thomas Goyne +// +// 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 +#include + +namespace { +void process_font(CollectionResult& ret, NSFontDescriptor *font, int bold, bool italic, + std::vector 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 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; +}