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
16 #include "screen_cutout_controller.h"
17
18 #include "screen_scene_config.h"
19 #include "screen_session_manager.h"
20 #include "window_manager_hilog.h"
21
22 namespace OHOS::Rosen {
23 namespace {
24 constexpr std::vector<int>::size_type LEFT = 0;
25 constexpr std::vector<int>::size_type TOP = 1;
26 constexpr std::vector<int>::size_type RIGHT = 2;
27 constexpr std::vector<int>::size_type BOTTOM = 3;
28 constexpr uint8_t HALF_SCREEN = 2;
29 constexpr uint8_t QUARTER_SCREEN = 4;
30 constexpr HiviewDFX::HiLogLabel LABEL = { LOG_CORE, HILOG_DOMAIN_WINDOW, "ScreenCutoutController" };
31 }
32
33 uint32_t ScreenCutoutController::defaultDeviceRotation_ = 0;
34 std::map<DeviceRotationValue, Rotation> ScreenCutoutController::deviceToDisplayRotationMap_;
35
GetScreenCutoutInfo()36 sptr<CutoutInfo> ScreenCutoutController::GetScreenCutoutInfo()
37 {
38 WLOGFD("get screen cutout info.");
39 std::vector<DMRect> boundaryRects;
40 if (!ScreenSceneConfig::GetCutoutBoundaryRect().empty()) {
41 ConvertBoundaryRectsByRotation(boundaryRects);
42 }
43
44 CalcWaterfallRects();
45 sptr<CutoutInfo> cutoutInfo = new CutoutInfo(boundaryRects, waterfallDisplayAreaRects_);
46 return cutoutInfo;
47 }
48
ConvertBoundaryRectsByRotation(std::vector<DMRect> & boundaryRects)49 void ScreenCutoutController::ConvertBoundaryRectsByRotation(std::vector<DMRect>& boundaryRects)
50 {
51 std::vector<DMRect> finalVector;
52 sptr<DisplayInfo> displayInfo = ScreenSessionManager::GetInstance().GetDefaultDisplayInfo();
53 if (!displayInfo) {
54 WLOGFE("displayInfo invaild");
55 boundaryRects = finalVector;
56 return;
57 }
58
59 Rotation currentRotation = displayInfo->GetRotation();
60 std::vector<DMRect> displayBoundaryRects = ScreenSceneConfig::GetCutoutBoundaryRect();
61 CheckBoundaryRects(displayBoundaryRects, displayInfo);
62 if (currentRotation == Rotation::ROTATION_0) {
63 boundaryRects = displayBoundaryRects;
64 return;
65 }
66
67 uint32_t displayWidth = static_cast<uint32_t>(displayInfo->GetWidth());
68 uint32_t displayHeight = static_cast<uint32_t>(displayInfo->GetHeight());
69 switch (currentRotation) {
70 case Rotation::ROTATION_90: {
71 for (DMRect rect : displayBoundaryRects) {
72 finalVector.emplace_back(DMRect{
73 .posX_ = displayHeight - rect.posY_ - rect.height_,
74 .posY_ = rect.posX_,
75 .width_ = rect.height_,
76 .height_ = rect.width_ });
77 }
78 break;
79 }
80 case Rotation::ROTATION_180: {
81 for (DMRect rect : displayBoundaryRects) {
82 finalVector.emplace_back(DMRect{ displayWidth - rect.posX_ - rect.width_,
83 displayHeight - rect.posY_ - rect.height_, rect.width_, rect.height_ });
84 }
85 break;
86 }
87 case Rotation::ROTATION_270: {
88 for (DMRect rect : displayBoundaryRects) {
89 finalVector.emplace_back(
90 DMRect{ rect.posY_, displayWidth - rect.posX_ - rect.width_, rect.height_, rect.width_ });
91 }
92 break;
93 }
94 default:
95 break;
96 }
97 boundaryRects = finalVector;
98 }
99
CheckBoundaryRects(std::vector<DMRect> & boundaryRects,sptr<DisplayInfo> displayInfo)100 void ScreenCutoutController::CheckBoundaryRects(std::vector<DMRect>& boundaryRects, sptr<DisplayInfo> displayInfo)
101 {
102 if (!displayInfo) {
103 WLOGFE("displayInfo invaild");
104 return;
105 }
106
107 uint32_t displayWidth = static_cast<uint32_t>(displayInfo->GetWidth());
108 uint32_t displayHeight = static_cast<uint32_t>(displayInfo->GetHeight());
109 for (auto iter = boundaryRects.begin(); iter != boundaryRects.end();) {
110 DMRect boundaryRect = *iter;
111 if (boundaryRect.posX_ < 0 || boundaryRect.posY_ < 0 ||
112 static_cast<int32_t>(boundaryRect.width_) + boundaryRect.posX_ > static_cast<int32_t>(displayWidth) ||
113 static_cast<int32_t>(boundaryRect.height_) + boundaryRect.posY_ > static_cast<int32_t>(displayHeight) ||
114 boundaryRect.width_ > displayWidth || boundaryRect.height_ > displayHeight ||
115 boundaryRect.IsUninitializedRect()) {
116 WLOGFE("boundaryRect boundary is invalid");
117 iter = boundaryRects.erase(iter);
118 } else {
119 iter++;
120 }
121 }
122 }
123
CalcWaterfallRects()124 void ScreenCutoutController::CalcWaterfallRects()
125 {
126 WaterfallDisplayAreaRects emptyRects = {};
127 if (!ScreenSceneConfig::IsWaterfallDisplay()) {
128 WLOGFE("not waterfall display");
129 waterfallDisplayAreaRects_ = emptyRects;
130 return;
131 }
132
133 std::vector<int> numberVec = ScreenSceneConfig::GetCurvedScreenBoundaryConfig();
134 if (numberVec.empty()) {
135 WLOGFI("curved screen boundary is empty");
136 waterfallDisplayAreaRects_ = emptyRects;
137 return;
138 }
139
140 std::vector<uint32_t> realNumVec = { 0, 0, 0, 0 };
141 for (auto i = LEFT; i <= BOTTOM; i++) {
142 if (numberVec.size() > i) {
143 realNumVec[i] = static_cast<uint32_t>(numberVec[i]);
144 }
145 }
146 if (std::all_of(realNumVec.begin(), realNumVec.end(), [](uint32_t result) { return result == 0; })) {
147 waterfallDisplayAreaRects_ = emptyRects;
148 return;
149 }
150
151 sptr<DisplayInfo> displayInfo = ScreenSessionManager::GetInstance().GetDefaultDisplayInfo();
152 if (!displayInfo) {
153 WLOGFE("displayInfo invaild");
154 return;
155 }
156
157 uint32_t displayWidth = static_cast<uint32_t>(displayInfo->GetWidth());
158 uint32_t displayHeight = static_cast<uint32_t>(displayInfo->GetHeight());
159 if ((realNumVec[LEFT] > displayWidth / HALF_SCREEN) || (realNumVec[RIGHT] > displayWidth / HALF_SCREEN) ||
160 (realNumVec[TOP] > displayHeight / HALF_SCREEN) || (realNumVec[BOTTOM] > displayHeight / HALF_SCREEN)) {
161 WLOGFE("curved screen boundary data is not correct");
162 waterfallDisplayAreaRects_ = emptyRects;
163 return;
164 }
165
166 CalcWaterfallRectsByRotation(ScreenSessionManager::GetInstance().GetDefaultDisplayInfo()->GetRotation(),
167 displayHeight, displayWidth, realNumVec);
168 }
169
CalcWaterfallRectsByRotation(Rotation rotation,uint32_t displayHeight,uint32_t displayWidth,std::vector<uint32_t> realNumVec)170 void ScreenCutoutController::CalcWaterfallRectsByRotation(Rotation rotation, uint32_t displayHeight,
171 uint32_t displayWidth, std::vector<uint32_t> realNumVec)
172 {
173 switch (rotation) {
174 case Rotation::ROTATION_0: {
175 DMRect leftRect = CreateWaterfallRect(0, 0, realNumVec[LEFT], displayHeight);
176 DMRect topRect = CreateWaterfallRect(0, 0, displayWidth, realNumVec[TOP]);
177 DMRect rightRect =
178 CreateWaterfallRect(displayWidth - realNumVec[RIGHT], 0, realNumVec[RIGHT], displayHeight);
179 DMRect bottomRect =
180 CreateWaterfallRect(0, displayHeight - realNumVec[BOTTOM], displayWidth, realNumVec[BOTTOM]);
181 waterfallDisplayAreaRects_ = WaterfallDisplayAreaRects{ leftRect, topRect, rightRect, bottomRect };
182 return;
183 }
184 case Rotation::ROTATION_90: {
185 DMRect leftRect = CreateWaterfallRect(0, 0, realNumVec[BOTTOM], displayWidth);
186 DMRect topRect = CreateWaterfallRect(0, 0, displayHeight, realNumVec[LEFT]);
187 DMRect rightRect = CreateWaterfallRect(displayHeight - realNumVec[TOP], 0, realNumVec[TOP], displayWidth);
188 DMRect bottomRect =
189 CreateWaterfallRect(0, displayWidth - realNumVec[RIGHT], displayHeight, realNumVec[RIGHT]);
190 waterfallDisplayAreaRects_ = WaterfallDisplayAreaRects{ leftRect, topRect, rightRect, bottomRect };
191 return;
192 }
193 case Rotation::ROTATION_180: {
194 DMRect leftRect = CreateWaterfallRect(0, 0, realNumVec[RIGHT], displayHeight);
195 DMRect topRect = CreateWaterfallRect(0, 0, realNumVec[BOTTOM], displayWidth);
196 DMRect rightRect = CreateWaterfallRect(displayWidth - realNumVec[LEFT], 0, realNumVec[LEFT], displayHeight);
197 DMRect bottomRect = CreateWaterfallRect(0, displayHeight - realNumVec[TOP], displayWidth, realNumVec[TOP]);
198 waterfallDisplayAreaRects_ = WaterfallDisplayAreaRects{ leftRect, topRect, rightRect, bottomRect };
199 return;
200 }
201 case Rotation::ROTATION_270: {
202 DMRect leftRect = CreateWaterfallRect(0, 0, realNumVec[TOP], displayWidth);
203 DMRect topRect = CreateWaterfallRect(0, 0, displayHeight, realNumVec[RIGHT]);
204 DMRect rightRect =
205 CreateWaterfallRect(displayHeight - realNumVec[BOTTOM], 0, realNumVec[BOTTOM], displayWidth);
206 DMRect bottomRect =
207 CreateWaterfallRect(0, displayWidth - realNumVec[LEFT], displayHeight, realNumVec[LEFT]);
208 waterfallDisplayAreaRects_ = WaterfallDisplayAreaRects{ leftRect, topRect, rightRect, bottomRect };
209 return;
210 }
211 default: {
212 }
213 }
214 }
215
CreateWaterfallRect(uint32_t left,uint32_t top,uint32_t width,uint32_t height)216 DMRect ScreenCutoutController::CreateWaterfallRect(uint32_t left, uint32_t top, uint32_t width, uint32_t height)
217 {
218 if (width == 0 || height == 0) {
219 return DMRect{ 0, 0, 0, 0 };
220 }
221 return DMRect {left, top, width, height};
222 }
223
CalculateCurvedCompression(const ScreenProperty & screenProperty)224 RectF ScreenCutoutController::CalculateCurvedCompression(const ScreenProperty& screenProperty)
225 {
226 WLOGFI("calculate curved compression");
227 RectF finalRect = RectF(0, 0, 0, 0);
228 sptr<DisplayInfo> displayInfo = ScreenSessionManager::GetInstance().GetDefaultDisplayInfo();
229 uint32_t iCurvedSize = ScreenSceneConfig::GetCurvedCompressionAreaInLandscape();
230 if (!displayInfo || iCurvedSize == 0) {
231 WLOGFE("display Info. invalid or curved area config value is zero");
232 return finalRect;
233 }
234
235 uint32_t screenWidth = static_cast<uint32_t>(displayInfo->GetWidth());
236 uint32_t screenHeight = static_cast<uint32_t>(displayInfo->GetHeight());
237 uint32_t realWidth = static_cast<uint32_t>(iCurvedSize * screenProperty.GetVirtualPixelRatio());
238 if (realWidth >= screenHeight / QUARTER_SCREEN || realWidth >= screenWidth / QUARTER_SCREEN) {
239 WLOGFW("curved area is beyond the edge limit");
240 return finalRect;
241 }
242
243 Rotation rotation = displayInfo->GetRotation();
244 WLOGFI("realWidth : %{public}u rotation : %{public}u", realWidth, rotation);
245 bool isLandscape = screenHeight < screenWidth ? true : false;
246 uint32_t totalCompressedSize = realWidth * HALF_SCREEN; // *2 for both sides.
247 uint32_t displayHeightAfter =
248 isLandscape ? screenHeight - totalCompressedSize : screenWidth - totalCompressedSize;
249 finalRect.left_ = screenProperty.GetBounds().rect_.GetLeft();
250 finalRect.top_ = screenProperty.GetBounds().rect_.GetTop();
251 if (!IsDisplayRotationHorizontal(rotation)) {
252 finalRect.width_ = displayHeightAfter;
253 finalRect.height_ = screenProperty.GetBounds().rect_.GetHeight();
254 offsetY_ = realWidth;
255 SetWaterfallDisplayCompressionStatus(true);
256 } else {
257 if (GetWaterfallDisplayCompressionStatus()) {
258 displayHeightAfter =
259 isLandscape ? screenHeight + totalCompressedSize : screenWidth + totalCompressedSize;
260 }
261 finalRect.width_ = screenProperty.GetBounds().rect_.GetWidth();
262 finalRect.height_ = displayHeightAfter;
263 SetWaterfallDisplayCompressionStatus(false);
264 }
265 return finalRect;
266 }
267
IsDisplayRotationHorizontal(Rotation rotation)268 bool ScreenCutoutController::IsDisplayRotationHorizontal(Rotation rotation)
269 {
270 return (rotation == ConvertDeviceToDisplayRotation(DeviceRotationValue::ROTATION_LANDSCAPE)) ||
271 (rotation == ConvertDeviceToDisplayRotation(DeviceRotationValue::ROTATION_LANDSCAPE_INVERTED));
272 }
273
ConvertDeviceToDisplayRotation(DeviceRotationValue deviceRotation)274 Rotation ScreenCutoutController::ConvertDeviceToDisplayRotation(DeviceRotationValue deviceRotation)
275 {
276 if (deviceRotation == DeviceRotationValue::INVALID) {
277 return GetCurrentDisplayRotation();
278 }
279 if (deviceToDisplayRotationMap_.empty()) {
280 ProcessRotationMapping();
281 }
282 return deviceToDisplayRotationMap_.at(deviceRotation);
283 }
284
GetCurrentDisplayRotation()285 Rotation ScreenCutoutController::GetCurrentDisplayRotation()
286 {
287 sptr<DisplayInfo> displayInfo = ScreenSessionManager::GetInstance().GetDefaultDisplayInfo();
288 if (!displayInfo) {
289 WLOGFE("Cannot get default display info");
290 return defaultDeviceRotation_ == 0 ? ConvertDeviceToDisplayRotation(DeviceRotationValue::ROTATION_PORTRAIT) :
291 ConvertDeviceToDisplayRotation(DeviceRotationValue::ROTATION_LANDSCAPE);
292 }
293 return displayInfo->GetRotation();
294 }
295
ProcessRotationMapping()296 void ScreenCutoutController::ProcessRotationMapping()
297 {
298 sptr<DisplayInfo> displayInfo = ScreenSessionManager::GetInstance().GetDefaultDisplayInfo();
299 // 0 means PORTRAIT, 1 means LANDSCAPE.
300 defaultDeviceRotation_ =
301 (!displayInfo || (displayInfo && (displayInfo->GetWidth() < displayInfo->GetHeight()))) ? 0 : 1;
302 if (deviceToDisplayRotationMap_.empty()) {
303 deviceToDisplayRotationMap_ = {
304 {DeviceRotationValue::ROTATION_PORTRAIT,
305 defaultDeviceRotation_ == 0 ? Rotation::ROTATION_0 : Rotation::ROTATION_90},
306 {DeviceRotationValue::ROTATION_LANDSCAPE,
307 defaultDeviceRotation_ == 1 ? Rotation::ROTATION_0 : Rotation::ROTATION_90},
308 {DeviceRotationValue::ROTATION_PORTRAIT_INVERTED,
309 defaultDeviceRotation_ == 0 ? Rotation::ROTATION_180 : Rotation::ROTATION_270},
310 {DeviceRotationValue::ROTATION_LANDSCAPE_INVERTED,
311 defaultDeviceRotation_ == 1 ? Rotation::ROTATION_180 : Rotation::ROTATION_270},
312 };
313 }
314 }
315
GetOffsetY()316 uint32_t ScreenCutoutController::GetOffsetY()
317 {
318 return offsetY_;
319 }
320 } // namespace OHOS::Rosen
321