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
20 namespace OHOS::Ace {
21 namespace {
22
23 const ResValueWrapper ERROR_VALUE = { .type = ThemeConstantsType::ERROR };
24 // Don't use Color::BLACK in case Color haven't been initialized.
25 const Color ERROR_VALUE_COLOR = Color(0xff000000);
26 constexpr Dimension ERROR_VALUE_DIMENSION = 0.0_vp;
27 constexpr int32_t ERROR_VALUE_INT = 0;
28 constexpr uint32_t ERROR_VALUE_UINT = 0;
29 constexpr double ERROR_VALUE_DOUBLE = 0.0;
30 constexpr double BLEND_ALPHA_MAX = 1.0;
31 constexpr InternalResource::ResourceId ERROR_VALUE_RESOURCE_ID = InternalResource::ResourceId::NO_ID;
32 const char STYLES_FOLDER_PATH[] = "resources/styles/";
33 const char FILE_TYPE_JSON[] = ".json";
34 const char CUSTOM_STYLE_ROOT_NAME[] = "style";
35 const Color TRANSPARENT_BG_COLOR = Color::FromRGBO(0, 0, 0, 0.2);
36 // For global resource manager system, system resource id is in [0x7000000, 0x7ffffff],
37 // and the id of resource defined by developer in the "resource" directory is greater than or equal to 0x1000000.
38 constexpr uint32_t GLOBAL_RESOURCE_ID_START = 0x1000000;
39
40 DeviceType g_deviceType = DeviceType::PHONE;
41
42 // Check whether value is match with expected type
ValueTypeMatch(const ResValueWrapper & valueWrapper,uint32_t key,const ThemeConstantsType & expectType)43 bool ValueTypeMatch(const ResValueWrapper& valueWrapper, uint32_t key, const ThemeConstantsType& expectType)
44 {
45 if (valueWrapper.type == ThemeConstantsType::ERROR) {
46 return false;
47 }
48 if (valueWrapper.type != expectType) {
49 return false;
50 }
51 return true;
52 }
53
IsGlobalResource(uint32_t resId)54 bool IsGlobalResource(uint32_t resId)
55 {
56 return resId >= GLOBAL_RESOURCE_ID_START;
57 }
58
59 } // namespace
60
InitDeviceType()61 void ThemeConstants::InitDeviceType()
62 {
63 g_deviceType = SystemProperties::GetDeviceType();
64 }
65
GetPlatformConstants(uint32_t key)66 const ResValueWrapper* ThemeConstants::GetPlatformConstants(uint32_t key)
67 {
68 #ifdef WEARABLE_PRODUCT
69 if (g_deviceType == DeviceType::WATCH && key < ThemeConstants::WatchMapCount &&
70 ThemeConstants::styleMapWatch[key] != nullptr) {
71 return ThemeConstants::styleMapWatch[key];
72 }
73 #else
74 if (g_deviceType == DeviceType::TV && key < ThemeConstants::TvMapCount &&
75 ThemeConstants::styleMapTv[key] != nullptr) {
76 return ThemeConstants::styleMapTv[key];
77 }
78 #endif
79 if (key < ThemeConstants::DefaultMapCount) {
80 return ThemeConstants::styleMapDefault[key];
81 }
82 return nullptr;
83 }
84
GetColor(uint32_t key) const85 Color ThemeConstants::GetColor(uint32_t key) const
86 {
87 if (IsGlobalResource(key)) {
88 if (!resAdapter_) {
89 return ERROR_VALUE_COLOR;
90 }
91 return resAdapter_->GetColor(key);
92 }
93 const auto& valueWrapper = GetValue(key);
94 if (!ValueTypeMatch(valueWrapper, key, ThemeConstantsType::COLOR)) {
95 return ERROR_VALUE_COLOR;
96 }
97 auto colorPair = valueWrapper.GetValue<Color>(ERROR_VALUE_COLOR);
98 if (!colorPair.first) {
99 TAG_LOGW(AceLogTag::ACE_THEME, "Get theme color error: %{public}u, type: %{public}u", key, valueWrapper.type);
100 }
101 return colorPair.second;
102 }
103
GetColorByName(const std::string & resName) const104 Color ThemeConstants::GetColorByName(const std::string& resName) const
105 {
106 if (!resAdapter_) {
107 return ERROR_VALUE_COLOR;
108 }
109 return resAdapter_->GetColorByName(resName);
110 }
111
GetDimension(uint32_t key) const112 Dimension ThemeConstants::GetDimension(uint32_t key) const
113 {
114 if (IsGlobalResource(key)) {
115 if (!resAdapter_) {
116 return ERROR_VALUE_DIMENSION;
117 }
118 auto result = resAdapter_->GetDimension(key);
119 if (NearZero(result.Value())) {
120 result = StringUtils::StringToDimension(resAdapter_->GetString(key));
121 }
122 return result;
123 }
124 const auto& valueWrapper = GetValue(key);
125 if (!ValueTypeMatch(valueWrapper, key, ThemeConstantsType::DIMENSION)) {
126 return ERROR_VALUE_DIMENSION;
127 }
128 auto dimensionPair = valueWrapper.GetValue<Dimension>(ERROR_VALUE_DIMENSION);
129 if (!dimensionPair.first) {
130 TAG_LOGW(
131 AceLogTag::ACE_THEME, "Get theme dimension error: %{public}u, type: %{public}u", key, valueWrapper.type);
132 }
133 return dimensionPair.second;
134 }
135
GetDimensionByName(const std::string & resName) const136 Dimension ThemeConstants::GetDimensionByName(const std::string& resName) const
137 {
138 if (!resAdapter_) {
139 return ERROR_VALUE_DIMENSION;
140 }
141 auto result = resAdapter_->GetDimensionByName(resName);
142 if (NearZero(result.Value())) {
143 result = StringUtils::StringToDimension(resAdapter_->GetStringByName(resName));
144 }
145 return result;
146 }
147
GetInt(uint32_t key) const148 int32_t ThemeConstants::GetInt(uint32_t key) const
149 {
150 if (IsGlobalResource(key)) {
151 if (!resAdapter_) {
152 return ERROR_VALUE_INT;
153 }
154 return resAdapter_->GetInt(key);
155 }
156 const auto& valueWrapper = GetValue(key);
157 if (!ValueTypeMatch(valueWrapper, key, ThemeConstantsType::INT)) {
158 return ERROR_VALUE_INT;
159 }
160 auto intPair = valueWrapper.GetValue<int32_t>(ERROR_VALUE_INT);
161 if (!intPair.first) {
162 TAG_LOGW(AceLogTag::ACE_THEME, "Get theme int error: %{public}u, type: %{public}u", key, valueWrapper.type);
163 }
164 return intPair.second;
165 }
166
GetIntByName(const std::string & resName) const167 int32_t ThemeConstants::GetIntByName(const std::string& resName) const
168 {
169 if (!resAdapter_) {
170 return ERROR_VALUE_INT;
171 }
172 return resAdapter_->GetIntByName(resName);
173 }
174
GetDouble(uint32_t key) const175 double ThemeConstants::GetDouble(uint32_t key) const
176 {
177 if (IsGlobalResource(key)) {
178 if (!resAdapter_) {
179 return ERROR_VALUE_DOUBLE;
180 }
181 return resAdapter_->GetDouble(key);
182 }
183 const auto& valueWrapper = GetValue(key);
184 if (!ValueTypeMatch(valueWrapper, key, ThemeConstantsType::DOUBLE)) {
185 return ERROR_VALUE_DOUBLE;
186 }
187 auto doublePair = valueWrapper.GetValue<double>(ERROR_VALUE_DOUBLE);
188 if (!doublePair.first) {
189 TAG_LOGW(AceLogTag::ACE_THEME, "Get theme double error: %{public}u, type: %{public}u", key, valueWrapper.type);
190 }
191 return doublePair.second;
192 }
193
GetDoubleByName(const std::string & resName) const194 double ThemeConstants::GetDoubleByName(const std::string& resName) const
195 {
196 if (!resAdapter_) {
197 return ERROR_VALUE_DOUBLE;
198 }
199 return resAdapter_->GetDoubleByName(resName);
200 }
201
GetString(uint32_t key) const202 std::string ThemeConstants::GetString(uint32_t key) const
203 {
204 if (IsGlobalResource(key)) {
205 if (!resAdapter_) {
206 return "";
207 }
208 return resAdapter_->GetString(key);
209 }
210 const auto& valueWrapper = GetValue(key);
211 if (!ValueTypeMatch(valueWrapper, key, ThemeConstantsType::STRING)) {
212 return "";
213 }
214 auto stringPair = valueWrapper.GetValue<std::string>("");
215 if (!stringPair.first) {
216 TAG_LOGW(AceLogTag::ACE_THEME, "Get theme string error: %{public}u, type: %{public}u", key, valueWrapper.type);
217 }
218 return stringPair.second;
219 }
220
GetStringByName(const std::string & resName) const221 std::string ThemeConstants::GetStringByName(const std::string& resName) const
222 {
223 if (!resAdapter_) {
224 return "";
225 }
226 return resAdapter_->GetStringByName(resName);
227 }
228
GetPluralString(uint32_t key,int count) const229 std::string ThemeConstants::GetPluralString(uint32_t key, int count) const
230 {
231 if (IsGlobalResource(key)) {
232 if (!resAdapter_) {
233 return "";
234 }
235 return resAdapter_->GetPluralString(key, count);
236 }
237 const auto& valueWrapper = GetValue(key);
238 if (!ValueTypeMatch(valueWrapper, key, ThemeConstantsType::STRING)) {
239 return "";
240 }
241 auto stringPair = valueWrapper.GetValue<std::string>("");
242 if (!stringPair.first) {
243 TAG_LOGW(AceLogTag::ACE_THEME, "Get theme pluralString error: %{public}u, type: %{public}u", key,
244 valueWrapper.type);
245 }
246 return stringPair.second;
247 }
248
GetPluralStringByName(const std::string & resName,int count) const249 std::string ThemeConstants::GetPluralStringByName(const std::string& resName, int count) const
250 {
251 if (!resAdapter_) {
252 return "";
253 }
254 return resAdapter_->GetPluralStringByName(resName, count);
255 }
256
GetStringArray(uint32_t key) const257 std::vector<std::string> ThemeConstants::GetStringArray(uint32_t key) const
258 {
259 if (IsGlobalResource(key)) {
260 if (!resAdapter_) {
261 return {};
262 }
263 return resAdapter_->GetStringArray(key);
264 }
265 return {};
266 }
267
GetStringArrayByName(const std::string & resName) const268 std::vector<std::string> ThemeConstants::GetStringArrayByName(const std::string& resName) const
269 {
270 if (!resAdapter_) {
271 return {};
272 }
273 return resAdapter_->GetStringArrayByName(resName);
274 }
275
GetMediaPath(uint32_t key) const276 std::string ThemeConstants::GetMediaPath(uint32_t key) const
277 {
278 if (IsGlobalResource(key)) {
279 if (!resAdapter_) {
280 return "";
281 }
282 return resAdapter_->GetMediaPath(key);
283 }
284 return "";
285 }
286
GetMediaPathByName(const std::string & resName) const287 std::string ThemeConstants::GetMediaPathByName(const std::string& resName) const
288 {
289 if (!resAdapter_) {
290 return "";
291 }
292 return resAdapter_->GetMediaPathByName(resName);
293 }
294
GetRawfile(const std::string & fileName) const295 std::string ThemeConstants::GetRawfile(const std::string& fileName) const
296 {
297 if (!resAdapter_) {
298 return "";
299 }
300 return resAdapter_->GetRawfile(fileName);
301 }
302
GetRawFileDescription(const std::string & rawfileName,RawfileDescription & rawfileDescription) const303 bool ThemeConstants::GetRawFileDescription(const std::string& rawfileName, RawfileDescription& rawfileDescription) const
304 {
305 if (!resAdapter_) {
306 return false;
307 }
308 return resAdapter_->GetRawFileDescription(rawfileName, rawfileDescription);
309 }
310
CloseRawFileDescription(const std::string & rawfileName) const311 bool ThemeConstants::CloseRawFileDescription(const std::string& rawfileName) const
312 {
313 if (!resAdapter_) {
314 return false;
315 }
316 return resAdapter_->CloseRawFileDescription(rawfileName);
317 }
318
GetMediaById(const int32_t & resId,std::string & mediaPath) const319 bool ThemeConstants::GetMediaById(const int32_t& resId, std::string& mediaPath) const
320 {
321 if (!resAdapter_) {
322 return false;
323 }
324 return resAdapter_->GetMediaById(resId, mediaPath);
325 }
326
GetBoolean(uint32_t key) const327 bool ThemeConstants::GetBoolean(uint32_t key) const
328 {
329 if (IsGlobalResource(key)) {
330 if (!resAdapter_) {
331 return false;
332 }
333 return resAdapter_->GetBoolean(key);
334 }
335 return false;
336 }
337
GetBooleanByName(const std::string & resName) const338 bool ThemeConstants::GetBooleanByName(const std::string& resName) const
339 {
340 if (!resAdapter_) {
341 return false;
342 }
343 return resAdapter_->GetBooleanByName(resName);
344 }
345
GetSymbolByName(const char * name) const346 uint32_t ThemeConstants::GetSymbolByName(const char* name) const
347 {
348 if (!resAdapter_) {
349 return ERROR_VALUE_UINT;
350 }
351 return resAdapter_->GetSymbolByName(name);
352 }
353
GetIntArray(uint32_t key) const354 std::vector<uint32_t> ThemeConstants::GetIntArray(uint32_t key) const
355 {
356 if (IsGlobalResource(key)) {
357 if (!resAdapter_) {
358 return {};
359 }
360 return resAdapter_->GetIntArray(key);
361 }
362 return {};
363 }
364
GetIntArrayByName(const std::string & resName) const365 std::vector<uint32_t> ThemeConstants::GetIntArrayByName(const std::string& resName) const
366 {
367 if (!resAdapter_) {
368 return {};
369 }
370 return resAdapter_->GetIntArrayByName(resName);
371 }
372
GetResourceIdByName(const std::string & resName,const std::string & resType,uint32_t & resId) const373 bool ThemeConstants::GetResourceIdByName(const std::string& resName, const std::string& resType, uint32_t& resId) const
374 {
375 if (!resAdapter_) {
376 return false;
377 }
378 return resAdapter_->GetIdByName(resName, resType, resId);
379 }
380
GetResourceId(uint32_t key) const381 InternalResource::ResourceId ThemeConstants::GetResourceId(uint32_t key) const
382 {
383 const auto& valueWrapper = GetValue(key);
384 if (!ValueTypeMatch(valueWrapper, key, ThemeConstantsType::RESOURCE_ID)) {
385 return ERROR_VALUE_RESOURCE_ID;
386 }
387 auto resPair = valueWrapper.GetValue<InternalResource::ResourceId>(ERROR_VALUE_RESOURCE_ID);
388 if (!resPair.first) {
389 TAG_LOGW(
390 AceLogTag::ACE_THEME, "Get theme resourceId error: %{public}u, type: %{public}u", key, valueWrapper.type);
391 }
392 return resPair.second;
393 }
394
GetPixelMap(uint32_t key) const395 std::shared_ptr<Media::PixelMap> ThemeConstants::GetPixelMap(uint32_t key) const
396 {
397 if (IsGlobalResource(key)) {
398 if (!resAdapter_) {
399 return nullptr;
400 }
401 return resAdapter_->GetPixelMap(key);
402 }
403 return nullptr;
404 }
405
GetValue(uint32_t key) const406 ResValueWrapper ThemeConstants::GetValue(uint32_t key) const
407 {
408 // Find resource at custom styles.
409 auto customIter = customStyleMap_.find(key);
410 if (customIter != customStyleMap_.end()) {
411 return customIter->second;
412 }
413 // Find resource at prebuilt maps.
414 const auto platformConstants = ThemeConstants::GetPlatformConstants(key);
415 if (platformConstants == nullptr) {
416 return ERROR_VALUE;
417 }
418 if (platformConstants->type != ThemeConstantsType::REFERENCE) {
419 return *platformConstants;
420 }
421 // This value point to another style, recursively find target.
422 auto uintPtr = std::get_if<uint32_t>(&(platformConstants->value));
423 if (!uintPtr) {
424 return ERROR_VALUE;
425 }
426 // Copy reference value, blend alpha if need(reference color and current blendAlpha < 1.0).
427 auto refValue = GetValue(*uintPtr);
428 refValue.isPublic = platformConstants->isPublic;
429 auto blendAlpha = GetBlendAlpha(platformConstants->blendAlpha);
430 if ((refValue.type == ThemeConstantsType::COLOR) && (blendAlpha < BLEND_ALPHA_MAX)) {
431 auto colorPtr = std::get_if<Color>(&refValue.value);
432 if (!colorPtr) {
433 return ERROR_VALUE;
434 }
435 refValue.value = colorPtr->BlendOpacity(blendAlpha);
436 }
437 return refValue;
438 }
439
GetBlendAlpha(const BlendAlpha & blendAlpha) const440 double ThemeConstants::GetBlendAlpha(const BlendAlpha& blendAlpha) const
441 {
442 auto doublePtr = std::get_if<double>(&blendAlpha);
443 if (doublePtr) {
444 return *doublePtr;
445 }
446 auto idPtr = std::get_if<uint32_t>(&blendAlpha);
447 if (idPtr) {
448 return ThemeConstants::GetDouble(*idPtr);
449 }
450 return BLEND_ALPHA_MAX;
451 }
452
LoadTheme(int32_t themeId)453 void ThemeConstants::LoadTheme(int32_t themeId)
454 {
455 if (!resAdapter_) {
456 return;
457 }
458 currentThemeStyle_ = resAdapter_->GetTheme(themeId);
459 if (currentThemeStyle_) {
460 currentThemeStyle_->SetName(std::to_string(themeId));
461 }
462 }
463
ParseTheme()464 void ThemeConstants::ParseTheme()
465 {
466 if (currentThemeStyle_) {
467 currentThemeStyle_->ParseContent();
468 }
469 }
470
LoadCustomStyle(const RefPtr<AssetManager> & assetManager)471 void ThemeConstants::LoadCustomStyle(const RefPtr<AssetManager>& assetManager)
472 {
473 if (!assetManager) {
474 return;
475 }
476
477 std::vector<std::string> files;
478
479 assetManager->GetAssetList(STYLES_FOLDER_PATH, files);
480
481 std::vector<std::string> fileNameList;
482 for (const auto& file : files) {
483 if (StringUtils::EndWith(file, FILE_TYPE_JSON)) {
484 fileNameList.emplace_back(file.substr(0, file.size() - (sizeof(FILE_TYPE_JSON) - 1)));
485 }
486 }
487
488 std::vector<std::string> priorityFileList;
489 priorityFileList = AceResConfig::GetStyleResourceFallback(fileNameList);
490 for (auto fileIter = priorityFileList.rbegin(); fileIter != priorityFileList.rend(); ++fileIter) {
491 auto fileFullPath = STYLES_FOLDER_PATH + *fileIter + std::string(FILE_TYPE_JSON);
492 auto asset = assetManager->GetAsset(fileFullPath);
493 ThemeConstants::LoadFile(asset);
494 }
495 }
496
ParseCustomStyle(const std::string & content)497 void ThemeConstants::ParseCustomStyle(const std::string& content)
498 {
499 auto rootJson = JsonUtil::ParseJsonString(content);
500 auto rootNode = rootJson->GetObject(CUSTOM_STYLE_ROOT_NAME);
501 if (rootNode->IsNull()) {
502 return;
503 }
504 auto child = rootNode->GetChild();
505 while (child && !child->IsNull()) {
506 const auto& key = child->GetKey();
507 const auto& value = child->GetString();
508 child = child->GetNext();
509 uint32_t styleId = StringUtils::StringToUint(key, UINT32_MAX);
510 if (styleId == UINT32_MAX) {
511 // Id format error.
512 continue;
513 }
514 const auto& oldValue = ThemeConstants::GetValue(styleId);
515 if (oldValue.type == ThemeConstantsType::ERROR) {
516 // Id not found.
517 continue;
518 }
519 if (!oldValue.isPublic) {
520 // Id is not public.
521 continue;
522 }
523 const auto& newValue = ThemeUtils::ParseStyleValue(styleId, oldValue, value);
524 // Replace default style with user custom style, use type to check parse success.
525 if (newValue.type == oldValue.type) {
526 customStyleMap_[styleId] = newValue;
527 }
528 }
529 }
530
LoadFile(const RefPtr<Asset> & asset)531 void ThemeConstants::LoadFile(const RefPtr<Asset>& asset)
532 {
533 if (!asset) {
534 return;
535 }
536
537 auto fileSize = asset->GetSize();
538 if (fileSize <= 0) {
539 return;
540 }
541 const auto& fileData = asset->GetData();
542 if (!fileData) {
543 return;
544 }
545 std::string styleContent;
546 styleContent.assign(fileData, fileData + fileSize);
547 if (styleContent.empty()) {
548 return;
549 }
550 ParseCustomStyle(styleContent);
551 }
552
SetColorScheme(ColorScheme colorScheme)553 void ThemeConstants::SetColorScheme(ColorScheme colorScheme)
554 {
555 if (!currentThemeStyle_) {
556 return;
557 }
558 if (colorScheme == ColorScheme::SCHEME_TRANSPARENT) {
559 currentThemeStyle_->SetAttr(
560 THEME_ATTR_BG_COLOR, { .type = ThemeConstantsType::COLOR, .value = TRANSPARENT_BG_COLOR });
561 }
562 }
563
564 } // namespace OHOS::Ace
565