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