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