• 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_config.h"
17 
18 #include "cJSON.h"
19 #include <dirent.h>
20 #include <fstream>
21 #include <libgen.h>
22 #include <sys/stat.h>
23 #include <sys/types.h>
24 #include <unistd.h>
25 
26 #ifdef BUILD_NON_SDK_VER
27 #include "securec.h"
28 #endif
29 #include "texgine/utils/exlog.h"
30 
31 namespace OHOS {
32 namespace Rosen {
33 namespace TextEngine {
34 #define SUCCESSED 0
35 #define FAILED 1
36 
37 const char* FONT_DEFAULT_CONFIG = "/system/etc/fontconfig.json";
38 constexpr const char* FALLBACK_VARIATIONS_KEY = "variations";
39 constexpr const char* FALLBACK_INDEX_KEY = "index";
40 
FontConfig(const char * fname)41 FontConfig::FontConfig(const char* fname)
42 {
43     int err = ParseConfig(fname);
44     if (err != 0) {
45         LOGSO_FUNC_LINE(ERROR) << "parse config err";
46     }
47 }
48 
GetFileData(const char * fname,int & size)49 char* FontConfig::GetFileData(const char* fname, int& size)
50 {
51 #ifdef BUILD_NON_SDK_VER
52     char realPath[PATH_MAX] = {0};
53     if (fname == nullptr || realpath(fname, realPath) == NULL) {
54         LOGSO_FUNC_LINE(ERROR) << "path or realPath is NULL";
55         return nullptr;
56     }
57 #endif
58     std::ifstream file(fname);
59     if (file.good()) {
60         FILE* fp = fopen(fname, "r");
61         if (fp == nullptr) {
62             return nullptr;
63         }
64         fseek(fp, 0L, SEEK_END);
65         size = ftell(fp) + 1;
66         rewind(fp);
67         char* data = static_cast<char*>(malloc(size));
68         if (data == nullptr) {
69             fclose(fp);
70             return nullptr;
71         }
72 #ifdef BUILD_NON_SDK_VER
73         if (memset_s(data, size, 0, size) != EOK) {
74             LOGSO_FUNC_LINE(ERROR) << "memset failed";
75             free(data);
76             data = nullptr;
77             fclose(fp);
78             return nullptr;
79         }
80 #else
81             memset(data, 0, size);
82 #endif
83         (void)fread(data, size, 1, fp);
84         fclose(fp);
85         return data;
86     }
87 
88     return nullptr;
89 }
CheckConfigFile(const char * fname) const90 cJSON* FontConfig::CheckConfigFile(const char* fname) const
91 {
92     int size = 0;
93     char* data = GetFileData(fname, size);
94     if (data == nullptr) {
95         LOGSO_FUNC_LINE(ERROR) << "data is NULL";
96         return nullptr;
97     }
98     std::string pramsString;
99     pramsString.assign(data, size);
100     free(data);
101     return cJSON_Parse(pramsString.c_str());
102 }
103 
ParseFont(const cJSON * root)104 int FontConfig::ParseFont(const cJSON* root)
105 {
106     const char* tag = "font";
107     cJSON* filters = cJSON_GetObjectItem(root, tag);
108     if (filters == nullptr) {
109         LOGSO_FUNC_LINE(ERROR) << "parse font failed";
110         return FAILED;
111     }
112     int size = cJSON_GetArraySize(filters);
113     for (int i = 0; i < size;i++) {
114         cJSON* item = cJSON_GetArrayItem(filters, i);
115         if (item != nullptr && cJSON_IsString(item)) {
116             fontSet_.emplace_back(rootPath_ + std::string(item->valuestring));
117         }
118     }
119     return SUCCESSED;
120 }
121 
ParseConfig(const char * fname)122 int FontConfig::ParseConfig(const char* fname)
123 {
124     if (fname == nullptr) {
125         LOGSO_FUNC_LINE(ERROR) << "fname is null";
126         return FAILED;
127     }
128 
129     std::string rootPath(fname);
130     size_t idx = rootPath.rfind('/');
131     if (idx == 0 || idx == std::string::npos) {
132         LOGSO_FUNC_LINE(ERROR) << "fname is illegal";
133         return FAILED;
134     }
135     rootPath_.assign(rootPath.substr(0, idx) + "/");
136     cJSON* root = CheckConfigFile(fname);
137     if (root == nullptr) {
138         LOGSO_FUNC_LINE(ERROR) << "check config file failed";
139         return FAILED;
140     }
141     return ParseFont(root);
142 }
143 
Dump() const144 void FontConfig::Dump() const
145 {
146     for (auto it : fontSet_) {
147         LOGSO_FUNC_LINE(INFO) << "fname:" << it;
148     }
149 }
150 
GetFontSet() const151 std::vector<std::string> FontConfig::GetFontSet() const
152 {
153     return fontSet_;
154 }
155 
ParseFile(const char * fname)156 int FontConfigJson::ParseFile(const char* fname)
157 {
158     if (fname == nullptr) {
159         LOGSO_FUNC_LINE(DEBUG) << "ParseFile fname is nullptr";
160         fname = FONT_DEFAULT_CONFIG;
161     }
162 
163     LOGSO_FUNC_LINE(INFO) << "ParseFile fname is: " << fname;
164     fontPtr = std::make_shared<FontConfigJsonInfo>();
165     int err = ParseConfigList(fname);
166     if (err != 0) {
167         LOGSO_FUNC_LINE(ERROR) << "ParseFile ParseConfigList failed";
168         return err;
169     }
170     return SUCCESSED;
171 }
ParseFontFileMap(const char * fname)172 int FontConfigJson::ParseFontFileMap(const char* fname)
173 {
174     if (fname == nullptr) {
175         LOGSO_FUNC_LINE(DEBUG) << "ParseFontFileMap fname is nullptr";
176         fname = FONT_DEFAULT_CONFIG;
177     }
178 
179     LOGSO_FUNC_LINE(INFO) << "ParseFontFileMap fname is: " << fname;
180     fontFileMap = std::make_shared<FontFileMap>();
181     int err = ParseConfigListPath(fname);
182     if (err != 0) {
183         LOGSO_FUNC_LINE(ERROR) << "ParseFontFileMap ParseConfigList failed";
184         return err;
185     }
186     return SUCCESSED;
187 }
188 
AnalyseFontDir(const cJSON * root)189 void FontConfigJson::AnalyseFontDir(const cJSON* root)
190 {
191     if (root == nullptr) {
192         return;
193     }
194     int size = cJSON_GetArraySize(root);
195     for (int i = 0; i < size; i++) {
196         cJSON* item = cJSON_GetArrayItem(root, i);
197         if (item != nullptr && cJSON_IsString(item)) {
198             fontPtr->fontDirSet.emplace_back(std::string(item->valuestring));
199         }
200     }
201     return;
202 }
203 
ParseDir(const cJSON * root)204 int FontConfigJson::ParseDir(const cJSON* root)
205 {
206     if (root == nullptr) {
207         LOGSO_FUNC_LINE(ERROR) << "parse dir failed";
208         return FAILED;
209     }
210     const char* key = "fontdir";
211     cJSON* item = cJSON_GetObjectItem(root, key);
212     if (item != nullptr) {
213         AnalyseFontDir(item);
214     }
215     return SUCCESSED;
216 }
217 
ParseConfigList(const char * fname)218 int FontConfigJson::ParseConfigList(const char* fname)
219 {
220     if (fname == nullptr) {
221         LOGSO_FUNC_LINE(ERROR) << "ParseConfigList fname is nullptr";
222         return FAILED;
223     }
224     cJSON* root = CheckConfigFile(fname);
225     if (root == nullptr) {
226         LOGSO_FUNC_LINE(ERROR) << "ParseConfigList CheckConfigFile failed";
227         return FAILED;
228     }
229     // "generic", "fallback" - font attribute
230     const char* keys[] = {"generic", "fallback", "fontdir", nullptr};
231     int index = 0;
232     while (true) {
233         if (keys[index] == nullptr) {
234             break;
235         }
236         const char* key = keys[index++];
237         if (!strcmp(key, "fontdir")) {
238             ParseDir(root);
239         } else if (!strcmp(key, "generic")) {
240             ParseGeneric(root, key);
241         } else if (!strcmp(key, "fallback")) {
242             ParseFallback(root, key);
243         }
244     }
245     cJSON_Delete(root);
246     return SUCCESSED;
247 }
248 
ParseConfigListPath(const char * fname)249 int FontConfigJson::ParseConfigListPath(const char* fname)
250 {
251     if (fname == nullptr) {
252         LOGSO_FUNC_LINE(ERROR) << "ParseConfigListPath fname is nullptr";
253         return FAILED;
254     }
255     cJSON* root = CheckConfigFile(fname);
256     if (root == nullptr) {
257         LOGSO_FUNC_LINE(ERROR) << "ParseConfigListPath CheckConfigFile failed";
258         return FAILED;
259     }
260     ParseFontMap(root, "font_file_map");
261     cJSON_Delete(root);
262     return SUCCESSED;
263 }
264 
ParseAdjustArr(const cJSON * arr,FontGenericInfo & genericInfo)265 int FontConfigJson::ParseAdjustArr(const cJSON* arr, FontGenericInfo &genericInfo)
266 {
267     if (arr == nullptr) {
268         LOGSO_FUNC_LINE(ERROR) << "parse adjust arr failed";
269         return FAILED;
270     }
271     int size = cJSON_GetArraySize(arr);
272     for (int i = 0; i < size; i++) {
273         cJSON* item = cJSON_GetArrayItem(arr, i);
274         if (item == nullptr) {
275             continue;
276         }
277         ParseAdjust(item, genericInfo);
278     }
279     return SUCCESSED;
280 }
281 
ParseAliasArr(const cJSON * arr,FontGenericInfo & genericInfo)282 int FontConfigJson::ParseAliasArr(const cJSON* arr, FontGenericInfo &genericInfo)
283 {
284     if (arr == nullptr) {
285         LOGSO_FUNC_LINE(ERROR) << "ParseAliasArr failed";
286         return FAILED;
287     }
288     int size = cJSON_GetArraySize(arr);
289     for (int i = 0; i < size; i++) {
290         cJSON* item = cJSON_GetArrayItem(arr, i);
291         if (item == nullptr) {
292             continue;
293         }
294         ParseAlias(item, genericInfo);
295     }
296     return SUCCESSED;
297 }
298 
ParseGeneric(const cJSON * root,const char * key)299 int FontConfigJson::ParseGeneric(const cJSON* root, const char* key)
300 {
301     if (root == nullptr) {
302         LOGSO_FUNC_LINE(ERROR) << "root is nullptr";
303         return FAILED;
304     }
305     cJSON* filters = cJSON_GetObjectItem(root, key);
306     if (filters == nullptr || !cJSON_IsArray(filters)) {
307         LOGSO_FUNC_LINE(ERROR) << "ParseGeneric failed";
308         return FAILED;
309     }
310     int size = cJSON_GetArraySize(filters);
311     for (int i = 0; i < size; i++) {
312         cJSON* item = cJSON_GetArrayItem(filters, i);
313         if (item == nullptr) {
314             continue;
315         }
316         FontGenericInfo genericInfo;
317         cJSON* family = cJSON_GetObjectItem(item, "family");
318         if (family != nullptr && cJSON_IsString(family)) {
319             genericInfo.familyName = std::string(family->valuestring);
320         }
321 
322         cJSON* alias = cJSON_GetObjectItem(item, "alias");
323         if (alias != nullptr && cJSON_IsArray(alias)) {
324             ParseAliasArr(alias, genericInfo);
325         }
326 
327         cJSON* adjust = cJSON_GetObjectItem(item, "adjust");
328         if (adjust != nullptr && cJSON_IsArray(adjust)) {
329             ParseAdjustArr(adjust, genericInfo);
330         }
331 
332         fontPtr->genericSet.push_back(genericInfo);
333     }
334 
335     return SUCCESSED;
336 }
337 
ParseAlias(const cJSON * root,FontGenericInfo & genericInfo)338 int FontConfigJson::ParseAlias(const cJSON* root, FontGenericInfo &genericInfo)
339 {
340     if (root == nullptr) {
341         LOGSO_FUNC_LINE(ERROR) << "root is nullptr";
342         return FAILED;
343     }
344 
345     int size = cJSON_GetArraySize(root);
346     for (int i = 0; i < size; i++) {
347         cJSON* item = cJSON_GetArrayItem(root, i);
348         if (item == nullptr) {
349             continue;
350         }
351         std::string aliasName = std::string(item->string);
352         if (!cJSON_IsNumber(item)) {
353             continue;
354         }
355         int weight = item->valueint;
356         AliasInfo info = {aliasName, weight};
357         genericInfo.aliasSet.emplace_back(std::move(info));
358     }
359 
360     return SUCCESSED;
361 }
362 
ParseAdjust(const cJSON * root,FontGenericInfo & genericInfo)363 int FontConfigJson::ParseAdjust(const cJSON* root, FontGenericInfo &genericInfo)
364 {
365     if (root == nullptr) {
366         LOGSO_FUNC_LINE(ERROR) << "root is nullptr";
367         return FAILED;
368     }
369     int size = cJSON_GetArraySize(root);
370     const int count = 2; // the adjust item is 2
371     int value[count] = { 0 };
372     for (int i = 0; i < size; i++) {
373         if (i >= count) {
374             break;
375         }
376         cJSON* item = cJSON_GetArrayItem(root, i);
377         if (item == nullptr || !cJSON_IsNumber(item)) {
378             continue;
379         }
380         value[i] = item->valueint;
381     }
382 
383     AdjustInfo info = {value[0], value[1]};
384     genericInfo.adjustSet.emplace_back(std::move(info));
385     return SUCCESSED;
386 }
387 
ParseFallback(const cJSON * root,const char * key)388 int FontConfigJson::ParseFallback(const cJSON* root, const char* key)
389 {
390     if (root == nullptr) {
391         LOGSO_FUNC_LINE(ERROR) << "root is nullptr";
392         return FAILED;
393     }
394     cJSON* filters = cJSON_GetObjectItem(root, key);
395     if (filters == nullptr || !cJSON_IsArray(filters)) {
396         LOGSO_FUNC_LINE(ERROR) << "cJSON_GetObjectItem failed";
397         return FAILED;
398     }
399     cJSON* forItem = cJSON_GetArrayItem(cJSON_GetArrayItem(filters, 0), 0);
400     int size = cJSON_GetArraySize(forItem);
401     FallbackGroup fallbackGroup;
402     fallbackGroup.groupName = std::string("");
403     for (int i = 0; i < size; i++) {
404         cJSON* item = cJSON_GetArrayItem(forItem, i);
405         if (item == nullptr) {
406             continue;
407         }
408         // refer to FontConfig_OHOS::parseFallbackItem
409         int itemSize = cJSON_GetArraySize(item);
410         for (int j = itemSize - 1; j >= 0; --j) {
411             cJSON* item2 = cJSON_GetArrayItem(item, j);
412             if (item2 == nullptr || item2->valuestring == nullptr || item2->string == nullptr ||
413                 strcmp(item2->string, FALLBACK_VARIATIONS_KEY) == 0 ||
414                 strcmp(item2->string, FALLBACK_INDEX_KEY) == 0) {
415                 continue;
416             }
417             FallbackInfo fallbackInfo;
418             fallbackInfo.familyName = item2->valuestring;
419             fallbackInfo.font = item2->string;
420             fallbackGroup.fallbackInfoSet.emplace_back(std::move(fallbackInfo));
421             break;
422         }
423     }
424     fontPtr->fallbackGroupSet.emplace_back(std::move(fallbackGroup));
425     return SUCCESSED;
426 }
427 
ParseFontMap(const cJSON * root,const char * key)428 int FontConfigJson::ParseFontMap(const cJSON* root, const char* key)
429 {
430     if (root == nullptr) {
431         LOGSO_FUNC_LINE(ERROR) << "root is nullptr";
432         return FAILED;
433     }
434     cJSON* filters = cJSON_GetObjectItem(root, key);
435     if (filters == nullptr || !cJSON_IsArray(filters)) {
436         LOGSO_FUNC_LINE(ERROR) << "cJSON_GetObjectItem failed";
437         return FAILED;
438     }
439     int size = cJSON_GetArraySize(filters);
440     for (int i = 0; i < size; i++) {
441         cJSON* item = cJSON_GetArrayItem(filters, i);
442         if (item == nullptr) {
443             continue;
444         }
445         cJSON* item2 = cJSON_GetArrayItem(item, 0);
446         if (item2 == nullptr || item2->valuestring == nullptr || item2->string == nullptr) {
447             continue;
448         }
449         (*fontFileMap)[item2->string] = item2->valuestring;
450     }
451     return SUCCESSED;
452 }
453 
DumpAlias(const AliasSet & aliasSet) const454 void FontConfigJson::DumpAlias(const AliasSet &aliasSet) const
455 {
456     if (!aliasSet.empty()) {
457         const std::string space = "    ";
458         LOGSO_FUNC_LINE(INFO) << "  \"alias\": [";
459         for (auto it : aliasSet) {
460             LOGSO_FUNC_LINE(INFO) << "  {";
461             LOGSO_FUNC_LINE(INFO) << space << "  \"" <<
462                 it.familyName << "\" : " << it.weight;
463             LOGSO_FUNC_LINE(INFO) << "   },";
464         }
465         LOGSO_FUNC_LINE(INFO) << "  ],";
466     }
467 }
468 
DumpAjdust(const AdjustSet & adjustSet) const469 void FontConfigJson::DumpAjdust(const AdjustSet &adjustSet) const
470 {
471     if (!adjustSet.empty()) {
472         LOGSO_FUNC_LINE(INFO) << "  \"adjust\": [";
473         const std::string space = "    ";
474         for (auto it : adjustSet) {
475             LOGSO_FUNC_LINE(INFO) << "   {";
476             LOGSO_FUNC_LINE(INFO) << space << "  \"weght\" :" <<
477                 it.origValue << " , " << "\"to\" :" << it.newValue;
478             LOGSO_FUNC_LINE(INFO) << "   },";
479         }
480         LOGSO_FUNC_LINE(INFO) << "  ],";
481     }
482 }
483 
DumpGeneric() const484 void FontConfigJson::DumpGeneric() const
485 {
486     LOGSO_FUNC_LINE(INFO) << "generic : [";
487     if (!fontPtr->genericSet.empty()) {
488         for (auto it : fontPtr->genericSet) {
489             LOGSO_FUNC_LINE(INFO) << "  \"family\": [\""<< it.familyName << "\"],";
490             DumpAlias(it.aliasSet);
491             DumpAjdust(it.adjustSet);
492         }
493     }
494     LOGSO_FUNC_LINE(INFO) << "]";
495 }
496 
DumpForbak() const497 void FontConfigJson::DumpForbak() const
498 {
499     if (!fontPtr->fallbackGroupSet.empty()) {
500         LOGSO_FUNC_LINE(INFO) << "\"fallback\": [";
501         LOGSO_FUNC_LINE(INFO) << "{";
502         for (auto group : fontPtr->fallbackGroupSet) {
503             LOGSO_FUNC_LINE(INFO) << " \"" << group.groupName << "\" : [";
504             if (group.fallbackInfoSet.empty()) continue;
505             const std::string space = "    ";
506             for (auto it : group.fallbackInfoSet) {
507                 LOGSO_FUNC_LINE(INFO) << "  {";
508                 LOGSO_FUNC_LINE(INFO) << space << it.font << "\" : \""
509                     << it.familyName << "\"";
510                 LOGSO_FUNC_LINE(INFO) << "   },";
511             }
512             LOGSO_FUNC_LINE(INFO) << " ]";
513         }
514         LOGSO_FUNC_LINE(INFO) << "}";
515         LOGSO_FUNC_LINE(INFO) << "]";
516     }
517 }
518 
DumpFontDir() const519 void FontConfigJson::DumpFontDir() const
520 {
521     LOGSO_FUNC_LINE(INFO) << "fontdir : [";
522     if (!fontPtr->fontDirSet.empty()) {
523         for (auto it : fontPtr->fontDirSet) {
524             LOGSO_FUNC_LINE(INFO) << "\""<< it << "\",";
525         }
526     }
527     LOGSO_FUNC_LINE(INFO) << "]";
528 }
529 
DumpFontFileMap() const530 void FontConfigJson::DumpFontFileMap() const
531 {
532     for (auto it : (*fontFileMap)) {
533         LOGSO_FUNC_LINE(INFO) << "\"" << it.first << "\": \""
534             << it.second << "\"";
535     }
536 }
537 
Dump() const538 void FontConfigJson::Dump() const
539 {
540     if (fontPtr != nullptr) {
541         LOGSO_FUNC_LINE(INFO) << "font config dump fontPtr in";
542         DumpFontDir();
543         DumpGeneric();
544         DumpForbak();
545         LOGSO_FUNC_LINE(INFO) << "font config dump fontPtr out";
546     }
547     if (fontFileMap != nullptr) {
548         LOGSO_FUNC_LINE(INFO) << "font config dump fontFileMap in";
549         DumpFontFileMap();
550         LOGSO_FUNC_LINE(INFO) << "font config dump fontFileMap out";
551     }
552 }
553 } // namespace TextEngine
554 } // namespace Rosen
555 } // namespace OHOS
556