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