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