• 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 "remote_animation.h"
19 #include "window_helper.h"
20 #include "window_manager_hilog.h"
21 #include "wm_common_inner.h"
22 
23 namespace OHOS {
24 namespace Rosen {
25 namespace {
26     constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "WindowLayoutPolicy"};
27 }
28 
29 uint32_t WindowLayoutPolicy::floatingBottomPosY_ = 0;
30 
WindowLayoutPolicy(const sptr<DisplayGroupInfo> & displayGroupInfo,DisplayGroupWindowTree & displayGroupWindowTree)31 WindowLayoutPolicy::WindowLayoutPolicy(const sptr<DisplayGroupInfo>& displayGroupInfo,
32     DisplayGroupWindowTree& displayGroupWindowTree)
33     : displayGroupInfo_(displayGroupInfo), displayGroupWindowTree_(displayGroupWindowTree)
34 {
35 }
36 
Launch()37 void WindowLayoutPolicy::Launch()
38 {
39     WLOGFI("WindowLayoutPolicy::Launch");
40 }
41 
Clean()42 void WindowLayoutPolicy::Clean()
43 {
44     WLOGFI("WindowLayoutPolicy::Clean");
45 }
46 
Reorder()47 void WindowLayoutPolicy::Reorder()
48 {
49     WLOGFI("WindowLayoutPolicy::Reorder");
50 }
51 
GetExitSplitPoints(DisplayId displayId) const52 std::vector<int32_t> WindowLayoutPolicy::GetExitSplitPoints(DisplayId displayId) const
53 {
54     return {};
55 }
56 
LimitWindowToBottomRightCorner(const sptr<WindowNode> & node)57 void WindowLayoutPolicy::LimitWindowToBottomRightCorner(const sptr<WindowNode>& node)
58 {
59     Rect windowRect = node->GetRequestRect();
60     Rect displayRect = displayGroupInfo_->GetDisplayRect(node->GetDisplayId());
61     windowRect.posX_ = std::max(windowRect.posX_, displayRect.posX_);
62     windowRect.posY_ = std::max(windowRect.posY_, displayRect.posY_);
63     windowRect.width_ = std::min(windowRect.width_, displayRect.width_);
64     windowRect.height_ = std::min(windowRect.height_, displayRect.height_);
65 
66     if (windowRect.posX_ + static_cast<int32_t>(windowRect.width_) >
67         displayRect.posX_ + static_cast<int32_t>(displayRect.width_)) {
68         windowRect.posX_ = displayRect.posX_ + static_cast<int32_t>(displayRect.width_) -
69             static_cast<int32_t>(windowRect.width_);
70     }
71 
72     if (windowRect.posY_ + static_cast<int32_t>(windowRect.height_) >
73         displayRect.posY_ + static_cast<int32_t>(displayRect.height_)) {
74         windowRect.posY_ = displayRect.posY_ + static_cast<int32_t>(displayRect.height_) -
75             static_cast<int32_t>(windowRect.height_);
76     }
77     node->SetRequestRect(windowRect);
78 
79     WLOGFI("windowId: %{public}d, newRect: [%{public}d, %{public}d, %{public}d, %{public}d]",
80         node->GetWindowId(), windowRect.posX_, windowRect.posY_, windowRect.width_, windowRect.height_);
81 
82     for (auto& childNode : node->children_) {
83         LimitWindowToBottomRightCorner(childNode);
84     }
85 }
86 
UpdateDisplayGroupRect()87 void WindowLayoutPolicy::UpdateDisplayGroupRect()
88 {
89     Rect newDisplayGroupRect = { 0, 0, 0, 0 };
90     // current multi-display is only support left-right combination, maxNum is two
91     for (auto& elem : displayGroupInfo_->GetAllDisplayRects()) {
92         newDisplayGroupRect.posX_ = std::min(displayGroupRect_.posX_, elem.second.posX_);
93         newDisplayGroupRect.posY_ = std::min(displayGroupRect_.posY_, elem.second.posY_);
94         newDisplayGroupRect.width_ += elem.second.width_;
95         int32_t maxHeight = std::max(newDisplayGroupRect.posY_ + static_cast<int32_t>(newDisplayGroupRect.height_),
96                                      elem.second.posY_+ static_cast<int32_t>(elem.second.height_));
97         newDisplayGroupRect.height_ = maxHeight - newDisplayGroupRect.posY_;
98     }
99     displayGroupRect_ = newDisplayGroupRect;
100     WLOGFI("displayGroupRect_: [ %{public}d, %{public}d, %{public}d, %{public}d]",
101         displayGroupRect_.posX_, displayGroupRect_.posY_, displayGroupRect_.width_, displayGroupRect_.height_);
102 }
103 
UpdateDisplayGroupLimitRect()104 void WindowLayoutPolicy::UpdateDisplayGroupLimitRect()
105 {
106     auto firstDisplayLimitRect = limitRectMap_.begin()->second;
107     Rect newDisplayGroupLimitRect = { firstDisplayLimitRect.posX_, firstDisplayLimitRect.posY_, 0, 0 };
108     for (auto& elem : limitRectMap_) {
109         newDisplayGroupLimitRect.posX_ = std::min(newDisplayGroupLimitRect.posX_, elem.second.posX_);
110         newDisplayGroupLimitRect.posY_ = std::min(newDisplayGroupLimitRect.posY_, elem.second.posY_);
111 
112         int32_t maxWidth = std::max(newDisplayGroupLimitRect.posX_ +
113                                     static_cast<int32_t>(newDisplayGroupLimitRect.width_),
114                                     elem.second.posX_+ static_cast<int32_t>(elem.second.width_));
115 
116         int32_t maxHeight = std::max(newDisplayGroupLimitRect.posY_ +
117                                      static_cast<int32_t>(newDisplayGroupLimitRect.height_),
118                                      elem.second.posY_+ static_cast<int32_t>(elem.second.height_));
119         newDisplayGroupLimitRect.width_  = static_cast<uint32_t>(maxWidth - newDisplayGroupLimitRect.posX_);
120         newDisplayGroupLimitRect.height_ = static_cast<uint32_t>(maxHeight - newDisplayGroupLimitRect.posY_);
121     }
122     displayGroupLimitRect_ = newDisplayGroupLimitRect;
123     WLOGFI("displayGroupLimitRect_: [ %{public}d, %{public}d, %{public}d, %{public}d]",
124         displayGroupLimitRect_.posX_, displayGroupLimitRect_.posY_,
125         displayGroupLimitRect_.width_, displayGroupLimitRect_.height_);
126 }
127 
UpdateRectInDisplayGroup(const sptr<WindowNode> & node,const Rect & oriDisplayRect,const Rect & newDisplayRect)128 void WindowLayoutPolicy::UpdateRectInDisplayGroup(const sptr<WindowNode>& node,
129                                                   const Rect& oriDisplayRect,
130                                                   const Rect& newDisplayRect)
131 {
132     Rect newRect = node->GetRequestRect();
133     WLOGFI("before update rect in display group, windowId: %{public}d, rect: [%{public}d, %{public}d, "
134         "%{public}d, %{public}d]", node->GetWindowId(), newRect.posX_, newRect.posY_, newRect.width_, newRect.height_);
135 
136     newRect.posX_ = newRect.posX_ - oriDisplayRect.posX_ + newDisplayRect.posX_;
137     newRect.posY_ = newRect.posY_ - oriDisplayRect.posY_ + newDisplayRect.posY_;
138     node->SetRequestRect(newRect);
139     WLOGFI("after update rect in display group, windowId: %{public}d, newRect: [%{public}d, %{public}d, "
140         "%{public}d, %{public}d]", node->GetWindowId(), newRect.posX_, newRect.posY_, newRect.width_, newRect.height_);
141 
142     for (auto& childNode : node->children_) {
143         UpdateRectInDisplayGroup(childNode, oriDisplayRect, newDisplayRect);
144     }
145 }
146 
IsMultiDisplay()147 bool WindowLayoutPolicy::IsMultiDisplay()
148 {
149     return isMultiDisplay_;
150 }
151 
UpdateMultiDisplayFlag()152 void WindowLayoutPolicy::UpdateMultiDisplayFlag()
153 {
154     if (displayGroupInfo_->GetAllDisplayRects().size() > 1) {
155         isMultiDisplay_ = true;
156         WLOGFI("current mode is multi-display");
157     } else {
158         isMultiDisplay_ = false;
159         WLOGFI("current mode is not multi-display");
160     }
161 }
162 
UpdateRectInDisplayGroupForAllNodes(DisplayId displayId,const Rect & oriDisplayRect,const Rect & newDisplayRect)163 void WindowLayoutPolicy::UpdateRectInDisplayGroupForAllNodes(DisplayId displayId,
164                                                              const Rect& oriDisplayRect,
165                                                              const Rect& newDisplayRect)
166 {
167     WLOGFI("displayId: %{public}" PRIu64", oriDisplayRect: [ %{public}d, %{public}d, %{public}d, %{public}d] "
168         "newDisplayRect: [ %{public}d, %{public}d, %{public}d, %{public}d]",
169         displayId, oriDisplayRect.posX_, oriDisplayRect.posY_, oriDisplayRect.width_, oriDisplayRect.height_,
170         newDisplayRect.posX_, newDisplayRect.posY_, newDisplayRect.width_, newDisplayRect.height_);
171 
172     auto& displayWindowTree = displayGroupWindowTree_[displayId];
173     for (auto& iter : displayWindowTree) {
174         auto& nodeVector = *(iter.second);
175         for (auto& node : nodeVector) {
176             if (!node->isShowingOnMultiDisplays_) {
177                 UpdateRectInDisplayGroup(node, oriDisplayRect, newDisplayRect);
178             }
179             if (WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode())) {
180                 LimitWindowToBottomRightCorner(node);
181             }
182         }
183         WLOGFI("Recalculate window rect in display group, displayId: %{public}" PRIu64", rootType: %{public}d",
184             displayId, iter.first);
185     }
186 }
187 
UpdateDisplayRectAndDisplayGroupInfo(const std::map<DisplayId,Rect> & displayRectMap)188 void WindowLayoutPolicy::UpdateDisplayRectAndDisplayGroupInfo(const std::map<DisplayId, Rect>& displayRectMap)
189 {
190     for (auto& elem : displayRectMap) {
191         auto& displayId = elem.first;
192         auto& displayRect = elem.second;
193         displayGroupInfo_->SetDisplayRect(displayId, displayRect);
194     }
195 }
196 
PostProcessWhenDisplayChange()197 void WindowLayoutPolicy::PostProcessWhenDisplayChange()
198 {
199     displayGroupInfo_->UpdateLeftAndRightDisplayId();
200     UpdateMultiDisplayFlag();
201     UpdateDisplayGroupRect();
202     Launch();
203 }
204 
ProcessDisplayCreate(DisplayId displayId,const std::map<DisplayId,Rect> & displayRectMap)205 void WindowLayoutPolicy::ProcessDisplayCreate(DisplayId displayId, const std::map<DisplayId, Rect>& displayRectMap)
206 {
207     const auto& oriDisplayRectMap = displayGroupInfo_->GetAllDisplayRects();
208     // check displayId and displayRectMap size
209     if (oriDisplayRectMap.find(displayId) == oriDisplayRectMap.end() ||
210         displayRectMap.size() != oriDisplayRectMap.size()) {
211         WLOGFE("current display is exited or displayInfo map size is error, displayId: %{public}" PRIu64"", displayId);
212         return;
213     }
214     for (auto& elem : displayRectMap) {
215         auto iter = oriDisplayRectMap.find(elem.first);
216         if (iter != oriDisplayRectMap.end()) {
217             const auto& oriDisplayRect = iter->second;
218             const auto& newDisplayRect = elem.second;
219             UpdateRectInDisplayGroupForAllNodes(elem.first, oriDisplayRect, newDisplayRect);
220         } else {
221             if (elem.first != displayId) {
222                 WLOGFE("Wrong display, displayId: %{public}" PRIu64"", displayId);
223                 return;
224             }
225         }
226     }
227     UpdateDisplayRectAndDisplayGroupInfo(displayRectMap);
228     PostProcessWhenDisplayChange();
229     WLOGFI("Process display create, displayId: %{public}" PRIu64"", displayId);
230 }
231 
ProcessDisplayDestroy(DisplayId displayId,const std::map<DisplayId,Rect> & displayRectMap)232 void WindowLayoutPolicy::ProcessDisplayDestroy(DisplayId displayId, const std::map<DisplayId, Rect>& displayRectMap)
233 {
234     const auto& oriDisplayRectMap = displayGroupInfo_->GetAllDisplayRects();
235     // check displayId and displayRectMap size
236     if (oriDisplayRectMap.find(displayId) != oriDisplayRectMap.end() ||
237         displayRectMap.size() != oriDisplayRectMap.size()) {
238         WLOGFE("can not find current display or displayInfo map size is error, displayId: %{public}" PRIu64"",
239                displayId);
240         return;
241     }
242     for (auto oriIter = oriDisplayRectMap.begin(); oriIter != oriDisplayRectMap.end();) {
243         auto newIter = displayRectMap.find(oriIter->first);
244         if (newIter != displayRectMap.end()) {
245             const auto& oriDisplayRect = oriIter->second;
246             const auto& newDisplayRect = newIter->second;
247             UpdateRectInDisplayGroupForAllNodes(oriIter->first, oriDisplayRect, newDisplayRect);
248         } else {
249             if (oriIter->first != displayId) {
250                 WLOGFE("Wrong display, displayId: %{public}" PRIu64"", displayId);
251                 return;
252             }
253         }
254         ++oriIter;
255     }
256 
257     UpdateDisplayRectAndDisplayGroupInfo(displayRectMap);
258     PostProcessWhenDisplayChange();
259     WLOGFI("Process display destroy, displayId: %{public}" PRIu64"", displayId);
260 }
261 
ProcessDisplaySizeChangeOrRotation(DisplayId displayId,const std::map<DisplayId,Rect> & displayRectMap)262 void WindowLayoutPolicy::ProcessDisplaySizeChangeOrRotation(DisplayId displayId,
263                                                             const std::map<DisplayId, Rect>& displayRectMap)
264 {
265     const auto& oriDisplayRectMap = displayGroupInfo_->GetAllDisplayRects();
266     // check displayId and displayRectMap size
267     if (oriDisplayRectMap.find(displayId) == oriDisplayRectMap.end() ||
268         displayRectMap.size() != oriDisplayRectMap.size()) {
269         WLOGFE("can not find current display or displayInfo map size is error, displayId: %{public}" PRIu64"",
270                displayId);
271         return;
272     }
273 
274     for (auto& elem : displayRectMap) {
275         auto iter = oriDisplayRectMap.find(elem.first);
276         if (iter != oriDisplayRectMap.end()) {
277             UpdateRectInDisplayGroupForAllNodes(elem.first, iter->second, elem.second);
278         }
279     }
280 
281     UpdateDisplayRectAndDisplayGroupInfo(displayRectMap);
282     PostProcessWhenDisplayChange();
283     WLOGFI("Process display change, displayId: %{public}" PRIu64"", displayId);
284 }
285 
LayoutWindowNodesByRootType(const std::vector<sptr<WindowNode>> & nodeVec)286 void WindowLayoutPolicy::LayoutWindowNodesByRootType(const std::vector<sptr<WindowNode>>& nodeVec)
287 {
288     if (nodeVec.empty()) {
289         WLOGE("The node vector is empty!");
290         return;
291     }
292     for (auto& node : nodeVec) {
293         LayoutWindowNode(node);
294     }
295 }
296 
NotifyAnimationSizeChangeIfNeeded()297 void WindowLayoutPolicy::NotifyAnimationSizeChangeIfNeeded()
298 {
299     if (!RemoteAnimation::CheckAnimationController()) {
300         WLOGFD("no animation controller!");
301         return;
302     }
303     std::vector<uint32_t> fullScreenWinIds;
304     std::vector<uint32_t> floatMainIds;
305     for (auto& iter : displayGroupWindowTree_) {
306         auto& displayWindowTree = iter.second;
307         auto& nodeVec = *(displayWindowTree[WindowRootNodeType::APP_WINDOW_NODE]);
308         if (nodeVec.empty()) {
309             WLOGE("The node vector is empty!");
310             return;
311         }
312         for (auto& node : nodeVec) {
313             // just has one fullscreen app node on foreground
314             if (WindowHelper::IsMainFullScreenWindow(node->GetWindowType(), node->GetWindowMode())) {
315                 fullScreenWinIds.emplace_back(node->GetWindowId());
316             }
317             if (WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode())) {
318                 floatMainIds.emplace_back(node->GetWindowId());
319             }
320         }
321     }
322     RemoteAnimation::NotifyAnimationTargetsUpdate(fullScreenWinIds, floatMainIds);
323 }
324 
LayoutWindowTree(DisplayId displayId)325 void WindowLayoutPolicy::LayoutWindowTree(DisplayId displayId)
326 {
327     auto& displayWindowTree = displayGroupWindowTree_[displayId];
328     limitRectMap_[displayId] = displayGroupInfo_->GetDisplayRect(displayId);
329     // ensure that the avoid area windows are traversed first
330     LayoutWindowNodesByRootType(*(displayWindowTree[WindowRootNodeType::ABOVE_WINDOW_NODE]));
331     if (IsFullScreenRecentWindowExist(*(displayWindowTree[WindowRootNodeType::ABOVE_WINDOW_NODE]))) {
332         WLOGFI("recent window on top, early exit layout tree");
333         return;
334     }
335     LayoutWindowNodesByRootType(*(displayWindowTree[WindowRootNodeType::APP_WINDOW_NODE]));
336     LayoutWindowNodesByRootType(*(displayWindowTree[WindowRootNodeType::BELOW_WINDOW_NODE]));
337 }
338 
LayoutWindowNode(const sptr<WindowNode> & node)339 void WindowLayoutPolicy::LayoutWindowNode(const sptr<WindowNode>& node)
340 {
341     if (node == nullptr) {
342         return;
343     }
344     WLOGFI("LayoutWindowNode, window[%{public}u]", node->GetWindowId());
345     if (node->parent_ != nullptr) { // isn't root node
346         if (!node->currentVisibility_) {
347             WLOGFI("window[%{public}u] currently not visible, no need layout", node->GetWindowId());
348             return;
349         }
350         UpdateLayoutRect(node);
351         if (avoidTypes_.find(node->GetWindowType()) != avoidTypes_.end()) {
352             UpdateLimitRect(node, limitRectMap_[node->GetDisplayId()]);
353             UpdateDisplayGroupLimitRect();
354         }
355     }
356     for (auto& childNode : node->children_) {
357         LayoutWindowNode(childNode);
358     }
359 }
360 
IsVerticalDisplay(DisplayId displayId) const361 bool WindowLayoutPolicy::IsVerticalDisplay(DisplayId displayId) const
362 {
363     return displayGroupInfo_->GetDisplayRect(displayId).width_ < displayGroupInfo_->GetDisplayRect(displayId).height_;
364 }
365 
UpdateClientRect(const Rect & rect,const sptr<WindowNode> & node,WindowSizeChangeReason reason)366 void WindowLayoutPolicy::UpdateClientRect(const Rect& rect, const sptr<WindowNode>& node, WindowSizeChangeReason reason)
367 {
368     if (node->GetWindowToken()) {
369         WLOGFI("notify client id: %{public}d, windowRect:[%{public}d, %{public}d, %{public}u, %{public}u], reason: "
370             "%{public}u", node->GetWindowId(), rect.posX_, rect.posY_, rect.width_, rect.height_, reason);
371         node->GetWindowToken()->UpdateWindowRect(rect, node->GetDecoStatus(), reason);
372     }
373     NotifyAnimationSizeChangeIfNeeded();
374 }
375 
UpdateClientRectAndResetReason(const sptr<WindowNode> & node,const Rect & winRect)376 void WindowLayoutPolicy::UpdateClientRectAndResetReason(const sptr<WindowNode>& node, const Rect& winRect)
377 {
378     auto reason = node->GetWindowSizeChangeReason();
379     UpdateClientRect(winRect, node, reason);
380     if ((reason != WindowSizeChangeReason::MOVE) && (node->GetWindowType() != WindowType::WINDOW_TYPE_DOCK_SLICE)) {
381         node->ResetWindowSizeChangeReason();
382     }
383 }
384 
RemoveWindowNode(const sptr<WindowNode> & node)385 void WindowLayoutPolicy::RemoveWindowNode(const sptr<WindowNode>& node)
386 {
387     auto type = node->GetWindowType();
388     // affect other windows, trigger off global layout
389     if (avoidTypes_.find(type) != avoidTypes_.end()) {
390         LayoutWindowTree(node->GetDisplayId());
391     } else if (type == WindowType::WINDOW_TYPE_DOCK_SLICE) { // split screen mode
392         LayoutWindowTree(node->GetDisplayId());
393     }
394     UpdateClientRect(node->GetRequestRect(), node, WindowSizeChangeReason::HIDE);
395 }
396 
UpdateWindowNode(const sptr<WindowNode> & node,bool isAddWindow)397 void WindowLayoutPolicy::UpdateWindowNode(const sptr<WindowNode>& node, bool isAddWindow)
398 {
399     auto type = node->GetWindowType();
400     // affect other windows, trigger off global layout
401     if (avoidTypes_.find(type) != avoidTypes_.end()) {
402         LayoutWindowTree(node->GetDisplayId());
403     } else if (type == WindowType::WINDOW_TYPE_DOCK_SLICE) { // split screen mode
404         LayoutWindowTree(node->GetDisplayId());
405     } else { // layout single window
406         LayoutWindowNode(node);
407     }
408 }
409 
UpdateFloatingLayoutRect(Rect & limitRect,Rect & winRect)410 void WindowLayoutPolicy::UpdateFloatingLayoutRect(Rect& limitRect, Rect& winRect)
411 {
412     winRect.width_ = std::min(limitRect.width_, winRect.width_);
413     winRect.height_ = std::min(limitRect.height_, winRect.height_);
414     winRect.posX_ = std::max(limitRect.posX_, winRect.posX_);
415     winRect.posY_ = std::max(limitRect.posY_, winRect.posY_);
416     winRect.posX_ = std::min(
417         limitRect.posX_ + static_cast<int32_t>(limitRect.width_) - static_cast<int32_t>(winRect.width_),
418         winRect.posX_);
419     winRect.posY_ = std::min(
420         limitRect.posY_ + static_cast<int32_t>(limitRect.height_) - static_cast<int32_t>(winRect.height_),
421         winRect.posY_);
422 }
423 
ComputeDecoratedRequestRect(const sptr<WindowNode> & node) const424 void WindowLayoutPolicy::ComputeDecoratedRequestRect(const sptr<WindowNode>& node) const
425 {
426     auto property = node->GetWindowProperty();
427     if (property == nullptr) {
428         WLOGE("window property is nullptr");
429         return;
430     }
431     auto reqRect = property->GetRequestRect();
432     if (!property->GetDecorEnable() || property->GetDecoStatus() ||
433         node->GetWindowSizeChangeReason() == WindowSizeChangeReason::MOVE) {
434         return;
435     }
436     float virtualPixelRatio = GetVirtualPixelRatio(node->GetDisplayId());
437     uint32_t winFrameW = static_cast<uint32_t>(WINDOW_FRAME_WIDTH * virtualPixelRatio);
438     uint32_t winTitleBarH = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio);
439 
440     Rect rect;
441     rect.posX_ = reqRect.posX_;
442     rect.posY_ = reqRect.posY_;
443     rect.width_ = reqRect.width_ + winFrameW + winFrameW;
444     rect.height_ = reqRect.height_ + winTitleBarH + winFrameW;
445     property->SetRequestRect(rect);
446     property->SetDecoStatus(true);
447 }
448 
CalcEntireWindowHotZone(const sptr<WindowNode> & node,const Rect & winRect,uint32_t hotZone,float vpr,TransformHelper::Vector2 hotZoneScale) const449 Rect WindowLayoutPolicy::CalcEntireWindowHotZone(const sptr<WindowNode>& node, const Rect& winRect, uint32_t hotZone,
450     float vpr, TransformHelper::Vector2 hotZoneScale) const
451 {
452     Rect rect = winRect;
453     uint32_t hotZoneX = static_cast<uint32_t>(hotZone * vpr / hotZoneScale.x_);
454     uint32_t hotZoneY = static_cast<uint32_t>(hotZone * vpr / hotZoneScale.y_);
455 
456     if (node->GetWindowType() == WindowType::WINDOW_TYPE_DOCK_SLICE) {
457         if (rect.width_ < rect.height_) {
458             rect.posX_ -= static_cast<int32_t>(hotZoneX);
459             rect.width_ += (hotZoneX + hotZoneX);
460         } else {
461             rect.posY_ -= static_cast<int32_t>(hotZoneY);
462             rect.height_ += (hotZoneY + hotZoneY);
463         }
464     } else if (node->GetWindowType() == WindowType::WINDOW_TYPE_LAUNCHER_RECENT) {
465         rect = displayGroupInfo_->GetDisplayRect(node->GetDisplayId());
466     } else if (WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode())) {
467         rect.posX_ -= static_cast<int32_t>(hotZoneX);
468         rect.posY_ -= static_cast<int32_t>(hotZoneY);
469         rect.width_ += (hotZoneX + hotZoneX);
470         rect.height_ += (hotZoneY + hotZoneY);
471     }
472     return rect;
473 }
474 
CalcAndSetNodeHotZone(const Rect & winRect,const sptr<WindowNode> & node) const475 void WindowLayoutPolicy::CalcAndSetNodeHotZone(const Rect& winRect, const sptr<WindowNode>& node) const
476 {
477     float virtualPixelRatio = GetVirtualPixelRatio(node->GetDisplayId());
478     TransformHelper::Vector2 hotZoneScale(1, 1);
479     if (node->GetWindowProperty()->isNeedComputerTransform()) {
480         node->ComputeTransform();
481         hotZoneScale = WindowHelper::CalculateHotZoneScale(node->GetWindowProperty()->GetTransformMat());
482     }
483 
484     auto hotZoneRectTouch = CalcEntireWindowHotZone(node, winRect, HOTZONE_TOUCH, virtualPixelRatio, hotZoneScale);
485     auto hotZoneRectPointer = CalcEntireWindowHotZone(node, winRect, HOTZONE_POINTER, virtualPixelRatio, hotZoneScale);
486 
487     node->SetEntireWindowTouchHotArea(hotZoneRectTouch);
488     node->SetEntireWindowPointerHotArea(hotZoneRectPointer);
489 
490     std::vector<Rect> requestedHotAreas;
491     node->GetWindowProperty()->GetTouchHotAreas(requestedHotAreas);
492     std::vector<Rect> touchHotAreas;
493     std::vector<Rect> pointerHotAreas;
494     if (requestedHotAreas.empty()) {
495         touchHotAreas.emplace_back(hotZoneRectTouch);
496         pointerHotAreas.emplace_back(hotZoneRectPointer);
497     } else {
498         if (!WindowHelper::CalculateTouchHotAreas(winRect, requestedHotAreas, touchHotAreas)) {
499             WLOGFW("some parameters in requestedHotAreas are abnormal");
500         }
501         pointerHotAreas = touchHotAreas;
502     }
503     node->SetTouchHotAreas(touchHotAreas);
504     node->SetPointerHotAreas(pointerHotAreas);
505 }
506 
FixWindowSizeByRatioIfDragBeyondLimitRegion(const sptr<WindowNode> & node,Rect & winRect)507 void WindowLayoutPolicy::FixWindowSizeByRatioIfDragBeyondLimitRegion(const sptr<WindowNode>& node, Rect& winRect)
508 {
509     const auto& sizeLimits = node->GetWindowUpdatedSizeLimits();
510     if (sizeLimits.maxWidth_ == sizeLimits.minWidth_ &&
511         sizeLimits.maxHeight_ == sizeLimits.minHeight_) {
512         WLOGFI("window rect can not be changed");
513         return;
514     }
515     if (winRect.height_ == 0) {
516         WLOGFE("the height of window is zero");
517         return;
518     }
519     float curRatio = static_cast<float>(winRect.width_) / static_cast<float>(winRect.height_);
520     if (sizeLimits.minRatio_ <= curRatio && curRatio <= sizeLimits.maxRatio_) {
521         WLOGFI("window ratio is satisfied with limit ratio, curRatio: %{public}f", curRatio);
522         return;
523     }
524 
525     float virtualPixelRatio = GetVirtualPixelRatio(node->GetDisplayId());
526     uint32_t windowTitleBarH = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio);
527     Rect limitRect = isMultiDisplay_ ? displayGroupLimitRect_ : limitRectMap_[node->GetDisplayId()];
528     int32_t limitMinPosX = limitRect.posX_ + static_cast<int32_t>(windowTitleBarH);
529     int32_t limitMaxPosX = limitRect.posX_ + static_cast<int32_t>(limitRect.width_ - windowTitleBarH);
530     int32_t limitMinPosY = limitRect.posY_;
531     int32_t limitMaxPosY = limitRect.posY_ + static_cast<int32_t>(limitRect.height_ - windowTitleBarH);
532 
533     Rect dockWinRect;
534     DockWindowShowState dockShownState = GetDockWindowShowState(node->GetDisplayId(), dockWinRect);
535     if (dockShownState == DockWindowShowState::SHOWN_IN_BOTTOM) {
536         WLOGFD("dock window show in bottom");
537         limitMaxPosY = dockWinRect.posY_ - static_cast<int32_t>(windowTitleBarH);
538     } else if (dockShownState == DockWindowShowState::SHOWN_IN_LEFT) {
539         WLOGFD("dock window show in left");
540         limitMinPosX = dockWinRect.posX_ + static_cast<int32_t>(dockWinRect.width_ + windowTitleBarH);
541     } else if (dockShownState == DockWindowShowState::SHOWN_IN_RIGHT) {
542         WLOGFD("dock window show in right");
543         limitMaxPosX = dockWinRect.posX_ - static_cast<int32_t>(windowTitleBarH);
544     }
545 
546     float newRatio = curRatio < sizeLimits.minRatio_ ? sizeLimits.minRatio_ : sizeLimits.maxRatio_;
547     if ((winRect.posX_ + static_cast<int32_t>(winRect.width_) == limitMinPosX) || (winRect.posX_ == limitMaxPosX)) {
548         // height can not be changed
549         if (sizeLimits.maxHeight_ == sizeLimits.minHeight_) {
550             return;
551         }
552         winRect.height_ = static_cast<uint32_t>(static_cast<float>(winRect.width_) / newRatio);
553     }
554 
555     if ((winRect.posY_ == limitMinPosY) || (winRect.posX_ == limitMaxPosY)) {
556         // width can not be changed
557         if (sizeLimits.maxWidth_ == sizeLimits.minWidth_) {
558             return;
559         }
560         winRect.width_ = static_cast<uint32_t>(static_cast<float>(winRect.height_) * newRatio);
561     }
562     WLOGFI("After limit by ratio if beyond limit region, winRect: %{public}d %{public}d %{public}u %{public}u",
563         winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
564 }
565 
GetSystemSizeLimits(const sptr<WindowNode> & node,const Rect & displayRect,float virtualPixelRatio)566 WindowSizeLimits WindowLayoutPolicy::GetSystemSizeLimits(const sptr<WindowNode>& node,
567     const Rect& displayRect, float virtualPixelRatio)
568 {
569     WindowSizeLimits systemLimits;
570     systemLimits.maxWidth_ = static_cast<uint32_t>(MAX_FLOATING_SIZE * virtualPixelRatio);
571     systemLimits.maxHeight_ = static_cast<uint32_t>(MAX_FLOATING_SIZE * virtualPixelRatio);
572 
573     // Float camera window has a special limit:
574     // if display sw <= 600dp, portrait: min width = display sw * 30%, landscape: min width = sw * 50%
575     // if display sw > 600dp, portrait: min width = display sw * 12%, landscape: min width = sw * 30%
576     if (node->GetWindowType() == WindowType::WINDOW_TYPE_FLOAT_CAMERA) {
577         uint32_t smallWidth = displayRect.height_ <= displayRect.width_ ? displayRect.height_ : displayRect.width_;
578         float hwRatio = static_cast<float>(displayRect.height_) / static_cast<float>(displayRect.width_);
579         if (smallWidth <= static_cast<uint32_t>(600 * virtualPixelRatio)) { // sw <= 600dp
580             if (displayRect.width_ <= displayRect.height_) {
581                 systemLimits.minWidth_ = static_cast<uint32_t>(smallWidth * 0.3); // min width = display sw * 0.3
582             } else {
583                 systemLimits.minWidth_ = static_cast<uint32_t>(smallWidth * 0.5); // min width = display sw * 0.5
584             }
585         } else {
586             if (displayRect.width_ <= displayRect.height_) {
587                 systemLimits.minWidth_ = static_cast<uint32_t>(smallWidth * 0.12); // min width = display sw * 0.12
588             } else {
589                 systemLimits.minWidth_ = static_cast<uint32_t>(smallWidth * 0.3); // min width = display sw * 0.3
590             }
591         }
592         systemLimits.minHeight_ = static_cast<uint32_t>(systemLimits.minWidth_ * hwRatio);
593     } else {
594         systemLimits.minWidth_ = static_cast<uint32_t>(MIN_FLOATING_WIDTH * virtualPixelRatio);
595         systemLimits.minHeight_ = static_cast<uint32_t>(MIN_FLOATING_HEIGHT * virtualPixelRatio);
596     }
597     WLOGFD("[System SizeLimits] [maxWidth: %{public}u, minWidth: %{public}u, maxHeight: %{public}u, "
598         "minHeight: %{public}u]", systemLimits.maxWidth_, systemLimits.minWidth_,
599         systemLimits.maxHeight_, systemLimits.minHeight_);
600     return systemLimits;
601 }
602 
UpdateWindowSizeLimits(const sptr<WindowNode> & node)603 void WindowLayoutPolicy::UpdateWindowSizeLimits(const sptr<WindowNode>& node)
604 {
605     const auto& displayRect = displayGroupInfo_->GetDisplayRect(node->GetDisplayId());
606     const auto& virtualPixelRatio = GetVirtualPixelRatio(node->GetDisplayId());
607     const auto& systemLimits = GetSystemSizeLimits(node, displayRect, virtualPixelRatio);
608     const auto& customizedLimits = node->GetWindowSizeLimits();
609 
610     WindowSizeLimits newLimits = systemLimits;
611 
612     // configured limits of floating window
613     uint32_t configuredMaxWidth = static_cast<uint32_t>(customizedLimits.maxWidth_ * virtualPixelRatio);
614     uint32_t configuredMaxHeight = static_cast<uint32_t>(customizedLimits.maxHeight_ * virtualPixelRatio);
615     uint32_t configuredMinWidth = static_cast<uint32_t>(customizedLimits.minWidth_ * virtualPixelRatio);
616     uint32_t configuredMinHeight = static_cast<uint32_t>(customizedLimits.minHeight_ * virtualPixelRatio);
617 
618     // calculate new limit size
619     if (systemLimits.minWidth_ <= configuredMaxWidth && configuredMaxWidth <= systemLimits.maxWidth_) {
620         newLimits.maxWidth_ = configuredMaxWidth;
621     }
622     if (systemLimits.minHeight_ <= configuredMaxHeight && configuredMaxHeight <= systemLimits.maxHeight_) {
623         newLimits.maxHeight_ = configuredMaxHeight;
624     }
625     if (systemLimits.minWidth_ <= configuredMinWidth && configuredMinWidth <= newLimits.maxWidth_) {
626         newLimits.minWidth_ = configuredMinWidth;
627     }
628     if (systemLimits.minHeight_ <= configuredMinHeight && configuredMinHeight <= newLimits.maxHeight_) {
629         newLimits.minHeight_ = configuredMinHeight;
630     }
631 
632     // calculate new limit ratio
633     newLimits.maxRatio_ = static_cast<float>(newLimits.maxWidth_) / static_cast<float>(newLimits.minHeight_);
634     newLimits.minRatio_ = static_cast<float>(newLimits.minWidth_) / static_cast<float>(newLimits.maxHeight_);
635     if (newLimits.minRatio_ <= customizedLimits.maxRatio_ && customizedLimits.maxRatio_ <= newLimits.maxRatio_) {
636         newLimits.maxRatio_ = customizedLimits.maxRatio_;
637     }
638     if (newLimits.minRatio_ <= customizedLimits.minRatio_ && customizedLimits.minRatio_ <= newLimits.maxRatio_) {
639         newLimits.minRatio_ = customizedLimits.minRatio_;
640     }
641 
642     // recalculate limit size by new ratio
643     uint32_t newMaxWidth = static_cast<uint32_t>(static_cast<float>(newLimits.maxHeight_) * newLimits.maxRatio_);
644     newLimits.maxWidth_ = std::min(newMaxWidth, newLimits.maxWidth_);
645     uint32_t newMinWidth = static_cast<uint32_t>(static_cast<float>(newLimits.minHeight_) * newLimits.minRatio_);
646     newLimits.minWidth_ = std::max(newMinWidth, newLimits.minWidth_);
647     uint32_t newMaxHeight = static_cast<uint32_t>(static_cast<float>(newLimits.maxWidth_) / newLimits.minRatio_);
648     newLimits.maxHeight_ = std::min(newMaxHeight, newLimits.maxHeight_);
649     uint32_t newMinHeight = static_cast<uint32_t>(static_cast<float>(newLimits.minWidth_) / newLimits.maxRatio_);
650     newLimits.minHeight_ = std::max(newMinHeight, newLimits.minHeight_);
651 
652     WLOGFI("[Update SizeLimits] winId: %{public}u, Width: [max:%{public}u, min:%{public}u], Height: [max:%{public}u, "
653         "min:%{public}u], Ratio: [max:%{public}f, min:%{public}f]", node->GetWindowId(), newLimits.maxWidth_,
654         newLimits.minWidth_, newLimits.maxHeight_, newLimits.minHeight_, newLimits.maxRatio_, newLimits.minRatio_);
655     node->SetWindowUpdatedSizeLimits(newLimits);
656 }
657 
UpdateFloatingWindowSizeForStretchableWindow(const sptr<WindowNode> & node,const Rect & displayRect,Rect & winRect) const658 void WindowLayoutPolicy::UpdateFloatingWindowSizeForStretchableWindow(const sptr<WindowNode>& node,
659     const Rect& displayRect, Rect& winRect) const
660 {
661     if (node->GetWindowSizeChangeReason() == WindowSizeChangeReason::DRAG) {
662         const Rect &originRect = node->GetOriginRect();
663         if (originRect.height_ == 0 || originRect.width_ == 0) {
664             WLOGE("invalid originRect. window id: %{public}u", node->GetWindowId());
665             return;
666         }
667         auto dragType = node->GetDragType();
668         if (dragType == DragType::DRAG_BOTTOM_OR_TOP) {
669             // if drag height, use height to fix size.
670             winRect.width_ = winRect.height_ * originRect.width_ / originRect.height_;
671         } else if (dragType == DragType::DRAG_LEFT_TOP_CORNER || dragType == DragType::DRAG_RIGHT_TOP_CORNER ||
672                    dragType == DragType::DRAG_LEFT_OR_RIGHT) {
673             // if drag width or corner, use width to fix size.
674             winRect.height_ = winRect.width_ * originRect.height_ / originRect.width_;
675         }
676     }
677     // limit minimum size of window
678 
679     const auto& sizeLimits = node->GetWindowUpdatedSizeLimits();
680     float scale = std::min(static_cast<float>(winRect.width_) / sizeLimits.minWidth_,
681         static_cast<float>(winRect.height_) / sizeLimits.minHeight_);
682     if (scale == 0) {
683         WLOGE("invalid sizeLimits");
684         return;
685     }
686     if (scale < 1.0f) {
687         winRect.width_ = static_cast<uint32_t>(static_cast<float>(winRect.width_) / scale);
688         winRect.height_ = static_cast<uint32_t>(static_cast<float>(winRect.height_) / scale);
689     }
690 }
691 
UpdateFloatingWindowSizeBySizeLimits(const sptr<WindowNode> & node,const Rect & displayRect,Rect & winRect) const692 void WindowLayoutPolicy::UpdateFloatingWindowSizeBySizeLimits(const sptr<WindowNode>& node,
693     const Rect& displayRect, Rect& winRect) const
694 {
695     // get new limit config with the settings of system and app
696     const auto& sizeLimits = node->GetWindowUpdatedSizeLimits();
697 
698     // limit minimum size of floating (not system type) window
699     if (!WindowHelper::IsSystemWindow(node->GetWindowType()) ||
700         node->GetWindowType() == WindowType::WINDOW_TYPE_FLOAT_CAMERA) {
701         winRect.width_ = std::max(sizeLimits.minWidth_, winRect.width_);
702         winRect.height_ = std::max(sizeLimits.minHeight_, winRect.height_);
703     }
704     winRect.width_ = std::min(sizeLimits.maxWidth_, winRect.width_);
705     winRect.height_ = std::min(sizeLimits.maxHeight_, winRect.height_);
706     WLOGFD("After limit by size, winRect: %{public}d %{public}d %{public}u %{public}u",
707         winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
708 
709     // width and height can not be changed
710     if (sizeLimits.maxWidth_ == sizeLimits.minWidth_ &&
711         sizeLimits.maxHeight_ == sizeLimits.minHeight_) {
712         winRect.width_ = sizeLimits.maxWidth_;
713         winRect.height_ = sizeLimits.maxHeight_;
714         WLOGFD("window rect can not be changed");
715         return;
716     }
717 
718     float curRatio = static_cast<float>(winRect.width_) / static_cast<float>(winRect.height_);
719     // there is no need to fix size by ratio if this is not main floating window
720     if (!WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode()) ||
721         (sizeLimits.minRatio_ <= curRatio && curRatio <= sizeLimits.maxRatio_)) {
722         WLOGFD("window is system window or ratio is satisfied with limits, curSize: [%{public}d, %{public}d], "
723             "curRatio: %{public}f", winRect.width_, winRect.height_, curRatio);
724         return;
725     }
726 
727     float newRatio = curRatio < sizeLimits.minRatio_ ? sizeLimits.minRatio_ : sizeLimits.maxRatio_;
728     if (sizeLimits.maxWidth_ == sizeLimits.minWidth_) {
729         winRect.height_ = static_cast<uint32_t>(static_cast<float>(winRect.width_) / newRatio);
730         return;
731     }
732     if (sizeLimits.maxHeight_ == sizeLimits.minHeight_) {
733         winRect.width_ = static_cast<uint32_t>(static_cast<float>(winRect.height_) * newRatio);
734         return;
735     }
736 
737     auto dragType = node->GetDragType();
738     if (dragType == DragType::DRAG_BOTTOM_OR_TOP) {
739         // if drag height, use height to fix size.
740         winRect.width_ = static_cast<uint32_t>(static_cast<float>(winRect.height_) * newRatio);
741     } else {
742         // if drag width or corner, use width to fix size.
743         winRect.height_ = static_cast<uint32_t>(static_cast<float>(winRect.width_) / newRatio);
744     }
745     WLOGFI("After limit by customize config, winRect: %{public}d %{public}d %{public}u %{public}u",
746         winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
747 }
748 
LimitFloatingWindowSize(const sptr<WindowNode> & node,const Rect & displayRect,Rect & winRect) const749 void WindowLayoutPolicy::LimitFloatingWindowSize(const sptr<WindowNode>& node,
750                                                  const Rect& displayRect,
751                                                  Rect& winRect) const
752 {
753     if (node->GetWindowMode() != WindowMode::WINDOW_MODE_FLOATING
754         || node->GetWindowType() == WindowType::WINDOW_TYPE_APP_COMPONENT) {
755         return;
756     }
757     Rect oriWinRect = winRect;
758     UpdateFloatingWindowSizeBySizeLimits(node, displayRect, winRect);
759 
760     if (node->GetStretchable() &&
761         WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode())) {
762         UpdateFloatingWindowSizeForStretchableWindow(node, displayRect, winRect);
763     }
764 
765     // fix size in case of moving window when dragging
766     const auto& lastWinRect = node->GetWindowRect();
767     if (node->GetWindowSizeChangeReason() == WindowSizeChangeReason::DRAG) {
768         if (oriWinRect.posX_ != lastWinRect.posX_) {
769             winRect.posX_ = oriWinRect.posX_ + static_cast<int32_t>(oriWinRect.width_) -
770                 static_cast<int32_t>(winRect.width_);
771         }
772         if (oriWinRect.posY_ != lastWinRect.posY_) {
773             winRect.posY_ = oriWinRect.posY_ + static_cast<int32_t>(oriWinRect.height_) -
774                 static_cast<int32_t>(winRect.height_);
775         }
776     }
777 }
778 
LimitMainFloatingWindowPosition(const sptr<WindowNode> & node,Rect & winRect) const779 void WindowLayoutPolicy::LimitMainFloatingWindowPosition(const sptr<WindowNode>& node, Rect& winRect) const
780 {
781     if (!WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode())) {
782         return;
783     }
784 
785     auto reason = node->GetWindowSizeChangeReason();
786     // if drag or move window, limit size and position
787     if (reason == WindowSizeChangeReason::DRAG) {
788         LimitWindowPositionWhenDrag(node, winRect);
789         if (WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode())) {
790             const_cast<WindowLayoutPolicy*>(this)->FixWindowSizeByRatioIfDragBeyondLimitRegion(node, winRect);
791         }
792     } else {
793         // Limit window position, such as init window rect when show
794         LimitWindowPositionWhenInitRectOrMove(node, winRect);
795     }
796 }
797 
LimitWindowPositionWhenDrag(const sptr<WindowNode> & node,Rect & winRect) const798 void WindowLayoutPolicy::LimitWindowPositionWhenDrag(const sptr<WindowNode>& node,
799                                                      Rect& winRect) const
800 {
801     float virtualPixelRatio = GetVirtualPixelRatio(node->GetDisplayId());
802     uint32_t windowTitleBarH = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio);
803     const Rect& lastRect = node->GetWindowRect();
804     Rect oriWinRect = winRect;
805 
806     Rect limitRect = isMultiDisplay_ ? displayGroupLimitRect_ : limitRectMap_[node->GetDisplayId()];
807     int32_t limitMinPosX = limitRect.posX_ + static_cast<int32_t>(windowTitleBarH);
808     int32_t limitMaxPosX = limitRect.posX_ + static_cast<int32_t>(limitRect.width_ - windowTitleBarH);
809     int32_t limitMinPosY = limitRect.posY_;
810     int32_t limitMaxPosY = limitRect.posY_ + static_cast<int32_t>(limitRect.height_ - windowTitleBarH);
811 
812     Rect dockWinRect;
813     DockWindowShowState dockShownState = GetDockWindowShowState(node->GetDisplayId(), dockWinRect);
814     if (dockShownState == DockWindowShowState::SHOWN_IN_BOTTOM) {
815         WLOGFD("dock window show in bottom");
816         limitMaxPosY = dockWinRect.posY_ - static_cast<int32_t>(windowTitleBarH);
817     } else if (dockShownState == DockWindowShowState::SHOWN_IN_LEFT) {
818         WLOGFD("dock window show in left");
819         limitMinPosX = dockWinRect.posX_ + static_cast<int32_t>(dockWinRect.width_ + windowTitleBarH);
820     } else if (dockShownState == DockWindowShowState::SHOWN_IN_RIGHT) {
821         WLOGFD("dock window show in right");
822         limitMaxPosX = dockWinRect.posX_ - static_cast<int32_t>(windowTitleBarH);
823     }
824 
825     // limitMinPosX is minimum (x + width)
826     if (oriWinRect.posX_ + static_cast<int32_t>(oriWinRect.width_) < limitMinPosX) {
827         if (oriWinRect.width_ != lastRect.width_) {
828             winRect.width_ = static_cast<uint32_t>(limitMinPosX - oriWinRect.posX_);
829         }
830     }
831     // maximum position x
832     if (oriWinRect.posX_ > limitMaxPosX) {
833         winRect.posX_ = limitMaxPosX;
834         if (oriWinRect.width_ != lastRect.width_) {
835             winRect.width_ = static_cast<uint32_t>(
836                 oriWinRect.posX_ + static_cast<int32_t>(oriWinRect.width_) - winRect.posX_);
837         }
838     }
839     // minimum position y
840     if (oriWinRect.posY_ < limitMinPosY) {
841         winRect.posY_ = limitMinPosY;
842         if (oriWinRect.height_ != lastRect.height_) {
843             winRect.height_ = static_cast<uint32_t>(
844                 oriWinRect.posY_ + static_cast<int32_t>(oriWinRect.height_) - winRect.posY_);
845         }
846     }
847     // maximum position y
848     if (winRect.posY_ > limitMaxPosY) {
849         winRect.posY_ = limitMaxPosY;
850         if (oriWinRect.height_ != lastRect.height_) {
851             winRect.height_ = static_cast<uint32_t>(
852                 oriWinRect.posY_ + static_cast<int32_t>(oriWinRect.height_) - winRect.posY_);
853         }
854     }
855     WLOGFI("After limit by position, winRect: %{public}d %{public}d %{public}u %{public}u",
856         winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
857 }
858 
LimitWindowPositionWhenInitRectOrMove(const sptr<WindowNode> & node,Rect & winRect) const859 void WindowLayoutPolicy::LimitWindowPositionWhenInitRectOrMove(const sptr<WindowNode>& node, Rect& winRect) const
860 {
861     float virtualPixelRatio = GetVirtualPixelRatio(node->GetDisplayId());
862     uint32_t windowTitleBarH = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio);
863 
864     Rect limitRect;
865     // if is cross-display window, the limit rect should be full limitRect
866     if (node->isShowingOnMultiDisplays_) {
867         limitRect = displayGroupLimitRect_;
868     } else {
869         limitRect = limitRectMap_[node->GetDisplayId()];
870     }
871 
872     // limit position of the main floating window(window which support dragging)
873     if (WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode())) {
874         Rect dockWinRect;
875         DockWindowShowState dockShownState = GetDockWindowShowState(node->GetDisplayId(), dockWinRect);
876         winRect.posY_ = std::max(limitRect.posY_, winRect.posY_);
877         winRect.posY_ = std::min(limitRect.posY_ + static_cast<int32_t>(limitRect.height_ - windowTitleBarH),
878                                  winRect.posY_);
879         if (dockShownState == DockWindowShowState::SHOWN_IN_BOTTOM) {
880             WLOGFD("dock window show in bottom");
881             winRect.posY_ = std::min(dockWinRect.posY_ - static_cast<int32_t>(windowTitleBarH),
882                                      winRect.posY_);
883         }
884         winRect.posX_ = std::max(limitRect.posX_ + static_cast<int32_t>(windowTitleBarH - winRect.width_),
885                                  winRect.posX_);
886         if (dockShownState == DockWindowShowState::SHOWN_IN_LEFT) {
887             WLOGFD("dock window show in left");
888             winRect.posX_ = std::max(static_cast<int32_t>(dockWinRect.width_ + windowTitleBarH - winRect.width_),
889                                      winRect.posX_);
890         }
891         winRect.posX_ = std::min(limitRect.posX_ + static_cast<int32_t>(limitRect.width_ - windowTitleBarH),
892                                  winRect.posX_);
893         if (dockShownState == DockWindowShowState::SHOWN_IN_RIGHT) {
894             WLOGFD("dock window show in right");
895             winRect.posX_ = std::min(dockWinRect.posX_ - static_cast<int32_t>(windowTitleBarH),
896                                      winRect.posX_);
897         }
898         auto reason = node->GetWindowSizeChangeReason();
899         // if init window on pc, limit position
900         if (floatingBottomPosY_ != 0 && reason == WindowSizeChangeReason::UNDEFINED) {
901             uint32_t bottomPosY = static_cast<uint32_t>(floatingBottomPosY_ * virtualPixelRatio);
902             if (winRect.posY_ + static_cast<int32_t>(winRect.height_) >= bottomPosY) {
903                 winRect.posY_ = limitRect.posY_;
904             }
905         }
906     }
907     WLOGFI("After limit by position if init or move, winRect: %{public}d %{public}d %{public}u %{public}u",
908         winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
909 }
910 
GetDockWindowShowState(DisplayId displayId,Rect & dockWinRect) const911 DockWindowShowState WindowLayoutPolicy::GetDockWindowShowState(DisplayId displayId, Rect& dockWinRect) const
912 {
913     auto& displayWindowTree = displayGroupWindowTree_[displayId];
914     auto& nodeVec = *(displayWindowTree[WindowRootNodeType::ABOVE_WINDOW_NODE]);
915     for (auto& node : nodeVec) {
916         if (node->GetWindowType() != WindowType::WINDOW_TYPE_LAUNCHER_DOCK) {
917             continue;
918         }
919 
920         dockWinRect = node->GetWindowRect();
921         auto displayRect = displayGroupInfo_->GetDisplayRect(displayId);
922         WLOGFI("begin dockWinRect :[%{public}d, %{public}d, %{public}u, %{public}u]",
923             dockWinRect.posX_, dockWinRect.posY_, dockWinRect.width_, dockWinRect.height_);
924         if (dockWinRect.height_ < dockWinRect.width_) {
925             if (static_cast<uint32_t>(dockWinRect.posY_) + dockWinRect.height_ == displayRect.height_) {
926                 return DockWindowShowState::SHOWN_IN_BOTTOM;
927             } else {
928                 return DockWindowShowState::NOT_SHOWN;
929             }
930         } else {
931             if (dockWinRect.posX_ == 0) {
932                 return DockWindowShowState::SHOWN_IN_LEFT;
933             } else if (static_cast<uint32_t>(dockWinRect.posX_) + dockWinRect.width_ == displayRect.width_) {
934                 return DockWindowShowState::SHOWN_IN_RIGHT;
935             } else {
936                 return DockWindowShowState::NOT_SHOWN;
937             }
938         }
939     }
940     return DockWindowShowState::NOT_SHOWN;
941 }
942 
GetAvoidPosType(const Rect & rect,DisplayId displayId) const943 AvoidPosType WindowLayoutPolicy::GetAvoidPosType(const Rect& rect, DisplayId displayId) const
944 {
945     const auto& displayRectMap = displayGroupInfo_->GetAllDisplayRects();
946     if (displayRectMap.find(displayId) == std::end(displayRectMap)) {
947         WLOGFE("GetAvoidPosType fail. Get display fail. displayId: %{public}" PRIu64"", displayId);
948         return AvoidPosType::AVOID_POS_UNKNOWN;
949     }
950     const auto& displayRect = displayGroupInfo_->GetDisplayRect(displayId);
951     return WindowHelper::GetAvoidPosType(rect, displayRect);
952 }
953 
UpdateLimitRect(const sptr<WindowNode> & node,Rect & limitRect)954 void WindowLayoutPolicy::UpdateLimitRect(const sptr<WindowNode>& node, Rect& limitRect)
955 {
956     const auto& layoutRect = node->GetWindowRect();
957     int32_t limitH = static_cast<int32_t>(limitRect.height_);
958     int32_t limitW = static_cast<int32_t>(limitRect.width_);
959     int32_t layoutH = static_cast<int32_t>(layoutRect.height_);
960     int32_t layoutW = static_cast<int32_t>(layoutRect.width_);
961     if (node->GetWindowType() == WindowType::WINDOW_TYPE_STATUS_BAR ||
962         node->GetWindowType() == WindowType::WINDOW_TYPE_NAVIGATION_BAR) {
963         auto avoidPosType = GetAvoidPosType(layoutRect, node->GetDisplayId());
964         int32_t offsetH = 0;
965         int32_t offsetW = 0;
966         switch (avoidPosType) {
967             case AvoidPosType::AVOID_POS_TOP:
968                 offsetH = layoutRect.posY_ + layoutH - limitRect.posY_;
969                 limitRect.posY_ += offsetH;
970                 limitH -= offsetH;
971                 break;
972             case AvoidPosType::AVOID_POS_BOTTOM:
973                 offsetH = limitRect.posY_ + limitH - layoutRect.posY_;
974                 limitH -= offsetH;
975                 break;
976             case AvoidPosType::AVOID_POS_LEFT:
977                 offsetW = layoutRect.posX_ + layoutW - limitRect.posX_;
978                 limitRect.posX_ += offsetW;
979                 limitW -= offsetW;
980                 break;
981             case AvoidPosType::AVOID_POS_RIGHT:
982                 offsetW = limitRect.posX_ + limitW - layoutRect.posX_;
983                 limitW -= offsetW;
984                 break;
985             default:
986                 WLOGFE("invalid avoidPosType: %{public}d", avoidPosType);
987         }
988     }
989     limitRect.height_ = static_cast<uint32_t>(limitH < 0 ? 0 : limitH);
990     limitRect.width_ = static_cast<uint32_t>(limitW < 0 ? 0 : limitW);
991     WLOGFI("Type: %{public}d, limitRect: %{public}d %{public}d %{public}u %{public}u",
992         node->GetWindowType(), limitRect.posX_, limitRect.posY_, limitRect.width_, limitRect.height_);
993 }
994 
Reset()995 void WindowLayoutPolicy::Reset()
996 {
997 }
998 
GetVirtualPixelRatio(DisplayId displayId) const999 float WindowLayoutPolicy::GetVirtualPixelRatio(DisplayId displayId) const
1000 {
1001     float virtualPixelRatio = displayGroupInfo_->GetDisplayVirtualPixelRatio(displayId);
1002     WLOGFI("GetVirtualPixel success. displayId:%{public}" PRIu64", vpr:%{public}f", displayId, virtualPixelRatio);
1003     return virtualPixelRatio;
1004 }
1005 
IsFullScreenRecentWindowExist(const std::vector<sptr<WindowNode>> & nodeVec) const1006 bool WindowLayoutPolicy::IsFullScreenRecentWindowExist(const std::vector<sptr<WindowNode>>& nodeVec) const
1007 {
1008     for (auto& node : nodeVec) {
1009         if (node->GetWindowType() == WindowType::WINDOW_TYPE_LAUNCHER_RECENT &&
1010             node->GetWindowMode() == WindowMode::WINDOW_MODE_FULLSCREEN) {
1011             return true;
1012         }
1013     }
1014     return false;
1015 }
1016 
SetBounds(const sptr<WindowNode> & node,const Rect & winRect,const Rect & preRect)1017 static void SetBounds(const sptr<WindowNode>& node, const Rect& winRect, const Rect& preRect)
1018 {
1019     if (node->GetWindowType() == WindowType::WINDOW_TYPE_APP_COMPONENT ||
1020         node->GetWindowSizeChangeReason() == WindowSizeChangeReason::TRANSFORM) {
1021         WLOGFI("not need to update bounds");
1022         return;
1023     }
1024     // set surface node gravity based on WindowSizeChangeReason
1025     if (node->GetWindowSizeChangeReason() == WindowSizeChangeReason::DRAG_START ||
1026         node->GetWindowSizeChangeReason() == WindowSizeChangeReason::DRAG ||
1027         node->GetWindowSizeChangeReason() == WindowSizeChangeReason::ROTATION) {
1028         if (node->surfaceNode_) {
1029             node->surfaceNode_->SetFrameGravity(Gravity::RESIZE);
1030         }
1031     } else {
1032         if (node->surfaceNode_) {
1033             node->surfaceNode_->SetFrameGravity(Gravity::TOP_LEFT);
1034         }
1035     }
1036     WLOGFD("name:%{public}s id:%{public}u preRect:[x:%{public}d, y:%{public}d, w:%{public}d, h:%{public}d]",
1037         node->GetWindowName().c_str(), node->GetWindowId(),
1038         preRect.posX_, preRect.posY_, preRect.width_, preRect.height_);
1039     WLOGFD("name:%{public}s id:%{public}u winRect:[x:%{public}d, y:%{public}d, w:%{public}d, h:%{public}d]",
1040         node->GetWindowName().c_str(), node->GetWindowId(),
1041         winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
1042     if (node->leashWinSurfaceNode_) {
1043         if (winRect != preRect) {
1044             // avoid animation interpreted when client coming
1045             node->leashWinSurfaceNode_->SetBounds(winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
1046         }
1047         if (node->startingWinSurfaceNode_) {
1048             node->startingWinSurfaceNode_->SetBounds(0, 0, winRect.width_, winRect.height_);
1049         }
1050         if (node->surfaceNode_) {
1051             node->surfaceNode_->SetBounds(0, 0, winRect.width_, winRect.height_);
1052         }
1053     } else if (node->surfaceNode_) {
1054         node->surfaceNode_->SetBounds(winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
1055     }
1056 }
1057 
UpdateSurfaceBounds(const sptr<WindowNode> & node,const Rect & winRect,const Rect & preRect)1058 void WindowLayoutPolicy::UpdateSurfaceBounds(const sptr<WindowNode>& node, const Rect& winRect, const Rect& preRect)
1059 {
1060     wptr<WindowNode> weakNode = node;
1061     auto SetBoundsFunc = [weakNode, winRect, preRect]() {
1062         auto winNode = weakNode.promote();
1063         if (winNode == nullptr) {
1064             WLOGFI("winNode is nullptr");
1065             return;
1066         }
1067         SetBounds(winNode, winRect, preRect);
1068     };
1069 
1070     switch (node->GetWindowSizeChangeReason()) {
1071         case WindowSizeChangeReason::MAXIMIZE:
1072             [[fallthrough]];
1073         case WindowSizeChangeReason::RECOVER: {
1074             const RSAnimationTimingProtocol timingProtocol(400); // animation time
1075             RSNode::Animate(timingProtocol, RSAnimationTimingCurve::EASE_OUT, SetBoundsFunc);
1076             break;
1077         }
1078         case WindowSizeChangeReason::ROTATION: {
1079             const RSAnimationTimingProtocol timingProtocol(600); // animation time
1080             const RSAnimationTimingCurve curve_ = RSAnimationTimingCurve::CreateCubicCurve(
1081                 0.2, 0.0, 0.2, 1.0); // animation curve: cubic [0.2, 0.0, 0.2, 1.0]
1082             RSNode::Animate(timingProtocol, curve_, SetBoundsFunc);
1083             break;
1084         }
1085         case WindowSizeChangeReason::UNDEFINED:
1086             [[fallthrough]];
1087         default:
1088             SetBoundsFunc();
1089     }
1090 }
1091 
GetDisplayGroupRect() const1092 Rect WindowLayoutPolicy::GetDisplayGroupRect() const
1093 {
1094     return displayGroupRect_;
1095 }
1096 
SetSplitRatioConfig(const SplitRatioConfig & splitRatioConfig)1097 void WindowLayoutPolicy::SetSplitRatioConfig(const SplitRatioConfig& splitRatioConfig)
1098 {
1099     splitRatioConfig_ = splitRatioConfig;
1100 }
1101 
GetDividerRect(DisplayId displayId) const1102 Rect WindowLayoutPolicy::GetDividerRect(DisplayId displayId) const
1103 {
1104     return INVALID_EMPTY_RECT;
1105 }
1106 
IsTileRectSatisfiedWithSizeLimits(const sptr<WindowNode> & node)1107 bool WindowLayoutPolicy::IsTileRectSatisfiedWithSizeLimits(const sptr<WindowNode>& node)
1108 {
1109     return true;
1110 }
1111 
SetCascadeRectBottomPosYLimit(uint32_t floatingBottomPosY)1112 void WindowLayoutPolicy::SetCascadeRectBottomPosYLimit(uint32_t floatingBottomPosY)
1113 {
1114     floatingBottomPosY_ = floatingBottomPosY;
1115 }
1116 }
1117 }
1118