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 "texgine/utils/exlog.h"
32 
33 namespace OHOS {
34 namespace Rosen {
35 namespace TextEngine {
36 #define SUCCESSED 0
37 #define FAILED 1
38 
39 #define FONT_CONFIG_FILE  "/system/fonts/visibility_list.json"
40 #define FONT_CONFIG_PROD_FILE "/sys_prod/fonts/visibility_list.json"
41 #define SYSTEM_FONT_PATH "/system/fonts/"
42 #define SYS_PROD_FONT_PATH "/sys_prod/fonts/"
43 
44 #define HALF(a) ((a) / 2)
45 
FontParser()46 FontParser::FontParser()
47 {
48     data_ = nullptr;
49     length_ = 0;
50     fontSet_.clear();
51     FontConfig fontConfig(FONT_CONFIG_FILE);
52     auto fonts = fontConfig.GetFontSet();
53     fontSet_.insert(fontSet_.end(), fonts.begin(), fonts.end());
54     FontConfig fontProdConfig(FONT_CONFIG_PROD_FILE);
55     auto prodFonts = fontProdConfig.GetFontSet();
56     fontSet_.insert(fontSet_.end(), prodFonts.begin(), prodFonts.end());
57 }
58 
ProcessCmapTable(const struct CmapTables* cmapTable, FontParser::FontDescriptor& fontDescriptor)59 void FontParser::ProcessCmapTable(const struct CmapTables* cmapTable, FontParser::FontDescriptor& fontDescriptor)
60 {
61     for (auto i = 0; i < cmapTable->numTables.Get(); ++i) {
62         const auto& record = cmapTable->encodingRecords[i];
63         FontParser::PlatformId platformId = static_cast<FontParser::PlatformId>(record.platformID.Get());
64         FontParser::EncodingIdWin encodingId = static_cast<FontParser::EncodingIdWin>(record.encodingID.Get());
65         if (platformId == FontParser::PlatformId::WINDOWS && encodingId == FontParser::EncodingIdWin::SYMBOL) {
66             fontDescriptor.symbolic = true;
67             break;
68         }
69     }
70 }
71 
GetStringFromNameId(FontParser::NameId nameId, unsigned int languageId, const std::string& nameString, FontParser::FontDescriptor& fontDescriptor)72 void FontParser::GetStringFromNameId(FontParser::NameId nameId, unsigned int languageId, const std::string& nameString,
73     FontParser::FontDescriptor& fontDescriptor)
74 {
75     switch (nameId) {
76         case FontParser::NameId::FONT_FAMILY: {
77             SetNameString(fontDescriptor, fontDescriptor.fontFamily, fontDescriptor.fontFamilyLid,
78                 languageId, nameString);
79             break;
80         }
81         case FontParser::NameId::FONT_SUBFAMILY: {
82             SetNameString(fontDescriptor, fontDescriptor.fontSubfamily, fontDescriptor.fontSubfamilyLid,
83                 languageId, nameString);
84             break;
85         }
86         case FontParser::NameId::FULL_NAME: {
87             if (!fontDescriptor.requestedFullname.empty() &&
88                 fontDescriptor.fullName == fontDescriptor.requestedFullname) {
89                 break;
90             }
91 
92             SetNameString(fontDescriptor, fontDescriptor.fullName, fontDescriptor.fullNameLid,
93                 languageId, nameString);
94             break;
95         }
96         case FontParser::NameId::POSTSCRIPT_NAME: {
97             SetNameString(fontDescriptor, fontDescriptor.postScriptName, fontDescriptor.postScriptNameLid,
98                 languageId, nameString);
99             break;
100         }
101         default: {
102             break;
103         }
104     }
105 }
106 
SetNameString(FontParser::FontDescriptor& fontDescriptor, std::string& field, unsigned int& fieldLid, unsigned int languageId, const std::string& nameString)107 void FontParser::SetNameString(FontParser::FontDescriptor& fontDescriptor, std::string& field, unsigned int& fieldLid,
108     unsigned int languageId, const std::string& nameString)
109 {
110     bool willSet = field.empty();
111     if (!willSet) {
112         if (languageId == fontDescriptor.requestedLid) {
113             willSet = true;
114         } else if (fieldLid != fontDescriptor.requestedLid && languageId == LANGUAGE_DEFAULT) {
115             willSet = true;
116         }
117     }
118 
119     if (willSet) {
120         fieldLid = languageId;
121         field = nameString;
122     }
123 }
124 
ProcessNameTable(const struct NameTable* nameTable, FontParser::FontDescriptor& fontDescriptor) const125 int FontParser::ProcessNameTable(const struct NameTable* nameTable, FontParser::FontDescriptor& fontDescriptor) const
126 {
127     auto count = nameTable->count.Get();
128     auto storageOffset = nameTable->storageOffset.Get();
129     auto stringStorage = data_ + storageOffset;
130     for (int i = 0; i < count; ++i) {
131         if (nameTable->nameRecord[i].stringOffset.Get() == 0 && nameTable->nameRecord[i].length.Get() == 0) {
132             continue;
133         }
134         FontParser::NameId nameId = static_cast<FontParser::NameId>(nameTable->nameRecord[i].nameId.Get());
135         // Parsing fields with NameId greater than 7 is not currently supported.
136         if (nameId > FontParser::NameId::TRADEMARK) {
137             continue;
138         }
139         unsigned int languageId = static_cast<unsigned int>(nameTable->nameRecord[i].languageId.Get());
140         FontParser::PlatformId platformId =
141             static_cast<FontParser::PlatformId>(nameTable->nameRecord[i].platformId.Get());
142         auto len = nameTable->nameRecord[i].length.Get();
143         auto stringOffset = nameTable->nameRecord[i].stringOffset.Get();
144         const char* data = stringStorage + stringOffset;
145         if (platformId == FontParser::PlatformId::MACINTOSH) {
146 #ifdef BUILD_NON_SDK_VER
147             std::string nameString = ToUtf8(std::string(data, len));
148 #else
149             std::string nameString(data, len);
150 #endif
151             GetStringFromNameId(nameId, languageId, nameString, fontDescriptor);
152         } else if (platformId == FontParser::PlatformId::WINDOWS) {
153             std::wstring_convert<std::codecvt_utf16<char16_t>, char16_t> converter;
154             std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> converterUtf8;
155             const std::u16string u16str = converter.from_bytes(data, data + len);
156             std::string nameString = converterUtf8.to_bytes(u16str);
157             GetStringFromNameId(nameId, languageId, nameString, fontDescriptor);
158         }
159     }
160 
161     return SUCCESSED;
162 }
163 
ProcessPostTable(const struct PostTable* postTable, FontParser::FontDescriptor& fontDescriptor)164 void FontParser::ProcessPostTable(const struct PostTable* postTable, FontParser::FontDescriptor& fontDescriptor)
165 {
166     if (postTable->italicAngle.Get() != 0) {
167         fontDescriptor.italic = 1; // means support italics
168     } else {
169         fontDescriptor.italic = 0;
170     }
171     if (postTable->isFixedPitch.Get() == 1) {
172         fontDescriptor.monoSpace = true;
173     }
174 }
175 
ParseCmapTable(std::shared_ptr<Drawing::Typeface> typeface, FontParser::FontDescriptor& fontDescriptor)176 int FontParser::ParseCmapTable(std::shared_ptr<Drawing::Typeface> typeface, FontParser::FontDescriptor& fontDescriptor)
177 {
178     auto tag = HB_TAG('c', 'm', 'a', 'p');
179     auto size = typeface->GetTableSize(tag);
180     if (size <= 0) {
181         LOGSO_FUNC_LINE(ERROR) << "haven't cmap";
182         return FAILED;
183     }
184     std::unique_ptr<char[]> tableData = nullptr;
185     tableData = std::make_unique<char[]>(size);
186     auto retTableData = typeface->GetTableData(tag, 0, size, tableData.get());
187     if (size != retTableData) {
188         LOGSO_FUNC_LINE(ERROR) <<"get table data failed size: " << size << ", ret: " << retTableData;
189         return FAILED;
190     }
191     hb_blob_t* hblob = nullptr;
192     hblob = hb_blob_create(
193         reinterpret_cast<const char*>(tableData.get()), size, HB_MEMORY_MODE_WRITABLE, tableData.get(), nullptr);
194     if (hblob == nullptr) {
195         LOGSO_FUNC_LINE(ERROR) << "hblob is nullptr";
196         return FAILED;
197     }
198     data_ = hb_blob_get_data(hblob, nullptr);
199     length_ = hb_blob_get_length(hblob);
200     auto parseCmap = std::make_shared<CmapTableParser>(data_, length_);
201     auto cmapTable = parseCmap->Parse(data_, length_);
202     ProcessCmapTable(cmapTable, fontDescriptor);
203     hb_blob_destroy(hblob);
204     return SUCCESSED;
205 }
206 
ParseNameTable(std::shared_ptr<Drawing::Typeface> typeface, FontParser::FontDescriptor& fontDescriptor)207 int FontParser::ParseNameTable(std::shared_ptr<Drawing::Typeface> typeface, FontParser::FontDescriptor& fontDescriptor)
208 {
209     auto tag = HB_TAG('n', 'a', 'm', 'e');
210     auto size = typeface->GetTableSize(tag);
211     if (size <= 0) {
212         LOGSO_FUNC_LINE(ERROR) << "haven't name";
213         return FAILED;
214     }
215     std::unique_ptr<char[]> tableData = nullptr;
216     tableData = std::make_unique<char[]>(size);
217     auto retTableData = typeface->GetTableData(tag, 0, size, tableData.get());
218     if (size != retTableData) {
219         LOGSO_FUNC_LINE(ERROR) <<"get table data failed size: " << size << ", ret: " << retTableData;
220         return FAILED;
221     }
222     hb_blob_t* hblob = nullptr;
223     hblob = hb_blob_create(
224         reinterpret_cast<const char*>(tableData.get()), size, HB_MEMORY_MODE_WRITABLE, tableData.get(), nullptr);
225     if (hblob == nullptr) {
226         LOGSO_FUNC_LINE(ERROR) << "hblob is nullptr";
227         return FAILED;
228     }
229     data_ = hb_blob_get_data(hblob, nullptr);
230     length_ = hb_blob_get_length(hblob);
231     auto parseName = std::make_shared<NameTableParser>(data_, length_);
232     auto nameTable = parseName->Parse(data_, length_);
233     int ret = ProcessNameTable(nameTable, fontDescriptor);
234     if (ret != SUCCESSED) {
235         LOGSO_FUNC_LINE(ERROR) << "process name table failed";
236         hb_blob_destroy(hblob);
237         return FAILED;
238     }
239     hb_blob_destroy(hblob);
240     return SUCCESSED;
241 }
242 
ParsePostTable(std::shared_ptr<Drawing::Typeface> typeface, FontParser::FontDescriptor& fontDescriptor)243 int FontParser::ParsePostTable(std::shared_ptr<Drawing::Typeface> typeface, FontParser::FontDescriptor& fontDescriptor)
244 {
245     auto tag = HB_TAG('p', 'o', 's', 't');
246     auto size = typeface->GetTableSize(tag);
247     if (size <= 0) {
248         LOGSO_FUNC_LINE(ERROR) << "haven't post";
249         return FAILED;
250     }
251     std::unique_ptr<char[]> tableData = nullptr;
252     tableData = std::make_unique<char[]>(size);
253     auto retTableData = typeface->GetTableData(tag, 0, size, tableData.get());
254     if (size != retTableData) {
255         LOGSO_FUNC_LINE(ERROR) <<"get table data failed size: " << size << ", ret: " << retTableData;
256         return FAILED;
257     }
258     hb_blob_t* hblob = nullptr;
259     hblob = hb_blob_create(
260         reinterpret_cast<const char*>(tableData.get()), size, HB_MEMORY_MODE_WRITABLE, tableData.get(), nullptr);
261     if (hblob == nullptr) {
262         LOGSO_FUNC_LINE(ERROR) << "hblob is nullptr";
263         return FAILED;
264     }
265     data_ = hb_blob_get_data(hblob, nullptr);
266     length_ = hb_blob_get_length(hblob);
267     auto parsePost = std::make_shared<PostTableParser>(data_, length_);
268     auto postTable = parsePost->Parse(data_, length_);
269     ProcessPostTable(postTable, fontDescriptor);
270     hb_blob_destroy(hblob);
271     return SUCCESSED;
272 }
273 
ParseTable(std::shared_ptr<Drawing::Typeface> typeface, FontParser::FontDescriptor& fontDescriptor)274 int FontParser::ParseTable(std::shared_ptr<Drawing::Typeface> typeface, FontParser::FontDescriptor& fontDescriptor)
275 {
276     if (ParseCmapTable(typeface, fontDescriptor) != SUCCESSED) {
277         LOGSO_FUNC_LINE(ERROR) << "parse cmap failed";
278         return FAILED;
279     }
280     if (ParseNameTable(typeface, fontDescriptor) != SUCCESSED) {
281         LOGSO_FUNC_LINE(ERROR) << "parse name failed";
282         return FAILED;
283     }
284     if (ParsePostTable(typeface, fontDescriptor) != SUCCESSED) {
285         LOGSO_FUNC_LINE(ERROR) << "parse post failed";
286         return FAILED;
287     }
288 
289     return SUCCESSED;
290 }
291 
SetFontDescriptor(const unsigned int languageId)292 int FontParser::SetFontDescriptor(const unsigned int languageId)
293 {
294     visibilityFonts_.clear();
295     std::list<std::string> fontSetCache;
296     for (unsigned int i = 0; i < fontSet_.size(); ++i) {
297         FontParser::FontDescriptor fontDescriptor;
298         fontDescriptor.requestedLid = languageId;
299         fontDescriptor.path = fontSet_[i];
300         const char* path = fontSet_[i].c_str();
301         auto typeface = Drawing::Typeface::MakeFromFile(path);
302         if (typeface == nullptr) {
303             LOGSO_FUNC_LINE(ERROR) << "typeface is nullptr, can not parse: " << fontDescriptor.path;
304             continue;
305         }
306         auto fontStyle = typeface->GetFontStyle();
307         fontDescriptor.weight = fontStyle.GetWeight();
308         fontDescriptor.width = fontStyle.GetWidth();
309         if (ParseTable(typeface, fontDescriptor) !=  SUCCESSED) {
310             LOGSO_FUNC_LINE(ERROR) << "parse table failed";
311             return FAILED;
312         }
313 
314         size_t idx = fontSet_[i].rfind('/');
315         std::string fontName = fontSet_[i].substr(idx + 1, fontSet_[i].size() - idx - 1);
316         if (std::find(fontSetCache.begin(), fontSetCache.end(), fontName) == fontSetCache.end()) {
317             fontSetCache.push_back(fontName);
318             visibilityFonts_.emplace_back(fontDescriptor);
319         }
320     }
321 
322     return SUCCESSED;
323 }
324 
325 #ifdef BUILD_NON_SDK_VER
ToUtf8(const std::string& str)326 std::string FontParser::ToUtf8(const std::string& str)
327 {
328     std::string utf8Str;
329     // UTF-8 and GB2312 is encoding format of string
330     iconv_t conv = iconv_open("UTF-8", "GB2312");
331     if (conv == (iconv_t)-1) {
332         return utf8Str;
333     }
334     char* inBuf = const_cast<char*>(str.c_str());
335     size_t inBytesLeft = str.length();
336     size_t outBytesLeft = inBytesLeft * 2;
337     char* outBuf = new char[outBytesLeft];
338     char* outBufStart = outBuf;
339     size_t res = iconv(conv, &inBuf, &inBytesLeft, &outBuf, &outBytesLeft);
340     if (res != (size_t)-1) {
341         utf8Str.assign(outBufStart, outBuf - outBufStart);
342     }
343     delete[] outBufStart;
344     iconv_close(conv);
345     return utf8Str;
346 }
347 #endif
348 
GetVisibilityFonts(const std::string &locale)349 std::vector<FontParser::FontDescriptor> FontParser::GetVisibilityFonts(const std::string &locale)
350 {
351     if (SetFontDescriptor(GetLanguageId(locale)) != SUCCESSED) {
352         LOGSO_FUNC_LINE(ERROR) << "set visibility font descriptor failed";
353     }
354 
355     return visibilityFonts_;
356 }
357 
358 class SystemFont {
359 public:
SystemFont(const char* fPath = SYSTEM_FONT_PATH)360     explicit SystemFont(const char* fPath = SYSTEM_FONT_PATH)
361     {
362         ParseConfig(fPath);
363     }
364 
365     ~SystemFont() = default;
366 
GetSystemFontSet() const367     std::shared_ptr<std::vector<std::string>> GetSystemFontSet() const
368     {
369         return systemFontSet_;
370     }
371 
372 private:
ParseConfig(const char* fPath)373     void ParseConfig(const char* fPath)
374     {
375         if (fPath == nullptr) {
376             return;
377         }
378         systemFontSet_ = std::make_shared<std::vector<std::string>>();
379         DIR *dir = opendir(fPath);
380         if (dir == nullptr) {
381             return;
382         }
383         struct dirent *entry;
384         while ((entry = readdir(dir)) != nullptr) {
385             if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
386                 continue;
387             }
388             std::string tmp = entry->d_name;
389             systemFontSet_->push_back(SYSTEM_FONT_PATH + tmp);
390         }
391         closedir(dir);
392     }
393 
394     std::shared_ptr<std::vector<std::string>> systemFontSet_;
395 };
396 
GetSystemFonts(const std::string locale)397 std::vector<std::shared_ptr<FontParser::FontDescriptor>> FontParser::GetSystemFonts(const std::string locale)
398 {
399     std::vector<std::shared_ptr<Drawing::Typeface>> typefaces = Drawing::Typeface::GetSystemFonts();
400     if (typefaces.empty()) {
401         return {};
402     }
403 
404     std::vector<std::shared_ptr<FontDescriptor>> descriptors;
405     descriptors.reserve(typefaces.size());
406     for (auto& item : typefaces) {
407         FontDescriptor desc;
408         desc.requestedLid = GetLanguageId(locale);
409         desc.path = item->GetFontPath();
410         auto fontStyle = item->GetFontStyle();
411         desc.weight = fontStyle.GetWeight();
412         desc.width = fontStyle.GetWidth();
413         if (ParseTable(item, desc) !=  SUCCESSED) {
414             continue;
415         }
416         descriptors.emplace_back(std::make_shared<FontDescriptor>(desc));
417     }
418     return descriptors;
419 }
420 
ParserFontDescriptorFromPath(const std::string& path, std::vector<std::shared_ptr<FontDescriptor>>& descriptors, const std::string locale)421 bool FontParser::ParserFontDescriptorFromPath(const std::string& path,
422     std::vector<std::shared_ptr<FontDescriptor>>& descriptors, const std::string locale)
423 {
424     std::shared_ptr<Drawing::Typeface> typeface;
425     int index = 0;
426     FontDescriptor desc;
427     desc.requestedLid = GetLanguageId(locale);
428     desc.path = path;
429     while ((typeface = Drawing::Typeface::MakeFromFile(path.c_str(), index)) != nullptr) {
430         index++;
431         auto fontStyle = typeface->GetFontStyle();
432         desc.weight = fontStyle.GetWeight();
433         desc.width = fontStyle.GetWidth();
434         if (ParseTable(typeface, desc) != SUCCESSED) {
435             continue;
436         }
437         descriptors.emplace_back(std::make_shared<FontDescriptor>(desc));
438     }
439     if (descriptors.size() > 0) {
440         return true;
441     }
442     return false;
443 }
444 
ParseFontDescriptor(const std::string& fontName, const unsigned int languageId)445 std::unique_ptr<FontParser::FontDescriptor> FontParser::ParseFontDescriptor(const std::string& fontName,
446     const unsigned int languageId)
447 {
448     FontConfigJson fontConfigJson;
449     fontConfigJson.ParseFontFileMap();
450     std::shared_ptr<FontFileMap> fontFileMap = fontConfigJson.GetFontFileMap();
451     if (fontFileMap == nullptr || (*fontFileMap).empty()) {
452         LOGSO_FUNC_LINE(ERROR) << "fontFileMap is nullptr";
453         return nullptr;
454     }
455     if ((*fontFileMap).find(fontName) == (*fontFileMap).end()) {
456         LOGSO_FUNC_LINE(ERROR) << "full name not found";
457         return nullptr;
458     }
459     std::string path = SYSTEM_FONT_PATH + (*fontFileMap)[fontName];
460     auto typeface = Drawing::Typeface::MakeFromFile(path.c_str());
461     if (typeface == nullptr) {
462         path = SYS_PROD_FONT_PATH + (*fontFileMap)[fontName];
463         typeface = Drawing::Typeface::MakeFromFile(path.c_str());
464         if (typeface == nullptr) {
465             LOGSO_FUNC_LINE(ERROR) << "typeface is nullptr, can not parse: " << path.c_str();
466             return nullptr;
467         }
468     }
469     FontParser::FontDescriptor fontDescriptor;
470     fontDescriptor.requestedLid = languageId;
471     fontDescriptor.path = path;
472     fontDescriptor.requestedFullname = fontName;
473     auto fontStyle = typeface->GetFontStyle();
474     fontDescriptor.weight = fontStyle.GetWeight();
475     fontDescriptor.width = fontStyle.GetWidth();
476     if (ParseTable(typeface, fontDescriptor) !=  SUCCESSED) {
477         LOGSO_FUNC_LINE(ERROR) << "parse table failed";
478         return nullptr;
479     }
480     if (fontDescriptor.fullName == fontName) {
481         return std::make_unique<FontDescriptor>(fontDescriptor);
482     }
483     return nullptr;
484 }
485 
GetVisibilityFontByName(const std::string& fontName, const std::string locale)486 std::unique_ptr<FontParser::FontDescriptor> FontParser::GetVisibilityFontByName(const std::string& fontName,
487     const std::string locale)
488 {
489     return ParseFontDescriptor(fontName, GetLanguageId(locale));
490 }
491 } // namespace TextEngine
492 } // namespace Rosen
493 } // namespace OHOS
494