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 <cstdint>
20 #include <dirent.h>
21 #include <fcntl.h>
22 #include <fstream>
23 #include <sys/stat.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 "text/font_mgr.h"
30 #include "utils/text_log.h"
31
32 #define INSTALL_FONT_CONFIG_FILE "/data/service/el1/public/for-all-app/fonts/install_fontconfig.json"
33
34 namespace OHOS::Rosen {
35 namespace {
36 constexpr uint32_t WEIGHT_400 = 400;
37 constexpr int SPECIAL_WEIGHT_DIFF = 50;
38 constexpr int WEIGHT_MODULE = 100;
39 }
40
FontDescriptorCache()41 FontDescriptorCache::FontDescriptorCache() {}
42
~FontDescriptorCache()43 FontDescriptorCache::~FontDescriptorCache() {}
44
ClearFontFileCache()45 void FontDescriptorCache::ClearFontFileCache()
46 {
47 allFontDescriptor_.clear();
48 fontFamilyMap_.clear();
49 fullNameMap_.clear();
50 postScriptNameMap_.clear();
51 fontSubfamilyNameMap_.clear();
52 boldCache_.clear();
53 italicCache_.clear();
54 monoSpaceCache_.clear();
55 symbolicCache_.clear();
56 stylishFullNameMap_.clear();
57 dynamicFullNameMap_.clear();
58 }
59
ParserSystemFonts()60 void FontDescriptorCache::ParserSystemFonts()
61 {
62 // System fonts have already been parsed
63 if (!fullNameMap_.empty()) {
64 return;
65 }
66 for (auto& item : parser_.GetSystemFonts()) {
67 FontDescriptorScatter(item);
68 }
69 Dump();
70 }
71
ParserStylishFonts()72 void FontDescriptorCache::ParserStylishFonts()
73 {
74 // Stylish fonts have already been parsed
75 if (!stylishFullNameMap_.empty()) {
76 return;
77 }
78 std::vector<TextEngine::FontParser::FontDescriptor> descriptors = parser_.GetVisibilityFonts(TextEngine::ENGLISH);
79 for (const auto& descriptor : descriptors) {
80 FontDescSharedPtr descriptorPtr = std::make_shared<TextEngine::FontParser::FontDescriptor>(descriptor);
81 descriptorPtr->weight = WeightAlignment(descriptorPtr->weight);
82 stylishFullNameMap_[descriptorPtr->fullName].emplace(descriptorPtr);
83 }
84 }
85
ParserFontsByFontType(int32_t fontType)86 void FontDescriptorCache::ParserFontsByFontType(int32_t fontType)
87 {
88 if (static_cast<uint32_t>(fontType) & TextEngine::FontParser::SystemFontType::GENERIC) {
89 ParserSystemFonts();
90 }
91 if (static_cast<uint32_t>(fontType) & TextEngine::FontParser::SystemFontType::STYLISH) {
92 ParserStylishFonts();
93 }
94 }
95
FontDescriptorScatter(FontDescSharedPtr desc)96 void FontDescriptorCache::FontDescriptorScatter(FontDescSharedPtr desc)
97 {
98 auto ret = allFontDescriptor_.emplace(desc);
99 if (!ret.second) {
100 return;
101 }
102
103 auto handleMapScatter = [desc](auto& map, const auto& key) {
104 map[key].emplace(desc);
105 };
106
107 handleMapScatter(fontFamilyMap_, desc->fontFamily);
108 handleMapScatter(fullNameMap_, desc->fullName);
109 handleMapScatter(postScriptNameMap_, desc->postScriptName);
110 handleMapScatter(fontSubfamilyNameMap_, desc->fontSubfamily);
111
112 desc->weight = WeightAlignment(desc->weight);
113 if (static_cast<uint32_t>(desc->weight) > WEIGHT_400) {
114 boldCache_.emplace(desc);
115 }
116
117 if (desc->italic != 0) {
118 italicCache_.emplace(desc);
119 }
120
121 if (desc->monoSpace) {
122 monoSpaceCache_.emplace(desc);
123 }
124
125 if (desc->symbolic) {
126 symbolicCache_.emplace(desc);
127 }
128 }
129
ParserInstallFontsPathList(std::vector<std::string> & fontPathList)130 bool FontDescriptorCache::ParserInstallFontsPathList(std::vector<std::string>& fontPathList)
131 {
132 std::shared_ptr<Drawing::FontMgr> fontMgr = Drawing::FontMgr::CreateDynamicFontMgr();
133 if (fontMgr == nullptr) {
134 return false;
135 }
136 int ret = fontMgr->ParseInstallFontConfig(INSTALL_FONT_CONFIG_FILE, fontPathList);
137 return ret == Drawing::FontCheckCode::SUCCESSED;
138 }
139
GetInstallFontList()140 std::unordered_set<std::string> FontDescriptorCache::GetInstallFontList()
141 {
142 std::unordered_set<std::string> fullNameList;
143 std::vector<std::string> fontPathList;
144 if (!ParserInstallFontsPathList(fontPathList)) {
145 TEXT_LOGE("Failed to parser install fonts path list");
146 return fullNameList;
147 }
148 for (const auto& path : fontPathList) {
149 std::vector<FontDescSharedPtr> descriptors = parser_.ParserFontDescriptorsFromPath(path);
150 for (const auto& item : descriptors) {
151 fullNameList.emplace(item->fullName);
152 }
153 }
154 return fullNameList;
155 }
156
GetStylishFontList()157 std::unordered_set<std::string> FontDescriptorCache::GetStylishFontList()
158 {
159 std::unordered_set<std::string> fullNameList;
160 for (const auto& temp : stylishFullNameMap_) {
161 fullNameList.emplace(temp.first);
162 }
163 return fullNameList;
164 }
165
GetGenericFontList()166 std::unordered_set<std::string> FontDescriptorCache::GetGenericFontList()
167 {
168 std::unordered_set<std::string> fullNameList;
169 for (const auto& temp : allFontDescriptor_) {
170 fullNameList.emplace(temp->fullName);
171 }
172 return fullNameList;
173 }
174
GetDynamicFontList()175 std::unordered_set<std::string> FontDescriptorCache::GetDynamicFontList()
176 {
177 std::unordered_set<std::string> fullNameList;
178 for (const auto& temp : dynamicFullNameMap_) {
179 fullNameList.emplace(temp.first);
180 }
181 return fullNameList;
182 }
183
ProcessSystemFontType(int32_t systemFontType,int32_t & fontType)184 bool FontDescriptorCache::ProcessSystemFontType(int32_t systemFontType, int32_t& fontType)
185 {
186 if ((static_cast<uint32_t>(systemFontType) & (TextEngine::FontParser::SystemFontType::ALL |
187 TextEngine::FontParser::SystemFontType::GENERIC |
188 TextEngine::FontParser::SystemFontType::STYLISH |
189 TextEngine::FontParser::SystemFontType::INSTALLED |
190 TextEngine::FontParser::SystemFontType::CUSTOMIZED)) != systemFontType) {
191 TEXT_LOGE("Invalid system font type %{public}d", systemFontType);
192 return false;
193 }
194 fontType = systemFontType;
195 if (static_cast<uint32_t>(systemFontType) & TextEngine::FontParser::SystemFontType::ALL) {
196 fontType = TextEngine::FontParser::SystemFontType::GENERIC |
197 TextEngine::FontParser::SystemFontType::STYLISH |
198 TextEngine::FontParser::SystemFontType::INSTALLED |
199 TextEngine::FontParser::SystemFontType::CUSTOMIZED;
200 }
201 return true;
202 }
203
GetSystemFontFullNamesByType(int32_t systemFontType,std::unordered_set<std::string> & fontList)204 void FontDescriptorCache::GetSystemFontFullNamesByType(
205 int32_t systemFontType, std::unordered_set<std::string> &fontList)
206 {
207 if (systemFontType < 0) {
208 TEXT_LOGE("Invalid system font type %{public}d", systemFontType);
209 return;
210 }
211 int32_t fontType = 0;
212 if (!ProcessSystemFontType(systemFontType, fontType)) {
213 fontList.clear();
214 return;
215 }
216
217 ParserFontsByFontType(fontType);
218
219 uint32_t fontCategory = static_cast<uint32_t>(fontType);
220 if (fontCategory & TextEngine::FontParser::SystemFontType::GENERIC) {
221 auto fullNameList = GetGenericFontList();
222 fontList.insert(fullNameList.begin(), fullNameList.end());
223 }
224
225 if (fontCategory & TextEngine::FontParser::SystemFontType::STYLISH) {
226 auto fullNameList = GetStylishFontList();
227 fontList.insert(fullNameList.begin(), fullNameList.end());
228 }
229
230 if (fontCategory & TextEngine::FontParser::SystemFontType::INSTALLED) {
231 auto fullNameList = GetInstallFontList();
232 fontList.insert(fullNameList.begin(), fullNameList.end());
233 }
234
235 if (fontCategory & TextEngine::FontParser::SystemFontType::CUSTOMIZED) {
236 auto fullNameList = GetDynamicFontList();
237 fontList.insert(fullNameList.begin(), fullNameList.end());
238 }
239 }
240
ParseInstallFontDescSharedPtrByName(const std::string & fullName,FontDescSharedPtr & result)241 bool FontDescriptorCache::ParseInstallFontDescSharedPtrByName(const std::string& fullName, FontDescSharedPtr& result)
242 {
243 std::vector<std::string> fontPathList;
244 if (!ParserInstallFontsPathList(fontPathList)) {
245 TEXT_LOGE("Failed to parser install fonts path list");
246 return false;
247 }
248 for (const auto& path : fontPathList) {
249 std::vector<FontDescSharedPtr> descriptors = parser_.ParserFontDescriptorsFromPath(path);
250 for (const auto& item : descriptors) {
251 if (item->fullName == fullName) {
252 item->weight = WeightAlignment(item->weight);
253 result = item;
254 return true;
255 }
256 }
257 }
258 TEXT_LOGE_LIMIT3_MIN("Failed to parser installed font descriptor by full name: %{public}s", fullName.c_str());
259 return false;
260 }
261
GetFontTypeFromParams(const std::string & fullName,int32_t systemFontType,int32_t & fontType)262 bool FontDescriptorCache::GetFontTypeFromParams(const std::string& fullName,
263 int32_t systemFontType, int32_t& fontType)
264 {
265 if (fullName.empty()) {
266 TEXT_LOGE("Empty full name");
267 return false;
268 }
269 if (!ProcessSystemFontType(systemFontType, fontType)) {
270 return false;
271 }
272 if (systemFontType < 0) {
273 TEXT_LOGE("Invalid system font type %{public}d", systemFontType);
274 return false;
275 }
276 return true;
277 }
278
GetFontDescSharedPtrByFullName(const std::string & fullName,int32_t systemFontType,FontDescSharedPtr & result)279 void FontDescriptorCache::GetFontDescSharedPtrByFullName(const std::string& fullName,
280 int32_t systemFontType, FontDescSharedPtr& result)
281 {
282 int32_t fontType = 0;
283 if (!GetFontTypeFromParams(fullName, systemFontType, fontType)) {
284 return;
285 }
286
287 ParserFontsByFontType(fontType);
288
289 auto tryFindFontDescriptor = [&fullName, &result](const std::unordered_map<std::string,
290 std::set<FontDescSharedPtr>>& map) -> bool {
291 auto it = map.find(fullName);
292 if (it != map.end()) {
293 result = *(it->second.begin());
294 return true;
295 }
296 return false;
297 };
298
299 uint32_t fontCategory = static_cast<uint32_t>(fontType);
300 if ((fontCategory & TextEngine::FontParser::SystemFontType::GENERIC) &&
301 tryFindFontDescriptor(fullNameMap_)) {
302 return;
303 }
304 if ((fontCategory & TextEngine::FontParser::SystemFontType::STYLISH) &&
305 tryFindFontDescriptor(stylishFullNameMap_)) {
306 return;
307 }
308 if ((fontCategory & TextEngine::FontParser::SystemFontType::INSTALLED) &&
309 ParseInstallFontDescSharedPtrByName(fullName, result)) {
310 return;
311 }
312 if ((fontCategory & TextEngine::FontParser::SystemFontType::CUSTOMIZED)) {
313 auto it = dynamicFullNameMap_.find(fullName);
314 if (it != dynamicFullNameMap_.end()) {
315 result = dynamicFullNameMap_[fullName];
316 return;
317 }
318 }
319 TEXT_LOGD("Failed to get fontDescriptor by full name: %{public}s", fullName.c_str());
320 result = nullptr;
321 }
322
CacheDynamicTypeface(std::shared_ptr<Drawing::Typeface> typeface,const std::string & familyName)323 void FontDescriptorCache::CacheDynamicTypeface(std::shared_ptr<Drawing::Typeface> typeface,
324 const std::string &familyName)
325 {
326 std::vector<std::shared_ptr<TextEngine::FontParser::FontDescriptor>> fontDescArr =
327 parser_.CreateFontDescriptors({typeface});
328 for (auto fontDesc : fontDescArr) {
329 fontDesc->fontFamily = familyName;
330 dynamicFullNameMap_[fontDesc->fontFamily] = fontDesc;
331 }
332 }
333
DeleteDynamicTypefaceFromCache(const std::string & familyName)334 void FontDescriptorCache::DeleteDynamicTypefaceFromCache(const std::string &familyName)
335 {
336 dynamicFullNameMap_.erase(familyName);
337 }
338
HandleMapIntersection(std::set<FontDescSharedPtr> & finishRet,const std::string & name,std::unordered_map<std::string,std::set<FontDescSharedPtr>> & map)339 bool FontDescriptorCache::HandleMapIntersection(std::set<FontDescSharedPtr>& finishRet, const std::string& name,
340 std::unordered_map<std::string, std::set<FontDescSharedPtr>>& map)
341 {
342 if (name.empty()) {
343 return true;
344 }
345 auto iter = map.find(name);
346 if (iter == map.end()) {
347 return false;
348 }
349 if (finishRet.empty()) {
350 finishRet = iter->second;
351 } else {
352 std::set<FontDescSharedPtr> temp;
353 std::set_intersection(iter->second.begin(), iter->second.end(), finishRet.begin(), finishRet.end(),
354 std::insert_iterator<std::set<FontDescSharedPtr>>(temp, temp.begin()));
355 if (temp.empty()) {
356 return false;
357 }
358 finishRet = std::move(temp);
359 }
360 return true;
361 }
362
FilterBoldCache(int weight,std::set<FontDescSharedPtr> & finishRet)363 bool FontDescriptorCache::FilterBoldCache(int weight, std::set<FontDescSharedPtr>& finishRet)
364 {
365 if (weight < 0) {
366 return false;
367 }
368
369 if (weight == 0) {
370 return true;
371 }
372
373 std::set<FontDescSharedPtr> temp;
374 std::set<FontDescSharedPtr>::iterator begin;
375 std::set<FontDescSharedPtr>::iterator end;
376 if (!finishRet.empty()) {
377 begin = finishRet.begin();
378 end = finishRet.end();
379 } else if (static_cast<uint32_t>(weight) > WEIGHT_400) {
380 begin = boldCache_.begin();
381 end = boldCache_.end();
382 } else {
383 begin = allFontDescriptor_.begin();
384 end = allFontDescriptor_.end();
385 }
386 std::for_each(begin, end, [&](FontDescSharedPtr item) {
387 if (item->weight == weight) {
388 temp.emplace(item);
389 }
390 });
391
392 if (temp.empty()) {
393 TEXT_LOGD("Failed to match weight");
394 return false;
395 }
396 finishRet = std::move(temp);
397 return true;
398 }
399
FilterWidthCache(int width,std::set<FontDescSharedPtr> & finishRet)400 bool FontDescriptorCache::FilterWidthCache(int width, std::set<FontDescSharedPtr>& finishRet)
401 {
402 if (width < 0) {
403 return false;
404 }
405
406 if (width == 0) {
407 return true;
408 }
409
410 std::set<FontDescSharedPtr> temp;
411 std::set<FontDescSharedPtr>::iterator begin;
412 std::set<FontDescSharedPtr>::iterator end;
413 if (!finishRet.empty()) {
414 begin = finishRet.begin();
415 end = finishRet.end();
416 } else {
417 begin = allFontDescriptor_.begin();
418 end = allFontDescriptor_.end();
419 }
420 std::for_each(begin, end, [&](FontDescSharedPtr item) {
421 if (item->width == width) {
422 temp.emplace(item);
423 }
424 });
425
426 if (temp.empty()) {
427 TEXT_LOGD("Failed to match width");
428 return false;
429 }
430 finishRet = std::move(temp);
431 return true;
432 }
433
FilterItalicCache(int italic,std::set<FontDescSharedPtr> & finishRet)434 bool FontDescriptorCache::FilterItalicCache(int italic, std::set<FontDescSharedPtr>& finishRet)
435 {
436 if (italic == 0) {
437 return true;
438 }
439 std::set<FontDescSharedPtr> temp;
440 if (!finishRet.empty()) {
441 std::for_each(finishRet.begin(), finishRet.end(), [&](FontDescSharedPtr item) {
442 if (item->italic != 0) {
443 temp.emplace(item);
444 }
445 });
446 } else {
447 temp = italicCache_;
448 }
449 if (temp.empty()) {
450 TEXT_LOGD("Failed to match italic");
451 return false;
452 }
453 finishRet = std::move(temp);
454 return true;
455 }
456
FilterMonoSpaceCache(bool monoSpace,std::set<FontDescSharedPtr> & finishRet)457 bool FontDescriptorCache::FilterMonoSpaceCache(bool monoSpace, std::set<FontDescSharedPtr>& finishRet)
458 {
459 if (!monoSpace) {
460 return true;
461 }
462
463 std::set<FontDescSharedPtr> temp;
464 if (!finishRet.empty()) {
465 std::for_each(finishRet.begin(), finishRet.end(), [&](FontDescSharedPtr item) {
466 if (item->monoSpace) {
467 temp.emplace(item);
468 }
469 });
470 } else {
471 temp = monoSpaceCache_;
472 }
473 if (temp.empty()) {
474 TEXT_LOGD("Failed to match monoSpace");
475 return false;
476 }
477 finishRet = std::move(temp);
478 return true;
479 }
480
FilterSymbolicCache(bool symbolic,std::set<FontDescSharedPtr> & finishRet)481 bool FontDescriptorCache::FilterSymbolicCache(bool symbolic, std::set<FontDescSharedPtr>& finishRet)
482 {
483 if (!symbolic) {
484 return true;
485 }
486 std::set<FontDescSharedPtr> temp;
487 if (!finishRet.empty()) {
488 std::for_each(finishRet.begin(), finishRet.end(), [&](FontDescSharedPtr item) {
489 if (item->symbolic) {
490 temp.emplace(item);
491 }
492 });
493 } else {
494 temp = symbolicCache_;
495 }
496 if (temp.empty()) {
497 TEXT_LOGD("Failed to match symbolic");
498 return false;
499 }
500 finishRet = std::move(temp);
501 return true;
502 }
503
IsDefault(FontDescSharedPtr desc)504 bool FontDescriptorCache::IsDefault(FontDescSharedPtr desc)
505 {
506 if (desc->fontFamily.empty() && desc->fullName.empty() && desc->postScriptName.empty()
507 && desc->fontSubfamily.empty() && desc->weight == 0 && desc->width == 0 && desc->italic == 0
508 && !desc->monoSpace && !desc->symbolic) {
509 return true;
510 }
511 return false;
512 }
513
MatchFromFontDescriptor(FontDescSharedPtr desc,std::set<FontDescSharedPtr> & result)514 void FontDescriptorCache::MatchFromFontDescriptor(FontDescSharedPtr desc, std::set<FontDescSharedPtr>& result)
515 {
516 if (desc == nullptr) {
517 TEXT_LOGE("Null desc");
518 return;
519 }
520 ParserSystemFonts();
521 if (IsDefault(desc)) {
522 result = std::set<FontDescSharedPtr>(allFontDescriptor_.begin(), allFontDescriptor_.end());
523 return;
524 }
525 desc->weight = (desc->weight > 0) ? WeightAlignment(desc->weight) : desc->weight;
526 std::set<FontDescSharedPtr> finishRet;
527 TEXT_INFO_CHECK(HandleMapIntersection(finishRet, desc->fontFamily, fontFamilyMap_), return,
528 "Failed to match font family");
529 TEXT_INFO_CHECK(HandleMapIntersection(finishRet, desc->fullName, fullNameMap_), return, "Failed to match fullName");
530 TEXT_INFO_CHECK(HandleMapIntersection(finishRet, desc->postScriptName, postScriptNameMap_), return,
531 "Failed to match post script name");
532 TEXT_INFO_CHECK(HandleMapIntersection(finishRet, desc->fontSubfamily, fontSubfamilyNameMap_), return,
533 "Failed to match font subfamily");
534
535 TEXT_CHECK(FilterBoldCache(desc->weight, finishRet), return);
536 TEXT_CHECK(FilterWidthCache(desc->width, finishRet), return);
537 TEXT_CHECK(FilterItalicCache(desc->italic, finishRet), return);
538 TEXT_CHECK(FilterMonoSpaceCache(desc->monoSpace, finishRet), return);
539 TEXT_CHECK(FilterSymbolicCache(desc->symbolic, finishRet), return);
540 result = std::move(finishRet);
541 }
542
Dump()543 void FontDescriptorCache::Dump()
544 {
545 TEXT_LOGD("allFontDescriptor size: %{public}zu, fontFamilyMap size: %{public}zu, fullNameMap size: %{public}zu \
546 postScriptNameMap size: %{public}zu, fontSubfamilyNameMap size: %{public}zu, boldCache size: %{public}zu \
547 italicCache size: %{public}zu, monoSpaceCache size: %{public}zu, symbolicCache size: %{public}zu",
548 allFontDescriptor_.size(), fontFamilyMap_.size(), fullNameMap_.size(), postScriptNameMap_.size(),
549 fontSubfamilyNameMap_.size(), boldCache_.size(), italicCache_.size(), monoSpaceCache_.size(),
550 symbolicCache_.size());
551 }
552
WeightAlignment(int32_t weight)553 int32_t FontDescriptorCache::WeightAlignment(int32_t weight)
554 {
555 if (weight < Drawing::FontStyle::THIN_WEIGHT) {
556 return Drawing::FontStyle::THIN_WEIGHT;
557 }
558
559 if (weight > Drawing::FontStyle::EXTRA_BLACK_WEIGHT) {
560 return Drawing::FontStyle::EXTRA_BLACK_WEIGHT;
561 }
562
563 if ((weight % WEIGHT_MODULE) == 0) {
564 return weight;
565 }
566
567 static const std::vector<int> weightType = {
568 Drawing::FontStyle::THIN_WEIGHT,
569 Drawing::FontStyle::EXTRA_LIGHT_WEIGHT,
570 Drawing::FontStyle::LIGHT_WEIGHT,
571 Drawing::FontStyle::NORMAL_WEIGHT,
572 Drawing::FontStyle::MEDIUM_WEIGHT,
573 Drawing::FontStyle::SEMI_BOLD_WEIGHT,
574 Drawing::FontStyle::BOLD_WEIGHT,
575 Drawing::FontStyle::EXTRA_BOLD_WEIGHT,
576 Drawing::FontStyle::BLACK_WEIGHT,
577 Drawing::FontStyle::EXTRA_BLACK_WEIGHT
578 };
579 // Obtain weight ranges for non-whole hundred values
580 auto it = std::lower_bound(weightType.begin(), weightType.end(), weight);
581 std::vector<int> targetRange = { *(it - 1), *it };
582
583 /**
584 * When the font weight is less than NORMAL_WEIGHT, round down as much as possible;
585 * when the font weight exceeds NORMAL_WEIGHT, round up where possible. For example, when weight is 360,
586 * the final font weight is set to 300; when weight is 620, the final font weight is set to 700.
587 */
588 uint32_t minDiff = 0xFFFFFFFF;
589 int resultWeight = 0;
590 for (const auto& item : targetRange) {
591 /**
592 * The maximum weight is EXTRA_BLACK_WEIGHT (1000), when weight and item are at the different
593 * side of NORMAL_WEIGHT, the weight difference between them should be more than 500 (1000/2).
594 */
595 uint32_t weightDiff = 0;
596 constexpr int kWeightDiffThreshold = Drawing::FontStyle::EXTRA_BLACK_WEIGHT / 2;
597 if ((weight == Drawing::FontStyle::NORMAL_WEIGHT && item == Drawing::FontStyle::MEDIUM_WEIGHT) ||
598 (weight == Drawing::FontStyle::MEDIUM_WEIGHT && item == Drawing::FontStyle::NORMAL_WEIGHT)) {
599 weightDiff = static_cast<uint32_t>(SPECIAL_WEIGHT_DIFF);
600 } else if (weight <= Drawing::FontStyle::NORMAL_WEIGHT) {
601 weightDiff = (item <= weight) ? static_cast<uint32_t>(weight - item) :
602 static_cast<uint32_t>(item - weight + kWeightDiffThreshold);
603 } else if (weight > Drawing::FontStyle::NORMAL_WEIGHT) {
604 weightDiff = (item >= weight) ? static_cast<uint32_t>(item - weight) :
605 static_cast<uint32_t>(weight - item + kWeightDiffThreshold);
606 }
607
608 // Retain the font weight with the smallest difference
609 if (weightDiff < minDiff) {
610 minDiff = weightDiff;
611 resultWeight = item;
612 }
613 }
614 return resultWeight;
615 }
616 }