1 /*
2 * Copyright (c) 2021 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
GetMediaById(const int32_t & resId,std::string & mediaPath) const311 bool ThemeConstants::GetMediaById(const int32_t& resId, std::string& mediaPath) const
312 {
313 if (!resAdapter_) {
314 return false;
315 }
316 return resAdapter_->GetMediaById(resId, mediaPath);
317 }
318
GetBoolean(uint32_t key) const319 bool ThemeConstants::GetBoolean(uint32_t key) const
320 {
321 if (IsGlobalResource(key)) {
322 if (!resAdapter_) {
323 return false;
324 }
325 return resAdapter_->GetBoolean(key);
326 }
327 return false;
328 }
329
GetBooleanByName(const std::string & resName) const330 bool ThemeConstants::GetBooleanByName(const std::string& resName) const
331 {
332 if (!resAdapter_) {
333 return false;
334 }
335 return resAdapter_->GetBooleanByName(resName);
336 }
337
GetSymbolByName(const char * name) const338 uint32_t ThemeConstants::GetSymbolByName(const char* name) const
339 {
340 if (!resAdapter_) {
341 return ERROR_VALUE_UINT;
342 }
343 return resAdapter_->GetSymbolByName(name);
344 }
345
GetIntArray(uint32_t key) const346 std::vector<uint32_t> ThemeConstants::GetIntArray(uint32_t key) const
347 {
348 if (IsGlobalResource(key)) {
349 if (!resAdapter_) {
350 return {};
351 }
352 return resAdapter_->GetIntArray(key);
353 }
354 return {};
355 }
356
GetIntArrayByName(const std::string & resName) const357 std::vector<uint32_t> ThemeConstants::GetIntArrayByName(const std::string& resName) const
358 {
359 if (!resAdapter_) {
360 return {};
361 }
362 return resAdapter_->GetIntArrayByName(resName);
363 }
364
GetResourceIdByName(const std::string & resName,const std::string & resType,uint32_t & resId) const365 bool ThemeConstants::GetResourceIdByName(const std::string& resName, const std::string& resType, uint32_t& resId) const
366 {
367 if (!resAdapter_) {
368 return false;
369 }
370 return resAdapter_->GetIdByName(resName, resType, resId);
371 }
372
GetResourceId(uint32_t key) const373 InternalResource::ResourceId ThemeConstants::GetResourceId(uint32_t key) const
374 {
375 const auto& valueWrapper = GetValue(key);
376 if (!ValueTypeMatch(valueWrapper, key, ThemeConstantsType::RESOURCE_ID)) {
377 return ERROR_VALUE_RESOURCE_ID;
378 }
379 auto resPair = valueWrapper.GetValue<InternalResource::ResourceId>(ERROR_VALUE_RESOURCE_ID);
380 if (!resPair.first) {
381 TAG_LOGW(
382 AceLogTag::ACE_THEME, "Get theme resourceId error: %{public}u, type: %{public}u", key, valueWrapper.type);
383 }
384 return resPair.second;
385 }
386
GetPixelMap(uint32_t key) const387 std::shared_ptr<Media::PixelMap> ThemeConstants::GetPixelMap(uint32_t key) const
388 {
389 if (IsGlobalResource(key)) {
390 if (!resAdapter_) {
391 return nullptr;
392 }
393 return resAdapter_->GetPixelMap(key);
394 }
395 return nullptr;
396 }
397
GetValue(uint32_t key) const398 ResValueWrapper ThemeConstants::GetValue(uint32_t key) const
399 {
400 // Find resource at custom styles.
401 auto customIter = customStyleMap_.find(key);
402 if (customIter != customStyleMap_.end()) {
403 return customIter->second;
404 }
405 // Find resource at prebuilt maps.
406 const auto platformConstants = ThemeConstants::GetPlatformConstants(key);
407 if (platformConstants == nullptr) {
408 return ERROR_VALUE;
409 }
410 if (platformConstants->type != ThemeConstantsType::REFERENCE) {
411 return *platformConstants;
412 }
413 // This value point to another style, recursively find target.
414 auto uintPtr = std::get_if<uint32_t>(&(platformConstants->value));
415 if (!uintPtr) {
416 return ERROR_VALUE;
417 }
418 // Copy reference value, blend alpha if need(reference color and current blendAlpha < 1.0).
419 auto refValue = GetValue(*uintPtr);
420 refValue.isPublic = platformConstants->isPublic;
421 auto blendAlpha = GetBlendAlpha(platformConstants->blendAlpha);
422 if ((refValue.type == ThemeConstantsType::COLOR) && (blendAlpha < BLEND_ALPHA_MAX)) {
423 auto colorPtr = std::get_if<Color>(&refValue.value);
424 if (!colorPtr) {
425 return ERROR_VALUE;
426 }
427 refValue.value = colorPtr->BlendOpacity(blendAlpha);
428 }
429 return refValue;
430 }
431
GetBlendAlpha(const BlendAlpha & blendAlpha) const432 double ThemeConstants::GetBlendAlpha(const BlendAlpha& blendAlpha) const
433 {
434 auto doublePtr = std::get_if<double>(&blendAlpha);
435 if (doublePtr) {
436 return *doublePtr;
437 }
438 auto idPtr = std::get_if<uint32_t>(&blendAlpha);
439 if (idPtr) {
440 return ThemeConstants::GetDouble(*idPtr);
441 }
442 return BLEND_ALPHA_MAX;
443 }
444
LoadTheme(int32_t themeId)445 void ThemeConstants::LoadTheme(int32_t themeId)
446 {
447 if (!resAdapter_) {
448 return;
449 }
450 currentThemeStyle_ = resAdapter_->GetTheme(themeId);
451 if (currentThemeStyle_) {
452 currentThemeStyle_->SetName(std::to_string(themeId));
453 }
454 }
455
ParseTheme()456 void ThemeConstants::ParseTheme()
457 {
458 if (currentThemeStyle_) {
459 currentThemeStyle_->ParseContent();
460 }
461 }
462
LoadCustomStyle(const RefPtr<AssetManager> & assetManager)463 void ThemeConstants::LoadCustomStyle(const RefPtr<AssetManager>& assetManager)
464 {
465 if (!assetManager) {
466 return;
467 }
468
469 std::vector<std::string> files;
470
471 assetManager->GetAssetList(STYLES_FOLDER_PATH, files);
472
473 std::vector<std::string> fileNameList;
474 for (const auto& file : files) {
475 if (StringUtils::EndWith(file, FILE_TYPE_JSON)) {
476 fileNameList.emplace_back(file.substr(0, file.size() - (sizeof(FILE_TYPE_JSON) - 1)));
477 }
478 }
479
480 std::vector<std::string> priorityFileList;
481 priorityFileList = AceResConfig::GetStyleResourceFallback(fileNameList);
482 for (auto fileIter = priorityFileList.rbegin(); fileIter != priorityFileList.rend(); ++fileIter) {
483 auto fileFullPath = STYLES_FOLDER_PATH + *fileIter + std::string(FILE_TYPE_JSON);
484 auto asset = assetManager->GetAsset(fileFullPath);
485 ThemeConstants::LoadFile(asset);
486 }
487 }
488
ParseCustomStyle(const std::string & content)489 void ThemeConstants::ParseCustomStyle(const std::string& content)
490 {
491 auto rootJson = JsonUtil::ParseJsonString(content);
492 auto rootNode = rootJson->GetObject(CUSTOM_STYLE_ROOT_NAME);
493 if (rootNode->IsNull()) {
494 return;
495 }
496 auto child = rootNode->GetChild();
497 while (child && !child->IsNull()) {
498 const auto& key = child->GetKey();
499 const auto& value = child->GetString();
500 child = child->GetNext();
501 uint32_t styleId = StringUtils::StringToUint(key, UINT32_MAX);
502 if (styleId == UINT32_MAX) {
503 // Id format error.
504 continue;
505 }
506 const auto& oldValue = ThemeConstants::GetValue(styleId);
507 if (oldValue.type == ThemeConstantsType::ERROR) {
508 // Id not found.
509 continue;
510 }
511 if (!oldValue.isPublic) {
512 // Id is not public.
513 continue;
514 }
515 const auto& newValue = ThemeUtils::ParseStyleValue(styleId, oldValue, value);
516 // Replace default style with user custom style, use type to check parse success.
517 if (newValue.type == oldValue.type) {
518 customStyleMap_[styleId] = newValue;
519 }
520 }
521 }
522
LoadFile(const RefPtr<Asset> & asset)523 void ThemeConstants::LoadFile(const RefPtr<Asset>& asset)
524 {
525 if (!asset) {
526 return;
527 }
528
529 auto fileSize = asset->GetSize();
530 if (fileSize <= 0) {
531 return;
532 }
533 const auto& fileData = asset->GetData();
534 if (!fileData) {
535 return;
536 }
537 std::string styleContent;
538 styleContent.assign(fileData, fileData + fileSize);
539 if (styleContent.empty()) {
540 return;
541 }
542 ParseCustomStyle(styleContent);
543 }
544
SetColorScheme(ColorScheme colorScheme)545 void ThemeConstants::SetColorScheme(ColorScheme colorScheme)
546 {
547 if (!currentThemeStyle_) {
548 return;
549 }
550 if (colorScheme == ColorScheme::SCHEME_TRANSPARENT) {
551 currentThemeStyle_->SetAttr(
552 THEME_ATTR_BG_COLOR, { .type = ThemeConstantsType::COLOR, .value = TRANSPARENT_BG_COLOR });
553 }
554 }
555
556 } // namespace OHOS::Ace
557