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
46 // "weight" and "italic" will assigned value 0 and 1, -1 used to exclude unassigned
FontDescriptor()47 FontParser::FontDescriptor::FontDescriptor(): path(""), postScriptName(""), fullName(""),
48 fontFamily(""), fontSubfamily(""), postScriptNameLid(0), fullNameLid(0), fontFamilyLid(0),
49 fontSubfamilyLid(0), requestedLid(0), weight(-1), width(0), italic(-1), monoSpace(0), symbolic(0)
50 {
51 }
52
FontParser()53 FontParser::FontParser()
54 {
55 data_ = nullptr;
56 length_ = 0;
57 fontSet_.clear();
58 FontConfig fontConfig(FONT_CONFIG_FILE);
59 auto fonts = fontConfig.GetFontSet();
60 fontSet_.insert(fontSet_.end(), fonts.begin(), fonts.end());
61 FontConfig fontProdConfig(FONT_CONFIG_PROD_FILE);
62 auto prodFonts = fontProdConfig.GetFontSet();
63 fontSet_.insert(fontSet_.end(), prodFonts.begin(), prodFonts.end());
64 }
65
ProcessCmapTable(const struct CmapTables * cmapTable,FontParser::FontDescriptor & fontDescriptor)66 void FontParser::ProcessCmapTable(const struct CmapTables* cmapTable, FontParser::FontDescriptor& fontDescriptor)
67 {
68 for (auto i = 0; i < cmapTable->numTables.Get(); ++i) {
69 const auto& record = cmapTable->encodingRecords[i];
70 FontParser::PlatformId platformId = static_cast<FontParser::PlatformId>(record.platformID.Get());
71 FontParser::EncodingIdWin encodingId = static_cast<FontParser::EncodingIdWin>(record.encodingID.Get());
72 if (platformId == FontParser::PlatformId::WINDOWS && encodingId == FontParser::EncodingIdWin::SYMBOL) {
73 fontDescriptor.symbolic = true;
74 break;
75 }
76 }
77 }
78
GetStringFromNameId(FontParser::NameId nameId,unsigned int languageId,const std::string & nameString,FontParser::FontDescriptor & fontDescriptor)79 void FontParser::GetStringFromNameId(FontParser::NameId nameId, unsigned int languageId, const std::string& nameString,
80 FontParser::FontDescriptor& fontDescriptor)
81 {
82 switch (nameId) {
83 case FontParser::NameId::FONT_FAMILY: {
84 SetNameString(fontDescriptor, fontDescriptor.fontFamily, fontDescriptor.fontFamilyLid,
85 languageId, nameString);
86 break;
87 }
88 case FontParser::NameId::FONT_SUBFAMILY: {
89 SetNameString(fontDescriptor, fontDescriptor.fontSubfamily, fontDescriptor.fontSubfamilyLid,
90 languageId, nameString);
91 break;
92 }
93 case FontParser::NameId::FULL_NAME: {
94 if (!fontDescriptor.requestedFullname.empty() &&
95 fontDescriptor.fullName == fontDescriptor.requestedFullname) {
96 break;
97 }
98
99 SetNameString(fontDescriptor, fontDescriptor.fullName, fontDescriptor.fullNameLid,
100 languageId, nameString);
101 break;
102 }
103 case FontParser::NameId::POSTSCRIPT_NAME: {
104 SetNameString(fontDescriptor, fontDescriptor.postScriptName, fontDescriptor.postScriptNameLid,
105 languageId, nameString);
106 break;
107 }
108 default: {
109 break;
110 }
111 }
112 }
113
SetNameString(FontParser::FontDescriptor & fontDescriptor,std::string & field,unsigned int & fieldLid,unsigned int languageId,const std::string & nameString)114 void FontParser::SetNameString(FontParser::FontDescriptor& fontDescriptor, std::string& field, unsigned int& fieldLid,
115 unsigned int languageId, const std::string& nameString)
116 {
117 bool willSet = field.empty();
118 if (!willSet) {
119 willSet = languageId == fontDescriptor.requestedLid ||
120 (fieldLid != fontDescriptor.requestedLid && languageId == LANGUAGE_DEFAULT);
121 }
122
123 if (willSet) {
124 fieldLid = languageId;
125 field = nameString;
126 }
127 }
128
ProcessNameTable(const struct NameTable * nameTable,FontParser::FontDescriptor & fontDescriptor) const129 int FontParser::ProcessNameTable(const struct NameTable* nameTable, FontParser::FontDescriptor& fontDescriptor) const
130 {
131 auto count = nameTable->count.Get();
132 auto storageOffset = nameTable->storageOffset.Get();
133 auto stringStorage = data_ + storageOffset;
134 for (int i = 0; i < count; ++i) {
135 if (nameTable->nameRecord[i].stringOffset.Get() == 0 || nameTable->nameRecord[i].length.Get() == 0) {
136 continue;
137 }
138 FontParser::NameId nameId = static_cast<FontParser::NameId>(nameTable->nameRecord[i].nameId.Get());
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 size_t idx = fontSet_[i].rfind('/');
314 std::string fontName = fontSet_[i].substr(idx + 1, fontSet_[i].size() - idx - 1);
315 if (std::find(fontSetCache.begin(), fontSetCache.end(), fontName) == fontSetCache.end()) {
316 fontSetCache.push_back(fontName);
317 visibilityFonts_.emplace_back(fontDescriptor);
318 }
319 }
320
321 return SUCCESSED;
322 }
323
324 #ifdef BUILD_NON_SDK_VER
ToUtf8(const std::string & str)325 std::string FontParser::ToUtf8(const std::string& str)
326 {
327 std::string utf8Str;
328 // UTF-8 and GB2312 is encoding format of string
329 iconv_t conv = iconv_open("UTF-8", "GB2312");
330 if (conv == (iconv_t)-1) {
331 return utf8Str;
332 }
333 char* inBuf = const_cast<char*>(str.c_str());
334 size_t inBytesLeft = str.length();
335 size_t outBytesLeft = inBytesLeft * 2;
336 char* outBuf = new char[outBytesLeft];
337 char* outBufStart = outBuf;
338 size_t res = iconv(conv, &inBuf, &inBytesLeft, &outBuf, &outBytesLeft);
339 if (res != (size_t)-1) {
340 utf8Str.assign(outBufStart, outBuf - outBufStart);
341 }
342 delete[] outBufStart;
343 iconv_close(conv);
344 return utf8Str;
345 }
346 #endif
347
GetVisibilityFonts(const std::string & locale)348 std::vector<FontParser::FontDescriptor> FontParser::GetVisibilityFonts(const std::string &locale)
349 {
350 if (SetFontDescriptor(GetLanguageId(locale)) != SUCCESSED) {
351 LOGSO_FUNC_LINE(ERROR) << "set visibility font descriptor failed";
352 }
353
354 return visibilityFonts_;
355 }
356
357 class SystemFont {
358 public:
SystemFont(const char * fPath=SYSTEM_FONT_PATH)359 explicit SystemFont(const char* fPath = SYSTEM_FONT_PATH)
360 {
361 ParseConfig(fPath);
362 }
363
364 ~SystemFont() = default;
365
GetSystemFontSet() const366 std::shared_ptr<std::vector<std::string>> GetSystemFontSet() const
367 {
368 return systemFontSet_;
369 }
370
371 private:
ParseConfig(const char * fPath)372 void ParseConfig(const char* fPath)
373 {
374 if (fPath == nullptr) {
375 return;
376 }
377 systemFontSet_ = std::make_shared<std::vector<std::string>>();
378 DIR *dir = opendir(fPath);
379 if (dir == nullptr) {
380 return;
381 }
382 struct dirent *entry;
383 while ((entry = readdir(dir)) != nullptr) {
384 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
385 continue;
386 }
387 std::string tmp = entry->d_name;
388 systemFontSet_->push_back(SYSTEM_FONT_PATH + tmp);
389 }
390 closedir(dir);
391 }
392
393 std::shared_ptr<std::vector<std::string>> systemFontSet_;
394 };
395
ParseFontDescriptor(const std::string & fontName,const unsigned int languageId)396 std::unique_ptr<FontParser::FontDescriptor> FontParser::ParseFontDescriptor(const std::string& fontName,
397 const unsigned int languageId)
398 {
399 FontConfigJson fontConfigJson;
400 fontConfigJson.ParseFontFileMap();
401 std::shared_ptr<FontFileMap> fontFileMap = fontConfigJson.GetFontFileMap();
402 if (fontFileMap == nullptr || (*fontFileMap).empty()) {
403 LOGSO_FUNC_LINE(ERROR) << "fontFileMap is nullptr";
404 return nullptr;
405 }
406 if ((*fontFileMap).find(fontName) == (*fontFileMap).end()) {
407 LOGSO_FUNC_LINE(ERROR) << "full name not found";
408 return nullptr;
409 }
410 std::string path = SYSTEM_FONT_PATH + (*fontFileMap)[fontName];
411 auto typeface = Drawing::Typeface::MakeFromFile(path.c_str());
412 if (typeface == nullptr) {
413 path = SYS_PROD_FONT_PATH + (*fontFileMap)[fontName];
414 typeface = Drawing::Typeface::MakeFromFile(path.c_str());
415 if (typeface == nullptr) {
416 LOGSO_FUNC_LINE(ERROR) << "typeface is nullptr, can not parse: " << path.c_str();
417 return nullptr;
418 }
419 }
420
421 FontParser::FontDescriptor fontDescriptor;
422 fontDescriptor.requestedLid = languageId;
423 fontDescriptor.path = path;
424
425 fontDescriptor.requestedFullname = fontName;
426 auto fontStyle = typeface->GetFontStyle();
427 fontDescriptor.weight = fontStyle.GetWeight();
428 fontDescriptor.width = fontStyle.GetWidth();
429
430 if (ParseTable(typeface, fontDescriptor) != SUCCESSED) {
431 LOGSO_FUNC_LINE(ERROR) << "parse table failed";
432 return nullptr;
433 }
434 if (fontDescriptor.fullName == fontName) {
435 return std::make_unique<FontDescriptor>(fontDescriptor);
436 }
437 return nullptr;
438 }
439
GetVisibilityFontByName(const std::string & fontName,const std::string locale)440 std::unique_ptr<FontParser::FontDescriptor> FontParser::GetVisibilityFontByName(const std::string& fontName,
441 const std::string locale)
442 {
443 return ParseFontDescriptor(fontName, GetLanguageId(locale));
444 }
445 } // namespace TextEngine
446 } // namespace Rosen
447 } // namespace OHOS
448