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