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 if (g_deviceType == DeviceType::WATCH && key < ThemeConstants::WatchMapCount &&
70 ThemeConstants::styleMapWatch[key] != nullptr) {
71 return ThemeConstants::styleMapWatch[key];
72 }
73 if (g_deviceType == DeviceType::TV && key < ThemeConstants::TvMapCount &&
74 ThemeConstants::styleMapTv[key] != nullptr) {
75 return ThemeConstants::styleMapTv[key];
76 }
77 if (key < ThemeConstants::DefaultMapCount) {
78 return ThemeConstants::styleMapDefault[key];
79 }
80 return nullptr;
81 }
82
GetColor(uint32_t key) const83 Color ThemeConstants::GetColor(uint32_t key) const
84 {
85 if (IsGlobalResource(key)) {
86 if (!resAdapter_) {
87 return ERROR_VALUE_COLOR;
88 }
89 return resAdapter_->GetColor(key);
90 }
91 const auto& valueWrapper = GetValue(key);
92 if (!ValueTypeMatch(valueWrapper, key, ThemeConstantsType::COLOR)) {
93 return ERROR_VALUE_COLOR;
94 }
95 auto colorPair = valueWrapper.GetValue<Color>(ERROR_VALUE_COLOR);
96 if (!colorPair.first) {
97 TAG_LOGW(AceLogTag::ACE_THEME, "Get theme color error: %{public}u, type: %{public}u", key, valueWrapper.type);
98 }
99 return colorPair.second;
100 }
101
GetColorByName(const std::string & resName) const102 Color ThemeConstants::GetColorByName(const std::string& resName) const
103 {
104 if (!resAdapter_) {
105 return ERROR_VALUE_COLOR;
106 }
107 return resAdapter_->GetColorByName(resName);
108 }
109
GetDimension(uint32_t key) const110 Dimension ThemeConstants::GetDimension(uint32_t key) const
111 {
112 if (IsGlobalResource(key)) {
113 if (!resAdapter_) {
114 return ERROR_VALUE_DIMENSION;
115 }
116 auto result = resAdapter_->GetDimension(key);
117 if (NearZero(result.Value())) {
118 result = StringUtils::StringToDimension(resAdapter_->GetString(key));
119 }
120 return result;
121 }
122 const auto& valueWrapper = GetValue(key);
123 if (!ValueTypeMatch(valueWrapper, key, ThemeConstantsType::DIMENSION)) {
124 return ERROR_VALUE_DIMENSION;
125 }
126 auto dimensionPair = valueWrapper.GetValue<Dimension>(ERROR_VALUE_DIMENSION);
127 if (!dimensionPair.first) {
128 TAG_LOGW(
129 AceLogTag::ACE_THEME, "Get theme dimension error: %{public}u, type: %{public}u", key, valueWrapper.type);
130 }
131 return dimensionPair.second;
132 }
133
GetDimensionByName(const std::string & resName) const134 Dimension ThemeConstants::GetDimensionByName(const std::string& resName) const
135 {
136 if (!resAdapter_) {
137 return ERROR_VALUE_DIMENSION;
138 }
139 auto result = resAdapter_->GetDimensionByName(resName);
140 if (NearZero(result.Value())) {
141 result = StringUtils::StringToDimension(resAdapter_->GetStringByName(resName));
142 }
143 return result;
144 }
145
GetInt(uint32_t key) const146 int32_t ThemeConstants::GetInt(uint32_t key) const
147 {
148 if (IsGlobalResource(key)) {
149 if (!resAdapter_) {
150 return ERROR_VALUE_INT;
151 }
152 return resAdapter_->GetInt(key);
153 }
154 const auto& valueWrapper = GetValue(key);
155 if (!ValueTypeMatch(valueWrapper, key, ThemeConstantsType::INT)) {
156 return ERROR_VALUE_INT;
157 }
158 auto intPair = valueWrapper.GetValue<int32_t>(ERROR_VALUE_INT);
159 if (!intPair.first) {
160 TAG_LOGW(AceLogTag::ACE_THEME, "Get theme int error: %{public}u, type: %{public}u", key, valueWrapper.type);
161 }
162 return intPair.second;
163 }
164
GetIntByName(const std::string & resName) const165 int32_t ThemeConstants::GetIntByName(const std::string& resName) const
166 {
167 if (!resAdapter_) {
168 return ERROR_VALUE_INT;
169 }
170 return resAdapter_->GetIntByName(resName);
171 }
172
GetDouble(uint32_t key) const173 double ThemeConstants::GetDouble(uint32_t key) const
174 {
175 if (IsGlobalResource(key)) {
176 if (!resAdapter_) {
177 return ERROR_VALUE_DOUBLE;
178 }
179 return resAdapter_->GetDouble(key);
180 }
181 const auto& valueWrapper = GetValue(key);
182 if (!ValueTypeMatch(valueWrapper, key, ThemeConstantsType::DOUBLE)) {
183 return ERROR_VALUE_DOUBLE;
184 }
185 auto doublePair = valueWrapper.GetValue<double>(ERROR_VALUE_DOUBLE);
186 if (!doublePair.first) {
187 TAG_LOGW(AceLogTag::ACE_THEME, "Get theme double error: %{public}u, type: %{public}u", key, valueWrapper.type);
188 }
189 return doublePair.second;
190 }
191
GetDoubleByName(const std::string & resName) const192 double ThemeConstants::GetDoubleByName(const std::string& resName) const
193 {
194 if (!resAdapter_) {
195 return ERROR_VALUE_DOUBLE;
196 }
197 return resAdapter_->GetDoubleByName(resName);
198 }
199
GetString(uint32_t key) const200 std::string ThemeConstants::GetString(uint32_t key) const
201 {
202 if (IsGlobalResource(key)) {
203 if (!resAdapter_) {
204 return "";
205 }
206 return resAdapter_->GetString(key);
207 }
208 const auto& valueWrapper = GetValue(key);
209 if (!ValueTypeMatch(valueWrapper, key, ThemeConstantsType::STRING)) {
210 return "";
211 }
212 auto stringPair = valueWrapper.GetValue<std::string>("");
213 if (!stringPair.first) {
214 TAG_LOGW(AceLogTag::ACE_THEME, "Get theme string error: %{public}u, type: %{public}u", key, valueWrapper.type);
215 }
216 return stringPair.second;
217 }
218
GetStringByName(const std::string & resName) const219 std::string ThemeConstants::GetStringByName(const std::string& resName) const
220 {
221 if (!resAdapter_) {
222 return "";
223 }
224 return resAdapter_->GetStringByName(resName);
225 }
226
GetPluralString(uint32_t key,int count) const227 std::string ThemeConstants::GetPluralString(uint32_t key, int count) const
228 {
229 if (IsGlobalResource(key)) {
230 if (!resAdapter_) {
231 return "";
232 }
233 return resAdapter_->GetPluralString(key, count);
234 }
235 const auto& valueWrapper = GetValue(key);
236 if (!ValueTypeMatch(valueWrapper, key, ThemeConstantsType::STRING)) {
237 return "";
238 }
239 auto stringPair = valueWrapper.GetValue<std::string>("");
240 if (!stringPair.first) {
241 TAG_LOGW(AceLogTag::ACE_THEME, "Get theme pluralString error: %{public}u, type: %{public}u", key,
242 valueWrapper.type);
243 }
244 return stringPair.second;
245 }
246
GetPluralStringByName(const std::string & resName,int count) const247 std::string ThemeConstants::GetPluralStringByName(const std::string& resName, int count) const
248 {
249 if (!resAdapter_) {
250 return "";
251 }
252 return resAdapter_->GetPluralStringByName(resName, count);
253 }
254
GetStringArray(uint32_t key) const255 std::vector<std::string> ThemeConstants::GetStringArray(uint32_t key) const
256 {
257 if (IsGlobalResource(key)) {
258 if (!resAdapter_) {
259 return {};
260 }
261 return resAdapter_->GetStringArray(key);
262 }
263 return {};
264 }
265
GetStringArrayByName(const std::string & resName) const266 std::vector<std::string> ThemeConstants::GetStringArrayByName(const std::string& resName) const
267 {
268 if (!resAdapter_) {
269 return {};
270 }
271 return resAdapter_->GetStringArrayByName(resName);
272 }
273
GetMediaPath(uint32_t key) const274 std::string ThemeConstants::GetMediaPath(uint32_t key) const
275 {
276 if (IsGlobalResource(key)) {
277 if (!resAdapter_) {
278 return "";
279 }
280 return resAdapter_->GetMediaPath(key);
281 }
282 return "";
283 }
284
GetMediaPathByName(const std::string & resName) const285 std::string ThemeConstants::GetMediaPathByName(const std::string& resName) const
286 {
287 if (!resAdapter_) {
288 return "";
289 }
290 return resAdapter_->GetMediaPathByName(resName);
291 }
292
GetRawfile(const std::string & fileName) const293 std::string ThemeConstants::GetRawfile(const std::string& fileName) const
294 {
295 if (!resAdapter_) {
296 return "";
297 }
298 return resAdapter_->GetRawfile(fileName);
299 }
300
GetRawFileDescription(const std::string & rawfileName,RawfileDescription & rawfileDescription) const301 bool ThemeConstants::GetRawFileDescription(const std::string& rawfileName, RawfileDescription& rawfileDescription) const
302 {
303 if (!resAdapter_) {
304 return false;
305 }
306 return resAdapter_->GetRawFileDescription(rawfileName, rawfileDescription);
307 }
308
CloseRawFileDescription(const std::string & rawfileName) const309 bool ThemeConstants::CloseRawFileDescription(const std::string& rawfileName) const
310 {
311 if (!resAdapter_) {
312 return false;
313 }
314 return resAdapter_->CloseRawFileDescription(rawfileName);
315 }
316
GetRawFD(const std::string & rawfileName,RawfileDescription & rawfileDescription) const317 bool ThemeConstants::GetRawFD(const std::string& rawfileName, RawfileDescription& rawfileDescription) const
318 {
319 if (!resAdapter_) {
320 return false;
321 }
322 return resAdapter_->GetRawFD(rawfileName, rawfileDescription);
323 }
324
GetMediaById(const int32_t & resId,std::string & mediaPath) const325 bool ThemeConstants::GetMediaById(const int32_t& resId, std::string& mediaPath) const
326 {
327 if (!resAdapter_) {
328 return false;
329 }
330 return resAdapter_->GetMediaById(resId, mediaPath);
331 }
332
GetBoolean(uint32_t key) const333 bool ThemeConstants::GetBoolean(uint32_t key) const
334 {
335 if (IsGlobalResource(key)) {
336 if (!resAdapter_) {
337 return false;
338 }
339 return resAdapter_->GetBoolean(key);
340 }
341 return false;
342 }
343
GetBooleanByName(const std::string & resName) const344 bool ThemeConstants::GetBooleanByName(const std::string& resName) const
345 {
346 if (!resAdapter_) {
347 return false;
348 }
349 return resAdapter_->GetBooleanByName(resName);
350 }
351
GetSymbolByName(const char * name) const352 uint32_t ThemeConstants::GetSymbolByName(const char* name) const
353 {
354 if (!resAdapter_) {
355 return ERROR_VALUE_UINT;
356 }
357 return resAdapter_->GetSymbolByName(name);
358 }
359
GetIntArray(uint32_t key) const360 std::vector<uint32_t> ThemeConstants::GetIntArray(uint32_t key) const
361 {
362 if (IsGlobalResource(key)) {
363 if (!resAdapter_) {
364 return {};
365 }
366 return resAdapter_->GetIntArray(key);
367 }
368 return {};
369 }
370
GetIntArrayByName(const std::string & resName) const371 std::vector<uint32_t> ThemeConstants::GetIntArrayByName(const std::string& resName) const
372 {
373 if (!resAdapter_) {
374 return {};
375 }
376 return resAdapter_->GetIntArrayByName(resName);
377 }
378
GetResourceIdByName(const std::string & resName,const std::string & resType,uint32_t & resId) const379 bool ThemeConstants::GetResourceIdByName(const std::string& resName, const std::string& resType, uint32_t& resId) const
380 {
381 if (!resAdapter_) {
382 return false;
383 }
384 return resAdapter_->GetIdByName(resName, resType, resId);
385 }
386
GetResourceId(uint32_t key) const387 InternalResource::ResourceId ThemeConstants::GetResourceId(uint32_t key) const
388 {
389 const auto& valueWrapper = GetValue(key);
390 if (!ValueTypeMatch(valueWrapper, key, ThemeConstantsType::RESOURCE_ID)) {
391 return ERROR_VALUE_RESOURCE_ID;
392 }
393 auto resPair = valueWrapper.GetValue<InternalResource::ResourceId>(ERROR_VALUE_RESOURCE_ID);
394 if (!resPair.first) {
395 TAG_LOGW(
396 AceLogTag::ACE_THEME, "Get theme resourceId error: %{public}u, type: %{public}u", key, valueWrapper.type);
397 }
398 return resPair.second;
399 }
400
GetPixelMap(uint32_t key) const401 std::shared_ptr<Media::PixelMap> ThemeConstants::GetPixelMap(uint32_t key) const
402 {
403 if (IsGlobalResource(key)) {
404 if (!resAdapter_) {
405 return nullptr;
406 }
407 return resAdapter_->GetPixelMap(key);
408 }
409 return nullptr;
410 }
411
GetValue(uint32_t key) const412 ResValueWrapper ThemeConstants::GetValue(uint32_t key) const
413 {
414 // Find resource at custom styles.
415 auto customIter = customStyleMap_.find(key);
416 if (customIter != customStyleMap_.end()) {
417 return customIter->second;
418 }
419 // Find resource at prebuilt maps.
420 const auto platformConstants = ThemeConstants::GetPlatformConstants(key);
421 if (platformConstants == nullptr) {
422 return ERROR_VALUE;
423 }
424 if (platformConstants->type != ThemeConstantsType::REFERENCE) {
425 return *platformConstants;
426 }
427 // This value point to another style, recursively find target.
428 auto uintPtr = std::get_if<uint32_t>(&(platformConstants->value));
429 if (!uintPtr) {
430 return ERROR_VALUE;
431 }
432 // Copy reference value, blend alpha if need(reference color and current blendAlpha < 1.0).
433 auto refValue = GetValue(*uintPtr);
434 refValue.isPublic = platformConstants->isPublic;
435 auto blendAlpha = GetBlendAlpha(platformConstants->blendAlpha);
436 if ((refValue.type == ThemeConstantsType::COLOR) && (blendAlpha < BLEND_ALPHA_MAX)) {
437 auto colorPtr = std::get_if<Color>(&refValue.value);
438 if (!colorPtr) {
439 return ERROR_VALUE;
440 }
441 refValue.value = colorPtr->BlendOpacity(blendAlpha);
442 }
443 return refValue;
444 }
445
GetBlendAlpha(const BlendAlpha & blendAlpha) const446 double ThemeConstants::GetBlendAlpha(const BlendAlpha& blendAlpha) const
447 {
448 auto doublePtr = std::get_if<double>(&blendAlpha);
449 if (doublePtr) {
450 return *doublePtr;
451 }
452 auto idPtr = std::get_if<uint32_t>(&blendAlpha);
453 if (idPtr) {
454 return ThemeConstants::GetDouble(*idPtr);
455 }
456 return BLEND_ALPHA_MAX;
457 }
458
LoadTheme(int32_t themeId)459 void ThemeConstants::LoadTheme(int32_t themeId)
460 {
461 if (!resAdapter_) {
462 return;
463 }
464 currentThemeStyle_ = resAdapter_->GetTheme(themeId);
465 if (currentThemeStyle_) {
466 currentThemeStyle_->SetName(std::to_string(themeId));
467 }
468 }
469
ParseTheme()470 void ThemeConstants::ParseTheme()
471 {
472 if (currentThemeStyle_) {
473 currentThemeStyle_->ParseContent();
474 }
475 }
476
LoadCustomStyle(const RefPtr<AssetManager> & assetManager)477 void ThemeConstants::LoadCustomStyle(const RefPtr<AssetManager>& assetManager)
478 {
479 if (!assetManager) {
480 return;
481 }
482
483 std::vector<std::string> files;
484
485 assetManager->GetAssetList(STYLES_FOLDER_PATH, files);
486
487 std::vector<std::string> fileNameList;
488 for (const auto& file : files) {
489 if (StringUtils::EndWith(file, FILE_TYPE_JSON)) {
490 fileNameList.emplace_back(file.substr(0, file.size() - (sizeof(FILE_TYPE_JSON) - 1)));
491 }
492 }
493
494 std::vector<std::string> priorityFileList;
495 priorityFileList = AceResConfig::GetStyleResourceFallback(fileNameList);
496 for (auto fileIter = priorityFileList.rbegin(); fileIter != priorityFileList.rend(); ++fileIter) {
497 auto fileFullPath = STYLES_FOLDER_PATH + *fileIter + std::string(FILE_TYPE_JSON);
498 auto asset = assetManager->GetAsset(fileFullPath);
499 ThemeConstants::LoadFile(asset);
500 }
501 }
502
ParseCustomStyle(const std::string & content)503 void ThemeConstants::ParseCustomStyle(const std::string& content)
504 {
505 auto rootJson = JsonUtil::ParseJsonString(content);
506 auto rootNode = rootJson->GetObject(CUSTOM_STYLE_ROOT_NAME);
507 if (rootNode->IsNull()) {
508 return;
509 }
510 auto child = rootNode->GetChild();
511 while (child && !child->IsNull()) {
512 const auto& key = child->GetKey();
513 const auto& value = child->GetString();
514 child = child->GetNext();
515 uint32_t styleId = StringUtils::StringToUint(key, UINT32_MAX);
516 if (styleId == UINT32_MAX) {
517 // Id format error.
518 continue;
519 }
520 const auto& oldValue = ThemeConstants::GetValue(styleId);
521 if (oldValue.type == ThemeConstantsType::ERROR) {
522 // Id not found.
523 continue;
524 }
525 if (!oldValue.isPublic) {
526 // Id is not public.
527 continue;
528 }
529 const auto& newValue = ThemeUtils::ParseStyleValue(styleId, oldValue, value);
530 // Replace default style with user custom style, use type to check parse success.
531 if (newValue.type == oldValue.type) {
532 customStyleMap_[styleId] = newValue;
533 }
534 }
535 }
536
LoadFile(const RefPtr<Asset> & asset)537 void ThemeConstants::LoadFile(const RefPtr<Asset>& asset)
538 {
539 if (!asset) {
540 return;
541 }
542
543 auto fileSize = asset->GetSize();
544 if (fileSize <= 0) {
545 return;
546 }
547 const auto& fileData = asset->GetData();
548 if (!fileData) {
549 return;
550 }
551 std::string styleContent;
552 styleContent.assign(fileData, fileData + fileSize);
553 if (styleContent.empty()) {
554 return;
555 }
556 ParseCustomStyle(styleContent);
557 }
558
SetColorScheme(ColorScheme colorScheme)559 void ThemeConstants::SetColorScheme(ColorScheme colorScheme)
560 {
561 if (!currentThemeStyle_) {
562 return;
563 }
564 if (colorScheme == ColorScheme::SCHEME_TRANSPARENT) {
565 currentThemeStyle_->SetAttr(
566 THEME_ATTR_BG_COLOR, { .type = ThemeConstantsType::COLOR, .value = TRANSPARENT_BG_COLOR });
567 }
568 }
569
GetPatternByName(const std::string & patternName)570 RefPtr<ThemeStyle> ThemeConstants::GetPatternByName(const std::string& patternName)
571 {
572 // if LocalColorMode is different from SystemColorMode, GetPattern from SysResMgr directly by LocolColorMode
573 if (auto pipelineContext = NG::PipelineContext::GetCurrentContext(); pipelineContext) {
574 ColorMode systemMode = pipelineContext->GetColorMode();
575 ColorMode localMode = pipelineContext->GetLocalColorMode();
576 if (localMode != ColorMode::COLOR_MODE_UNDEFINED && localMode != systemMode) {
577 // currentThemeStyle_ contains patterns for different color scheme, so need to get pattern from resAdapter_
578 auto patternStyle = resAdapter_ ? resAdapter_->GetPatternByName(patternName) : nullptr;
579 if (patternStyle != nullptr) {
580 return patternStyle;
581 }
582 }
583 }
584
585 if (!currentThemeStyle_) {
586 TAG_LOGE(AceLogTag::ACE_THEME, "Get theme by name error: currentThemeStyle_ is null");
587 return nullptr;
588 }
589 currentThemeStyle_->CheckThemeStyleLoaded(patternName);
590 auto patternStyle = currentThemeStyle_->GetAttr<RefPtr<ThemeStyle>>(patternName, nullptr);
591 if (!patternStyle && resAdapter_) {
592 patternStyle = resAdapter_->GetPatternByName(patternName);
593 ResValueWrapper value = { .type = ThemeConstantsType::PATTERN,
594 .value = patternStyle };
595 currentThemeStyle_->SetAttr(patternName, value);
596 }
597 return patternStyle;
598 }
599
600 } // namespace OHOS::Ace
601