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