• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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