• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "font_parser.h"
17 
18 #include <codecvt>
19 #include <dirent.h>
20 #include <map>
21 #include <list>
22 #include <algorithm>
23 #include <iostream>
24 #include <iomanip>
25 #include <securec.h>
26 #ifdef BUILD_NON_SDK_VER
27 #include <iconv.h>
28 #endif
29 
30 #include "font_config.h"
31 #include "utils/text_log.h"
32 
33 namespace OHOS {
34 namespace Rosen {
35 namespace TextEngine {
36 #define FONT_CONFIG_FILE  "/system/fonts/visibility_list.json"
37 #define FONT_CONFIG_PROD_FILE "/sys_prod/fonts/visibility_list.json"
38 #define SYSTEM_FONT_PATH "/system/fonts/"
39 #define SYS_PROD_FONT_PATH "/sys_prod/fonts/"
40 
HB_TAG(uint32_t c1,uint32_t c2,uint32_t c3,uint32_t c4)41 constexpr uint32_t HB_TAG(uint32_t c1, uint32_t c2, uint32_t c3, uint32_t c4)
42 {
43     // 24 means 32-24 bit, 16 means 24-16 bit, 8 means 16-8 bit, 0 means 8-0 bit, 0xFF means only 8 bit
44     return ((c1 & 0xFF) << 24) | ((c2 & 0xFF) << 16) | ((c3 & 0xFF) << 8) | (c4 & 0xFF);
45 }
46 
FontParser()47 FontParser::FontParser()
48 {
49     data_ = nullptr;
50     length_ = 0;
51         fontSet_.clear();
52     FontConfig fontConfig(FONT_CONFIG_FILE);
53     auto fonts = fontConfig.GetFontSet();
54     fontSet_.insert(fontSet_.end(), fonts.begin(), fonts.end());
55     FontConfig fontProdConfig(FONT_CONFIG_PROD_FILE);
56     auto prodFonts = fontProdConfig.GetFontSet();
57     fontSet_.insert(fontSet_.end(), prodFonts.begin(), prodFonts.end());
58 }
59 
ProcessTable(const CmapTables * cmapTable,FontParser::FontDescriptor & fontDescriptor)60 void FontParser::ProcessTable(const CmapTables* cmapTable, FontParser::FontDescriptor& fontDescriptor)
61 {
62     for (auto i = 0; i < cmapTable->numTables.Get(); ++i) {
63         const auto& record = cmapTable->encodingRecords[i];
64         FontParser::PlatformId platformId = static_cast<FontParser::PlatformId>(record.platformID.Get());
65         FontParser::EncodingIdWin encodingId = static_cast<FontParser::EncodingIdWin>(record.encodingID.Get());
66         if (platformId == FontParser::PlatformId::WINDOWS && encodingId == FontParser::EncodingIdWin::SYMBOL) {
67             fontDescriptor.symbolic = true;
68             break;
69         }
70     }
71 }
72 
GetStringFromNameId(FontParser::NameId nameId,unsigned int languageId,const std::string & nameString,FontParser::FontDescriptor & fontDescriptor)73 void FontParser::GetStringFromNameId(FontParser::NameId nameId, unsigned int languageId, const std::string& nameString,
74     FontParser::FontDescriptor& fontDescriptor)
75 {
76     switch (nameId) {
77         case FontParser::NameId::FONT_FAMILY: {
78             SetNameString(fontDescriptor, fontDescriptor.fontFamily, fontDescriptor.fontFamilyLid,
79                 languageId, nameString);
80             break;
81         }
82         case FontParser::NameId::FONT_SUBFAMILY: {
83             SetNameString(fontDescriptor, fontDescriptor.fontSubfamily, fontDescriptor.fontSubfamilyLid,
84                 languageId, nameString);
85             break;
86         }
87         case FontParser::NameId::FULL_NAME: {
88             if (!fontDescriptor.requestedFullname.empty() &&
89                 fontDescriptor.fullName == fontDescriptor.requestedFullname) {
90                 break;
91             }
92 
93             SetNameString(fontDescriptor, fontDescriptor.fullName, fontDescriptor.fullNameLid,
94                 languageId, nameString);
95             break;
96         }
97         case FontParser::NameId::POSTSCRIPT_NAME: {
98             SetNameString(fontDescriptor, fontDescriptor.postScriptName, fontDescriptor.postScriptNameLid,
99                 languageId, nameString);
100             break;
101         }
102         default: {
103             break;
104         }
105     }
106 }
107 
SetNameString(FontParser::FontDescriptor & fontDescriptor,std::string & field,unsigned int & fieldLid,unsigned int languageId,const std::string & nameString)108 void FontParser::SetNameString(FontParser::FontDescriptor& fontDescriptor, std::string& field, unsigned int& fieldLid,
109     unsigned int languageId, const std::string& nameString)
110 {
111     bool willSet = field.empty();
112     if (!willSet) {
113         willSet = languageId == fontDescriptor.requestedLid ||
114             (fieldLid != fontDescriptor.requestedLid && languageId == LANGUAGE_DEFAULT);
115     }
116 
117     if (willSet) {
118         fieldLid = languageId;
119         field = nameString;
120     }
121 }
122 
ProcessTable(const NameTable * nameTable,FontParser::FontDescriptor & fontDescriptor)123 void FontParser::ProcessTable(const NameTable* nameTable, FontParser::FontDescriptor& fontDescriptor)
124 {
125     auto count = nameTable->count.Get();
126     auto storageOffset = nameTable->storageOffset.Get();
127     const char* stringStorage = reinterpret_cast<const char*>(nameTable) + storageOffset;
128     for (int i = 0; i < count; ++i) {
129         if (nameTable->nameRecord[i].stringOffset.Get() == 0 && nameTable->nameRecord[i].length.Get() == 0) {
130             continue;
131         }
132         FontParser::NameId nameId = static_cast<FontParser::NameId>(nameTable->nameRecord[i].nameId.Get());
133         // Parsing fields with NameId greater than 7 is not currently supported.
134         if (nameId > FontParser::NameId::TRADEMARK) {
135             continue;
136         }
137         unsigned int languageId = static_cast<unsigned int>(nameTable->nameRecord[i].languageId.Get());
138         FontParser::PlatformId platformId =
139             static_cast<FontParser::PlatformId>(nameTable->nameRecord[i].platformId.Get());
140         auto len = nameTable->nameRecord[i].length.Get();
141         auto stringOffset = nameTable->nameRecord[i].stringOffset.Get();
142         const char* data = stringStorage + stringOffset;
143         if (platformId == FontParser::PlatformId::MACINTOSH) {
144 #ifdef BUILD_NON_SDK_VER
145             std::string nameString = ConvertToString(std::string(data, len), "GB2312", "UTF-8");
146 #else
147             std::string nameString(data, len);
148 #endif
149             GetStringFromNameId(nameId, languageId, nameString, fontDescriptor);
150         } else if (platformId == FontParser::PlatformId::WINDOWS) {
151 #ifdef BUILD_NON_SDK_VER
152             std::string nameString = ConvertToString(std::string(data, len), "UTF-16BE", "UTF-8");
153 #else
154             std::string nameString(data, len);
155 #endif
156             GetStringFromNameId(nameId, languageId, nameString, fontDescriptor);
157         }
158     }
159 }
160 
ProcessTable(const PostTable * postTable,FontParser::FontDescriptor & fontDescriptor)161 void FontParser::ProcessTable(const PostTable* postTable, FontParser::FontDescriptor& fontDescriptor)
162 {
163     if (postTable->italicAngle.Get() != 0) {
164         fontDescriptor.italic = 1; // means support italics
165     } else {
166         fontDescriptor.italic = 0;
167     }
168     if (postTable->isFixedPitch.Get() == 1) {
169         fontDescriptor.monoSpace = true;
170     }
171 }
172 
173 template<typename T>
ParseOneTable(std::shared_ptr<Drawing::Typeface> typeface,FontParser::FontDescriptor & fontDescriptor)174 bool FontParser::ParseOneTable(std::shared_ptr<Drawing::Typeface> typeface, FontParser::FontDescriptor& fontDescriptor)
175 {
176     // get tag by a four bytes string
177     uint32_t tag = HB_TAG(T::tag[0], T::tag[1], T::tag[2], T::tag[3]);
178     auto size = typeface->GetTableSize(tag);
179     if (size < sizeof(T)) {
180         TEXT_LOGE("No table");
181         return false;
182     }
183     std::unique_ptr<char[]> tableData = std::make_unique<char[]>(size);
184     auto readSize = typeface->GetTableData(tag, 0, size, tableData.get());
185     if (size != readSize) {
186         TEXT_LOGE("Failed to get table, size %{public}zu, ret %{public}zu", size, readSize);
187         return false;
188     }
189     ProcessTable(reinterpret_cast<T*>(tableData.get()), fontDescriptor);
190     return true;
191 }
192 
193 using TableTypes = std::tuple<CmapTables, NameTable, PostTable>;
194 
195 template<typename Tuple, size_t... Is>
ParseAllTables(std::shared_ptr<Drawing::Typeface> typeface,FontParser::FontDescriptor & fontDescriptor,std::index_sequence<Is...>)196 bool FontParser::ParseAllTables(
197     std::shared_ptr<Drawing::Typeface> typeface, FontParser::FontDescriptor& fontDescriptor, std::index_sequence<Is...>)
198 {
199     return (ParseOneTable<std::tuple_element_t<Is, Tuple>>(typeface, fontDescriptor) && ...);
200 }
201 
ParseTable(std::shared_ptr<Drawing::Typeface> typeface,FontParser::FontDescriptor & fontDescriptor)202 bool FontParser::ParseTable(std::shared_ptr<Drawing::Typeface> typeface, FontParser::FontDescriptor& fontDescriptor)
203 {
204     return ParseAllTables<TableTypes>(
205         typeface, fontDescriptor, std::make_index_sequence<std::tuple_size_v<TableTypes>>());
206 }
207 
SetFontDescriptor(const unsigned int languageId)208 bool FontParser::SetFontDescriptor(const unsigned int languageId)
209 {
210         visibilityFonts_.clear();
211     std::list<std::string> fontSetCache;
212     for (unsigned int i = 0; i < fontSet_.size(); ++i) {
213         FontParser::FontDescriptor fontDescriptor;
214         fontDescriptor.requestedLid = languageId;
215         fontDescriptor.path = fontSet_[i];
216         const char* path = fontSet_[i].c_str();
217         auto typeface = Drawing::Typeface::MakeFromFile(path);
218         if (typeface == nullptr) {
219             TEXT_LOGE("Failed to parse file %{public}s", fontDescriptor.path.c_str());
220             continue;
221         }
222         auto fontStyle = typeface->GetFontStyle();
223         fontDescriptor.weight = fontStyle.GetWeight();
224         fontDescriptor.width = fontStyle.GetWidth();
225         if (!ParseTable(typeface, fontDescriptor)) {
226             TEXT_LOGE("Failed to parse table");
227             return false;
228         }
229         size_t idx = fontSet_[i].rfind('/');
230         std::string fontName = fontSet_[i].substr(idx + 1, fontSet_[i].size() - idx - 1);
231         if (std::find(fontSetCache.begin(), fontSetCache.end(), fontName) == fontSetCache.end()) {
232             fontSetCache.push_back(fontName);
233             visibilityFonts_.emplace_back(fontDescriptor);
234         }
235     }
236 
237     return true;
238 }
239 
240 #ifdef BUILD_NON_SDK_VER
ConvertToString(const std::string & src,const std::string & srcType,const std::string & targetType)241 std::string FontParser::ConvertToString(const std::string& src, const std::string& srcType,
242     const std::string& targetType)
243 {
244     std::string utf8Str;
245     iconv_t conv = iconv_open(targetType.c_str(), srcType.c_str());
246     if (conv == (iconv_t)-1) {
247         return utf8Str;
248     }
249     char* inBuf = const_cast<char*>(src.c_str());
250     size_t inBytesLeft = src.length();
251     size_t outBytesLeft = inBytesLeft * 2;
252     char* outBuf = new char[outBytesLeft];
253     char* outBufStart = outBuf;
254     size_t res = iconv(conv, &inBuf, &inBytesLeft, &outBuf, &outBytesLeft);
255     if (res != (size_t)-1) {
256         utf8Str.assign(outBufStart, outBuf - outBufStart);
257     }
258     delete[] outBufStart;
259     iconv_close(conv);
260     return utf8Str;
261 }
262 #endif
263 
GetVisibilityFonts(const std::string & locale)264 std::vector<FontParser::FontDescriptor> FontParser::GetVisibilityFonts(const std::string &locale)
265 {
266     if (!SetFontDescriptor(GetLanguageId(locale))) {
267         TEXT_LOGE("Failed to set visibility font descriptor");
268     }
269 
270     return visibilityFonts_;
271 }
272 
273 class SystemFont {
274 public:
SystemFont(const char * fPath=SYSTEM_FONT_PATH)275     explicit SystemFont(const char* fPath = SYSTEM_FONT_PATH)
276     {
277         ParseConfig(fPath);
278     }
279 
280     ~SystemFont() = default;
281 
GetSystemFontSet() const282     std::shared_ptr<std::vector<std::string>> GetSystemFontSet() const
283     {
284         return systemFontSet_;
285     }
286 
287 private:
ParseConfig(const char * fPath)288     void ParseConfig(const char* fPath)
289     {
290         if (fPath == nullptr) {
291             return;
292         }
293         systemFontSet_ = std::make_shared<std::vector<std::string>>();
294         DIR *dir = opendir(fPath);
295         if (dir == nullptr) {
296             return;
297         }
298         struct dirent *entry;
299         while ((entry = readdir(dir)) != nullptr) {
300             if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
301                 continue;
302             }
303             std::string tmp = entry->d_name;
304             systemFontSet_->push_back(SYSTEM_FONT_PATH + tmp);
305         }
306         closedir(dir);
307     }
308 
309     std::shared_ptr<std::vector<std::string>> systemFontSet_;
310 };
311 
GetSystemFonts(const std::string locale)312 std::vector<std::shared_ptr<FontParser::FontDescriptor>> FontParser::GetSystemFonts(const std::string locale)
313 {
314     std::vector<std::shared_ptr<Drawing::Typeface>> typefaces = Drawing::Typeface::GetSystemFonts();
315     return CreateFontDescriptors(typefaces, locale);
316 }
317 
ParserFontDescriptorsFromPath(const std::string & path,const std::string & locale)318 std::vector<std::shared_ptr<FontParser::FontDescriptor>> FontParser::ParserFontDescriptorsFromPath(
319     const std::string& path, const std::string& locale)
320 {
321     std::vector<std::shared_ptr<Drawing::Typeface>> typefaces;
322     int index = 0;
323     std::shared_ptr<Drawing::Typeface> typeface = nullptr;
324     while ((typeface = Drawing::Typeface::MakeFromFile(path.c_str(), index)) != nullptr) {
325         typefaces.push_back(typeface);
326         index++;
327     }
328     return CreateFontDescriptors(typefaces, locale);
329 }
330 
CreateFontDescriptors(const std::vector<std::shared_ptr<Drawing::Typeface>> & typefaces,const std::string & locale)331 std::vector<std::shared_ptr<FontParser::FontDescriptor>> FontParser::CreateFontDescriptors(
332     const std::vector<std::shared_ptr<Drawing::Typeface>>& typefaces, const std::string& locale)
333 {
334     if (typefaces.empty()) {
335         return {};
336     }
337 
338     std::vector<std::shared_ptr<FontDescriptor>> descriptors;
339     descriptors.reserve(typefaces.size());
340     unsigned int languageId = static_cast<unsigned int>(GetLanguageId(locale));
341     for (auto& item : typefaces) {
342         FontDescriptor desc;
343         desc.requestedLid = languageId;
344         desc.path = item->GetFontPath();
345         auto fontStyle = item->GetFontStyle();
346         desc.weight = fontStyle.GetWeight();
347         desc.width = fontStyle.GetWidth();
348         if (!ParseTable(item, desc)) {
349             continue;
350         }
351         descriptors.emplace_back(std::make_shared<FontDescriptor>(desc));
352     }
353     return descriptors;
354 }
355 
ParseFontDescriptor(const std::string & fontName,const unsigned int languageId)356 std::unique_ptr<FontParser::FontDescriptor> FontParser::ParseFontDescriptor(const std::string& fontName,
357     const unsigned int languageId)
358 {
359     FontConfigJson fontConfigJson;
360     fontConfigJson.ParseFontFileMap();
361     std::shared_ptr<FontFileMap> fontFileMap = fontConfigJson.GetFontFileMap();
362     if (fontFileMap == nullptr || (*fontFileMap).empty()) {
363         TEXT_LOGE("Empty font file map");
364         return nullptr;
365     }
366     if ((*fontFileMap).find(fontName) == (*fontFileMap).end()) {
367         TEXT_LOGE("Failed to find font name %{pubic}s", fontName.c_str());
368         return nullptr;
369     }
370     std::string path = SYSTEM_FONT_PATH + (*fontFileMap)[fontName];
371         auto typeface = Drawing::Typeface::MakeFromFile(path.c_str());
372     if (typeface == nullptr) {
373         path = SYS_PROD_FONT_PATH + (*fontFileMap)[fontName];
374         typeface = Drawing::Typeface::MakeFromFile(path.c_str());
375         if (typeface == nullptr) {
376             TEXT_LOGE("Failed to parse %{public}s", path.c_str());
377             return nullptr;
378         }
379     }
380 
381     FontParser::FontDescriptor fontDescriptor;
382     fontDescriptor.requestedLid = languageId;
383     fontDescriptor.path = path;
384 
385     fontDescriptor.requestedFullname = fontName;
386     auto fontStyle = typeface->GetFontStyle();
387     fontDescriptor.weight = fontStyle.GetWeight();
388     fontDescriptor.width = fontStyle.GetWidth();
389 
390     if (!ParseTable(typeface, fontDescriptor)) {
391         TEXT_LOGE("Failed to parse table");
392         return nullptr;
393     }
394     if (fontDescriptor.fullName == fontName) {
395         return std::make_unique<FontDescriptor>(fontDescriptor);
396     }
397     return nullptr;
398 }
399 
GetVisibilityFontByName(const std::string & fontName,const std::string locale)400 std::unique_ptr<FontParser::FontDescriptor> FontParser::GetVisibilityFontByName(const std::string& fontName,
401     const std::string locale)
402 {
403     return ParseFontDescriptor(fontName, GetLanguageId(locale));
404 }
405 } // namespace TextEngine
406 } // namespace Rosen
407 } // namespace OHOS
408