1 /*
2 * Copyright (c) 2021-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 "core/components/theme/theme_constants.h"
17
18 #include "base/resource/ace_res_config.h"
19 #include "core/pipeline_ng/pipeline_context.h"
20
21 namespace OHOS::Ace {
22 namespace {
23
24 const ResValueWrapper ERROR_VALUE = { .type = ThemeConstantsType::ERROR };
25 // Don't use Color::BLACK in case Color haven't been initialized.
26 const Color ERROR_VALUE_COLOR = Color(0xff000000);
27 constexpr Dimension ERROR_VALUE_DIMENSION = 0.0_vp;
28 constexpr int32_t ERROR_VALUE_INT = 0;
29 constexpr uint32_t ERROR_VALUE_UINT = 0;
30 constexpr double ERROR_VALUE_DOUBLE = 0.0;
31 constexpr double BLEND_ALPHA_MAX = 1.0;
32 constexpr InternalResource::ResourceId ERROR_VALUE_RESOURCE_ID = InternalResource::ResourceId::NO_ID;
33 const char STYLES_FOLDER_PATH[] = "resources/styles/";
34 const char FILE_TYPE_JSON[] = ".json";
35 const char CUSTOM_STYLE_ROOT_NAME[] = "style";
36 const Color TRANSPARENT_BG_COLOR = Color::FromRGBO(0, 0, 0, 0.2);
37 // For global resource manager system, system resource id is in [0x7000000, 0x7ffffff],
38 // and the id of resource defined by developer in the "resource" directory is greater than or equal to 0x1000000.
39 constexpr uint32_t GLOBAL_RESOURCE_ID_START = 0x1000000;
40
41 DeviceType g_deviceType = DeviceType::PHONE;
42
43 // Check whether value is match with expected type
ValueTypeMatch(const ResValueWrapper & valueWrapper,uint32_t key,const ThemeConstantsType & expectType)44 bool ValueTypeMatch(const ResValueWrapper& valueWrapper, uint32_t key, const ThemeConstantsType& expectType)
45 {
46 if (valueWrapper.type == ThemeConstantsType::ERROR) {
47 return false;
48 }
49 if (valueWrapper.type != expectType) {
50 return false;
51 }
52 return true;
53 }
54
IsGlobalResource(uint32_t resId)55 bool IsGlobalResource(uint32_t resId)
56 {
57 return resId >= GLOBAL_RESOURCE_ID_START;
58 }
59
60 } // namespace
61
InitDeviceType()62 void ThemeConstants::InitDeviceType()
63 {
64 g_deviceType = SystemProperties::GetDeviceType();
65 }
66
GetPlatformConstants(uint32_t key)67 const ResValueWrapper* ThemeConstants::GetPlatformConstants(uint32_t key)
68 {
69 #ifdef WEARABLE_PRODUCT
70 if (g_deviceType == DeviceType::WATCH && key < ThemeConstants::WatchMapCount &&
71 ThemeConstants::styleMapWatch[key] != nullptr) {
72 return ThemeConstants::styleMapWatch[key];
73 }
74 #else
75 if (g_deviceType == DeviceType::TV && key < ThemeConstants::TvMapCount &&
76 ThemeConstants::styleMapTv[key] != nullptr) {
77 return ThemeConstants::styleMapTv[key];
78 }
79 #endif
80 if (key < ThemeConstants::DefaultMapCount) {
81 return ThemeConstants::styleMapDefault[key];
82 }
83 return nullptr;
84 }
85
GetColor(uint32_t key) const86 Color ThemeConstants::GetColor(uint32_t key) const
87 {
88 if (IsGlobalResource(key)) {
89 if (!resAdapter_) {
90 return ERROR_VALUE_COLOR;
91 }
92 return resAdapter_->GetColor(key);
93 }
94 const auto& valueWrapper = GetValue(key);
95 if (!ValueTypeMatch(valueWrapper, key, ThemeConstantsType::COLOR)) {
96 return ERROR_VALUE_COLOR;
97 }
98 auto colorPair = valueWrapper.GetValue<Color>(ERROR_VALUE_COLOR);
99 if (!colorPair.first) {
100 TAG_LOGW(AceLogTag::ACE_THEME, "Get theme color error: %{public}u, type: %{public}u", key, valueWrapper.type);
101 }
102 return colorPair.second;
103 }
104
GetColorByName(const std::string & resName) const105 Color ThemeConstants::GetColorByName(const std::string& resName) const
106 {
107 if (!resAdapter_) {
108 return ERROR_VALUE_COLOR;
109 }
110 return resAdapter_->GetColorByName(resName);
111 }
112
GetDimension(uint32_t key) const113 Dimension ThemeConstants::GetDimension(uint32_t key) const
114 {
115 if (IsGlobalResource(key)) {
116 if (!resAdapter_) {
117 return ERROR_VALUE_DIMENSION;
118 }
119 auto result = resAdapter_->GetDimension(key);
120 if (NearZero(result.Value())) {
121 result = StringUtils::StringToDimension(resAdapter_->GetString(key));
122 }
123 return result;
124 }
125 const auto& valueWrapper = GetValue(key);
126 if (!ValueTypeMatch(valueWrapper, key, ThemeConstantsType::DIMENSION)) {
127 return ERROR_VALUE_DIMENSION;
128 }
129 auto dimensionPair = valueWrapper.GetValue<Dimension>(ERROR_VALUE_DIMENSION);
130 if (!dimensionPair.first) {
131 TAG_LOGW(
132 AceLogTag::ACE_THEME, "Get theme dimension error: %{public}u, type: %{public}u", key, valueWrapper.type);
133 }
134 return dimensionPair.second;
135 }
136
GetDimensionByName(const std::string & resName) const137 Dimension ThemeConstants::GetDimensionByName(const std::string& resName) const
138 {
139 if (!resAdapter_) {
140 return ERROR_VALUE_DIMENSION;
141 }
142 auto result = resAdapter_->GetDimensionByName(resName);
143 if (NearZero(result.Value())) {
144 result = StringUtils::StringToDimension(resAdapter_->GetStringByName(resName));
145 }
146 return result;
147 }
148
GetInt(uint32_t key) const149 int32_t ThemeConstants::GetInt(uint32_t key) const
150 {
151 if (IsGlobalResource(key)) {
152 if (!resAdapter_) {
153 return ERROR_VALUE_INT;
154 }
155 return resAdapter_->GetInt(key);
156 }
157 const auto& valueWrapper = GetValue(key);
158 if (!ValueTypeMatch(valueWrapper, key, ThemeConstantsType::INT)) {
159 return ERROR_VALUE_INT;
160 }
161 auto intPair = valueWrapper.GetValue<int32_t>(ERROR_VALUE_INT);
162 if (!intPair.first) {
163 TAG_LOGW(AceLogTag::ACE_THEME, "Get theme int error: %{public}u, type: %{public}u", key, valueWrapper.type);
164 }
165 return intPair.second;
166 }
167
GetIntByName(const std::string & resName) const168 int32_t ThemeConstants::GetIntByName(const std::string& resName) const
169 {
170 if (!resAdapter_) {
171 return ERROR_VALUE_INT;
172 }
173 return resAdapter_->GetIntByName(resName);
174 }
175
GetDouble(uint32_t key) const176 double ThemeConstants::GetDouble(uint32_t key) const
177 {
178 if (IsGlobalResource(key)) {
179 if (!resAdapter_) {
180 return ERROR_VALUE_DOUBLE;
181 }
182 return resAdapter_->GetDouble(key);
183 }
184 const auto& valueWrapper = GetValue(key);
185 if (!ValueTypeMatch(valueWrapper, key, ThemeConstantsType::DOUBLE)) {
186 return ERROR_VALUE_DOUBLE;
187 }
188 auto doublePair = valueWrapper.GetValue<double>(ERROR_VALUE_DOUBLE);
189 if (!doublePair.first) {
190 TAG_LOGW(AceLogTag::ACE_THEME, "Get theme double error: %{public}u, type: %{public}u", key, valueWrapper.type);
191 }
192 return doublePair.second;
193 }
194
GetDoubleByName(const std::string & resName) const195 double ThemeConstants::GetDoubleByName(const std::string& resName) const
196 {
197 if (!resAdapter_) {
198 return ERROR_VALUE_DOUBLE;
199 }
200 return resAdapter_->GetDoubleByName(resName);
201 }
202
GetString(uint32_t key) const203 std::string ThemeConstants::GetString(uint32_t key) const
204 {
205 if (IsGlobalResource(key)) {
206 if (!resAdapter_) {
207 return "";
208 }
209 return resAdapter_->GetString(key);
210 }
211 const auto& valueWrapper = GetValue(key);
212 if (!ValueTypeMatch(valueWrapper, key, ThemeConstantsType::STRING)) {
213 return "";
214 }
215 auto stringPair = valueWrapper.GetValue<std::string>("");
216 if (!stringPair.first) {
217 TAG_LOGW(AceLogTag::ACE_THEME, "Get theme string error: %{public}u, type: %{public}u", key, valueWrapper.type);
218 }
219 return stringPair.second;
220 }
221
GetStringByName(const std::string & resName) const222 std::string ThemeConstants::GetStringByName(const std::string& resName) const
223 {
224 if (!resAdapter_) {
225 return "";
226 }
227 return resAdapter_->GetStringByName(resName);
228 }
229
GetPluralString(uint32_t key,int count) const230 std::string ThemeConstants::GetPluralString(uint32_t key, int count) const
231 {
232 if (IsGlobalResource(key)) {
233 if (!resAdapter_) {
234 return "";
235 }
236 return resAdapter_->GetPluralString(key, count);
237 }
238 const auto& valueWrapper = GetValue(key);
239 if (!ValueTypeMatch(valueWrapper, key, ThemeConstantsType::STRING)) {
240 return "";
241 }
242 auto stringPair = valueWrapper.GetValue<std::string>("");
243 if (!stringPair.first) {
244 TAG_LOGW(AceLogTag::ACE_THEME, "Get theme pluralString error: %{public}u, type: %{public}u", key,
245 valueWrapper.type);
246 }
247 return stringPair.second;
248 }
249
GetPluralStringByName(const std::string & resName,int count) const250 std::string ThemeConstants::GetPluralStringByName(const std::string& resName, int count) const
251 {
252 if (!resAdapter_) {
253 return "";
254 }
255 return resAdapter_->GetPluralStringByName(resName, count);
256 }
257
GetStringArray(uint32_t key) const258 std::vector<std::string> ThemeConstants::GetStringArray(uint32_t key) const
259 {
260 if (IsGlobalResource(key)) {
261 if (!resAdapter_) {
262 return {};
263 }
264 return resAdapter_->GetStringArray(key);
265 }
266 return {};
267 }
268
GetStringArrayByName(const std::string & resName) const269 std::vector<std::string> ThemeConstants::GetStringArrayByName(const std::string& resName) const
270 {
271 if (!resAdapter_) {
272 return {};
273 }
274 return resAdapter_->GetStringArrayByName(resName);
275 }
276
GetMediaPath(uint32_t key) const277 std::string ThemeConstants::GetMediaPath(uint32_t key) const
278 {
279 if (IsGlobalResource(key)) {
280 if (!resAdapter_) {
281 return "";
282 }
283 return resAdapter_->GetMediaPath(key);
284 }
285 return "";
286 }
287
GetMediaPathByName(const std::string & resName) const288 std::string ThemeConstants::GetMediaPathByName(const std::string& resName) const
289 {
290 if (!resAdapter_) {
291 return "";
292 }
293 return resAdapter_->GetMediaPathByName(resName);
294 }
295
GetRawfile(const std::string & fileName) const296 std::string ThemeConstants::GetRawfile(const std::string& fileName) const
297 {
298 if (!resAdapter_) {
299 return "";
300 }
301 return resAdapter_->GetRawfile(fileName);
302 }
303
GetRawFileDescription(const std::string & rawfileName,RawfileDescription & rawfileDescription) const304 bool ThemeConstants::GetRawFileDescription(const std::string& rawfileName, RawfileDescription& rawfileDescription) const
305 {
306 if (!resAdapter_) {
307 return false;
308 }
309 return resAdapter_->GetRawFileDescription(rawfileName, rawfileDescription);
310 }
311
CloseRawFileDescription(const std::string & rawfileName) const312 bool ThemeConstants::CloseRawFileDescription(const std::string& rawfileName) const
313 {
314 if (!resAdapter_) {
315 return false;
316 }
317 return resAdapter_->CloseRawFileDescription(rawfileName);
318 }
319
GetRawFD(const std::string & rawfileName,RawfileDescription & rawfileDescription) const320 bool ThemeConstants::GetRawFD(const std::string& rawfileName, RawfileDescription& rawfileDescription) const
321 {
322 if (!resAdapter_) {
323 return false;
324 }
325 return resAdapter_->GetRawFD(rawfileName, rawfileDescription);
326 }
327
GetMediaById(const int32_t & resId,std::string & mediaPath) const328 bool ThemeConstants::GetMediaById(const int32_t& resId, std::string& mediaPath) const
329 {
330 if (!resAdapter_) {
331 return false;
332 }
333 return resAdapter_->GetMediaById(resId, mediaPath);
334 }
335
GetBoolean(uint32_t key) const336 bool ThemeConstants::GetBoolean(uint32_t key) const
337 {
338 if (IsGlobalResource(key)) {
339 if (!resAdapter_) {
340 return false;
341 }
342 return resAdapter_->GetBoolean(key);
343 }
344 return false;
345 }
346
GetBooleanByName(const std::string & resName) const347 bool ThemeConstants::GetBooleanByName(const std::string& resName) const
348 {
349 if (!resAdapter_) {
350 return false;
351 }
352 return resAdapter_->GetBooleanByName(resName);
353 }
354
GetSymbolByName(const char * name) const355 uint32_t ThemeConstants::GetSymbolByName(const char* name) const
356 {
357 if (!resAdapter_) {
358 return ERROR_VALUE_UINT;
359 }
360 return resAdapter_->GetSymbolByName(name);
361 }
362
GetSymbolById(uint32_t resId) const363 uint32_t ThemeConstants::GetSymbolById(uint32_t resId) const
364 {
365 if (!resAdapter_) {
366 return ERROR_VALUE_UINT;
367 }
368 return resAdapter_->GetSymbolById(resId);
369 }
370
GetIntArray(uint32_t key) const371 std::vector<uint32_t> ThemeConstants::GetIntArray(uint32_t key) const
372 {
373 if (IsGlobalResource(key)) {
374 if (!resAdapter_) {
375 return {};
376 }
377 return resAdapter_->GetIntArray(key);
378 }
379 return {};
380 }
381
GetIntArrayByName(const std::string & resName) const382 std::vector<uint32_t> ThemeConstants::GetIntArrayByName(const std::string& resName) const
383 {
384 if (!resAdapter_) {
385 return {};
386 }
387 return resAdapter_->GetIntArrayByName(resName);
388 }
389
GetResourceIdByName(const std::string & resName,const std::string & resType,uint32_t & resId) const390 bool ThemeConstants::GetResourceIdByName(const std::string& resName, const std::string& resType, uint32_t& resId) const
391 {
392 if (!resAdapter_) {
393 return false;
394 }
395 return resAdapter_->GetIdByName(resName, resType, resId);
396 }
397
GetResourceId(uint32_t key) const398 InternalResource::ResourceId ThemeConstants::GetResourceId(uint32_t key) const
399 {
400 const auto& valueWrapper = GetValue(key);
401 if (!ValueTypeMatch(valueWrapper, key, ThemeConstantsType::RESOURCE_ID)) {
402 return ERROR_VALUE_RESOURCE_ID;
403 }
404 auto resPair = valueWrapper.GetValue<InternalResource::ResourceId>(ERROR_VALUE_RESOURCE_ID);
405 if (!resPair.first) {
406 TAG_LOGW(
407 AceLogTag::ACE_THEME, "Get theme resourceId error: %{public}u, type: %{public}u", key, valueWrapper.type);
408 }
409 return resPair.second;
410 }
411
GetPixelMap(uint32_t key) const412 std::shared_ptr<Media::PixelMap> ThemeConstants::GetPixelMap(uint32_t key) const
413 {
414 if (IsGlobalResource(key)) {
415 if (!resAdapter_) {
416 return nullptr;
417 }
418 return resAdapter_->GetPixelMap(key);
419 }
420 return nullptr;
421 }
422
GetValue(uint32_t key) const423 ResValueWrapper ThemeConstants::GetValue(uint32_t key) const
424 {
425 // Find resource at custom styles.
426 auto customIter = customStyleMap_.find(key);
427 if (customIter != customStyleMap_.end()) {
428 return customIter->second;
429 }
430 // Find resource at prebuilt maps.
431 const auto platformConstants = ThemeConstants::GetPlatformConstants(key);
432 if (platformConstants == nullptr) {
433 return ERROR_VALUE;
434 }
435 if (platformConstants->type != ThemeConstantsType::REFERENCE) {
436 return *platformConstants;
437 }
438 // This value point to another style, recursively find target.
439 auto uintPtr = std::get_if<uint32_t>(&(platformConstants->value));
440 if (!uintPtr) {
441 return ERROR_VALUE;
442 }
443 // Copy reference value, blend alpha if need(reference color and current blendAlpha < 1.0).
444 auto refValue = GetValue(*uintPtr);
445 refValue.isPublic = platformConstants->isPublic;
446 auto blendAlpha = GetBlendAlpha(platformConstants->blendAlpha);
447 if ((refValue.type == ThemeConstantsType::COLOR) && (blendAlpha < BLEND_ALPHA_MAX)) {
448 auto colorPtr = std::get_if<Color>(&refValue.value);
449 if (!colorPtr) {
450 return ERROR_VALUE;
451 }
452 refValue.value = colorPtr->BlendOpacity(blendAlpha);
453 }
454 return refValue;
455 }
456
GetBlendAlpha(const BlendAlpha & blendAlpha) const457 double ThemeConstants::GetBlendAlpha(const BlendAlpha& blendAlpha) const
458 {
459 auto doublePtr = std::get_if<double>(&blendAlpha);
460 if (doublePtr) {
461 return *doublePtr;
462 }
463 auto idPtr = std::get_if<uint32_t>(&blendAlpha);
464 if (idPtr) {
465 return ThemeConstants::GetDouble(*idPtr);
466 }
467 return BLEND_ALPHA_MAX;
468 }
469
LoadTheme(int32_t themeId)470 void ThemeConstants::LoadTheme(int32_t themeId)
471 {
472 if (!resAdapter_) {
473 return;
474 }
475 currentThemeStyle_ = resAdapter_->GetTheme(themeId);
476 if (currentThemeStyle_) {
477 currentThemeStyle_->SetName(std::to_string(themeId));
478 }
479 }
480
ParseTheme()481 void ThemeConstants::ParseTheme()
482 {
483 if (currentThemeStyle_) {
484 currentThemeStyle_->ParseContent();
485 }
486 }
487
LoadCustomStyle(const RefPtr<AssetManager> & assetManager)488 void ThemeConstants::LoadCustomStyle(const RefPtr<AssetManager>& assetManager)
489 {
490 if (!assetManager) {
491 return;
492 }
493
494 std::vector<std::string> files;
495
496 assetManager->GetAssetList(STYLES_FOLDER_PATH, files);
497
498 std::vector<std::string> fileNameList;
499 for (const auto& file : files) {
500 if (StringUtils::EndWith(file, FILE_TYPE_JSON)) {
501 fileNameList.emplace_back(file.substr(0, file.size() - (sizeof(FILE_TYPE_JSON) - 1)));
502 }
503 }
504
505 std::vector<std::string> priorityFileList;
506 priorityFileList = AceResConfig::GetStyleResourceFallback(fileNameList);
507 for (auto fileIter = priorityFileList.rbegin(); fileIter != priorityFileList.rend(); ++fileIter) {
508 auto fileFullPath = STYLES_FOLDER_PATH + *fileIter + std::string(FILE_TYPE_JSON);
509 auto asset = assetManager->GetAsset(fileFullPath);
510 ThemeConstants::LoadFile(asset);
511 }
512 }
513
ParseCustomStyle(const std::string & content)514 void ThemeConstants::ParseCustomStyle(const std::string& content)
515 {
516 auto rootJson = JsonUtil::ParseJsonString(content);
517 auto rootNode = rootJson->GetObject(CUSTOM_STYLE_ROOT_NAME);
518 if (rootNode->IsNull()) {
519 return;
520 }
521 auto child = rootNode->GetChild();
522 while (child && !child->IsNull()) {
523 const auto& key = child->GetKey();
524 const auto& value = child->GetString();
525 child = child->GetNext();
526 uint32_t styleId = StringUtils::StringToUint(key, UINT32_MAX);
527 if (styleId == UINT32_MAX) {
528 // Id format error.
529 continue;
530 }
531 const auto& oldValue = ThemeConstants::GetValue(styleId);
532 if (oldValue.type == ThemeConstantsType::ERROR) {
533 // Id not found.
534 continue;
535 }
536 if (!oldValue.isPublic) {
537 // Id is not public.
538 continue;
539 }
540 const auto& newValue = ThemeUtils::ParseStyleValue(styleId, oldValue, value);
541 // Replace default style with user custom style, use type to check parse success.
542 if (newValue.type == oldValue.type) {
543 customStyleMap_[styleId] = newValue;
544 }
545 }
546 }
547
LoadFile(const RefPtr<Asset> & asset)548 void ThemeConstants::LoadFile(const RefPtr<Asset>& asset)
549 {
550 if (!asset) {
551 return;
552 }
553
554 auto fileSize = asset->GetSize();
555 if (fileSize <= 0) {
556 return;
557 }
558 const auto& fileData = asset->GetData();
559 if (!fileData) {
560 return;
561 }
562 std::string styleContent;
563 styleContent.assign(fileData, fileData + fileSize);
564 if (styleContent.empty()) {
565 return;
566 }
567 ParseCustomStyle(styleContent);
568 }
569
SetColorScheme(ColorScheme colorScheme)570 void ThemeConstants::SetColorScheme(ColorScheme colorScheme)
571 {
572 if (!currentThemeStyle_) {
573 return;
574 }
575 if (colorScheme == ColorScheme::SCHEME_TRANSPARENT) {
576 currentThemeStyle_->SetAttr(
577 THEME_ATTR_BG_COLOR, { .type = ThemeConstantsType::COLOR, .value = TRANSPARENT_BG_COLOR });
578 }
579 }
580
GetPatternByName(const std::string & patternName)581 RefPtr<ThemeStyle> ThemeConstants::GetPatternByName(const std::string& patternName)
582 {
583 // if LocalColorMode is different from SystemColorMode, GetPattern from SysResMgr directly by LocolColorMode
584 if (auto pipelineContext = NG::PipelineContext::GetCurrentContext(); pipelineContext) {
585 ColorMode systemMode = pipelineContext->GetColorMode();
586 ColorMode localMode = pipelineContext->GetLocalColorMode();
587 if (localMode != ColorMode::COLOR_MODE_UNDEFINED && localMode != systemMode) {
588 // currentThemeStyle_ contains patterns for different color scheme, so need to get pattern from resAdapter_
589 auto patternStyle = resAdapter_ ? resAdapter_->GetPatternByName(patternName) : nullptr;
590 if (patternStyle != nullptr) {
591 return patternStyle;
592 }
593 }
594 }
595
596 if (!currentThemeStyle_) {
597 TAG_LOGE(AceLogTag::ACE_THEME, "Get theme by name error: currentThemeStyle_ is null");
598 return nullptr;
599 }
600 currentThemeStyle_->CheckThemeStyleLoaded(patternName);
601 auto patternStyle = currentThemeStyle_->GetAttr<RefPtr<ThemeStyle>>(patternName, nullptr);
602 if (!patternStyle && resAdapter_) {
603 patternStyle = resAdapter_->GetPatternByName(patternName);
604 ResValueWrapper value = { .type = ThemeConstantsType::PATTERN,
605 .value = patternStyle };
606 currentThemeStyle_->SetAttr(patternName, value);
607 }
608 return patternStyle;
609 }
610
611 } // namespace OHOS::Ace
612