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