• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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_cascade.h"
17 
18 #include <hitrace_meter.h>
19 
20 #include "minimize_app.h"
21 #include "window_helper.h"
22 #include "window_inner_manager.h"
23 #include "window_manager_hilog.h"
24 
25 namespace OHOS {
26 namespace Rosen {
27 namespace {
28     constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "WindowLayoutPolicyCascade"};
29 }
30 
WindowLayoutPolicyCascade(const sptr<DisplayGroupInfo> & displayGroupInfo,DisplayGroupWindowTree & displayGroupWindowTree)31 WindowLayoutPolicyCascade::WindowLayoutPolicyCascade(const sptr<DisplayGroupInfo>& displayGroupInfo,
32     DisplayGroupWindowTree& displayGroupWindowTree)
33     : WindowLayoutPolicy(displayGroupInfo, displayGroupWindowTree)
34 {
35     LayoutRects cascadeRects {
36         .primaryRect_        = {0, 0, 0, 0},
37         .secondaryRect_      = {0, 0, 0, 0},
38         .primaryLimitRect_   = {0, 0, 0, 0},
39         .secondaryLimitRect_ = {0, 0, 0, 0},
40         .dividerRect_        = {0, 0, 0, 0},
41         .firstCascadeRect_   = {0, 0, 0, 0},
42     };
43     for (auto& iter : displayGroupInfo_->GetAllDisplayRects()) {
44         cascadeRectsMap_.insert(std::make_pair(iter.first, cascadeRects));
45     }
46 }
47 
Launch()48 void WindowLayoutPolicyCascade::Launch()
49 {
50     InitAllRects();
51     for (const auto& iter : displayGroupInfo_->GetAllDisplayRects()) {
52         DisplayId displayId = iter.first;
53         auto& displayWindowTree = displayGroupWindowTree_[displayId];
54         LayoutWindowNodesByRootType(*(displayWindowTree[WindowRootNodeType::APP_WINDOW_NODE]));
55         LayoutWindowNodesByRootType(*(displayWindowTree[WindowRootNodeType::BELOW_WINDOW_NODE]));
56     }
57     WLOGFI("WindowLayoutPolicyCascade::Launch");
58 }
59 
Clean()60 void WindowLayoutPolicyCascade::Clean()
61 {
62     WLOGFI("WindowLayoutPolicyCascade::Clean");
63 }
64 
Reset()65 void WindowLayoutPolicyCascade::Reset()
66 {
67     const auto& displayRectMap = displayGroupInfo_->GetAllDisplayRects();
68     // reset split and limit rects
69     for (auto& iter : displayRectMap) {
70         InitSplitRects(iter.first);
71         InitLimitRects(iter.first);
72     }
73     displayGroupLimitRect_ = displayGroupRect_;
74 }
75 
InitAllRects()76 void WindowLayoutPolicyCascade::InitAllRects()
77 {
78     const auto& displayRectMap = displayGroupInfo_->GetAllDisplayRects();
79     for (auto& iter : displayRectMap) {
80         // init split and limit rects
81         InitSplitRects(iter.first);
82         InitLimitRects(iter.first);
83         // init full displayRect
84         displayGroupLimitRect_ = displayGroupRect_;
85         // init cascade rect
86         auto& displayWindowTree = displayGroupWindowTree_[iter.first];
87         LayoutWindowNodesByRootType(*(displayWindowTree[WindowRootNodeType::ABOVE_WINDOW_NODE]));
88         InitCascadeRect(iter.first);
89     }
90 }
91 
LayoutWindowNode(const sptr<WindowNode> & node)92 void WindowLayoutPolicyCascade::LayoutWindowNode(const sptr<WindowNode>& node)
93 {
94     if (node == nullptr) {
95         return;
96     }
97     if (node->parent_ != nullptr) { // isn't root node
98         if (!node->currentVisibility_) {
99             WLOGFI("window[%{public}u] currently not visible, no need layout", node->GetWindowId());
100             return;
101         }
102         UpdateLayoutRect(node);
103         if (avoidTypes_.find(node->GetWindowType()) != avoidTypes_.end()) {
104             const DisplayId& displayId = node->GetDisplayId();
105             Rect& primaryLimitRect = cascadeRectsMap_[displayId].primaryLimitRect_;
106             Rect& secondaryLimitRect = cascadeRectsMap_[displayId].secondaryLimitRect_;
107             UpdateLimitRect(node, limitRectMap_[displayId]);
108             UpdateSplitLimitRect(limitRectMap_[displayId], primaryLimitRect);
109             UpdateSplitLimitRect(limitRectMap_[displayId], secondaryLimitRect);
110             UpdateSplitRatioPoints(displayId);
111             UpdateDisplayGroupLimitRect();
112             WLOGFI("priLimitRect: %{public}d %{public}d %{public}u %{public}u, " \
113                 "secLimitRect: %{public}d %{public}d %{public}u %{public}u", primaryLimitRect.posX_,
114                 primaryLimitRect.posY_, primaryLimitRect.width_, primaryLimitRect.height_, secondaryLimitRect.posX_,
115                 secondaryLimitRect.posY_, secondaryLimitRect.width_, secondaryLimitRect.height_);
116         }
117     }
118     for (auto& childNode : node->children_) {
119         LayoutWindowNode(childNode);
120     }
121 }
122 
LayoutWindowTree(DisplayId displayId)123 void WindowLayoutPolicyCascade::LayoutWindowTree(DisplayId displayId)
124 {
125     InitLimitRects(displayId);
126     WindowLayoutPolicy::LayoutWindowTree(displayId);
127 }
128 
RemoveWindowNode(const sptr<WindowNode> & node)129 void WindowLayoutPolicyCascade::RemoveWindowNode(const sptr<WindowNode>& node)
130 {
131     HITRACE_METER(HITRACE_TAG_WINDOW_MANAGER);
132     auto type = node->GetWindowType();
133     // affect other windows, trigger off global layout
134     if (avoidTypes_.find(type) != avoidTypes_.end()) {
135         LayoutWindowTree(node->GetDisplayId());
136     } else if (type == WindowType::WINDOW_TYPE_DOCK_SLICE) { // split screen mode
137         InitSplitRects(node->GetDisplayId());
138         LayoutWindowTree(node->GetDisplayId());
139     }
140     UpdateClientRect(node->GetRequestRect(), node, WindowSizeChangeReason::HIDE);
141 }
142 
GetExitSplitPoints(DisplayId displayId) const143 std::vector<int32_t> WindowLayoutPolicyCascade::GetExitSplitPoints(DisplayId displayId) const
144 {
145     return cascadeRectsMap_[displayId].exitSplitPoints_;
146 }
147 
SpecialReasonProcess(const sptr<WindowNode> & node,bool isAddWindow) const148 bool WindowLayoutPolicyCascade::SpecialReasonProcess(const sptr<WindowNode>& node, bool isAddWindow) const
149 {
150     const DisplayId& displayId = node->GetDisplayId();
151     if ((node->GetWindowSizeChangeReason() == WindowSizeChangeReason::MOVE) ||
152         (node->GetWindowSizeChangeReason() == WindowSizeChangeReason::RESIZE)) {
153         if ((node->GetRequestRect() == node->GetWindowRect()) && (!isAddWindow)) {
154             return false;
155         }
156     }
157     if (node->GetWindowSizeChangeReason() == WindowSizeChangeReason::ROTATION) {
158         const auto& windowNodeVecSptrs = displayGroupWindowTree_[displayId];
159         for (const auto& windowNodeVecSptr : windowNodeVecSptrs) {
160             const auto& windowNodeVec = *(windowNodeVecSptr.second);
161             for (auto& childNode : windowNodeVec) {
162                 childNode->SetWindowSizeChangeReason(WindowSizeChangeReason::ROTATION);
163             }
164         }
165     }
166     return true;
167 }
168 
UpdateWindowNode(const sptr<WindowNode> & node,bool isAddWindow)169 void WindowLayoutPolicyCascade::UpdateWindowNode(const sptr<WindowNode>& node, bool isAddWindow)
170 {
171     HITRACE_METER(HITRACE_TAG_WINDOW_MANAGER);
172     auto type = node->GetWindowType();
173     const DisplayId& displayId = node->GetDisplayId();
174     UpdateWindowNodeRectOffset(node);
175     // affect other windows, trigger off global layout
176     if (avoidTypes_.find(type) != avoidTypes_.end()) {
177         bool ret = SpecialReasonProcess(node, isAddWindow);
178         if (ret != true) {
179             return;
180         }
181         LayoutWindowTree(displayId);
182     } else if (type == WindowType::WINDOW_TYPE_DOCK_SLICE) { // split screen mode
183         UpdateLayoutRect(node);
184         auto splitDockerRect = node->GetWindowRect();
185         SetSplitRect(splitDockerRect, displayId); // calculate primary/secondary depend on divider rect
186         WLOGFI("UpdateDividerRects WinId: %{public}u, Rect: %{public}d %{public}d %{public}u %{public}u",
187             node->GetWindowId(), splitDockerRect.posX_, splitDockerRect.posY_,
188             splitDockerRect.width_, splitDockerRect.height_);
189         if (!isAddWindow) {
190             const auto& appWindowNodeVec = *(displayGroupWindowTree_[displayId][WindowRootNodeType::APP_WINDOW_NODE]);
191             for (auto& childNode : appWindowNodeVec) { // update split node size change reason
192                 if (childNode->IsSplitMode()) {
193                     childNode->SetWindowSizeChangeReason(WindowSizeChangeReason::DRAG);
194                 }
195             }
196         }
197         LayoutWindowTree(displayId);
198     } else if (node->IsSplitMode()) {
199         LayoutWindowTree(displayId);
200     } else { // layout single window
201         LayoutWindowNode(node);
202     }
203 }
204 
AddWindowNode(const sptr<WindowNode> & node)205 void WindowLayoutPolicyCascade::AddWindowNode(const sptr<WindowNode>& node)
206 {
207     HITRACE_METER(HITRACE_TAG_WINDOW_MANAGER);
208     auto property = node->GetWindowProperty();
209     if (property == nullptr) {
210         WLOGFE("window property is nullptr.");
211         return;
212     }
213 
214     if (WindowHelper::IsEmptyRect(property->GetRequestRect())) {
215         SetCascadeRect(node);
216     }
217     UpdateWindowNodeRectOffset(node);
218     if (node->GetWindowType() == WindowType::WINDOW_TYPE_DOCK_SLICE) {
219         node->SetRequestRect(cascadeRectsMap_[node->GetDisplayId()].dividerRect_); // init divider bar
220         DisplayId displayId = node->GetDisplayId();
221         if (!WindowHelper::IsEmptyRect(restoringDividerWindowRects_[displayId])) {
222             node->SetRequestRect(restoringDividerWindowRects_[displayId]);
223         }
224         restoringDividerWindowRects_.erase(displayId);
225     }
226     UpdateWindowNode(node, true); // currently, update and add do the same process
227 }
228 
SetSplitDividerWindowRects(std::map<DisplayId,Rect> dividerWindowRects)229 void WindowLayoutPolicyCascade::SetSplitDividerWindowRects(std::map<DisplayId, Rect> dividerWindowRects)
230 {
231     restoringDividerWindowRects_ = dividerWindowRects;
232 }
233 
LimitDividerMoveBounds(Rect & rect,DisplayId displayId) const234 void WindowLayoutPolicyCascade::LimitDividerMoveBounds(Rect& rect, DisplayId displayId) const
235 {
236     const Rect& limitRect = limitRectMap_[displayId];
237     if (rect.width_ < rect.height_) {
238         if (rect.posX_ < limitRect.posX_) {
239             rect.posX_ = limitRect.posX_;
240         } else if (rect.posX_ + static_cast<int32_t>(rect.width_) >
241             limitRect.posX_ + static_cast<int32_t>(limitRect.width_)) {
242             rect.posX_ = limitRect.posX_ + static_cast<int32_t>(limitRect.width_ - rect.width_);
243         }
244     } else {
245         if (rect.posY_ < limitRect.posY_) {
246             rect.posY_ = limitRect.posY_;
247         } else if (rect.posY_ + static_cast<int32_t>(rect.height_) >
248             limitRect.posY_ + static_cast<int32_t>(limitRect.height_)) {
249             rect.posY_ = limitRect.posY_ + static_cast<int32_t>(limitRect.height_ - rect.height_);
250         }
251     }
252     WLOGFI("limit divider move bounds:[%{public}d, %{public}d, %{public}u, %{public}u]",
253         rect.posX_, rect.posY_, rect.width_, rect.height_);
254 }
255 
InitCascadeRect(DisplayId displayId)256 void WindowLayoutPolicyCascade::InitCascadeRect(DisplayId displayId)
257 {
258     constexpr uint32_t half = 2;
259     constexpr float ratio = DEFAULT_ASPECT_RATIO;
260 
261     /*
262      * Calculate default width and height, if width or height is
263      * smaller than minWidth or minHeight, use the minimum limits
264      */
265     const auto& displayRect = displayGroupInfo_->GetDisplayRect(displayId);
266     auto vpr = displayGroupInfo_->GetDisplayVirtualPixelRatio(displayId);
267     uint32_t defaultW = std::max(static_cast<uint32_t>(displayRect.width_ * ratio),
268                                  static_cast<uint32_t>(MIN_FLOATING_WIDTH * vpr));
269     uint32_t defaultH = std::max(static_cast<uint32_t>(displayRect.height_ * ratio),
270                                  static_cast<uint32_t>(MIN_FLOATING_HEIGHT * vpr));
271 
272     // calculate default x and y
273     Rect resRect = {0, 0, defaultW, defaultH};
274     const Rect& limitRect = limitRectMap_[displayId];
275     if (defaultW <= limitRect.width_ && defaultH <= limitRect.height_) {
276         int32_t centerPosX = limitRect.posX_ + static_cast<int32_t>(limitRect.width_ / half);
277         resRect.posX_ = centerPosX - static_cast<int32_t>(defaultW / half);
278 
279         int32_t centerPosY = limitRect.posY_ + static_cast<int32_t>(limitRect.height_ / half);
280         resRect.posY_ = centerPosY - static_cast<int32_t>(defaultH / half);
281     }
282     WLOGFI("init CascadeRect :[%{public}d, %{public}d, %{public}d, %{public}d]",
283         resRect.posX_, resRect.posY_, resRect.width_, resRect.height_);
284     cascadeRectsMap_[displayId].firstCascadeRect_ = resRect;
285 }
286 
ApplyWindowRectConstraints(const sptr<WindowNode> & node,Rect & winRect) const287 void WindowLayoutPolicyCascade::ApplyWindowRectConstraints(const sptr<WindowNode>& node, Rect& winRect) const
288 {
289     WLOGFI("Before apply constraints winRect:[%{public}d, %{public}d, %{public}u, %{public}u]",
290         winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
291     auto reason = node->GetWindowSizeChangeReason();
292     DisplayId displayId = node->GetDisplayId();
293     if (node->GetWindowType() == WindowType::WINDOW_TYPE_DOCK_SLICE) {
294         // make sure the divider is entirely within display
295         LimitDividerMoveBounds(winRect, displayId);
296         if (reason == WindowSizeChangeReason::DRAG_END) {
297             if (!IsVerticalDisplay(displayId)) {
298                 UpdateDockSlicePosition(displayId, winRect.posX_);
299             } else {
300                 UpdateDockSlicePosition(displayId, winRect.posY_);
301             }
302         }
303         /*
304          * use the layout orientation of the window and the layout orientation of the screen
305          * to determine whether the screen is rotating
306          */
307         if ((!WindowHelper::IsLandscapeRect(winRect) && IsVerticalDisplay(displayId)) ||
308             (WindowHelper::IsLandscapeRect(winRect) && !IsVerticalDisplay(displayId))) {
309             // resets the rect of the divider window when the screen is rotating
310             WLOGFD("Reset divider when display rotate rect:[%{public}d, %{public}d, %{public}u, %{public}u]",
311                 winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
312             winRect = cascadeRectsMap_[displayId].dividerRect_;
313             node->SetRequestRect(winRect);
314         }
315     }
316     LimitFloatingWindowSize(node, displayGroupInfo_->GetDisplayRect(node->GetDisplayId()), winRect);
317     LimitMainFloatingWindowPosition(node, winRect);
318     WLOGFI("After apply constraints winRect:[%{public}d, %{public}d, %{public}u, %{public}u]",
319         winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
320 }
321 
UpdateLayoutRect(const sptr<WindowNode> & node)322 void WindowLayoutPolicyCascade::UpdateLayoutRect(const sptr<WindowNode>& node)
323 {
324     auto type = node->GetWindowType();
325     auto mode = node->GetWindowMode();
326     auto property = node->GetWindowProperty();
327     if (property == nullptr) {
328         WLOGFE("window property is nullptr.");
329         return;
330     }
331     UpdateWindowSizeLimits(node);
332     bool needAvoid = (node->GetWindowFlags() & static_cast<uint32_t>(WindowFlag::WINDOW_FLAG_NEED_AVOID));
333     bool parentLimit = (node->GetWindowFlags() & static_cast<uint32_t>(WindowFlag::WINDOW_FLAG_PARENT_LIMIT));
334     bool subWindow = WindowHelper::IsSubWindow(type) || WindowHelper::IsSystemSubWindow(type);
335     bool floatingWindow = (mode == WindowMode::WINDOW_MODE_FLOATING);
336     const Rect lastWinRect = node->GetWindowRect();
337     Rect displayRect = GetDisplayRect(mode, node->GetDisplayId());
338     Rect limitRect = displayRect;
339     ComputeDecoratedRequestRect(node);
340     Rect winRect = property->GetRequestRect();
341 
342     WLOGFI("Id:%{public}u, avoid:%{public}d parLimit:%{public}d floating:%{public}d, sub:%{public}d, " \
343         "deco:%{public}d, type:%{public}d, requestRect:[%{public}d, %{public}d, %{public}u, %{public}u]",
344         node->GetWindowId(), needAvoid, parentLimit, floatingWindow, subWindow, property->GetDecorEnable(),
345         static_cast<uint32_t>(type), winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
346     if (needAvoid) {
347         limitRect = GetLimitRect(mode, node->GetDisplayId());
348     }
349 
350     if (!floatingWindow) { // fullscreen window
351         winRect = limitRect;
352     } else { // floating window
353         if (subWindow && parentLimit && node->parent_) { // subwindow and limited by parent
354             limitRect = node->parent_->GetWindowRect();
355             UpdateFloatingLayoutRect(limitRect, winRect);
356         }
357     }
358     ApplyWindowRectConstraints(node, winRect);
359     node->SetWindowRect(winRect);
360     CalcAndSetNodeHotZone(winRect, node);
361     // update node bounds before reset reason
362     UpdateSurfaceBounds(node, winRect, lastWinRect);
363     UpdateClientRectAndResetReason(node, winRect);
364 }
365 
InitLimitRects(DisplayId displayId)366 void WindowLayoutPolicyCascade::InitLimitRects(DisplayId displayId)
367 {
368     limitRectMap_[displayId] = displayGroupInfo_->GetDisplayRect(displayId);
369     cascadeRectsMap_[displayId].primaryLimitRect_ = cascadeRectsMap_[displayId].primaryRect_;
370     cascadeRectsMap_[displayId].secondaryLimitRect_ = cascadeRectsMap_[displayId].secondaryRect_;
371     UpdateSplitRatioPoints(displayId);
372 }
373 
GetLimitRect(const WindowMode mode,DisplayId displayId) const374 Rect WindowLayoutPolicyCascade::GetLimitRect(const WindowMode mode, DisplayId displayId) const
375 {
376     if (mode == WindowMode::WINDOW_MODE_SPLIT_PRIMARY) {
377         return cascadeRectsMap_[displayId].primaryLimitRect_;
378     } else if (mode == WindowMode::WINDOW_MODE_SPLIT_SECONDARY) {
379         return cascadeRectsMap_[displayId].secondaryLimitRect_;
380     } else {
381         return limitRectMap_[displayId];
382     }
383 }
384 
GetDisplayRect(const WindowMode mode,DisplayId displayId) const385 Rect WindowLayoutPolicyCascade::GetDisplayRect(const WindowMode mode, DisplayId displayId) const
386 {
387     if (mode == WindowMode::WINDOW_MODE_SPLIT_PRIMARY) {
388         return cascadeRectsMap_[displayId].primaryRect_;
389     } else if (mode == WindowMode::WINDOW_MODE_SPLIT_SECONDARY) {
390         return cascadeRectsMap_[displayId].secondaryRect_;
391     } else {
392         return displayGroupInfo_->GetDisplayRect(displayId);
393     }
394 }
395 
UpdateSplitRatioPoints(DisplayId displayId)396 void WindowLayoutPolicyCascade::UpdateSplitRatioPoints(DisplayId displayId)
397 {
398     LayoutRects& cascadeRects = cascadeRectsMap_[displayId];
399     cascadeRects.exitSplitPoints_.clear();
400     cascadeRects.splitRatioPoints_.clear();
401     cascadeRects.exitSplitPoints_.push_back(GetSplitRatioPoint(splitRatioConfig_.exitSplitStartRatio, displayId));
402     cascadeRects.exitSplitPoints_.push_back(GetSplitRatioPoint(splitRatioConfig_.exitSplitEndRatio, displayId));
403     for (const auto& ratio : splitRatioConfig_.splitRatios) {
404         cascadeRects.splitRatioPoints_.push_back(GetSplitRatioPoint(ratio, displayId));
405     }
406 }
407 
UpdateDockSlicePosition(DisplayId displayId,int32_t & origin) const408 void WindowLayoutPolicyCascade::UpdateDockSlicePosition(DisplayId displayId, int32_t& origin) const
409 {
410     const LayoutRects& cascadeRects = cascadeRectsMap_[displayId];
411     if (cascadeRects.splitRatioPoints_.size() == 0) {
412         return;
413     }
414     uint32_t minDiff = std::max(limitRectMap_[displayId].width_, limitRectMap_[displayId].height_);
415     int32_t closestPoint = origin;
416     for (const auto& elem : cascadeRects.splitRatioPoints_) {
417         uint32_t diff = (origin > elem) ? static_cast<uint32_t>(origin - elem) : static_cast<uint32_t>(elem - origin);
418         if (diff < minDiff) {
419             closestPoint = elem;
420             minDiff = diff;
421         }
422     }
423     origin = closestPoint;
424 }
425 
UpdateSplitLimitRect(const Rect & limitRect,Rect & limitSplitRect)426 void WindowLayoutPolicyCascade::UpdateSplitLimitRect(const Rect& limitRect, Rect& limitSplitRect)
427 {
428     Rect curLimitRect = limitSplitRect;
429     limitSplitRect.posX_ = std::max(limitRect.posX_, curLimitRect.posX_);
430     limitSplitRect.posY_ = std::max(limitRect.posY_, curLimitRect.posY_);
431     limitSplitRect.width_ = std::min(limitRect.posX_ + limitRect.width_,
432                                      curLimitRect.posX_ + curLimitRect.width_) -
433                                      limitSplitRect.posX_;
434     limitSplitRect.height_ = std::min(limitRect.posY_ + limitRect.height_,
435                                       curLimitRect.posY_ + curLimitRect.height_) -
436                                       limitSplitRect.posY_;
437 }
438 
InitSplitRects(DisplayId displayId)439 void WindowLayoutPolicyCascade::InitSplitRects(DisplayId displayId)
440 {
441     float virtualPixelRatio = GetVirtualPixelRatio(displayId);
442     uint32_t dividerWidth = static_cast<uint32_t>(DIVIDER_WIDTH * virtualPixelRatio);
443     auto& dividerRect = cascadeRectsMap_[displayId].dividerRect_;
444     const auto& displayRect = displayGroupInfo_->GetDisplayRect(displayId);
445     if (!IsVerticalDisplay(displayId)) {
446         dividerRect = { static_cast<uint32_t>((displayRect.width_ - dividerWidth) * DEFAULT_SPLIT_RATIO), 0,
447                 dividerWidth, displayRect.height_ };
448     } else {
449         dividerRect = { 0, static_cast<uint32_t>((displayRect.height_ - dividerWidth) * DEFAULT_SPLIT_RATIO),
450                displayRect.width_, dividerWidth };
451     }
452     WLOGFI("init dividerRect :[%{public}d, %{public}d, %{public}u, %{public}u]",
453         dividerRect.posX_, dividerRect.posY_, dividerRect.width_, dividerRect.height_);
454     SetSplitRect(dividerRect, displayId);
455 }
456 
GetSplitRatioPoint(float ratio,DisplayId displayId)457 int32_t WindowLayoutPolicyCascade::GetSplitRatioPoint(float ratio, DisplayId displayId)
458 {
459     auto dividerRect = cascadeRectsMap_[displayId].dividerRect_;
460     auto displayRect = displayGroupInfo_->GetDisplayRect(displayId);
461     if (!IsVerticalDisplay(displayId)) {
462         return displayRect.posX_ +
463             static_cast<int32_t>((displayRect.width_ - dividerRect.width_) * ratio);
464     } else {
465         return displayRect.posY_ +
466             static_cast<int32_t>((displayRect.height_ - dividerRect.height_) * ratio);
467     }
468 }
469 
SetSplitRect(const Rect & divRect,DisplayId displayId)470 void WindowLayoutPolicyCascade::SetSplitRect(const Rect& divRect, DisplayId displayId)
471 {
472     auto& dividerRect = cascadeRectsMap_[displayId].dividerRect_;
473     auto& primaryRect = cascadeRectsMap_[displayId].primaryRect_;
474     auto& secondaryRect = cascadeRectsMap_[displayId].secondaryRect_;
475     const auto& displayRect = displayGroupInfo_->GetDisplayRect(displayId);
476 
477     dividerRect.width_ = divRect.width_;
478     dividerRect.height_ = divRect.height_;
479     if (!IsVerticalDisplay(displayId)) {
480         primaryRect.posX_ = displayRect.posX_;
481         primaryRect.posY_ = displayRect.posY_;
482         primaryRect.width_ = divRect.posX_;
483         primaryRect.height_ = displayRect.height_;
484 
485         secondaryRect.posX_ = divRect.posX_ + static_cast<int32_t>(dividerRect.width_);
486         secondaryRect.posY_ = displayRect.posY_;
487         secondaryRect.width_ = static_cast<uint32_t>(static_cast<int32_t>(displayRect.width_) - secondaryRect.posX_);
488         secondaryRect.height_ = displayRect.height_;
489     } else {
490         primaryRect.posX_ = displayRect.posX_;
491         primaryRect.posY_ = displayRect.posY_;
492         primaryRect.height_ = divRect.posY_;
493         primaryRect.width_ = displayRect.width_;
494 
495         secondaryRect.posX_ = displayRect.posX_;
496         secondaryRect.posY_ = divRect.posY_ + static_cast<int32_t>(dividerRect.height_);
497         secondaryRect.height_ = static_cast<uint32_t>(static_cast<int32_t>(displayRect.height_) - secondaryRect.posY_);
498         secondaryRect.width_ = displayRect.width_;
499     }
500 }
501 
Reorder()502 void WindowLayoutPolicyCascade::Reorder()
503 {
504     WLOGFI("Cascade reorder start");
505     for (const auto& iter : displayGroupInfo_->GetAllDisplayRects()) {
506         DisplayId displayId = iter.first;
507         Rect rect = cascadeRectsMap_[displayId].firstCascadeRect_;
508         bool isFirstReorderedWindow = true;
509         const auto& appWindowNodeVec = *(displayGroupWindowTree_[displayId][WindowRootNodeType::APP_WINDOW_NODE]);
510         for (auto nodeIter = appWindowNodeVec.begin(); nodeIter != appWindowNodeVec.end(); nodeIter++) {
511             auto node = *nodeIter;
512             if (node == nullptr || node->GetWindowType() != WindowType::WINDOW_TYPE_APP_MAIN_WINDOW) {
513                 WLOGFI("get node failed or not app window.");
514                 continue;
515             }
516             // if window don't support floating mode, or default rect of cascade is not satisfied with limits
517             if (!WindowHelper::IsWindowModeSupported(node->GetModeSupportInfo(), WindowMode::WINDOW_MODE_FLOATING) ||
518                 !WindowHelper::IsRectSatisfiedWithSizeLimits(rect, node->GetWindowUpdatedSizeLimits())) {
519                 MinimizeApp::AddNeedMinimizeApp(node, MinimizeReason::LAYOUT_CASCADE);
520                 continue;
521             }
522             if (isFirstReorderedWindow) {
523                 isFirstReorderedWindow = false;
524             } else {
525                 rect = StepCascadeRect(rect, displayId);
526             }
527             node->SetRequestRect(rect);
528             node->SetDecoStatus(true);
529             if (node->GetWindowMode() != WindowMode::WINDOW_MODE_FLOATING) {
530                 node->SetWindowMode(WindowMode::WINDOW_MODE_FLOATING);
531                 if (node->GetWindowToken()) {
532                     node->GetWindowToken()->UpdateWindowMode(WindowMode::WINDOW_MODE_FLOATING);
533                 }
534             }
535             WLOGFI("Cascade reorder Id: %{public}d, rect:[%{public}d, %{public}d, %{public}d, %{public}d]",
536                 node->GetWindowId(), rect.posX_, rect.posY_, rect.width_, rect.height_);
537         }
538         LayoutWindowTree(displayId);
539     }
540     WLOGFI("Reorder end");
541 }
542 
GetCurCascadeRect(const sptr<WindowNode> & node) const543 Rect WindowLayoutPolicyCascade::GetCurCascadeRect(const sptr<WindowNode>& node) const
544 {
545     Rect cascadeRect = {0, 0, 0, 0};
546     const DisplayId& displayId = node->GetDisplayId();
547     const auto& appWindowNodeVec = *(const_cast<WindowLayoutPolicyCascade*>(this)->
548         displayGroupWindowTree_[displayId][WindowRootNodeType::APP_WINDOW_NODE]);
549     const auto& aboveAppWindowNodeVec = *(const_cast<WindowLayoutPolicyCascade*>(this)->
550         displayGroupWindowTree_[displayId][WindowRootNodeType::ABOVE_WINDOW_NODE]);
551 
552     std::vector<std::vector<sptr<WindowNode>>> roots = { aboveAppWindowNodeVec, appWindowNodeVec };
553     for (auto& root : roots) {
554         for (auto iter = root.rbegin(); iter != root.rend(); iter++) {
555             if ((*iter)->GetWindowType() == WindowType::WINDOW_TYPE_APP_MAIN_WINDOW &&
556                 (*iter)->GetWindowId() != node->GetWindowId()) {
557                 auto property = (*iter)->GetWindowProperty();
558                 if (property != nullptr) {
559                     cascadeRect = ((*iter)->GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING ?
560                         property->GetWindowRect() : property->GetRequestRect());
561                 }
562                 WLOGFI("Get current cascadeRect: %{public}u [%{public}d, %{public}d, %{public}u, %{public}u]",
563                     (*iter)->GetWindowId(), cascadeRect.posX_, cascadeRect.posY_,
564                     cascadeRect.width_, cascadeRect.height_);
565                 break;
566             }
567         }
568     }
569 
570     if (WindowHelper::IsEmptyRect(cascadeRect)) {
571         WLOGFI("cascade rect is empty use first cascade rect");
572         return cascadeRectsMap_[displayId].firstCascadeRect_;
573     }
574     return StepCascadeRect(cascadeRect, displayId);
575 }
576 
StepCascadeRect(Rect rect,DisplayId displayId) const577 Rect WindowLayoutPolicyCascade::StepCascadeRect(Rect rect, DisplayId displayId) const
578 {
579     float virtualPixelRatio = GetVirtualPixelRatio(displayId);
580     uint32_t cascadeWidth = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio);
581     uint32_t cascadeHeight = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio);
582 
583     const Rect& limitRect = limitRectMap_[displayId];
584     Rect cascadeRect = {0, 0, 0, 0};
585     cascadeRect.width_ = rect.width_;
586     cascadeRect.height_ = rect.height_;
587     cascadeRect.posX_ = (rect.posX_ + static_cast<int32_t>(cascadeWidth) >= limitRect.posX_) &&
588                         (rect.posX_ + static_cast<int32_t>(rect.width_ + cascadeWidth) <=
589                         (limitRect.posX_ + static_cast<int32_t>(limitRect.width_))) ?
590                         (rect.posX_ + static_cast<int32_t>(cascadeWidth)) : limitRect.posX_;
591     cascadeRect.posY_ = (rect.posY_ + static_cast<int32_t>(cascadeHeight) >= limitRect.posY_) &&
592                         (rect.posY_ + static_cast<int32_t>(rect.height_ + cascadeHeight) <=
593                         (limitRect.posY_ + static_cast<int32_t>(limitRect.height_))) ?
594                         (rect.posY_ + static_cast<int32_t>(cascadeHeight)) : limitRect.posY_;
595     WLOGFI("step cascadeRect :[%{public}d, %{public}d, %{public}u, %{public}u]",
596         cascadeRect.posX_, cascadeRect.posY_, cascadeRect.width_, cascadeRect.height_);
597     return cascadeRect;
598 }
599 
SetCascadeRect(const sptr<WindowNode> & node)600 void WindowLayoutPolicyCascade::SetCascadeRect(const sptr<WindowNode>& node)
601 {
602     static bool isFirstAppWindow = true;
603     Rect rect;
604     auto property = node->GetWindowProperty();
605     if (property == nullptr) {
606         WLOGFE("window property is nullptr.");
607         return;
608     }
609     if (WindowHelper::IsAppWindow(property->GetWindowType()) && isFirstAppWindow) {
610         WLOGFI("set first app window cascade rect");
611         rect = cascadeRectsMap_[node->GetDisplayId()].firstCascadeRect_;
612         isFirstAppWindow = false;
613     } else if (WindowHelper::IsAppWindow(property->GetWindowType()) && !isFirstAppWindow) {
614         WLOGFI("set other app window cascade rect");
615         rect = GetCurCascadeRect(node);
616     } else {
617         // system window
618         WLOGFI("set system window cascade rect");
619         rect = cascadeRectsMap_[node->GetDisplayId()].firstCascadeRect_;
620     }
621     WLOGFI("set cascadeRect :[%{public}d, %{public}d, %{public}u, %{public}u]",
622         rect.posX_, rect.posY_, rect.width_, rect.height_);
623     node->SetRequestRect(rect);
624     node->SetDecoStatus(true);
625 }
GetDividerRect(DisplayId displayId) const626 Rect WindowLayoutPolicyCascade::GetDividerRect(DisplayId displayId) const
627 {
628     Rect dividerRect = {0, 0, 0, 0};
629     if (cascadeRectsMap_.find(displayId) != std::end(cascadeRectsMap_)) {
630         dividerRect = cascadeRectsMap_[displayId].dividerRect_;
631     }
632     return dividerRect;
633 }
634 
UpdateWindowNodeRectOffset(const sptr<WindowNode> & node) const635 void WindowLayoutPolicyCascade::UpdateWindowNodeRectOffset(const sptr<WindowNode>& node) const
636 {
637     WLOGFD("UpdateWindowNodeRectOffset, windowId: %{public}u", node->GetWindowId());
638     auto displayId = node->GetDisplayId();
639     const Rect& displayRect = displayGroupInfo_->GetDisplayRect(displayId);
640     auto displayInfo = displayGroupInfo_->GetDisplayInfo(displayId);
641     auto type = node->GetWindowType();
642     Rect rect = node->GetRequestRect();
643     WLOGFD("RequestRect before, width: %{public}u, height: %{public}u, posX:%{public}d, posY:%{public}d",
644         rect.width_, rect.height_, rect.posX_, rect.posY_);
645     switch (type) {
646         case WindowType::WINDOW_TYPE_STATUS_BAR: {
647             rect.posY_ = displayRect.posY_;
648             break;
649         }
650         case WindowType::WINDOW_TYPE_NAVIGATION_BAR: {
651             rect.posY_ = static_cast<int32_t>(displayRect.height_) + displayRect.posY_ -
652                 static_cast<int32_t>(rect.height_);
653             break;
654         }
655         default: {
656             if (displayInfo->GetWaterfallDisplayCompressionStatus()) {
657                 if (rect.posY_ < displayRect.posY_) {
658                     rect.posY_ = displayRect.posY_;
659                 } else if (rect.posY_ > displayRect.posY_ + static_cast<int32_t>(displayRect.height_)) {
660                     rect.posY_ = displayRect.posY_ + static_cast<int32_t>(displayRect.height_);
661                 }
662             }
663         }
664     }
665     node->SetRequestRect(rect);
666     WLOGFD("RequestRect after, width: %{public}u, height: %{public}u, posX:%{public}d, posY:%{public}d",
667         rect.width_, rect.height_, rect.posX_, rect.posY_);
668 }
669 
670 } // Rosen
671 } // OHOS
672