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