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 "include/core/SkStream.h"
9 #include "src/core/SkFontDescriptor.h"
10 #include "src/core/SkMakeUnique.h"
11 #include "src/ports/SkFontMgr_custom.h"
12 
13 struct SkEmbeddedResource { const uint8_t* data; size_t size; };
14 struct SkEmbeddedResourceHeader { const SkEmbeddedResource* entries; int count; };
15 
16 static void load_font_from_data(const SkTypeface_FreeType::Scanner& scanner,
17                                 const uint8_t* data, size_t size, int index,
18                                 SkFontMgr_Custom::Families* families);
19 
20 class EmbeddedSystemFontLoader : public SkFontMgr_Custom::SystemFontLoader {
21 public:
EmbeddedSystemFontLoader(const SkEmbeddedResourceHeader * header)22     EmbeddedSystemFontLoader(const SkEmbeddedResourceHeader* header) : fHeader(header) { }
23 
loadSystemFonts(const SkTypeface_FreeType::Scanner & scanner,SkFontMgr_Custom::Families * families) const24     void loadSystemFonts(const SkTypeface_FreeType::Scanner& scanner,
25                          SkFontMgr_Custom::Families* families) const override
26     {
27         for (int i = 0; i < fHeader->count; ++i) {
28             const SkEmbeddedResource& fontEntry = fHeader->entries[i];
29             load_font_from_data(scanner, fontEntry.data, fontEntry.size, i, families);
30         }
31 
32         if (families->empty()) {
33             SkFontStyleSet_Custom* family = new SkFontStyleSet_Custom(SkString());
34             families->push_back().reset(family);
35             family->appendTypeface(sk_make_sp<SkTypeface_Empty>());
36         }
37     }
38 
39     const SkEmbeddedResourceHeader* fHeader;
40 };
41 
42 class DataFontLoader : public SkFontMgr_Custom::SystemFontLoader {
43 public:
DataFontLoader(const uint8_t ** datas,const size_t * sizes,int n)44     DataFontLoader(const uint8_t** datas, const size_t* sizes, int n) : fDatas(datas), fSizes(sizes), fNum(n) { }
45 
loadSystemFonts(const SkTypeface_FreeType::Scanner & scanner,SkFontMgr_Custom::Families * families) const46     void loadSystemFonts(const SkTypeface_FreeType::Scanner& scanner,
47                          SkFontMgr_Custom::Families* families) const override
48     {
49         for (int i = 0; i < fNum; ++i) {
50             load_font_from_data(scanner, fDatas[i], fSizes[i], i, families);
51         }
52 
53         if (families->empty()) {
54             SkFontStyleSet_Custom* family = new SkFontStyleSet_Custom(SkString());
55             families->push_back().reset(family);
56             family->appendTypeface(sk_make_sp<SkTypeface_Empty>());
57         }
58     }
59 
60     const uint8_t** fDatas;
61     const size_t* fSizes;
62     const int fNum;
63 };
64 
find_family(SkFontMgr_Custom::Families & families,const char familyName[])65 static SkFontStyleSet_Custom* find_family(SkFontMgr_Custom::Families& families,
66                                           const char familyName[])
67 {
68    for (int i = 0; i < families.count(); ++i) {
69         if (families[i]->getFamilyName().equals(familyName)) {
70             return families[i].get();
71         }
72     }
73     return nullptr;
74 }
75 
load_font_from_data(const SkTypeface_FreeType::Scanner & scanner,const uint8_t * data,size_t size,int index,SkFontMgr_Custom::Families * families)76 static void load_font_from_data(const SkTypeface_FreeType::Scanner& scanner,
77                                 const uint8_t* data, size_t size, int index,
78                                 SkFontMgr_Custom::Families* families)
79 {
80     auto stream = skstd::make_unique<SkMemoryStream>(data, size, false);
81 
82     int numFaces;
83     if (!scanner.recognizedFont(stream.get(), &numFaces)) {
84         SkDebugf("---- failed to open <%d> as a font\n", index);
85         return;
86     }
87 
88     for (int faceIndex = 0; faceIndex < numFaces; ++faceIndex) {
89         bool isFixedPitch;
90         SkString realname;
91         SkFontStyle style = SkFontStyle(); // avoid uninitialized warning
92         if (!scanner.scanFont(stream.get(), faceIndex,
93                               &realname, &style, &isFixedPitch, nullptr))
94         {
95             SkDebugf("---- failed to open <%d> <%d> as a font\n", index, faceIndex);
96             return;
97         }
98 
99         SkFontStyleSet_Custom* addTo = find_family(*families, realname.c_str());
100         if (nullptr == addTo) {
101             addTo = new SkFontStyleSet_Custom(realname);
102             families->push_back().reset(addTo);
103         }
104         auto data = skstd::make_unique<SkFontData>(std::move(stream), faceIndex, nullptr, 0);
105         addTo->appendTypeface(sk_make_sp<SkTypeface_Stream>(std::move(data),
106                                                             style, isFixedPitch,
107                                                             true, realname));
108     }
109 }
110 
SkFontMgr_New_Custom_Embedded(const SkEmbeddedResourceHeader * header)111 sk_sp<SkFontMgr> SkFontMgr_New_Custom_Embedded(const SkEmbeddedResourceHeader* header) {
112     return sk_make_sp<SkFontMgr_Custom>(EmbeddedSystemFontLoader(header));
113 }
114 
115 // SkFontMgr_New_Custom_Data expects to be called with the data for n font files. datas and sizes
116 // are parallel arrays of bytes and byte lengths.
SkFontMgr_New_Custom_Data(const uint8_t ** datas,const size_t * sizes,int n)117 sk_sp<SkFontMgr> SkFontMgr_New_Custom_Data(const uint8_t** datas, const size_t* sizes, int n) {
118     SkASSERT(datas != nullptr);
119     SkASSERT(sizes != nullptr);
120     SkASSERT(n > 0);
121     return sk_make_sp<SkFontMgr_Custom>(DataFontLoader(datas, sizes, n));
122 }
123