• 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 
CheckFullNameParamInvalid(FontParser::FontDescriptor & fontDescriptor,unsigned int languageId,const std::string & nameString)73 bool FontParser::CheckFullNameParamInvalid(FontParser::FontDescriptor& fontDescriptor, unsigned int languageId,
74     const std::string& nameString)
75 {
76     if (!fontDescriptor.requestedFullname.empty() &&
77         fontDescriptor.fullName == fontDescriptor.requestedFullname) {
78         return true;
79     }
80     if (nameString.empty()) {
81         return true;
82     }
83     if (fontDescriptor.requestedLid != LANGUAGE_DEFAULT) {
84         if (fontDescriptor.fullName.empty()) {
85             return false;
86         }
87 
88         if (fontDescriptor.requestedLid == fontDescriptor.fullNameLid) {
89             return true;
90         }
91 
92         if (fontDescriptor.requestedLid != languageId) {
93             return true;
94         }
95     }
96     return false;
97 }
98 
GetStringFromNameId(FontParser::NameId nameId,unsigned int languageId,const std::string & nameString,FontParser::FontDescriptor & fontDescriptor)99 void FontParser::GetStringFromNameId(FontParser::NameId nameId, unsigned int languageId, const std::string& nameString,
100     FontParser::FontDescriptor& fontDescriptor)
101 {
102     switch (nameId) {
103         case FontParser::NameId::FONT_FAMILY: {
104             SetNameString(fontDescriptor, fontDescriptor.fontFamily, fontDescriptor.fontFamilyLid,
105                 languageId, nameString);
106             break;
107         }
108         case FontParser::NameId::FONT_SUBFAMILY: {
109             SetNameString(fontDescriptor, fontDescriptor.fontSubfamily, fontDescriptor.fontSubfamilyLid,
110                 languageId, nameString);
111             break;
112         }
113         case FontParser::NameId::FULL_NAME: {
114             if (CheckFullNameParamInvalid(fontDescriptor, languageId, nameString)) {
115                 break;
116             }
117 
118             SetNameString(fontDescriptor, fontDescriptor.fullName, fontDescriptor.fullNameLid,
119                 languageId, nameString);
120             break;
121         }
122         case FontParser::NameId::POSTSCRIPT_NAME: {
123             SetNameString(fontDescriptor, fontDescriptor.postScriptName, fontDescriptor.postScriptNameLid,
124                 languageId, nameString);
125             break;
126         }
127         default: {
128             break;
129         }
130     }
131 }
132 
SetNameString(FontParser::FontDescriptor & fontDescriptor,std::string & field,unsigned int & fieldLid,unsigned int languageId,const std::string & nameString)133 void FontParser::SetNameString(FontParser::FontDescriptor& fontDescriptor, std::string& field, unsigned int& fieldLid,
134     unsigned int languageId, const std::string& nameString)
135 {
136     bool willSet = field.empty();
137     if (!willSet) {
138         willSet = languageId == fontDescriptor.requestedLid ||
139             (fieldLid != fontDescriptor.requestedLid && languageId == LANGUAGE_DEFAULT);
140     }
141 
142     if (willSet) {
143         fieldLid = languageId;
144         field = nameString;
145     }
146 }
147 
ProcessTable(const NameTable * nameTable,FontParser::FontDescriptor & fontDescriptor)148 void FontParser::ProcessTable(const NameTable* nameTable, FontParser::FontDescriptor& fontDescriptor)
149 {
150     auto count = nameTable->count.Get();
151     auto storageOffset = nameTable->storageOffset.Get();
152     const char* stringStorage = reinterpret_cast<const char*>(nameTable) + storageOffset;
153     for (int i = 0; i < count; ++i) {
154         if (nameTable->nameRecord[i].stringOffset.Get() == 0 && nameTable->nameRecord[i].length.Get() == 0) {
155             continue;
156         }
157         FontParser::NameId nameId = static_cast<FontParser::NameId>(nameTable->nameRecord[i].nameId.Get());
158         // Parsing fields with NameId greater than 7 is not currently supported.
159         if (nameId > FontParser::NameId::TRADEMARK) {
160             continue;
161         }
162         unsigned int languageId = static_cast<unsigned int>(nameTable->nameRecord[i].languageId.Get());
163         FontParser::PlatformId platformId =
164             static_cast<FontParser::PlatformId>(nameTable->nameRecord[i].platformId.Get());
165         auto len = nameTable->nameRecord[i].length.Get();
166         auto stringOffset = nameTable->nameRecord[i].stringOffset.Get();
167         const char* data = stringStorage + stringOffset;
168         if (platformId == FontParser::PlatformId::MACINTOSH) {
169 #ifdef BUILD_NON_SDK_VER
170             std::string nameString = ConvertToString(std::string(data, len), "GB2312", "UTF-8");
171 #else
172             std::string nameString(data, len);
173 #endif
174             GetStringFromNameId(nameId, languageId, nameString, fontDescriptor);
175         } else if (platformId == FontParser::PlatformId::WINDOWS) {
176 #ifdef BUILD_NON_SDK_VER
177             std::string nameString = ConvertToString(std::string(data, len), "UTF-16BE", "UTF-8");
178 #else
179             std::string nameString(data, len);
180 #endif
181             GetStringFromNameId(nameId, languageId, nameString, fontDescriptor);
182         }
183     }
184 }
185 
ProcessTable(const PostTable * postTable,FontParser::FontDescriptor & fontDescriptor)186 void FontParser::ProcessTable(const PostTable* postTable, FontParser::FontDescriptor& fontDescriptor)
187 {
188     if (postTable->italicAngle.Get() != 0) {
189         fontDescriptor.italic = 1; // means support italics
190     } else {
191         fontDescriptor.italic = 0;
192     }
193     if (postTable->isFixedPitch.Get() == 1) {
194         fontDescriptor.monoSpace = true;
195     }
196 }
197 
198 template<typename T>
ParseOneTable(std::shared_ptr<Drawing::Typeface> typeface,FontParser::FontDescriptor & fontDescriptor)199 bool FontParser::ParseOneTable(std::shared_ptr<Drawing::Typeface> typeface, FontParser::FontDescriptor& fontDescriptor)
200 {
201     // get tag by a four bytes string
202     uint32_t tag = HB_TAG(T::tag[0], T::tag[1], T::tag[2], T::tag[3]);
203     auto size = typeface->GetTableSize(tag);
204     if (size < sizeof(T)) {
205         TEXT_LOGE("No table");
206         return false;
207     }
208     std::unique_ptr<char[]> tableData = std::make_unique<char[]>(size);
209     auto readSize = typeface->GetTableData(tag, 0, size, tableData.get());
210     if (size != readSize) {
211         TEXT_LOGE("Failed to get table, size %{public}zu, ret %{public}zu", size, readSize);
212         return false;
213     }
214     ProcessTable(reinterpret_cast<T*>(tableData.get()), fontDescriptor);
215     return true;
216 }
217 
218 using TableTypes = std::tuple<CmapTables, NameTable, PostTable>;
219 
220 template<typename Tuple, size_t... Is>
ParseAllTables(std::shared_ptr<Drawing::Typeface> typeface,FontParser::FontDescriptor & fontDescriptor,std::index_sequence<Is...>) const221 bool FontParser::ParseAllTables(std::shared_ptr<Drawing::Typeface> typeface, FontParser::FontDescriptor& fontDescriptor,
222     std::index_sequence<Is...>) const
223 {
224     return (ParseOneTable<std::tuple_element_t<Is, Tuple>>(typeface, fontDescriptor) && ...);
225 }
226 
ParseTable(std::shared_ptr<Drawing::Typeface> typeface,FontParser::FontDescriptor & fontDescriptor) const227 bool FontParser::ParseTable(
228     std::shared_ptr<Drawing::Typeface> typeface, FontParser::FontDescriptor& fontDescriptor) const
229 {
230     return ParseAllTables<TableTypes>(
231         typeface, fontDescriptor, std::make_index_sequence<std::tuple_size_v<TableTypes>>());
232 }
233 
SetFontDescriptor(const unsigned int languageId)234 bool FontParser::SetFontDescriptor(const unsigned int languageId)
235 {
236         visibilityFonts_.clear();
237     std::list<std::string> fontSetCache;
238     for (unsigned int i = 0; i < fontSet_.size(); ++i) {
239         FontParser::FontDescriptor fontDescriptor;
240         fontDescriptor.requestedLid = languageId;
241         fontDescriptor.path = fontSet_[i];
242         const char* path = fontSet_[i].c_str();
243         auto typeface = Drawing::Typeface::MakeFromFile(path);
244         if (typeface == nullptr) {
245             TEXT_LOGE("Failed to parse file %{public}s", fontDescriptor.path.c_str());
246             continue;
247         }
248         auto fontStyle = typeface->GetFontStyle();
249         fontDescriptor.weight = fontStyle.GetWeight();
250         fontDescriptor.width = fontStyle.GetWidth();
251         if (!ParseTable(typeface, fontDescriptor)) {
252             TEXT_LOGE("Failed to parse table");
253             return false;
254         }
255         size_t idx = fontSet_[i].rfind('/');
256         std::string fontName = fontSet_[i].substr(idx + 1, fontSet_[i].size() - idx - 1);
257         if (std::find(fontSetCache.begin(), fontSetCache.end(), fontName) == fontSetCache.end()) {
258             fontSetCache.push_back(fontName);
259             visibilityFonts_.emplace_back(fontDescriptor);
260         }
261     }
262 
263     return true;
264 }
265 
266 #ifdef BUILD_NON_SDK_VER
ConvertToString(const std::string & src,const std::string & srcType,const std::string & targetType)267 std::string FontParser::ConvertToString(const std::string& src, const std::string& srcType,
268     const std::string& targetType)
269 {
270     std::string utf8Str;
271     iconv_t conv = iconv_open(targetType.c_str(), srcType.c_str());
272     if (conv == (iconv_t)-1) {
273         return utf8Str;
274     }
275     char* inBuf = const_cast<char*>(src.c_str());
276     size_t inBytesLeft = src.length();
277     size_t outBytesLeft = inBytesLeft * 2;
278     char* outBuf = new char[outBytesLeft];
279     char* outBufStart = outBuf;
280     size_t res = iconv(conv, &inBuf, &inBytesLeft, &outBuf, &outBytesLeft);
281     if (res != (size_t)-1) {
282         utf8Str.assign(outBufStart, outBuf - outBufStart);
283     }
284     delete[] outBufStart;
285     iconv_close(conv);
286     return utf8Str;
287 }
288 #endif
289 
GetVisibilityFonts(const std::string & locale)290 std::vector<FontParser::FontDescriptor> FontParser::GetVisibilityFonts(const std::string &locale)
291 {
292     if (!SetFontDescriptor(GetLanguageId(locale))) {
293         TEXT_LOGE("Failed to set visibility font descriptor");
294     }
295 
296     return visibilityFonts_;
297 }
298 
299 class SystemFont {
300 public:
SystemFont(const char * fPath=SYSTEM_FONT_PATH)301     explicit SystemFont(const char* fPath = SYSTEM_FONT_PATH)
302     {
303         ParseConfig(fPath);
304     }
305 
306     ~SystemFont() = default;
307 
GetSystemFontSet() const308     std::shared_ptr<std::vector<std::string>> GetSystemFontSet() const
309     {
310         return systemFontSet_;
311     }
312 
313 private:
ParseConfig(const char * fPath)314     void ParseConfig(const char* fPath)
315     {
316         if (fPath == nullptr) {
317             return;
318         }
319         systemFontSet_ = std::make_shared<std::vector<std::string>>();
320         DIR *dir = opendir(fPath);
321         if (dir == nullptr) {
322             return;
323         }
324         struct dirent *entry;
325         while ((entry = readdir(dir)) != nullptr) {
326             if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
327                 continue;
328             }
329             std::string tmp = entry->d_name;
330             systemFontSet_->push_back(SYSTEM_FONT_PATH + tmp);
331         }
332         closedir(dir);
333     }
334 
335     std::shared_ptr<std::vector<std::string>> systemFontSet_;
336 };
337 
GetSystemFonts(const std::string locale)338 std::vector<std::shared_ptr<FontParser::FontDescriptor>> FontParser::GetSystemFonts(const std::string locale)
339 {
340     std::vector<std::shared_ptr<Drawing::Typeface>> typefaces = Drawing::Typeface::GetSystemFonts();
341     return CreateFontDescriptors(typefaces, locale);
342 }
343 
ParserFontDescriptorFromPath(const std::string & path,size_t index,const std::string & locale) const344 std::shared_ptr<FontParser::FontDescriptor> FontParser::ParserFontDescriptorFromPath(
345     const std::string& path, size_t index, const std::string& locale) const
346 {
347     std::shared_ptr<Drawing::Typeface> typeface = Drawing::Typeface::MakeFromFile(path.c_str(), index);
348     return CreateFontDescriptor(typeface, GetLanguageId(locale));
349 }
350 
ParserFontDescriptorsFromPath(const std::string & path,const std::string & locale) const351 std::vector<std::shared_ptr<FontParser::FontDescriptor>> FontParser::ParserFontDescriptorsFromPath(
352     const std::string& path, const std::string& locale) const
353 {
354     std::vector<std::shared_ptr<Drawing::Typeface>> typefaces;
355     int index = 0;
356     std::shared_ptr<Drawing::Typeface> typeface = nullptr;
357     while ((typeface = Drawing::Typeface::MakeFromFile(path.c_str(), index)) != nullptr) {
358         typefaces.push_back(typeface);
359         index++;
360     }
361     return CreateFontDescriptors(typefaces, locale);
362 }
363 
CreateFontDescriptor(const std::shared_ptr<Drawing::Typeface> & typeface,unsigned int languageId) const364 std::shared_ptr<FontParser::FontDescriptor> FontParser::CreateFontDescriptor(
365     const std::shared_ptr<Drawing::Typeface>& typeface, unsigned int languageId) const
366 {
367     if (typeface == nullptr) {
368         return nullptr;
369     }
370     FontDescriptor desc;
371     desc.requestedLid = languageId;
372     desc.path = typeface->GetFontPath();
373     auto fontStyle = typeface->GetFontStyle();
374     desc.weight = fontStyle.GetWeight();
375     desc.width = fontStyle.GetWidth();
376     if (!ParseTable(typeface, desc)) {
377         return nullptr;
378     }
379     return std::make_shared<FontParser::FontDescriptor>(desc);
380 }
381 
CreateFontDescriptors(const std::vector<std::shared_ptr<Drawing::Typeface>> & typefaces,const std::string & locale) const382 std::vector<std::shared_ptr<FontParser::FontDescriptor>> FontParser::CreateFontDescriptors(
383     const std::vector<std::shared_ptr<Drawing::Typeface>>& typefaces, const std::string& locale) const
384 {
385     if (typefaces.empty()) {
386         return {};
387     }
388 
389     std::vector<std::shared_ptr<FontDescriptor>> descriptors;
390     descriptors.reserve(typefaces.size());
391     unsigned int languageId = static_cast<unsigned int>(GetLanguageId(locale));
392     for (auto& item : typefaces) {
393         std::shared_ptr<FontParser::FontDescriptor> desc = CreateFontDescriptor(item, languageId);
394         if (desc == nullptr) {
395             continue;
396         }
397         descriptors.push_back(std::move(desc));
398     }
399     return descriptors;
400 }
401 
ParseFontDescriptor(const std::string & fontName,const unsigned int languageId)402 std::unique_ptr<FontParser::FontDescriptor> FontParser::ParseFontDescriptor(const std::string& fontName,
403     const unsigned int languageId)
404 {
405     FontConfigJson fontConfigJson;
406     fontConfigJson.ParseFontFileMap();
407     std::shared_ptr<FontFileMap> fontFileMap = fontConfigJson.GetFontFileMap();
408     if (fontFileMap == nullptr || (*fontFileMap).empty()) {
409         TEXT_LOGE_LIMIT3_MIN("Empty font file map");
410         return nullptr;
411     }
412     if ((*fontFileMap).find(fontName) == (*fontFileMap).end()) {
413         TEXT_LOGE_LIMIT3_MIN("Failed to find font name %{public}s", fontName.c_str());
414         return nullptr;
415     }
416     std::string path = SYSTEM_FONT_PATH + (*fontFileMap)[fontName];
417         auto typeface = Drawing::Typeface::MakeFromFile(path.c_str());
418     if (typeface == nullptr) {
419         path = SYS_PROD_FONT_PATH + (*fontFileMap)[fontName];
420         typeface = Drawing::Typeface::MakeFromFile(path.c_str());
421         if (typeface == nullptr) {
422             TEXT_LOGE_LIMIT3_MIN("Failed to parse %{public}s", path.c_str());
423             return nullptr;
424         }
425     }
426 
427     FontParser::FontDescriptor fontDescriptor;
428     fontDescriptor.requestedLid = languageId;
429     fontDescriptor.path = path;
430 
431     fontDescriptor.requestedFullname = fontName;
432     auto fontStyle = typeface->GetFontStyle();
433     fontDescriptor.weight = fontStyle.GetWeight();
434     fontDescriptor.width = fontStyle.GetWidth();
435 
436     if (!ParseTable(typeface, fontDescriptor)) {
437         TEXT_LOGE_LIMIT3_MIN("Failed to parse table");
438         return nullptr;
439     }
440     if (fontDescriptor.fullName == fontName) {
441         return std::make_unique<FontDescriptor>(fontDescriptor);
442     }
443     return nullptr;
444 }
445 
GetVisibilityFontByName(const std::string & fontName,const std::string locale)446 std::unique_ptr<FontParser::FontDescriptor> FontParser::GetVisibilityFontByName(const std::string& fontName,
447     const std::string locale)
448 {
449     return ParseFontDescriptor(fontName, GetLanguageId(locale));
450 }
451 } // namespace TextEngine
452 } // namespace Rosen
453 } // namespace OHOS
454