xref: /aosp_15_r20/frameworks/minikin/tests/util/FontTestUtils.cpp (revision 834a2baab5fdfc28e9a428ee87c7ea8f6a06a53d)
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "FontTestUtils.h"
18 
19 #include <libxml/parser.h>
20 #include <log/log.h>
21 #include <unistd.h>
22 
23 #include "FreeTypeMinikinFontForTest.h"
24 #include "LocaleListCache.h"
25 #include "MinikinInternal.h"
26 #include "minikin/FontCollection.h"
27 #include "minikin/FontFamily.h"
28 #include "minikin/LocaleList.h"
29 
30 namespace minikin {
31 
32 namespace {
xmlTrim(const std::string & in)33 std::string xmlTrim(const std::string& in) {
34     if (in.empty()) {
35         return in;
36     }
37     const char XML_SPACES[] = "\u0020\u000D\u000A\u0009";
38     const size_t start = in.find_first_not_of(XML_SPACES);  // inclusive
39     const size_t end = in.find_last_not_of(XML_SPACES);     // inclusive
40     MINIKIN_ASSERT(start != std::string::npos, "Not a valid file name \"%s\"", in.c_str());
41     MINIKIN_ASSERT(end != std::string::npos, "Not a valid file name \"%s\"", in.c_str());
42     return in.substr(start, end - start + 1 /* +1 since end is inclusive */);
43 }
44 
45 }  // namespace
46 
getFontFamilies(const std::string & fontDir,const std::string & xmlPath)47 std::vector<std::shared_ptr<FontFamily>> getFontFamilies(const std::string& fontDir,
48                                                          const std::string& xmlPath) {
49     xmlDoc* doc = xmlReadFile(xmlPath.c_str(), NULL, 0);
50     xmlNode* familySet = xmlDocGetRootElement(doc);
51 
52     std::vector<std::shared_ptr<FontFamily>> families;
53     for (xmlNode* familyNode = familySet->children; familyNode; familyNode = familyNode->next) {
54         if (xmlStrcmp(familyNode->name, (const xmlChar*)"family") != 0) {
55             continue;
56         }
57 
58         xmlChar* variantXmlch = xmlGetProp(familyNode, (const xmlChar*)"variant");
59         FamilyVariant variant = FamilyVariant::DEFAULT;
60         if (variantXmlch) {
61             if (xmlStrcmp(variantXmlch, (const xmlChar*)"elegant") == 0) {
62                 variant = FamilyVariant::ELEGANT;
63             } else if (xmlStrcmp(variantXmlch, (const xmlChar*)"compact") == 0) {
64                 variant = FamilyVariant::COMPACT;
65             }
66         }
67 
68         std::vector<std::shared_ptr<Font>> fonts;
69         for (xmlNode* fontNode = familyNode->children; fontNode; fontNode = fontNode->next) {
70             if (xmlStrcmp(fontNode->name, (const xmlChar*)"font") != 0) {
71                 continue;
72             }
73 
74             uint16_t weight = atoi((const char*)(xmlGetProp(fontNode, (const xmlChar*)"weight")));
75             FontStyle::Slant italic = static_cast<FontStyle::Slant>(
76                     xmlStrcmp(xmlGetProp(fontNode, (const xmlChar*)"style"),
77                               (const xmlChar*)"italic") == 0);
78             xmlChar* index = xmlGetProp(familyNode, (const xmlChar*)"index");
79 
80             xmlChar* fontFileName = xmlNodeListGetString(doc, fontNode->xmlChildrenNode, 1);
81             const std::string fontPath = xmlTrim(fontDir + std::string((const char*)fontFileName));
82             xmlFree(fontFileName);
83 
84             // TODO: Support font variation axis.
85 
86             if (access(fontPath.c_str(), R_OK) != 0) {
87                 ALOGW("%s is not found.", fontPath.c_str());
88                 continue;
89             }
90 
91             FontStyle style(weight, italic);
92             if (index == nullptr) {
93                 std::shared_ptr<MinikinFont> minikinFont =
94                         std::make_shared<FreeTypeMinikinFontForTest>(fontPath);
95                 fonts.push_back(Font::Builder(minikinFont).setStyle(style).build());
96             } else {
97                 std::shared_ptr<MinikinFont> minikinFont =
98                         std::make_shared<FreeTypeMinikinFontForTest>(fontPath,
99                                                                      atoi((const char*)index));
100                 fonts.push_back(Font::Builder(minikinFont).setStyle(style).build());
101             }
102         }
103 
104         xmlChar* lang = xmlGetProp(familyNode, (const xmlChar*)"lang");
105         std::shared_ptr<FontFamily> family;
106         if (lang == nullptr) {
107             family = FontFamily::create(variant, std::move(fonts));
108         } else {
109             uint32_t langId = registerLocaleList(std::string((const char*)lang, xmlStrlen(lang)));
110             family = FontFamily::create(langId, variant, std::move(fonts),
111                                         false /* isCustomFallback */, false /* isdefaultFallback */,
112                                         VariationFamilyType::None);
113         }
114         families.push_back(family);
115     }
116     xmlFreeDoc(doc);
117     return families;
118 }
119 
buildFontCollection(const std::string & filePath)120 std::shared_ptr<FontCollection> buildFontCollection(const std::string& filePath) {
121     return FontCollection::create(buildFontFamily(filePath));
122 }
123 
buildFontFamily(const std::string & filePath)124 std::shared_ptr<FontFamily> buildFontFamily(const std::string& filePath) {
125     auto font = std::make_shared<FreeTypeMinikinFontForTest>(getTestFontPath(filePath));
126     std::vector<std::shared_ptr<Font>> fonts;
127     fonts.push_back(Font::Builder(font).build());
128     return FontFamily::create(std::move(fonts));
129 }
130 
buildFontFamily(const std::string & filePath,const std::string & lang,bool isCustomFallback)131 std::shared_ptr<FontFamily> buildFontFamily(const std::string& filePath, const std::string& lang,
132                                             bool isCustomFallback) {
133     auto font = std::make_shared<FreeTypeMinikinFontForTest>(getTestFontPath(filePath));
134     std::vector<std::shared_ptr<Font>> fonts;
135     fonts.push_back(Font::Builder(font).build());
136     return FontFamily::create(LocaleListCache::getId(lang), FamilyVariant::DEFAULT,
137                               std::move(fonts), isCustomFallback, false /* isDefaultFallback */,
138                               VariationFamilyType::None);
139 }
140 
141 }  // namespace minikin
142