1 /*
2 * Copyright (c) 2023 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 #include "screen_scene_config.h"
16
17 #include <climits>
18 #include <cstdint>
19 #include <cstdlib>
20 #include <libxml/globals.h>
21 #include <libxml/xmlstring.h>
22 #include <map>
23 #include <string>
24 #include <utility>
25 #include <vector>
26
27 #include "config_policy_utils.h"
28 #include "include/core/SkMatrix.h"
29 #include "include/core/SkPath.h"
30 #include "include/core/SkPathMeasure.h"
31 #include "include/utils/SkParsePath.h"
32 #include "window_manager_hilog.h"
33
34 namespace OHOS::Rosen {
35 namespace {
36 constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_DISPLAY, "ScreenSceneConfig"};
37 constexpr char IS_WATERFALL_DISPLAY[] = "isWaterfallDisplay";
38 constexpr char CURVED_SCREEN_BOUNDARY[] = "curvedScreenBoundary";
39 constexpr char CURVED_AREA_IN_LANDSCAPE[] = "waterfallAreaCompressionSizeWhenHorzontal";
40 constexpr char IS_CURVED_COMPRESS_ENABLED[] = "isWaterfallAreaCompressionEnableWhenHorizontal";
41 constexpr uint32_t NO_WATERFALL_DISPLAY_COMPRESSION_SIZE = 0;
42 }
43
44 std::map<std::string, bool> ScreenSceneConfig::enableConfig_;
45 std::map<std::string, std::vector<int>> ScreenSceneConfig::intNumbersConfig_;
46 std::map<std::string, std::string> ScreenSceneConfig::stringConfig_;
47 std::vector<DMRect> ScreenSceneConfig::cutoutBoundaryRect_;
48 bool ScreenSceneConfig::isWaterfallDisplay_ = false;
49 bool ScreenSceneConfig::isScreenCompressionEnableInLandscape_ = false;
50 uint32_t ScreenSceneConfig::curvedAreaInLandscape_ = 0;
51
Split(std::string str,std::string pattern)52 std::vector<std::string> ScreenSceneConfig::Split(std::string str, std::string pattern)
53 {
54 std::vector<std::string> result;
55 str += pattern;
56 int32_t length = static_cast<int32_t>(str.size());
57 for (int32_t i = 0; i < length; i++) {
58 int32_t position = static_cast<int32_t>(str.find(pattern, i));
59 if (position < length) {
60 std::string tmp = str.substr(i, position - i);
61 result.push_back(tmp);
62 i = position + static_cast<int32_t>(pattern.size()) - 1;
63 }
64 }
65 return result;
66 }
67
IsNumber(std::string str)68 bool ScreenSceneConfig::IsNumber(std::string str)
69 {
70 if (str.size() == 0) {
71 return false;
72 }
73 for (int32_t i = 0; i < static_cast<int32_t>(str.size()); i++) {
74 if (str.at(i) < '0' || str.at(i) > '9') {
75 return false;
76 }
77 }
78 return true;
79 }
80
GetConfigPath(const std::string & configFileName)81 std::string ScreenSceneConfig::GetConfigPath(const std::string& configFileName)
82 {
83 char buf[PATH_MAX + 1];
84 char* configPath = GetOneCfgFile(configFileName.c_str(), buf, PATH_MAX + 1);
85 char tmpPath[PATH_MAX + 1] = { 0 };
86 if (!configPath || strlen(configPath) == 0 || strlen(configPath) > PATH_MAX || !realpath(configPath, tmpPath)) {
87 WLOGFI("[SsConfig] can not get customization config file");
88 return "/system/" + configFileName;
89 }
90 return std::string(tmpPath);
91 }
92
LoadConfigXml()93 bool ScreenSceneConfig::LoadConfigXml()
94 {
95 auto configFilePath = GetConfigPath("etc/window/resources/display_manager_config.xml");
96 xmlDocPtr docPtr = nullptr;
97 {
98 std::lock_guard<std::recursive_mutex> lock(mutex_);
99 docPtr = xmlReadFile(configFilePath.c_str(), nullptr, XML_PARSE_NOBLANKS);
100 }
101 WLOGFI("[SsConfig] filePath: %{public}s", configFilePath.c_str());
102 if (docPtr == nullptr) {
103 WLOGFE("[SsConfig] load xml error!");
104 return false;
105 }
106
107 xmlNodePtr rootPtr = xmlDocGetRootElement(docPtr);
108 if (rootPtr == nullptr || rootPtr->name == nullptr ||
109 xmlStrcmp(rootPtr->name, reinterpret_cast<const xmlChar*>("Configs"))) {
110 WLOGFE("[SsConfig] get root element failed!");
111 xmlFreeDoc(docPtr);
112 return false;
113 }
114
115 for (xmlNodePtr curNodePtr = rootPtr->xmlChildrenNode; curNodePtr != nullptr; curNodePtr = curNodePtr->next) {
116 if (!IsValidNode(*curNodePtr)) {
117 WLOGFE("SsConfig]: invalid node!");
118 continue;
119 }
120
121 auto nodeName = curNodePtr->name;
122 if (!xmlStrcmp(nodeName, reinterpret_cast<const xmlChar*>(IS_WATERFALL_DISPLAY)) ||
123 !xmlStrcmp(nodeName, reinterpret_cast<const xmlChar*>(IS_CURVED_COMPRESS_ENABLED))) {
124 ReadEnableConfigInfo(curNodePtr);
125 continue;
126 }
127 if (!xmlStrcmp(nodeName, reinterpret_cast<const xmlChar*>("dpi")) ||
128 !xmlStrcmp(nodeName, reinterpret_cast<const xmlChar*>("defaultDeviceRotationOffset")) ||
129 !xmlStrcmp(nodeName, reinterpret_cast<const xmlChar*>(CURVED_SCREEN_BOUNDARY)) ||
130 !xmlStrcmp(nodeName, reinterpret_cast<const xmlChar*>(CURVED_AREA_IN_LANDSCAPE)) ||
131 !xmlStrcmp(nodeName, reinterpret_cast<const xmlChar*>("buildInDefaultOrientation"))) {
132 ReadIntNumbersConfigInfo(curNodePtr);
133 continue;
134 }
135 if (!xmlStrcmp(nodeName, reinterpret_cast<const xmlChar*>("defaultDisplayCutoutPath"))) {
136 ReadStringConfigInfo(curNodePtr);
137 continue;
138 }
139 }
140 xmlFreeDoc(docPtr);
141 return true;
142 }
143
IsValidNode(const xmlNode & currNode)144 bool ScreenSceneConfig::IsValidNode(const xmlNode& currNode)
145 {
146 if (currNode.name == nullptr || currNode.type == XML_COMMENT_NODE) {
147 return false;
148 }
149 return true;
150 }
151
ReadIntNumbersConfigInfo(const xmlNodePtr & currNode)152 void ScreenSceneConfig::ReadIntNumbersConfigInfo(const xmlNodePtr& currNode)
153 {
154 xmlChar* context = xmlNodeGetContent(currNode);
155 if (context == nullptr) {
156 WLOGFE("[SsConfig] read xml node error: nodeName:(%{public}s)", currNode->name);
157 return;
158 }
159
160 std::vector<int> numbersVec;
161 std::string numbersStr = reinterpret_cast<const char*>(context);
162 if (numbersStr.empty()) {
163 xmlFree(context);
164 return;
165 }
166 auto numbers = Split(numbersStr, " ");
167 for (auto& num : numbers) {
168 if (!IsNumber(num)) {
169 WLOGFE("[SsConfig] read number error: nodeName:(%{public}s)", currNode->name);
170 xmlFree(context);
171 return;
172 }
173 numbersVec.emplace_back(std::stoi(num));
174 }
175
176 std::string nodeName = reinterpret_cast<const char *>(currNode->name);
177 intNumbersConfig_[nodeName] = numbersVec;
178 xmlFree(context);
179 }
180
ReadEnableConfigInfo(const xmlNodePtr & currNode)181 void ScreenSceneConfig::ReadEnableConfigInfo(const xmlNodePtr& currNode)
182 {
183 xmlChar* enable = xmlGetProp(currNode, reinterpret_cast<const xmlChar*>("enable"));
184 if (enable == nullptr) {
185 WLOGFE("[SsConfig] read xml node error: nodeName:(%{public}s)", currNode->name);
186 return;
187 }
188
189 std::string nodeName = reinterpret_cast<const char *>(currNode->name);
190 if (!xmlStrcmp(enable, reinterpret_cast<const xmlChar*>("true"))) {
191 enableConfig_[nodeName] = true;
192 if (IS_WATERFALL_DISPLAY == nodeName) {
193 isWaterfallDisplay_ = true;
194 } else if (IS_CURVED_COMPRESS_ENABLED == nodeName) {
195 isScreenCompressionEnableInLandscape_ = true;
196 }
197 } else {
198 enableConfig_[nodeName] = false;
199 }
200 xmlFree(enable);
201 }
202
ReadStringConfigInfo(const xmlNodePtr & currNode)203 void ScreenSceneConfig::ReadStringConfigInfo(const xmlNodePtr& currNode)
204 {
205 xmlChar* context = xmlNodeGetContent(currNode);
206 if (context == nullptr) {
207 WLOGFE("[SsConfig] read xml node error: nodeName:(%{public}s)", currNode->name);
208 return;
209 }
210
211 std::string inputString = reinterpret_cast<const char*>(context);
212 std::string nodeName = reinterpret_cast<const char*>(currNode->name);
213 stringConfig_[nodeName] = inputString;
214 xmlFree(context);
215 }
216
GetEnableConfig()217 const std::map<std::string, bool>& ScreenSceneConfig::GetEnableConfig()
218 {
219 return enableConfig_;
220 }
221
GetIntNumbersConfig()222 const std::map<std::string, std::vector<int>>& ScreenSceneConfig::GetIntNumbersConfig()
223 {
224 return intNumbersConfig_;
225 }
226
GetStringConfig()227 const std::map<std::string, std::string>& ScreenSceneConfig::GetStringConfig()
228 {
229 return stringConfig_;
230 }
231
DumpConfig()232 void ScreenSceneConfig::DumpConfig()
233 {
234 for (auto& enable : enableConfig_) {
235 WLOGFI("[SsConfig] Enable: %{public}s %{public}u", enable.first.c_str(), enable.second);
236 }
237 for (auto& numbers : intNumbersConfig_) {
238 WLOGFI("[SsConfig] Numbers: %{public}s %{public}zu", numbers.first.c_str(), numbers.second.size());
239 for (auto& num : numbers.second) {
240 WLOGFI("[SsConfig] Num: %{public}d", num);
241 }
242 }
243 for (auto& string : stringConfig_) {
244 WLOGFI("[SsConfig] String: %{public}s", string.first.c_str());
245 }
246 }
247
SetCutoutSvgPath(const std::string & svgPath)248 void ScreenSceneConfig::SetCutoutSvgPath(const std::string& svgPath)
249 {
250 cutoutBoundaryRect_.clear();
251 cutoutBoundaryRect_.emplace_back(CalcCutoutBoundaryRect(svgPath));
252 }
253
CalcCutoutBoundaryRect(std::string svgPath)254 DMRect ScreenSceneConfig::CalcCutoutBoundaryRect(std::string svgPath)
255 {
256 DMRect emptyRect = { 0, 0, 0, 0 };
257 SkPath skCutoutSvgPath;
258 if (!SkParsePath::FromSVGString(svgPath.c_str(), &skCutoutSvgPath)) {
259 WLOGFE("Parse svg string path failed.");
260 return emptyRect;
261 }
262 SkRect skRect = skCutoutSvgPath.computeTightBounds();
263 if (skRect.isEmpty()) {
264 WLOGFW("Get empty skRect");
265 return emptyRect;
266 }
267 SkIRect skiRect = skRect.roundOut();
268 if (skiRect.isEmpty()) {
269 WLOGFW("Get empty skiRect");
270 return emptyRect;
271 }
272 int32_t left = static_cast<int32_t>(skiRect.left());
273 int32_t top = static_cast<int32_t>(skiRect.top());
274 uint32_t width = static_cast<uint32_t>(skiRect.width());
275 uint32_t height = static_cast<uint32_t>(skiRect.height());
276 WLOGFI("calc cutout boundary rect - left: [%{public}d top: %{public}d width: %{public}u height: %{public}u]", left,
277 top, width, height);
278 DMRect cutoutMinOuterRect = {
279 .posX_ = left,
280 .posY_ = top,
281 .width_ = width,
282 .height_ = height
283 };
284 return cutoutMinOuterRect;
285 }
286
GetCutoutBoundaryRect()287 std::vector<DMRect> ScreenSceneConfig::GetCutoutBoundaryRect()
288 {
289 return cutoutBoundaryRect_;
290 }
291
IsWaterfallDisplay()292 bool ScreenSceneConfig::IsWaterfallDisplay()
293 {
294 return isWaterfallDisplay_;
295 }
296
SetCurvedCompressionAreaInLandscape()297 void ScreenSceneConfig::SetCurvedCompressionAreaInLandscape()
298 {
299 if (intNumbersConfig_[CURVED_AREA_IN_LANDSCAPE].size() > 0) {
300 curvedAreaInLandscape_ = static_cast<uint32_t>(intNumbersConfig_[CURVED_AREA_IN_LANDSCAPE][0]);
301 } else {
302 WLOGFW("waterfallAreaCompressionSizeWhenHorzontal value is not exist");
303 }
304 }
305
GetCurvedScreenBoundaryConfig()306 std::vector<int> ScreenSceneConfig::GetCurvedScreenBoundaryConfig()
307 {
308 return intNumbersConfig_[CURVED_SCREEN_BOUNDARY];
309 }
310
GetCurvedCompressionAreaInLandscape()311 uint32_t ScreenSceneConfig::GetCurvedCompressionAreaInLandscape()
312 {
313 if (!isWaterfallDisplay_ || !isScreenCompressionEnableInLandscape_) {
314 WLOGFW("noy waterfall screen or waterfall compression is not enabled");
315 return NO_WATERFALL_DISPLAY_COMPRESSION_SIZE;
316 }
317 return curvedAreaInLandscape_;
318 }
319 } // namespace OHOS::Rosen
320