1 /*
2 * Copyright (c) 2021-2022 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 "window_layout_policy.h"
17 #include "display_manager_service_inner.h"
18 #include "window_helper.h"
19 #include "window_manager_hilog.h"
20 #include "wm_common_inner.h"
21 #include "wm_trace.h"
22
23 namespace OHOS {
24 namespace Rosen {
25 namespace {
26 constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "WindowLayoutPolicy"};
27 }
WindowLayoutPolicy(const Rect & displayRect,const uint64_t & screenId,sptr<WindowNode> & belowAppNode,sptr<WindowNode> & appNode,sptr<WindowNode> & aboveAppNode)28 WindowLayoutPolicy::WindowLayoutPolicy(const Rect& displayRect, const uint64_t& screenId,
29 sptr<WindowNode>& belowAppNode, sptr<WindowNode>& appNode, sptr<WindowNode>& aboveAppNode)
30 : displayRect_(displayRect), screenId_(screenId),
31 belowAppWindowNode_(belowAppNode), appWindowNode_(appNode), aboveAppWindowNode_(aboveAppNode)
32 {
33 }
34
UpdateDisplayInfo()35 void WindowLayoutPolicy::UpdateDisplayInfo()
36 {
37 limitRect_ = displayRect_;
38 UpdateDefaultFoatingRect();
39 }
40
Launch()41 void WindowLayoutPolicy::Launch()
42 {
43 UpdateDisplayInfo();
44 WLOGFI("WindowLayoutPolicy::Launch");
45 }
46
Clean()47 void WindowLayoutPolicy::Clean()
48 {
49 WLOGFI("WindowLayoutPolicy::Clean");
50 }
51
Reorder()52 void WindowLayoutPolicy::Reorder()
53 {
54 WLOGFI("WindowLayoutPolicy::Reorder");
55 }
56
LayoutWindowTree()57 void WindowLayoutPolicy::LayoutWindowTree()
58 {
59 limitRect_ = displayRect_;
60 LayoutWindowNode(aboveAppWindowNode_); // ensure that the avoid area windows are traversed first
61 if (IsFullScreenRecentWindowExist()) {
62 WLOGFI("recent window on top, early exit layout tree");
63 return;
64 }
65 LayoutWindowNode(appWindowNode_);
66 LayoutWindowNode(belowAppWindowNode_);
67 }
68
LayoutWindowNode(sptr<WindowNode> & node)69 void WindowLayoutPolicy::LayoutWindowNode(sptr<WindowNode>& node)
70 {
71 if (node == nullptr) {
72 return;
73 }
74 if (node->parent_ != nullptr) { // isn't root node
75 if (!node->currentVisibility_) {
76 WLOGFI("window[%{public}u] currently not visible, no need layout", node->GetWindowId());
77 return;
78 }
79 UpdateLayoutRect(node);
80 if (avoidTypes_.find(node->GetWindowType()) != avoidTypes_.end()) {
81 UpdateLimitRect(node, limitRect_);
82 }
83 }
84 for (auto& childNode : node->children_) {
85 LayoutWindowNode(childNode);
86 }
87 }
88
AddWindowNode(sptr<WindowNode> & node)89 void WindowLayoutPolicy::AddWindowNode(sptr<WindowNode>& node)
90 {
91 WM_FUNCTION_TRACE();
92 if (WindowHelper::IsEmptyRect(node->GetWindowProperty()->GetWindowRect())) {
93 SetRectForFloating(node);
94 }
95 UpdateWindowNode(node); // currently, update and add do the same process
96 }
97
UpdateDefaultFoatingRect()98 void WindowLayoutPolicy::UpdateDefaultFoatingRect()
99 {
100 constexpr uint32_t half = 2;
101 constexpr float ratio = 0.75; // 0.75: default height/width ratio
102
103 // calculate default H and w
104 uint32_t defaultW = static_cast<uint32_t>(displayRect_.width_ * ratio);
105 uint32_t defaultH = static_cast<uint32_t>(displayRect_.height_ * ratio);
106
107 // calculate default x and y
108 Rect resRect = {0, 0, defaultW, defaultH};
109 if (defaultW <= limitRect_.width_ && defaultH <= limitRect_.height_) {
110 int32_t centerPosX = limitRect_.posX_ + static_cast<int32_t>(limitRect_.width_ / half);
111 resRect.posX_ = centerPosX - static_cast<int32_t>(defaultW / half);
112
113 int32_t centerPosY = limitRect_.posY_ + static_cast<int32_t>(limitRect_.height_ / half);
114 resRect.posY_ = centerPosY - static_cast<int32_t>(defaultH / half);
115 }
116 defaultFloatingRect_ = resRect;
117 }
118
SetRectForFloating(const sptr<WindowNode> & node)119 void WindowLayoutPolicy::SetRectForFloating(const sptr<WindowNode>& node)
120 {
121 float virtualPixelRatio = GetVirtualPixelRatio();
122 uint32_t winFrameW = static_cast<uint32_t>(WINDOW_FRAME_WIDTH * virtualPixelRatio);
123 uint32_t winTitleBarH = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio);
124 // deduct decor size
125 Rect rect = defaultFloatingRect_;
126 if (node->GetWindowProperty()->GetDecorEnable()) {
127 rect.width_ -= (winFrameW + winFrameW);
128 rect.height_ -= (winTitleBarH + winFrameW);
129 }
130
131 node->SetWindowRect(rect);
132 }
133
IsVertical() const134 bool WindowLayoutPolicy::IsVertical() const
135 {
136 return displayRect_.width_ < displayRect_.height_;
137 }
138
RemoveWindowNode(sptr<WindowNode> & node)139 void WindowLayoutPolicy::RemoveWindowNode(sptr<WindowNode>& node)
140 {
141 WM_FUNCTION_TRACE();
142 auto type = node->GetWindowType();
143 // affect other windows, trigger off global layout
144 if (avoidTypes_.find(type) != avoidTypes_.end()) {
145 LayoutWindowTree();
146 } else if (type == WindowType::WINDOW_TYPE_DOCK_SLICE) { // split screen mode
147 LayoutWindowTree();
148 }
149 Rect winRect = node->GetWindowProperty()->GetWindowRect();
150 node->SetLayoutRect(winRect);
151 node->GetWindowToken()->UpdateWindowRect(winRect, WindowSizeChangeReason::HIDE);
152 }
153
UpdateWindowNode(sptr<WindowNode> & node,bool isAddWindow)154 void WindowLayoutPolicy::UpdateWindowNode(sptr<WindowNode>& node, bool isAddWindow)
155 {
156 WM_FUNCTION_TRACE();
157 auto type = node->GetWindowType();
158 // affect other windows, trigger off global layout
159 if (avoidTypes_.find(type) != avoidTypes_.end()) {
160 LayoutWindowTree();
161 } else if (type == WindowType::WINDOW_TYPE_DOCK_SLICE) { // split screen mode
162 LayoutWindowTree();
163 } else { // layout single window
164 LayoutWindowNode(node);
165 }
166 }
167
UpdateFloatingLayoutRect(Rect & limitRect,Rect & winRect)168 void WindowLayoutPolicy::UpdateFloatingLayoutRect(Rect& limitRect, Rect& winRect)
169 {
170 winRect.width_ = std::min(limitRect.width_, winRect.width_);
171 winRect.height_ = std::min(limitRect.height_, winRect.height_);
172 winRect.posX_ = std::max(limitRect.posX_, winRect.posX_);
173 winRect.posY_ = std::max(limitRect.posY_, winRect.posY_);
174 winRect.posX_ = std::min(
175 limitRect.posX_ + static_cast<int32_t>(limitRect.width_) - static_cast<int32_t>(winRect.width_),
176 winRect.posX_);
177 winRect.posY_ = std::min(
178 limitRect.posY_ + static_cast<int32_t>(limitRect.height_) - static_cast<int32_t>(winRect.height_),
179 winRect.posY_);
180 }
181
ComputeDecoratedWindowRect(const Rect & winRect)182 Rect WindowLayoutPolicy::ComputeDecoratedWindowRect(const Rect& winRect)
183 {
184 float virtualPixelRatio = GetVirtualPixelRatio();
185 uint32_t winFrameW = static_cast<uint32_t>(WINDOW_FRAME_WIDTH * virtualPixelRatio);
186 uint32_t winTitleBarH = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio);
187
188 Rect rect;
189 rect.posX_ = winRect.posX_;
190 rect.posY_ = winRect.posY_;
191 rect.width_ = winRect.width_ + winFrameW + winFrameW;
192 rect.height_ = winRect.height_ + winTitleBarH + winFrameW;
193 return rect;
194 }
195
CalcAndSetNodeHotZone(Rect layoutOutRect,sptr<WindowNode> & node)196 void WindowLayoutPolicy::CalcAndSetNodeHotZone(Rect layoutOutRect, sptr<WindowNode>& node)
197 {
198 Rect rect = layoutOutRect;
199 float virtualPixelRatio = GetVirtualPixelRatio();
200 uint32_t hotZone = static_cast<uint32_t>(HOTZONE * virtualPixelRatio);
201
202 if (node->GetWindowType() == WindowType::WINDOW_TYPE_DOCK_SLICE) {
203 if (rect.width_ < rect.height_) {
204 rect.posX_ -= hotZone;
205 rect.width_ += (hotZone + hotZone);
206 } else {
207 rect.posY_ -= hotZone;
208 rect.height_ += (hotZone + hotZone);
209 }
210 } else if (node->GetWindowType() == WindowType::WINDOW_TYPE_LAUNCHER_RECENT) {
211 rect = displayRect_;
212 } else if (WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode())) {
213 rect.posX_ -= hotZone;
214 rect.posY_ -= hotZone;
215 rect.width_ += (hotZone + hotZone);
216 rect.height_ += (hotZone + hotZone);
217 }
218 node->SetHotZoneRect(rect);
219 }
220
LimitWindowSize(const sptr<WindowNode> & node,const Rect & displayRect,Rect & winRect)221 void WindowLayoutPolicy::LimitWindowSize(const sptr<WindowNode>& node, const Rect& displayRect, Rect& winRect)
222 {
223 float virtualPixelRatio = GetVirtualPixelRatio();
224 uint32_t minVerticalFloatingW = static_cast<uint32_t>(MIN_VERTICAL_FLOATING_WIDTH * virtualPixelRatio);
225 uint32_t minVerticalFloatingH = static_cast<uint32_t>(MIN_VERTICAL_FLOATING_HEIGHT * virtualPixelRatio);
226 uint32_t windowTitleBarH = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio);
227
228 WindowType windowType = node->GetWindowType();
229 WindowMode windowMode = node->GetWindowMode();
230 bool isVertical = (displayRect.height_ > displayRect.width_) ? true : false;
231
232 if (windowMode == WindowMode::WINDOW_MODE_FLOATING) {
233 // limit minimum size of floating (not system type) window
234 if (!WindowHelper::IsSystemWindow(windowType)) {
235 if (isVertical) {
236 winRect.width_ = std::max(minVerticalFloatingW, winRect.width_);
237 winRect.height_ = std::max(minVerticalFloatingH, winRect.height_);
238 } else {
239 winRect.width_ = std::max(minVerticalFloatingH, winRect.width_);
240 winRect.height_ = std::max(minVerticalFloatingW, winRect.height_);
241 }
242 }
243 // limit maximum size of all floating window
244 winRect.width_ = std::min(static_cast<uint32_t>(MAX_FLOATING_SIZE * virtualPixelRatio), winRect.width_);
245 winRect.height_ = std::min(static_cast<uint32_t>(MAX_FLOATING_SIZE * virtualPixelRatio), winRect.height_);
246 }
247
248 // limit position of the main floating window(window which support dragging)
249 if (WindowHelper::IsMainFloatingWindow(windowType, windowMode)) {
250 winRect.posY_ = std::max(limitRect_.posY_, winRect.posY_);
251 winRect.posY_ = std::min(limitRect_.posY_ + static_cast<int32_t>(limitRect_.height_ - windowTitleBarH),
252 winRect.posY_);
253
254 winRect.posX_ = std::max(limitRect_.posX_ + static_cast<int32_t>(windowTitleBarH - winRect.width_),
255 winRect.posX_);
256 winRect.posX_ = std::min(limitRect_.posX_ + static_cast<int32_t>(limitRect_.width_ - windowTitleBarH),
257 winRect.posX_);
258 }
259 }
260
GetAvoidPosType(const Rect & rect)261 AvoidPosType WindowLayoutPolicy::GetAvoidPosType(const Rect& rect)
262 {
263 auto display = DisplayManagerServiceInner::GetInstance().GetDisplayById(screenId_);
264 if (display == nullptr) {
265 WLOGFE("GetAvoidPosType fail. Get display fail. displayId:%{public}" PRIu64"", screenId_);
266 return AvoidPosType::AVOID_POS_UNKNOWN;
267 }
268 uint32_t displayWidth = display->GetWidth();
269 uint32_t displayHeight = display->GetHeight();
270
271 return WindowHelper::GetAvoidPosType(rect, displayWidth, displayHeight);
272 }
273
UpdateLimitRect(const sptr<WindowNode> & node,Rect & limitRect)274 void WindowLayoutPolicy::UpdateLimitRect(const sptr<WindowNode>& node, Rect& limitRect)
275 {
276 auto& layoutRect = node->GetLayoutRect();
277 int32_t limitH = static_cast<int32_t>(limitRect.height_);
278 int32_t limitW = static_cast<int32_t>(limitRect.width_);
279 int32_t layoutH = static_cast<int32_t>(layoutRect.height_);
280 int32_t layoutW = static_cast<int32_t>(layoutRect.width_);
281 if (node->GetWindowType() == WindowType::WINDOW_TYPE_STATUS_BAR ||
282 node->GetWindowType() == WindowType::WINDOW_TYPE_NAVIGATION_BAR) {
283 auto avoidPosType = GetAvoidPosType(layoutRect);
284 int32_t offsetH = 0;
285 int32_t offsetW = 0;
286 switch (avoidPosType) {
287 case AvoidPosType::AVOID_POS_TOP:
288 offsetH = layoutRect.posY_ + layoutH - limitRect.posY_;
289 limitRect.posY_ += offsetH;
290 limitH -= offsetH;
291 break;
292 case AvoidPosType::AVOID_POS_BOTTOM:
293 offsetH = limitRect.posY_ + limitH - layoutRect.posY_;
294 limitH -= offsetH;
295 break;
296 case AvoidPosType::AVOID_POS_LEFT:
297 offsetW = layoutRect.posX_ + layoutW - limitRect.posX_;
298 limitRect.posX_ += offsetW;
299 limitW -= offsetW;
300 break;
301 case AvoidPosType::AVOID_POS_RIGHT:
302 offsetW = limitRect.posX_ + limitW - layoutRect.posX_;
303 limitW -= offsetW;
304 break;
305 default:
306 WLOGFE("invalid avoidPosType: %{public}d", avoidPosType);
307 }
308 }
309 limitRect.height_ = static_cast<uint32_t>(limitH < 0 ? 0 : limitH);
310 limitRect.width_ = static_cast<uint32_t>(limitW < 0 ? 0 : limitW);
311 WLOGFI("Type: %{public}d, limitRect: %{public}d %{public}d %{public}u %{public}u",
312 node->GetWindowType(), limitRect.posX_, limitRect.posY_, limitRect.width_, limitRect.height_);
313 }
314
Reset()315 void WindowLayoutPolicy::Reset()
316 {
317 }
318
GetVirtualPixelRatio() const319 float WindowLayoutPolicy::GetVirtualPixelRatio() const
320 {
321 auto display = DisplayManagerServiceInner::GetInstance().GetDisplayById(screenId_);
322 if (display == nullptr) {
323 WLOGFE("GetVirtualPixel fail. Get display fail. displayId:%{public}" PRIu64", use Default vpr:1.0", screenId_);
324 return 1.0; // Use DefaultVPR 1.0
325 }
326
327 float virtualPixelRatio = display->GetVirtualPixelRatio();
328 if (virtualPixelRatio == 0.0) {
329 WLOGFE("GetVirtualPixel fail. vpr is 0.0. displayId:%{public}" PRIu64", use Default vpr:1.0", screenId_);
330 return 1.0; // Use DefaultVPR 1.0
331 }
332
333 WLOGFI("GetVirtualPixel success. displayId:%{public}" PRIu64", vpr:%{public}f", screenId_, virtualPixelRatio);
334 return virtualPixelRatio;
335 }
336
IsFullScreenRecentWindowExist() const337 bool WindowLayoutPolicy::IsFullScreenRecentWindowExist() const
338 {
339 for (auto& childNode : aboveAppWindowNode_->children_) {
340 if (childNode->GetWindowType() == WindowType::WINDOW_TYPE_LAUNCHER_RECENT &&
341 childNode->GetWindowMode() == WindowMode::WINDOW_MODE_FULLSCREEN) {
342 return true;
343 }
344 }
345 return false;
346 }
347
GetDisplayLimitRect() const348 Rect WindowLayoutPolicy::GetDisplayLimitRect() const
349 {
350 return limitRect_;
351 }
352 }
353 }
354