• 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     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