1 /*
2 * Copyright (c) 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 "adapter/ohos/osal/resource_theme_style.h"
17
18 #include <regex>
19 #include <set>
20 #include <string>
21
22 namespace OHOS::Ace {
23 namespace {
24 constexpr char COLOR_VALUE_PREFIX[] = "$color:";
25 constexpr char MEDIA_VALUE_PREFIX[] = "/";
26 constexpr char REF_ATTR_VALUE_KEY_WORD[] = "?theme:";
27
28 constexpr char RES_TAG[] = "resource:///";
29 // resource manager hap for system resource
30 constexpr char RES_HAP_PREFIX[] = "ohos.global.systemres";
31 #ifdef PREVIEW
32 constexpr char RES_PATH_TAG[] = "file://";
33 // resource manager hap absolute path, as resource manager api don't return
34 constexpr char RES_HAP_PATH[] = "../resources/";
35 #else
36 constexpr char RES_PATH_TAG[] = "file:///";
37 // resource manager hap absolute path, as resource manager api don't return
38 constexpr char RES_HAP_PATH[] = "/data/storage/el1/bundle/ohos.global.systemres/ohos.global.systemres/assets/";
39 #endif
40
41 const std::string DIMENSION_PATTERN = R"(^([+-]?\d+(\.\d+)?)(px|fp|lpx|vp|%)?)";
42 constexpr int32_t WAIT_FOR_TIME = 50;
43 static const std::set<std::string> stringAttrs = {
44 "attribute_text_font_family_regular",
45 "attribute_text_font_family_medium",
46 "description_current_location",
47 "description_add_location",
48 "description_select_location",
49 "description_share_location",
50 "description_send_location",
51 "description_locating",
52 "description_location",
53 "description_send_current_location",
54 "description_relocation",
55 "description_punch_in",
56 "description_current_position",
57 "description_paste",
58 "description_download",
59 "description_download_file",
60 "description_save",
61 "description_save_image",
62 "description_save_file",
63 "description_download_and_share",
64 "description_receive",
65 "description_continue_to_receive",
66 "description_save_to_gallery",
67 "description_export_to_gallery",
68 "description_quick_save_to_gallery",
69 "description_quick_resave_to_gallery",
70 "draggable",
71 "divider_shadow_enable",
72 "camera_input",
73 "menu_bg_blur_effect_enable",
74 "menu_double_border_enable",
75 "section_unfocus_effect_enable",
76 "section_unfocus_color",
77 "sheet_type",
78 "sheet_bottom",
79 "multiple_dialog_display",
80 "menu_expand_display",
81 "popup_double_border_enable",
82 "popup_outer_border_color",
83 "popup_inner_border_color",
84 "dialog_expand_display",
85 "show_password_directly",
86 "textfield_show_handle",
87 "dialog_radius_level10",
88 "dialog_icon_primary",
89 "dialog_font_primary",
90 "menu_has_filter",
91 "calendar_picker_dialog_button_transparent",
92 "calendar_picker_dialog_divider_transparent",
93 "textfield_accessibility_property_clear",
94 "textfield_accessibility_show_password",
95 "textfield_accessibility_hide_password",
96 "rich_editor_show_handle",
97 "text_show_handle",
98 "textfield_show_password_button",
99 "textfield_hide_password_button",
100 "textfield_has_showed_password",
101 "textfield_has_hidden_password",
102 "calendar_picker_mon",
103 "calendar_picker_tue",
104 "calendar_picker_wed",
105 "calendar_picker_thu",
106 "calendar_picker_fri",
107 "calendar_picker_sat",
108 "calendar_picker_sun",
109 "slider_accessibility_selected",
110 "slider_accessibility_unselected",
111 "slider_accessibility_unselectedDesc",
112 "pass_point",
113 "slider_accessibility_disabledDesc",
114 "textfield_accessibility_clear",
115 "textfield_writting_bundle_name",
116 "textfield_writting_ability_name",
117 "rich_editor_writting_bundle_name",
118 "rich_editor_writting_ability_name",
119 "textfield_writting_is_support",
120 "rich_editor_writting_is_support",
121 "ai_write_menu_name"
122 };
123
ParseNumberUnit(const std::string & value,std::string & number,std::string & unit)124 void ParseNumberUnit(const std::string& value, std::string& number, std::string& unit)
125 {
126 std::regex regex(DIMENSION_PATTERN);
127 std::smatch results;
128 if (std::regex_search(value, results, regex)) {
129 number = results[1];
130 // The unit is in the 3rd sub-match. If the value doesn't have unit,
131 // the 3rd match result is empty.
132 unit = results[3];
133 }
134 }
135
ParseDimensionUnit(const std::string & unit)136 DimensionUnit ParseDimensionUnit(const std::string& unit)
137 {
138 if (unit == "px") {
139 return DimensionUnit::PX;
140 } else if (unit == "fp") {
141 return DimensionUnit::FP;
142 } else if (unit == "lpx") {
143 return DimensionUnit::LPX;
144 } else if (unit == "%") {
145 return DimensionUnit::PERCENT;
146 } else {
147 return DimensionUnit::VP;
148 }
149 }
150 }
151
ParseContent()152 void ResourceThemeStyle::ParseContent()
153 {
154 for (auto& [attrName, attrValue] : rawAttrs_) {
155 if (attrName.empty() || attrValue.empty()) {
156 continue;
157 }
158 if (stringAttrs.find(attrName) != stringAttrs.end()) {
159 // string
160 attributes_[attrName] = { .type = ThemeConstantsType::STRING, .value = attrValue };
161 continue;
162 }
163 if (attrValue.front() == '#' || attrValue.find(COLOR_VALUE_PREFIX) != std::string::npos) {
164 // color
165 attributes_[attrName] = { .type = ThemeConstantsType::COLOR, .value = Color::FromString(attrValue) };
166 } else if (attrValue.find(MEDIA_VALUE_PREFIX) != std::string::npos) {
167 OnParseResourceMedia(attrName, attrValue);
168 } else if (attrValue.find(REF_ATTR_VALUE_KEY_WORD) != std::string::npos) {
169 attributes_[attrName] = { .type = ThemeConstantsType::REFERENCE_ATTR, .value = attrValue };
170 } else {
171 // int & double & dimension
172 std::string number;
173 std::string unit;
174 ParseNumberUnit(attrValue, number, unit);
175 if (number.empty()) {
176 continue;
177 } else if (!unit.empty()) {
178 attributes_[attrName] = { .type = ThemeConstantsType::DIMENSION,
179 .value = Dimension(std::atof(number.c_str()), ParseDimensionUnit(unit)) };
180 } else if (number.find(".") == std::string::npos) {
181 attributes_[attrName] = { .type = ThemeConstantsType::INT, .value = std::atoi(number.c_str()) };
182 } else {
183 attributes_[attrName] = { .type = ThemeConstantsType::DOUBLE, .value = std::atof(number.c_str()) };
184 }
185 }
186 }
187 OnParseStyle();
188 }
189
OnParseStyle()190 void ResourceThemeStyle::OnParseStyle()
191 {
192 for (auto& [patternName, patternMap]: patternAttrs_) {
193 auto patternStyle = AceType::MakeRefPtr<ResourceThemeStyle>(resAdapter_);
194 patternStyle->SetName(patternName);
195 patternStyle->parentStyle_ = AceType::WeakClaim(this);
196 patternStyle->rawAttrs_ = patternMap;
197 patternStyle->ParseContent();
198 attributes_[patternName] = { .type = ThemeConstantsType::PATTERN,
199 .value = RefPtr<ThemeStyle>(std::move(patternStyle)) };
200 }
201 }
202
OnParseResourceMedia(const std::string & attrName,const std::string & attrValue)203 void ResourceThemeStyle::OnParseResourceMedia(const std::string& attrName, const std::string& attrValue)
204 {
205 std::string mediaPath;
206 if (SystemProperties::GetUnZipHap()) {
207 mediaPath = RES_PATH_TAG;
208 if (attrValue.find(RES_HAP_PREFIX) == std::string::npos) {
209 mediaPath.append(RES_HAP_PATH);
210 }
211 #ifdef PREVIEW
212 auto pos = attrValue.find(MEDIA_VALUE_PREFIX);
213 if (pos == std::string::npos) {
214 return;
215 }
216 mediaPath += attrValue.substr(pos + 1);
217 #else
218 mediaPath += attrValue;
219 #endif
220 } else {
221 // hap is not unzip, should use resource name to read file
222 auto pos = attrValue.find_last_of(MEDIA_VALUE_PREFIX);
223 if (pos == std::string::npos) {
224 LOGW("resource media invalid:[%{public}s, %{public}s]", attrName.c_str(), attrValue.c_str());
225 return;
226 }
227 mediaPath = std::string(RES_TAG) + attrValue.substr(pos + 1);
228 }
229 attributes_[attrName] = { .type = ThemeConstantsType::STRING, .value = mediaPath };
230 }
231
CheckThemeStyleLoaded(const std::string & patternName)232 void ResourceThemeStyle::CheckThemeStyleLoaded(const std::string& patternName)
233 {
234 if (!CheckThemeStyle(patternName)) {
235 return;
236 }
237 if (future_.valid()) {
238 future_.wait_until(std::chrono::system_clock::now() + std::chrono::milliseconds(WAIT_FOR_TIME));
239 }
240 }
241 } // namespace OHOS::Ace
242