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