• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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_utils.h"
17 
18 #include <cmath>
19 #include <regex>
20 #include <set>
21 
22 #include "base/log/log.h"
23 #include "base/utils/string_utils.h"
24 #include "base/utils/system_properties.h"
25 #include "core/components/theme/theme_constants.h"
26 #include "core/components/theme/theme_constants_defines.h"
27 
28 namespace OHOS::Ace {
29 namespace {
30 
31 constexpr uint32_t THEME_ID_MIN_SIZE = 5; // Input should contain "@id"
32 constexpr uint32_t THEME_ID_MATCH_SIZE = 2;
33 const std::regex THEME_ID_REGEX(R"(^\"@id([0-9]+)\"$)", std::regex::icase); // regex for "@id001"
34 constexpr uint32_t THEME_ATTR_MIN_SIZE = 7;
35 const std::regex THEME_ATTR_REGEX(R"(\?theme:([a-zA-Z0-9_]+))"); // regex for "?theme:attr_color_emphasis"
36 constexpr uint32_t CUSTOM_STYLE_STRING_MAX_SIZE = 128;
37 constexpr uint32_t OHOS_ID_MIN_SIZE = 7; // Input should contain "@ohos_id"
38 constexpr uint32_t SYSTEM_RES_ID_START = 0x7000000;
39 const std::regex OHOS_ID_REGEX(R"(^@ohos_id_([0-9]+)$)", std::regex::icase); // regex for "@ohos_id_001"
40 // regex for "@sys.type.xxx", xxx represents system resource id.
41 const std::regex SYS_TYPE_RES_ID_REGEX(R"(^@sys.(\w+).([0-9]+)$)", std::regex::icase);
42 constexpr uint32_t SYS_TYPE_RES_ID_MIN_SIZE = 7;
43 // regex for "@app.type.xxx", xxx represents application name.
44 const std::regex APP_TYPE_RES_NAME_REGEX(R"(^@app.(\w+).(\w+)$)", std::regex::icase);
45 constexpr uint32_t APP_TYPE_RES_NAME_MIN_SIZE = 7;
46 constexpr uint32_t TYPE_RESOURCE_MATCH_SIZE = 3;
47 // regex for "@sys.media.xxx", xxx represents system resource id.
48 const std::regex SYS_MEDIA_RES_ID_REGEX(R"(^@sys\.media\.([0-9]+)$)", std::regex::icase);
49 // regex for "@app.media.xxx", xxx represents resource name.
50 const std::regex APP_MEDIA_RES_NAME_REGEX(R"(^@app\.media\.(\w+)$)", std::regex::icase);
51 constexpr uint32_t MEDIA_RESOURCE_MATCH_SIZE = 2;
52 
53 const std::set<uint32_t> FONT_WEIGHT_STYLE_ID = {
54     THEME_BUTTON_TEXT_FONTWEIGHT,
55     THEME_DIALOG_TITLE_TEXT_FONTWEIGHT,
56     THEME_TOAST_TEXT_TEXT_FONTWEIGHT,
57     THEME_TEXTFIELD_FONT_WEIGHT,
58     THEME_SEARCH_FONT_WEIGHT
59 };
60 
61 } // namespace
62 
ParseThemeIdReference(const std::string & str,const RefPtr<ThemeConstants> & themeConstants)63 IdParseResult ThemeUtils::ParseThemeIdReference(const std::string& str, const RefPtr<ThemeConstants>& themeConstants)
64 {
65     std::smatch matches;
66     IdParseResult result { .parseSuccess = false, .isIdRef = false, .id = 0, .refAttr = "" };
67     if (str.size() > THEME_ID_MIN_SIZE && std::regex_match(str, matches, THEME_ID_REGEX) &&
68         matches.size() == THEME_ID_MATCH_SIZE) {
69         // Platform style id is no more than 32 bit.
70         result.id = static_cast<uint32_t>(std::stoul(matches[1].str()));
71         result.parseSuccess = true;
72         result.isIdRef = true;
73         return result;
74     }
75     if (str.size() > THEME_ATTR_MIN_SIZE && std::regex_match(str, matches, THEME_ATTR_REGEX) &&
76         matches.size() == THEME_ID_MATCH_SIZE) {
77         result.refAttr = matches[1].str();
78         result.parseSuccess = true;
79         result.isIdRef = false;
80         return result;
81     }
82     if (str.size() > OHOS_ID_MIN_SIZE && std::regex_match(str, matches, OHOS_ID_REGEX) &&
83         matches.size() == THEME_ID_MATCH_SIZE) {
84         // Platform style id is no more than 32 bit.
85         result.id = static_cast<uint32_t>(std::stoul(matches[1].str())) + SYSTEM_RES_ID_START;
86         result.parseSuccess = true;
87         result.isIdRef = true;
88         return result;
89     }
90     if (str.size() > SYS_TYPE_RES_ID_MIN_SIZE && std::regex_match(str, matches, SYS_TYPE_RES_ID_REGEX) &&
91         matches.size() == TYPE_RESOURCE_MATCH_SIZE) {
92         result.id = static_cast<uint32_t>(std::stoul(matches[2].str())) + SYSTEM_RES_ID_START;
93         result.parseSuccess = true;
94         result.isIdRef = true;
95         return result;
96     }
97     if (str.size() > APP_TYPE_RES_NAME_MIN_SIZE && std::regex_match(str, matches, APP_TYPE_RES_NAME_REGEX) &&
98         matches.size() == TYPE_RESOURCE_MATCH_SIZE) {
99         uint32_t resId = 0;
100         if (themeConstants && themeConstants->GetResourceIdByName(matches[2].str(), matches[1].str(), resId)) {
101             result.id = resId;
102             result.parseSuccess = true;
103             result.isIdRef = true;
104             return result;
105         }
106     }
107     // Not reference format, ignore.
108     return result;
109 }
110 
ParseStyleValue(uint32_t styleId,const ResValueWrapper & model,const std::string & value)111 ResValueWrapper ThemeUtils::ParseStyleValue(
112     uint32_t styleId, const ResValueWrapper& model, const std::string& value)
113 {
114     ResValueWrapper resultValue = { .type = model.type, .isPublic = model.isPublic };
115     if (FONT_WEIGHT_STYLE_ID.count(styleId) > 0) {
116         resultValue.value = static_cast<int32_t>(StringUtils::StringToFontWeight(value));
117         return resultValue;
118     }
119     switch (model.type) {
120         case ThemeConstantsType::COLOR:
121             resultValue.value = Color::FromString(value, COLOR_ALPHA_MASK);
122             break;
123         case ThemeConstantsType::DIMENSION:
124             resultValue.value = StringUtils::StringToDimension(value);
125             break;
126         case ThemeConstantsType::INT:
127             resultValue.value = StringUtils::StringToInt(value);
128             break;
129         case ThemeConstantsType::DOUBLE:
130             resultValue.value = StringUtils::StringToDouble(value);
131             break;
132         case ThemeConstantsType::STRING:
133             if (value.size() < CUSTOM_STYLE_STRING_MAX_SIZE) {
134                 resultValue.value = value;
135             } else {
136                 LOGE("Custom style value size over limit!");
137                 resultValue.type = ThemeConstantsType::ERROR;
138             }
139             break;
140         default:
141             resultValue.type = ThemeConstantsType::ERROR;
142             break;
143     }
144     return resultValue;
145 }
146 
ProcessImageSource(const std::string & imageSrc,const RefPtr<ThemeConstants> & themeConstants)147 std::string ThemeUtils::ProcessImageSource(const std::string& imageSrc, const RefPtr<ThemeConstants>& themeConstants)
148 {
149     std::smatch matches;
150     uint32_t resId = 0;
151     std::string resName;
152     if (std::regex_match(imageSrc, matches, APP_MEDIA_RES_NAME_REGEX) && matches.size() == MEDIA_RESOURCE_MATCH_SIZE) {
153         resName = matches[1].str();
154     }
155     if (std::regex_match(imageSrc, matches, SYS_MEDIA_RES_ID_REGEX) && matches.size() == MEDIA_RESOURCE_MATCH_SIZE) {
156         resId = static_cast<uint32_t>(std::stoul(matches[1].str())) + SYSTEM_RES_ID_START;
157     }
158     // not a image from global global resource manager subsystem, no need process.
159     if (resId == 0 && resName.empty()) {
160         return imageSrc;
161     }
162 
163     if (!themeConstants) {
164         LOGE("themeConstants is null, process image source failed");
165         return "";
166     }
167     if (resId == 0 && !themeConstants->GetResourceIdByName(resName, "media", resId)) {
168         LOGE("get image id failed");
169         return "";
170     }
171 
172     std::string imagePath = themeConstants->GetString(resId);
173     auto seperatorPos = imagePath.rfind('.');
174     if (seperatorPos == std::string::npos) {
175         LOGE("get image suffix failed");
176         return "";
177     }
178     // image format suffix, such as ".png",".svg" and so on.
179     std::string imageSuffix = imagePath.substr(seperatorPos);
180 
181     // resource name or resource id of image in global resource manager subsystem is the same in dark or light mode.
182     // image will not be reloaded if name is not changed when switching between dark and light modes.
183     std::string colorMode;
184     switch (SystemProperties::GetColorMode()) {
185         case ColorMode::LIGHT:
186             colorMode = "light";
187             break;
188         case ColorMode::DARK:
189             colorMode = "dark";
190             break;
191         default:
192             LOGW("color mode is undefined");
193             colorMode = "undefined";
194             break;
195     }
196     std::string result = "resource://" + colorMode + "/" + std::to_string(resId) + imageSuffix;
197     return result;
198 }
199 
200 } // namespace OHOS::Ace