1 /*
2 * Copyright (c) 2022-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
16 #include "display_cutout_controller.h"
17 #include <screen_manager/screen_types.h>
18 #include "display_manager_service_inner.h"
19
20 namespace OHOS {
21 namespace Rosen {
22 namespace {
23 constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_DISPLAY, "DisplayCutoutController"};
24 const uint32_t NO_WATERFALL_DISPLAY_COMPRESSION_SIZE = 0;
25 }
26
27 bool DisplayCutoutController::isWaterfallDisplay_ = false;
28 bool DisplayCutoutController::isWaterfallAreaCompressionEnableWhenHorizontal_ = false;
29 uint32_t DisplayCutoutController::waterfallAreaCompressionSizeWhenHorizontal_ = 0;
30
SetBuiltInDisplayCutoutSvgPath(const std::string & svgPath)31 void DisplayCutoutController::SetBuiltInDisplayCutoutSvgPath(const std::string& svgPath)
32 {
33 SetCutoutSvgPath(0, svgPath);
34 }
35
SetIsWaterfallDisplay(bool isWaterfallDisplay)36 void DisplayCutoutController::SetIsWaterfallDisplay(bool isWaterfallDisplay)
37 {
38 WLOGFI("Set isWaterfallDisplay: %{public}u", isWaterfallDisplay);
39 isWaterfallDisplay_ = isWaterfallDisplay;
40 }
41
IsWaterfallDisplay()42 bool DisplayCutoutController::IsWaterfallDisplay()
43 {
44 return isWaterfallDisplay_;
45 }
46
SetCurvedScreenBoundary(std::vector<int> curvedScreenBoundary)47 void DisplayCutoutController::SetCurvedScreenBoundary(std::vector<int> curvedScreenBoundary)
48 {
49 while (curvedScreenBoundary.size() < 4) { // 4 directions.
50 curvedScreenBoundary.emplace_back(0);
51 }
52 WLOGFI("Set curvedScreenBoundary");
53 curvedScreenBoundary_ = curvedScreenBoundary;
54 }
55
SetCutoutSvgPath(DisplayId displayId,const std::string & svgPath)56 void DisplayCutoutController::SetCutoutSvgPath(DisplayId displayId, const std::string& svgPath)
57 {
58 WLOGFI("Set SvgPath: %{public}s", svgPath.c_str());
59 if (svgPaths_.count(displayId) == 1) {
60 svgPaths_[displayId].emplace_back(svgPath);
61 } else {
62 std::vector<std::string> pathVec;
63 pathVec.emplace_back(svgPath);
64 svgPaths_[displayId] = pathVec;
65 }
66 DMRect boundingRect = CalcCutoutBoundingRect(svgPath);
67 if (boundingRects_.count(displayId) == 1) {
68 boundingRects_[displayId].emplace_back(boundingRect);
69 } else {
70 std::vector<DMRect> rectVec;
71 rectVec.emplace_back(boundingRect);
72 boundingRects_[displayId] = rectVec;
73 }
74 }
75
GetCutoutInfo(DisplayId displayId)76 sptr<CutoutInfo> DisplayCutoutController::GetCutoutInfo(DisplayId displayId)
77 {
78 WLOGFD("Get Cutout Info");
79 std::vector<DMRect> boundingRects;
80 WaterfallDisplayAreaRects waterfallDisplayAreaRects;
81 if (boundingRects_.count(displayId) == 1) {
82 TransferBoundingRectsByRotation(displayId, boundingRects);
83 }
84 if (displayId == DisplayManagerServiceInner::GetInstance().GetDefaultDisplayId()) {
85 CalcBuiltInDisplayWaterfallRects();
86 waterfallDisplayAreaRects = waterfallDisplayAreaRects_;
87 }
88 sptr<CutoutInfo> cutoutInfo(new CutoutInfo(boundingRects, waterfallDisplayAreaRects));
89 return cutoutInfo;
90 }
91
CheckBoundingRectsBoundary(DisplayId displayId,std::vector<DMRect> & boundingRects)92 void DisplayCutoutController::CheckBoundingRectsBoundary(DisplayId displayId, std::vector<DMRect>& boundingRects)
93 {
94 sptr<SupportedScreenModes> modes =
95 DisplayManagerServiceInner::GetInstance().GetScreenModesByDisplayId(displayId);
96 if (modes == nullptr) {
97 WLOGFE("DisplayId is invalid");
98 return;
99 }
100 uint32_t displayHeight = modes->height_;
101 uint32_t displayWidth = modes->width_;
102 for (auto iter = boundingRects.begin(); iter != boundingRects.end();) {
103 DMRect boundingRect = *iter;
104 if (boundingRect.posX_ < 0 || boundingRect.posY_ < 0 ||
105 static_cast<int32_t>(boundingRect.width_) + boundingRect.posX_ > static_cast<int32_t>(displayWidth) ||
106 static_cast<int32_t>(boundingRect.height_) + boundingRect.posY_ > static_cast<int32_t>(displayHeight) ||
107 boundingRect.width_ > displayWidth || boundingRect.height_ > displayHeight ||
108 boundingRect.IsUninitializedRect()) {
109 WLOGFE("boundingRect boundary is invalid");
110 iter = boundingRects.erase(iter);
111 } else {
112 iter++;
113 }
114 }
115 }
116
CalcCutoutBoundingRect(std::string svgPath)117 DMRect DisplayCutoutController::CalcCutoutBoundingRect(std::string svgPath)
118 {
119 DMRect emptyRect = {0, 0, 0, 0};
120 SkPath skCutoutSvgPath;
121 if (!SkParsePath::FromSVGString(svgPath.c_str(), &skCutoutSvgPath)) {
122 WLOGFE("Parse svg string path failed.");
123 return emptyRect;
124 }
125 SkRect skRect = skCutoutSvgPath.computeTightBounds();
126 if (skRect.isEmpty()) {
127 WLOGFW("Get empty skRect");
128 return emptyRect;
129 }
130 SkIRect skiRect = skRect.roundOut();
131 if (skiRect.isEmpty()) {
132 WLOGFW("Get empty skiRect");
133 return emptyRect;
134 }
135 int32_t left = static_cast<int32_t>(skiRect.left());
136 int32_t top = static_cast<int32_t>(skiRect.top());
137 uint32_t width = static_cast<uint32_t>(skiRect.width());
138 uint32_t height = static_cast<uint32_t>(skiRect.height());
139 WLOGFI("calc rect from path,[%{public}d, %{public}d, %{public}u, %{public}u]", left, top, width, height);
140 DMRect cutoutMinOuterRect = {.posX_ = left, .posY_ = top, .width_ = width, .height_ = height};
141 return cutoutMinOuterRect;
142 }
143
CalcBuiltInDisplayWaterfallRects()144 void DisplayCutoutController::CalcBuiltInDisplayWaterfallRects()
145 {
146 WaterfallDisplayAreaRects emptyRects = {};
147 if (!isWaterfallDisplay_) {
148 WLOGFI("not waterfall display");
149 waterfallDisplayAreaRects_ = emptyRects;
150 return;
151 }
152 if (curvedScreenBoundary_.empty()) {
153 WLOGFI("curved screen boundary is empty");
154 waterfallDisplayAreaRects_ = emptyRects;
155 return;
156 }
157 uint32_t left = static_cast<uint32_t>(curvedScreenBoundary_[0]);
158 uint32_t top = static_cast<uint32_t>(curvedScreenBoundary_[1]);
159 uint32_t right = static_cast<uint32_t>(curvedScreenBoundary_[2]);
160 uint32_t bottom = static_cast<uint32_t>(curvedScreenBoundary_[3]);
161 if (left == 0 && top == 0 && right == 0 && bottom == 0) {
162 waterfallDisplayAreaRects_ = emptyRects;
163 return;
164 }
165 sptr<SupportedScreenModes> modes =
166 DisplayManagerServiceInner::GetInstance().GetScreenModesByDisplayId(
167 DisplayManagerServiceInner::GetInstance().GetDefaultDisplayId());
168 if (!modes) {
169 WLOGE("support screen modes get failed");
170 waterfallDisplayAreaRects_ = emptyRects;
171 return;
172 }
173 uint32_t displayHeight = modes->height_;
174 uint32_t displayWidth = modes->width_;
175
176 if ((left > displayWidth / 2) || (right > displayWidth / 2) || // invalid if more than 1/2 width
177 (top > displayHeight / 2) || (bottom > displayHeight / 2)) { // invalid if more than 1/2 height
178 WLOGFE("Curved screen boundary data is not valid.");
179 waterfallDisplayAreaRects_ = emptyRects;
180 return;
181 }
182 CalcBuiltInDisplayWaterfallRectsByRotation(
183 DisplayManagerServiceInner::GetInstance().GetDefaultDisplay()->GetRotation(),
184 displayHeight, displayWidth);
185 }
186
CalcBuiltInDisplayWaterfallRectsByRotation(Rotation rotation,uint32_t displayHeight,uint32_t displayWidth)187 void DisplayCutoutController::CalcBuiltInDisplayWaterfallRectsByRotation(
188 Rotation rotation, uint32_t displayHeight, uint32_t displayWidth)
189 {
190 uint32_t left = static_cast<uint32_t>(curvedScreenBoundary_[0]);
191 uint32_t top = static_cast<uint32_t>(curvedScreenBoundary_[1]);
192 uint32_t right = static_cast<uint32_t>(curvedScreenBoundary_[2]);
193 uint32_t bottom = static_cast<uint32_t>(curvedScreenBoundary_[3]);
194 switch (rotation) {
195 case Rotation::ROTATION_0: {
196 DMRect leftRect = CreateWaterfallRect(0, 0, left, displayHeight);
197 DMRect topRect = CreateWaterfallRect(0, 0, displayWidth, top);
198 DMRect rightRect = CreateWaterfallRect(displayWidth - right, 0, right, displayHeight);
199 DMRect bottomRect = CreateWaterfallRect(0, displayHeight - bottom, displayWidth, bottom);
200 waterfallDisplayAreaRects_ = WaterfallDisplayAreaRects {leftRect, topRect, rightRect, bottomRect};
201 return;
202 }
203 case Rotation::ROTATION_90: {
204 DMRect leftRect = CreateWaterfallRect(0, 0, bottom, displayWidth);
205 DMRect topRect = CreateWaterfallRect(0, 0, displayHeight, left);
206 DMRect rightRect = CreateWaterfallRect(displayHeight - top, 0, top, displayWidth);
207 DMRect bottomRect = CreateWaterfallRect(0, displayWidth - right, displayHeight, right);
208 waterfallDisplayAreaRects_ = WaterfallDisplayAreaRects {leftRect, topRect, rightRect, bottomRect};
209 return;
210 }
211 case Rotation::ROTATION_180: {
212 DMRect leftRect = CreateWaterfallRect(0, 0, right, displayHeight);
213 DMRect topRect = CreateWaterfallRect(0, 0, bottom, displayWidth);
214 DMRect rightRect = CreateWaterfallRect(displayWidth - left, 0, left, displayHeight);
215 DMRect bottomRect = CreateWaterfallRect(0, displayHeight - top, displayWidth, top);
216 waterfallDisplayAreaRects_ = WaterfallDisplayAreaRects {leftRect, topRect, rightRect, bottomRect};
217 return;
218 }
219 case Rotation::ROTATION_270: {
220 DMRect leftRect = CreateWaterfallRect(0, 0, top, displayWidth);
221 DMRect topRect = CreateWaterfallRect(0, 0, displayHeight, right);
222 DMRect rightRect = CreateWaterfallRect(displayHeight - bottom, 0, bottom, displayWidth);
223 DMRect bottomRect = CreateWaterfallRect(0, displayWidth - left, displayHeight, left);
224 waterfallDisplayAreaRects_ = WaterfallDisplayAreaRects {leftRect, topRect, rightRect, bottomRect};
225 return;
226 }
227 default: {
228 }
229 }
230 }
231
TransferBoundingRectsByRotation(DisplayId displayId,std::vector<DMRect> & boundingRects)232 void DisplayCutoutController::TransferBoundingRectsByRotation(DisplayId displayId, std::vector<DMRect>& boundingRects)
233 {
234 std::vector<DMRect> resultVec;
235 if (boundingRects_.count(displayId) == 0) {
236 boundingRects = resultVec;
237 return;
238 }
239 std::vector<DMRect> displayBoundingRects = boundingRects_[displayId];
240 if (displayBoundingRects.empty()) {
241 boundingRects = resultVec;
242 return;
243 }
244 sptr<DisplayInfo> displayInfo = DisplayManagerServiceInner::GetInstance().GetDisplayById(displayId);
245 if (!displayInfo) {
246 WLOGFE("display invaild");
247 return;
248 }
249 Rotation currentRotation = displayInfo->GetRotation();
250 CheckBoundingRectsBoundary(displayId, displayBoundingRects);
251 if (currentRotation == Rotation::ROTATION_0) {
252 boundingRects = displayBoundingRects;
253 return;
254 }
255 sptr<SupportedScreenModes> modes =
256 DisplayManagerServiceInner::GetInstance().GetScreenModesByDisplayId(displayId);
257 if (!modes) {
258 WLOGE("support screen modes get failed");
259 return;
260 }
261 uint32_t displayHeight = modes->height_;
262 uint32_t displayWidth = modes->width_;
263
264 switch (currentRotation) {
265 case Rotation::ROTATION_90: {
266 for (DMRect rect : displayBoundingRects) {
267 resultVec.emplace_back(DMRect {.posX_ = displayHeight - rect.posY_ - rect.height_,
268 .posY_ = rect.posX_, .width_ = rect.height_, .height_ = rect.width_});
269 }
270 break;
271 }
272 case Rotation::ROTATION_180: {
273 for (DMRect rect : displayBoundingRects) {
274 resultVec.emplace_back(DMRect {displayWidth - rect.posX_ - rect.width_,
275 displayHeight - rect.posY_ - rect.height_, rect.width_, rect.height_});
276 }
277 break;
278 }
279 case Rotation::ROTATION_270: {
280 for (DMRect rect : displayBoundingRects) {
281 resultVec.emplace_back(DMRect {rect.posY_, displayWidth - rect.posX_ - rect.width_,
282 rect.height_, rect.width_});
283 }
284 break;
285 }
286 default: {
287 }
288 }
289 boundingRects = resultVec;
290 }
291
CreateWaterfallRect(uint32_t left,uint32_t top,uint32_t width,uint32_t height)292 DMRect DisplayCutoutController::CreateWaterfallRect(uint32_t left, uint32_t top, uint32_t width, uint32_t height)
293 {
294 if (width == 0 || height == 0) {
295 return DMRect {0, 0, 0, 0};
296 }
297 return DMRect {left, top, width, height};
298 }
299
SetWaterfallAreaCompressionEnableWhenHorzontal(bool isEnable)300 void DisplayCutoutController::SetWaterfallAreaCompressionEnableWhenHorzontal(bool isEnable)
301 {
302 isWaterfallAreaCompressionEnableWhenHorizontal_ = isEnable;
303 }
304
SetWaterfallAreaCompressionSizeWhenHorizontal(uint32_t size)305 void DisplayCutoutController::SetWaterfallAreaCompressionSizeWhenHorizontal(uint32_t size)
306 {
307 waterfallAreaCompressionSizeWhenHorizontal_ = size;
308 }
309
IsWaterfallAreaCompressionEnableWhenHorizontal()310 bool DisplayCutoutController::IsWaterfallAreaCompressionEnableWhenHorizontal()
311 {
312 return isWaterfallDisplay_ && isWaterfallAreaCompressionEnableWhenHorizontal_;
313 }
314
GetWaterfallAreaCompressionSizeWhenHorizontal()315 uint32_t DisplayCutoutController::GetWaterfallAreaCompressionSizeWhenHorizontal()
316 {
317 if (!isWaterfallDisplay_ || !isWaterfallAreaCompressionEnableWhenHorizontal_) {
318 WLOGFW("Not waterfall display or not enable waterfall compression");
319 return NO_WATERFALL_DISPLAY_COMPRESSION_SIZE;
320 }
321 return waterfallAreaCompressionSizeWhenHorizontal_;
322 }
323 } // Rosen
324 } // OHOS
325