• 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(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