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