1/* 2 * Copyright 2017 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "SkFontMgr_custom.h" 9#include "SkFontMgr_directory.h" 10#include "SkOSFile.h" 11#include "SkOSPath.h" 12#include "SkStream.h" 13 14class DirectorySystemFontLoader : public SkFontMgr_Custom::SystemFontLoader { 15public: 16 DirectorySystemFontLoader(const char* dir) : fBaseDirectory(dir) { } 17 18 void loadSystemFonts(const SkTypeface_FreeType::Scanner& scanner, 19 SkFontMgr_Custom::Families* families) const override 20 { 21 load_directory_fonts(scanner, fBaseDirectory, ".ttf", families); 22 load_directory_fonts(scanner, fBaseDirectory, ".ttc", families); 23 load_directory_fonts(scanner, fBaseDirectory, ".otf", families); 24 load_directory_fonts(scanner, fBaseDirectory, ".pfb", families); 25 26 if (families->empty()) { 27 SkFontStyleSet_Custom* family = new SkFontStyleSet_Custom(SkString()); 28 families->push_back().reset(family); 29 family->appendTypeface(sk_make_sp<SkTypeface_Empty>()); 30 } 31 } 32 33private: 34 static SkFontStyleSet_Custom* find_family(SkFontMgr_Custom::Families& families, 35 const char familyName[]) 36 { 37 for (int i = 0; i < families.count(); ++i) { 38 if (families[i]->getFamilyName().equals(familyName)) { 39 return families[i].get(); 40 } 41 } 42 return nullptr; 43 } 44 45 static void load_directory_fonts(const SkTypeface_FreeType::Scanner& scanner, 46 const SkString& directory, const char* suffix, 47 SkFontMgr_Custom::Families* families) 48 { 49 SkOSFile::Iter iter(directory.c_str(), suffix); 50 SkString name; 51 52 while (iter.next(&name, false)) { 53 SkString filename(SkOSPath::Join(directory.c_str(), name.c_str())); 54 std::unique_ptr<SkStreamAsset> stream = SkStream::MakeFromFile(filename.c_str()); 55 if (!stream) { 56 SkDebugf("---- failed to open <%s>\n", filename.c_str()); 57 continue; 58 } 59 60 int numFaces; 61 if (!scanner.recognizedFont(stream.get(), &numFaces)) { 62 SkDebugf("---- failed to open <%s> as a font\n", filename.c_str()); 63 continue; 64 } 65 66 for (int faceIndex = 0; faceIndex < numFaces; ++faceIndex) { 67 bool isFixedPitch; 68 SkString realname; 69 SkFontStyle style = SkFontStyle(); // avoid uninitialized warning 70 if (!scanner.scanFont(stream.get(), faceIndex, 71 &realname, &style, &isFixedPitch, nullptr)) 72 { 73 SkDebugf("---- failed to open <%s> <%d> as a font\n", 74 filename.c_str(), faceIndex); 75 continue; 76 } 77 78 SkFontStyleSet_Custom* addTo = find_family(*families, realname.c_str()); 79 if (nullptr == addTo) { 80 addTo = new SkFontStyleSet_Custom(realname); 81 families->push_back().reset(addTo); 82 } 83 addTo->appendTypeface(sk_make_sp<SkTypeface_File>(style, isFixedPitch, true, 84 realname, filename.c_str(), 85 faceIndex)); 86 } 87 } 88 89 SkOSFile::Iter dirIter(directory.c_str()); 90 while (dirIter.next(&name, true)) { 91 if (name.startsWith(".")) { 92 continue; 93 } 94 SkString dirname(SkOSPath::Join(directory.c_str(), name.c_str())); 95 load_directory_fonts(scanner, dirname, suffix, families); 96 } 97 } 98 99 SkString fBaseDirectory; 100}; 101 102SK_API sk_sp<SkFontMgr> SkFontMgr_New_Custom_Directory(const char* dir) { 103 return sk_make_sp<SkFontMgr_Custom>(DirectorySystemFontLoader(dir)); 104} 105