• 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 
GetDimension(uint32_t key) const115 Dimension ThemeConstants::GetDimension(uint32_t key) const
116 {
117     if (IsGlobalResource(key)) {
118         if (!resAdapter_) {
119             return ERROR_VALUE_DIMENSION;
120         }
121         return resAdapter_->GetDimension(key);
122     }
123     const auto& valueWrapper = GetValue(key);
124     if (!ValueTypeMatch(valueWrapper, key, ThemeConstantsType::DIMENSION)) {
125         return ERROR_VALUE_DIMENSION;
126     }
127     auto dimensionPair = valueWrapper.GetValue<Dimension>(ERROR_VALUE_DIMENSION);
128     if (!dimensionPair.first) {
129         LOGE("GetDimension error: %{public}u, type: %{public}u", key, valueWrapper.type);
130     }
131     return dimensionPair.second;
132 }
133 
GetInt(uint32_t key) const134 int32_t ThemeConstants::GetInt(uint32_t key) const
135 {
136     if (IsGlobalResource(key)) {
137         if (!resAdapter_) {
138             return ERROR_VALUE_INT;
139         }
140         return resAdapter_->GetInt(key);
141     }
142     const auto& valueWrapper = GetValue(key);
143     if (!ValueTypeMatch(valueWrapper, key, ThemeConstantsType::INT)) {
144         return ERROR_VALUE_INT;
145     }
146     auto intPair = valueWrapper.GetValue<int32_t>(ERROR_VALUE_INT);
147     if (!intPair.first) {
148         LOGE("GetInt error: %{public}u, type: %{public}u", key, valueWrapper.type);
149     }
150     return intPair.second;
151 }
152 
GetDouble(uint32_t key) const153 double ThemeConstants::GetDouble(uint32_t key) const
154 {
155     if (IsGlobalResource(key)) {
156         if (!resAdapter_) {
157             return ERROR_VALUE_DOUBLE;
158         }
159         return resAdapter_->GetDouble(key);
160     }
161     const auto& valueWrapper = GetValue(key);
162     if (!ValueTypeMatch(valueWrapper, key, ThemeConstantsType::DOUBLE)) {
163         return ERROR_VALUE_DOUBLE;
164     }
165     auto doublePair = valueWrapper.GetValue<double>(ERROR_VALUE_DOUBLE);
166     if (!doublePair.first) {
167         LOGE("GetDouble error: %{public}u, type: %{public}u", key, valueWrapper.type);
168     }
169     return doublePair.second;
170 }
171 
GetString(uint32_t key) const172 std::string ThemeConstants::GetString(uint32_t key) const
173 {
174     if (IsGlobalResource(key)) {
175         if (!resAdapter_) {
176             return "";
177         }
178         return resAdapter_->GetString(key);
179     }
180     const auto& valueWrapper = GetValue(key);
181     if (!ValueTypeMatch(valueWrapper, key, ThemeConstantsType::STRING)) {
182         return "";
183     }
184     auto stringPair = valueWrapper.GetValue<std::string>("");
185     if (!stringPair.first) {
186         LOGE("GetString error: %{public}u, type: %{public}u", key, valueWrapper.type);
187     }
188     return stringPair.second;
189 }
190 
GetPluralString(uint32_t key,int count) const191 std::string ThemeConstants::GetPluralString(uint32_t key, int count) const
192 {
193     if (IsGlobalResource(key)) {
194         if (!resAdapter_) {
195             return "";
196         }
197         return resAdapter_->GetPluralString(key, count);
198     }
199     const auto& valueWrapper = GetValue(key);
200     if (!ValueTypeMatch(valueWrapper, key, ThemeConstantsType::STRING)) {
201         return "";
202     }
203     auto stringPair = valueWrapper.GetValue<std::string>("");
204     if (!stringPair.first) {
205         LOGE("GetPluralString error: %{public}u, type: %{public}u", key, valueWrapper.type);
206     }
207     return stringPair.second;
208 }
209 
GetStringArray(uint32_t key) const210 std::vector<std::string> ThemeConstants::GetStringArray(uint32_t key) const
211 {
212     if (IsGlobalResource(key)) {
213         if (!resAdapter_) {
214             return {};
215         }
216         return resAdapter_->GetStringArray(key);
217     }
218     return {};
219 }
220 
GetMediaPath(uint32_t key) const221 std::string ThemeConstants::GetMediaPath(uint32_t key) const
222 {
223     if (IsGlobalResource(key)) {
224         if (!resAdapter_) {
225             return "";
226         }
227         return resAdapter_->GetMediaPath(key);
228     }
229     return "";
230 }
231 
GetRawfile(const std::string & fileName) const232 std::string ThemeConstants::GetRawfile(const std::string& fileName) const
233 {
234     if (!resAdapter_) {
235         return "";
236     }
237     return resAdapter_->GetRawfile(fileName);
238 }
239 
GetBoolean(uint32_t key) const240 bool ThemeConstants::GetBoolean(uint32_t key) const
241 {
242     if (IsGlobalResource(key)) {
243         if (!resAdapter_) {
244             return false;
245         }
246         return resAdapter_->GetBoolean(key);
247     }
248     return false;
249 }
250 
GetIntArray(uint32_t key) const251 std::vector<uint32_t> ThemeConstants::GetIntArray(uint32_t key) const
252 {
253     if (IsGlobalResource(key)) {
254         if (!resAdapter_) {
255             return {};
256         }
257         return resAdapter_->GetIntArray(key);
258     }
259     return {};
260 }
261 
GetResourceIdByName(const std::string & resName,const std::string & resType,uint32_t & resId) const262 bool ThemeConstants::GetResourceIdByName(const std::string& resName, const std::string& resType, uint32_t& resId) const
263 {
264     if (!resAdapter_) {
265         return false;
266     }
267     return resAdapter_->GetIdByName(resName, resType, resId);
268 }
269 
GetResourceId(uint32_t key) const270 InternalResource::ResourceId ThemeConstants::GetResourceId(uint32_t key) const
271 {
272     const auto& valueWrapper = GetValue(key);
273     if (!ValueTypeMatch(valueWrapper, key, ThemeConstantsType::RESOURCE_ID)) {
274         return ERROR_VALUE_RESOURCE_ID;
275     }
276     auto resPair = valueWrapper.GetValue<InternalResource::ResourceId>(ERROR_VALUE_RESOURCE_ID);
277     if (!resPair.first) {
278         LOGE("GetResourceId error: %{public}u, type: %{public}u", key, valueWrapper.type);
279     }
280     return resPair.second;
281 }
282 
GetValue(uint32_t key) const283 ResValueWrapper ThemeConstants::GetValue(uint32_t key) const
284 {
285     // Find resource at custom styles.
286     auto customIter = customStyleMap_.find(key);
287     if (customIter != customStyleMap_.end()) {
288         return customIter->second;
289     }
290     // Find resource at prebuilt maps.
291     const auto platformConstants = ThemeConstants::GetPlatformConstants(key);
292 
293     if (platformConstants == nullptr) {
294         return ERROR_VALUE;
295     }
296     if (platformConstants->type != ThemeConstantsType::REFERENCE) {
297         return *platformConstants;
298     }
299     // This value point to another style, recursively find target.
300     auto uintPtr = std::get_if<uint32_t>(&(platformConstants->value));
301     if (!uintPtr) {
302         return ERROR_VALUE;
303     }
304     // Copy reference value, blend alpha if need(reference color and current blendAlpha < 1.0).
305     auto refValue = GetValue(*uintPtr);
306     refValue.isPublic = platformConstants->isPublic;
307     auto blendAlpha = GetBlendAlpha(platformConstants->blendAlpha);
308     if ((refValue.type == ThemeConstantsType::COLOR) && (blendAlpha < BLEND_ALPHA_MAX)) {
309         auto colorPtr = std::get_if<Color>(&refValue.value);
310         if (!colorPtr) {
311             return ERROR_VALUE;
312         }
313         refValue.value = colorPtr->BlendOpacity(blendAlpha);
314     }
315     return refValue;
316 }
317 
GetBlendAlpha(const BlendAlpha & blendAlpha) const318 double ThemeConstants::GetBlendAlpha(const BlendAlpha& blendAlpha) const
319 {
320     auto doublePtr = std::get_if<double>(&blendAlpha);
321     if (doublePtr) {
322         return *doublePtr;
323     }
324     auto idPtr = std::get_if<uint32_t>(&blendAlpha);
325     if (idPtr) {
326         return ThemeConstants::GetDouble(*idPtr);
327     }
328     return BLEND_ALPHA_MAX;
329 }
330 
LoadTheme(int32_t themeId)331 void ThemeConstants::LoadTheme(int32_t themeId)
332 {
333     if (!resAdapter_) {
334         LOGE("resAdapter_ is null, load theme resource failed!");
335         return;
336     }
337     currentThemeStyle_ = resAdapter_->GetTheme(themeId);
338     if (currentThemeStyle_) {
339         currentThemeStyle_->SetName(std::to_string(themeId));
340     }
341 }
342 
ParseTheme()343 void ThemeConstants::ParseTheme()
344 {
345     if (currentThemeStyle_) {
346         currentThemeStyle_->ParseContent();
347     }
348 }
349 
LoadCustomStyle(const RefPtr<AssetManager> & assetManager)350 void ThemeConstants::LoadCustomStyle(const RefPtr<AssetManager>& assetManager)
351 {
352     if (!assetManager) {
353         LOGE("AssetManager is null, load custom style failed!");
354         return;
355     }
356 
357     std::vector<std::string> files;
358 
359     assetManager->GetAssetList(STYLES_FOLDER_PATH, files);
360 
361     std::vector<std::string> fileNameList;
362     for (const auto& file : files) {
363         if (StringUtils::EndWith(file, FILE_TYPE_JSON)) {
364             fileNameList.emplace_back(file.substr(0, file.size() - (sizeof(FILE_TYPE_JSON) - 1)));
365         }
366     }
367 
368     std::vector<std::string> priorityFileList;
369     priorityFileList = AceResConfig::GetStyleResourceFallback(fileNameList);
370     for (auto fileIter = priorityFileList.rbegin(); fileIter != priorityFileList.rend(); ++fileIter) {
371         auto fileFullPath = STYLES_FOLDER_PATH + *fileIter + std::string(FILE_TYPE_JSON);
372         auto asset = assetManager->GetAsset(fileFullPath);
373         ThemeConstants::LoadFile(asset);
374     }
375 }
376 
ParseCustomStyle(const std::string & content)377 void ThemeConstants::ParseCustomStyle(const std::string& content)
378 {
379     auto rootJson = JsonUtil::ParseJsonString(content);
380     auto rootNode = rootJson->GetObject(CUSTOM_STYLE_ROOT_NAME);
381     if (rootNode->IsNull()) {
382         LOGE("Load custom style, root node 'style' not found.");
383         return;
384     }
385     auto child = rootNode->GetChild();
386     while (child && !child->IsNull()) {
387         const auto& key = child->GetKey();
388         const auto& value = child->GetString();
389         child = child->GetNext();
390         uint32_t styleId = StringUtils::StringToUint(key, UINT32_MAX);
391         if (styleId == UINT32_MAX) {
392             // Id format error.
393             continue;
394         }
395         const auto& oldValue = ThemeConstants::GetValue(styleId);
396         if (oldValue.type == ThemeConstantsType::ERROR) {
397             // Id not found.
398             continue;
399         }
400         if (!oldValue.isPublic) {
401             // Id is not public.
402             continue;
403         }
404         const auto& newValue = ThemeUtils::ParseStyleValue(styleId, oldValue, value);
405         // Replace default style with user custom style, use type to check parse success.
406         if (newValue.type == oldValue.type) {
407             customStyleMap_[styleId] = newValue;
408         }
409     }
410 }
411 
LoadFile(const RefPtr<Asset> & asset)412 void ThemeConstants::LoadFile(const RefPtr<Asset>& asset)
413 {
414     if (!asset) {
415         LOGD("No custom style found.");
416         return;
417     }
418 
419     auto fileSize = asset->GetSize();
420     if (fileSize <= 0) {
421         LOGD("Load custom style, file is empty.");
422         return;
423     }
424     const auto& fileData = asset->GetData();
425     if (!fileData) {
426         LOGD("Load custom style, file data is null.");
427         return;
428     }
429     std::string styleContent;
430     styleContent.assign(fileData, fileData + fileSize);
431     if (styleContent.empty()) {
432         return;
433     }
434     ParseCustomStyle(styleContent);
435 }
436 
SetColorScheme(ColorScheme colorScheme)437 void ThemeConstants::SetColorScheme(ColorScheme colorScheme)
438 {
439     if (!currentThemeStyle_) {
440         return;
441     }
442     if (colorScheme == ColorScheme::SCHEME_TRANSPARENT) {
443         currentThemeStyle_->SetAttr(
444             THEME_ATTR_BG_COLOR, { .type = ThemeConstantsType::COLOR, .value = TRANSPARENT_BG_COLOR });
445     }
446 }
447 
448 } // namespace OHOS::Ace
449