• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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