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