1 /*
2 * Copyright (c) 2024 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_descriptor_cache.h"
17
18 #include <algorithm>
19 #include <dirent.h>
20 #include <fcntl.h>
21 #include <fstream>
22 #include <sys/stat.h>
23 #include <unicode/brkiter.h>
24 #include <unistd.h>
25
26 #include "font_config.h"
27 #include "text/common_utils.h"
28 #include "text/font_style.h"
29 #include "utils/text_log.h"
30
31 #define INSTALL_FONT_CONFIG_FILE "/data/service/el1/public/for-all-app/fonts/install_fontconfig.json"
32
33 namespace OHOS::Rosen {
34 namespace {
35 constexpr uint32_t WEIGHT_400 = 400;
36 constexpr int SPECIAL_WEIGHT_DIFF = 50;
37 constexpr int WEIGHT_MODULE = 100;
38 }
39
FontDescriptorCache()40 FontDescriptorCache::FontDescriptorCache() {}
41
~FontDescriptorCache()42 FontDescriptorCache::~FontDescriptorCache() {}
43
ClearFontFileCache()44 void FontDescriptorCache::ClearFontFileCache()
45 {
46 allFontDescriptor_.clear();
47 fontFamilyMap_.clear();
48 fullNameMap_.clear();
49 postScriptNameMap_.clear();
50 fontSubfamilyNameMap_.clear();
51 boldCache_.clear();
52 italicCache_.clear();
53 monoSpaceCache_.clear();
54 symbolicCache_.clear();
55 stylishFullNameMap_.clear();
56 }
57
ParserSystemFonts()58 void FontDescriptorCache::ParserSystemFonts()
59 {
60 for (auto& item : parser_.GetSystemFonts()) {
61 FontDescriptorScatter(item);
62 }
63 Dump();
64 }
65
ParserStylishFonts()66 void FontDescriptorCache::ParserStylishFonts()
67 {
68 std::vector<TextEngine::FontParser::FontDescriptor> descriptors = parser_.GetVisibilityFonts(TextEngine::ENGLISH);
69 for (const auto& descriptor : descriptors) {
70 FontDescSharedPtr descriptorPtr = std::make_shared<TextEngine::FontParser::FontDescriptor>(descriptor);
71 descriptorPtr->weight = WeightAlignment(descriptorPtr->weight);
72 stylishFullNameMap_[descriptorPtr->fullName].emplace(descriptorPtr);
73 }
74 }
75
FontDescriptorScatter(FontDescSharedPtr desc)76 void FontDescriptorCache::FontDescriptorScatter(FontDescSharedPtr desc)
77 {
78 auto ret = allFontDescriptor_.emplace(desc);
79 if (!ret.second) {
80 return;
81 }
82
83 auto handleMapScatter = [desc](auto& map, const auto& key) {
84 map[key].emplace(desc);
85 };
86
87 handleMapScatter(fontFamilyMap_, desc->fontFamily);
88 handleMapScatter(fullNameMap_, desc->fullName);
89 handleMapScatter(postScriptNameMap_, desc->postScriptName);
90 handleMapScatter(fontSubfamilyNameMap_, desc->fontSubfamily);
91
92 desc->weight = WeightAlignment(desc->weight);
93 if (static_cast<uint32_t>(desc->weight) > WEIGHT_400) {
94 boldCache_.emplace(desc);
95 }
96
97 if (desc->italic != 0) {
98 italicCache_.emplace(desc);
99 }
100
101 if (desc->monoSpace) {
102 monoSpaceCache_.emplace(desc);
103 }
104
105 if (desc->symbolic) {
106 symbolicCache_.emplace(desc);
107 }
108 }
109
ParserInstallFontsPathList(std::vector<std::string> & fontPathList)110 bool FontDescriptorCache::ParserInstallFontsPathList(std::vector<std::string>& fontPathList)
111 {
112 std::shared_ptr<Drawing::FontMgr> fontMgr = Drawing::FontMgr::CreateDynamicFontMgr();
113 if (fontMgr == nullptr) {
114 return false;
115 }
116 int ret = fontMgr->ParseInstallFontConfig(INSTALL_FONT_CONFIG_FILE, fontPathList);
117 return ret == Drawing::FontCheckCode::SUCCESSED;
118 }
119
GetInstallFontList()120 std::unordered_set<std::string> FontDescriptorCache::GetInstallFontList()
121 {
122 std::unordered_set<std::string> fullNameList;
123 std::vector<std::string> fontPathList;
124 if (!ParserInstallFontsPathList(fontPathList)) {
125 TEXT_LOGE("Parser install fonts path list failed");
126 return fullNameList;
127 }
128 for (const auto& path : fontPathList) {
129 std::vector<FontDescSharedPtr> descriptors = parser_.ParserFontDescriptorsFromPath(path);
130 for (const auto& item : descriptors) {
131 fullNameList.emplace(item->fullName);
132 }
133 }
134 return fullNameList;
135 }
136
GetStylishFontList()137 std::unordered_set<std::string> FontDescriptorCache::GetStylishFontList()
138 {
139 std::unordered_set<std::string> fullNameList;
140 for (const auto& temp : stylishFullNameMap_) {
141 fullNameList.emplace(temp.first);
142 }
143 return fullNameList;
144 }
145
GetGenericFontList()146 std::unordered_set<std::string> FontDescriptorCache::GetGenericFontList()
147 {
148 std::unordered_set<std::string> fullNameList;
149 for (const auto& temp : allFontDescriptor_) {
150 fullNameList.emplace(temp->fullName);
151 }
152 return fullNameList;
153 }
154
ProcessSystemFontType(const int32_t & systemFontType,int32_t & fontType)155 bool FontDescriptorCache::ProcessSystemFontType(const int32_t& systemFontType, int32_t& fontType)
156 {
157 if ((static_cast<uint32_t>(systemFontType) & (TextEngine::FontParser::SystemFontType::ALL |
158 TextEngine::FontParser::SystemFontType::GENERIC |
159 TextEngine::FontParser::SystemFontType::STYLISH |
160 TextEngine::FontParser::SystemFontType::INSTALLED)) != systemFontType) {
161 TEXT_LOGE("SystemFontType is invalid, systemFontType: %{public}d", systemFontType);
162 return false;
163 }
164 fontType = systemFontType;
165 if (static_cast<uint32_t>(systemFontType) & TextEngine::FontParser::SystemFontType::ALL) {
166 fontType = TextEngine::FontParser::SystemFontType::GENERIC |
167 TextEngine::FontParser::SystemFontType::STYLISH |
168 TextEngine::FontParser::SystemFontType::INSTALLED;
169 }
170 return true;
171 }
172
GetSystemFontFullNamesByType(const int32_t & systemFontType,std::unordered_set<std::string> & fontList)173 void FontDescriptorCache::GetSystemFontFullNamesByType(
174 const int32_t &systemFontType, std::unordered_set<std::string> &fontList)
175 {
176 if (systemFontType < 0) {
177 TEXT_LOGE("SystemFontType is an invalid value");
178 return;
179 }
180 int32_t fontType = 0;
181 if (!ProcessSystemFontType(systemFontType, fontType)) {
182 fontList.clear();
183 return;
184 }
185
186 if (static_cast<uint32_t>(fontType) & TextEngine::FontParser::SystemFontType::GENERIC) {
187 auto fullNameList = GetGenericFontList();
188 fontList.insert(fullNameList.begin(), fullNameList.end());
189 }
190
191 if (static_cast<uint32_t>(fontType) & TextEngine::FontParser::SystemFontType::STYLISH) {
192 auto fullNameList = GetStylishFontList();
193 fontList.insert(fullNameList.begin(), fullNameList.end());
194 }
195
196 if (static_cast<uint32_t>(fontType) & TextEngine::FontParser::SystemFontType::INSTALLED) {
197 auto fullNameList = GetInstallFontList();
198 fontList.insert(fullNameList.begin(), fullNameList.end());
199 }
200 }
201
ParseInstallFontDescSharedPtrByName(const std::string & fullName,FontDescSharedPtr & result)202 bool FontDescriptorCache::ParseInstallFontDescSharedPtrByName(const std::string& fullName, FontDescSharedPtr& result)
203 {
204 std::vector<std::string> fontPathList;
205 if (!ParserInstallFontsPathList(fontPathList)) {
206 TEXT_LOGE("Parser install fonts path list failed");
207 return false;
208 }
209 for (const auto& path : fontPathList) {
210 std::vector<FontDescSharedPtr> descriptors = parser_.ParserFontDescriptorsFromPath(path);
211 for (const auto& item : descriptors) {
212 if (item->fullName == fullName) {
213 item->weight = WeightAlignment(item->weight);
214 result = item;
215 return true;
216 }
217 }
218 }
219 TEXT_LOGE_LIMIT3_MIN("Parser installed fontDescriptor by name failed, fullName: %{public}s", fullName.c_str());
220 return false;
221 }
222
GetFontDescSharedPtrByFullName(const std::string & fullName,const int32_t & systemFontType,FontDescSharedPtr & result)223 void FontDescriptorCache::GetFontDescSharedPtrByFullName(const std::string& fullName,
224 const int32_t& systemFontType, FontDescSharedPtr& result)
225 {
226 if (fullName.empty()) {
227 TEXT_LOGE("Empty fullName is provided");
228 result = nullptr;
229 return;
230 }
231 int32_t fontType = 0;
232 if (!ProcessSystemFontType(systemFontType, fontType)) {
233 result = nullptr;
234 return;
235 }
236 if (systemFontType < 0) {
237 TEXT_LOGE("SystemFontType is an invalid value");
238 result = nullptr;
239 return;
240 }
241
242 auto tryFindFontDescriptor = [&fullName, &result](const std::unordered_map<std::string,
243 std::set<FontDescSharedPtr>>& map) -> bool {
244 auto it = map.find(fullName);
245 if (it != map.end()) {
246 result = *(it->second.begin());
247 return true;
248 }
249 return false;
250 };
251 if ((static_cast<uint32_t>(fontType) & TextEngine::FontParser::SystemFontType::GENERIC) &&
252 tryFindFontDescriptor(fullNameMap_)) {
253 return;
254 }
255 if ((static_cast<uint32_t>(fontType) & TextEngine::FontParser::SystemFontType::STYLISH) &&
256 tryFindFontDescriptor(stylishFullNameMap_)) {
257 return;
258 }
259 if ((static_cast<uint32_t>(fontType) & TextEngine::FontParser::SystemFontType::INSTALLED) &&
260 ParseInstallFontDescSharedPtrByName(fullName, result)) {
261 return;
262 }
263 TEXT_LOGD("Failed to get fontDescriptor by fullName: %{public}s", fullName.c_str());
264 result = nullptr;
265 }
266
Dump()267 void FontDescriptorCache::Dump()
268 {
269 TEXT_LOGD("allFontDescriptor size: %{public}zu, fontFamilyMap size: %{public}zu, fullNameMap size: %{public}zu \
270 postScriptNameMap size: %{public}zu, fontSubfamilyNameMap size: %{public}zu, boldCache size: %{public}zu \
271 italicCache size: %{public}zu, monoSpaceCache size: %{public}zu, symbolicCache size: %{public}zu",
272 allFontDescriptor_.size(), fontFamilyMap_.size(), fullNameMap_.size(), postScriptNameMap_.size(),
273 fontSubfamilyNameMap_.size(), boldCache_.size(), italicCache_.size(), monoSpaceCache_.size(),
274 symbolicCache_.size());
275 }
276
WeightAlignment(int32_t weight)277 int32_t FontDescriptorCache::WeightAlignment(int32_t weight)
278 {
279 if (weight < Drawing::FontStyle::THIN_WEIGHT) {
280 return Drawing::FontStyle::THIN_WEIGHT;
281 }
282
283 if (weight > Drawing::FontStyle::EXTRA_BLACK_WEIGHT) {
284 return Drawing::FontStyle::EXTRA_BLACK_WEIGHT;
285 }
286
287 if ((weight % WEIGHT_MODULE) == 0) {
288 return weight;
289 }
290
291 static const std::vector<int> weightType = {
292 Drawing::FontStyle::THIN_WEIGHT,
293 Drawing::FontStyle::EXTRA_LIGHT_WEIGHT,
294 Drawing::FontStyle::LIGHT_WEIGHT,
295 Drawing::FontStyle::NORMAL_WEIGHT,
296 Drawing::FontStyle::MEDIUM_WEIGHT,
297 Drawing::FontStyle::SEMI_BOLD_WEIGHT,
298 Drawing::FontStyle::BOLD_WEIGHT,
299 Drawing::FontStyle::EXTRA_BOLD_WEIGHT,
300 Drawing::FontStyle::BLACK_WEIGHT,
301 Drawing::FontStyle::EXTRA_BLACK_WEIGHT
302 };
303 // Obtain weight ranges for non-whole hundred values
304 auto it = std::lower_bound(weightType.begin(), weightType.end(), weight);
305 std::vector<int> targetRange = { *(it - 1), *it };
306
307 /**
308 * When the font weight is less than NORMAL_WEIGHT, round down as much as possible;
309 * when the font weight exceeds NORMAL_WEIGHT, round up where possible. For example, when weight is 360,
310 * the final font weight is set to 300; when weight is 620, the final font weight is set to 700.
311 */
312 uint32_t minDiff = 0xFFFFFFFF;
313 int resultWeight = 0;
314 for (const auto& item : targetRange) {
315 /**
316 * The maximum weight is EXTRA_BLACK_WEIGHT (1000), when weight and item are at the different
317 * side of NORMAL_WEIGHT, the weight difference between them should be more than 500 (1000/2).
318 */
319 uint32_t weightDiff = 0;
320 constexpr int kWeightDiffThreshold = Drawing::FontStyle::EXTRA_BLACK_WEIGHT / 2;
321 if ((weight == Drawing::FontStyle::NORMAL_WEIGHT && item == Drawing::FontStyle::MEDIUM_WEIGHT) ||
322 (weight == Drawing::FontStyle::MEDIUM_WEIGHT && item == Drawing::FontStyle::NORMAL_WEIGHT)) {
323 weightDiff = static_cast<uint32_t>(SPECIAL_WEIGHT_DIFF);
324 } else if (weight <= Drawing::FontStyle::NORMAL_WEIGHT) {
325 weightDiff = (item <= weight) ? static_cast<uint32_t>(weight - item) :
326 static_cast<uint32_t>(item - weight + kWeightDiffThreshold);
327 } else if (weight > Drawing::FontStyle::NORMAL_WEIGHT) {
328 weightDiff = (item >= weight) ? static_cast<uint32_t>(item - weight) :
329 static_cast<uint32_t>(weight - item + kWeightDiffThreshold);
330 }
331
332 // Retain the font weight with the smallest difference
333 if (weightDiff < minDiff) {
334 minDiff = weightDiff;
335 resultWeight = item;
336 }
337 }
338 return resultWeight;
339 }
340 }