1 /*
2  * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "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 #include "window_manager_service_utils.h"
25 #include "window_system_effect.h"
26 #include "wm_math.h"
27 
28 namespace OHOS {
29 namespace Rosen {
30 namespace {
31 constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "Cascade"};
32 }
33 
WindowLayoutPolicyCascade(DisplayGroupWindowTree& displayGroupWindowTree)34 WindowLayoutPolicyCascade::WindowLayoutPolicyCascade(DisplayGroupWindowTree& displayGroupWindowTree)
35     : WindowLayoutPolicy(displayGroupWindowTree)
36 {
37     CascadeRects cascadeRects {
38         .primaryRect_        = {0, 0, 0, 0},
39         .secondaryRect_      = {0, 0, 0, 0},
40         .dividerRect_        = {0, 0, 0, 0},
41         .defaultCascadeRect_ = {0, 0, 0, 0},
42     };
43     for (auto& iter : DisplayGroupInfo::GetInstance().GetAllDisplayRects()) {
44         cascadeRectsMap_.insert(std::make_pair(iter.first, cascadeRects));
45     }
46 }
47 
Launch()48 void WindowLayoutPolicyCascade::Launch()
49 {
50     InitAllRects();
51     WLOGI("WindowLayoutPolicyCascade::Launch");
52 }
53 
Reorder()54 void WindowLayoutPolicyCascade::Reorder()
55 {
56     WLOGFD("Cascade reorder start");
57     for (auto& iter : DisplayGroupInfo::GetInstance().GetAllDisplayRects()) {
58         DisplayId displayId = iter.first;
59         Rect rect = cascadeRectsMap_[displayId].defaultCascadeRect_;
60         bool isFirstReorderedWindow = true;
61         const auto& appWindowNodeVec = *(displayGroupWindowTree_[displayId][WindowRootNodeType::APP_WINDOW_NODE]);
62         for (auto nodeIter = appWindowNodeVec.begin(); nodeIter != appWindowNodeVec.end(); nodeIter++) {
63             auto node = *nodeIter;
64             if (node == nullptr || node->GetWindowType() != WindowType::WINDOW_TYPE_APP_MAIN_WINDOW) {
65                 WLOGFW("get node failed or not app window.");
66                 continue;
67             }
68             // if window don't support floating mode, or default rect of cascade is not satisfied with limits
69             if (!WindowHelper::IsWindowModeSupported(node->GetModeSupportInfo(), WindowMode::WINDOW_MODE_FLOATING) ||
70                 !WindowHelper::IsRectSatisfiedWithSizeLimits(rect, node->GetWindowUpdatedSizeLimits())) {
71                 MinimizeApp::AddNeedMinimizeApp(node, MinimizeReason::LAYOUT_CASCADE);
72                 continue;
73             }
74             if (isFirstReorderedWindow) {
75                 isFirstReorderedWindow = false;
76             } else {
77                 rect = StepCascadeRect(rect, displayId);
78             }
79             node->SetRequestRect(rect);
80             node->SetDecoStatus(true);
81             if (node->GetWindowMode() != WindowMode::WINDOW_MODE_FLOATING) {
82                 node->SetWindowMode(WindowMode::WINDOW_MODE_FLOATING);
83                 // when change mode, need to reset shadow and radius
84                 WindowSystemEffect::SetWindowEffect(node);
85                 if (node->GetWindowToken()) {
86                     node->GetWindowToken()->UpdateWindowMode(WindowMode::WINDOW_MODE_FLOATING);
87                 }
88             }
89             WLOGFD("Cascade reorder Id: %{public}d, rect:[%{public}d, %{public}d, %{public}d, %{public}d]",
90                 node->GetWindowId(), rect.posX_, rect.posY_, rect.width_, rect.height_);
91         }
92         LayoutWindowTree(displayId);
93     }
94     WLOGI("Cascade Reorder end");
95 }
96 
InitAllRects()97 void WindowLayoutPolicyCascade::InitAllRects()
98 {
99     UpdateDisplayGroupRect();
100     for (auto& iter : DisplayGroupInfo::GetInstance().GetAllDisplayRects()) {
101         auto displayId = iter.first;
102         InitSplitRects(displayId);
103         LayoutWindowTree(displayId);
104         InitCascadeRect(displayId);
105     }
106 }
107 
LayoutSplitNodes(DisplayId displayId, WindowUpdateType type, bool layoutByDivider)108 void WindowLayoutPolicyCascade::LayoutSplitNodes(DisplayId displayId, WindowUpdateType type, bool layoutByDivider)
109 {
110     std::vector<WindowRootNodeType> rootNodeType = {
111         WindowRootNodeType::ABOVE_WINDOW_NODE,
112         WindowRootNodeType::APP_WINDOW_NODE,
113         WindowRootNodeType::BELOW_WINDOW_NODE
114     };
115     for (const auto& rootType : rootNodeType) {
116         if (displayGroupWindowTree_[displayId].find(rootType) == displayGroupWindowTree_[displayId].end()) {
117             continue;
118         }
119         auto appWindowNodeVec = *(displayGroupWindowTree_[displayId][rootType]);
120         for (const auto& childNode : appWindowNodeVec) {
121             if (type == WindowUpdateType::WINDOW_UPDATE_REMOVED) {
122                 /*
123                 * If updateType is remove we need to layout all appNodes, cause remove split node or
124                 * divider means exit split mode, split node may change to other mode
125                 */
126                 LayoutWindowNode(childNode);
127             } else if (childNode->IsSplitMode()) { // add or update type, layout split node
128                 if (layoutByDivider && type == WindowUpdateType::WINDOW_UPDATE_ACTIVE) {
129                     childNode->SetWindowSizeChangeReason(WindowSizeChangeReason::DRAG);
130                 }
131                 LayoutWindowNode(childNode);
132             }
133         }
134     }
135 }
136 
LayoutDivider(const sptr<WindowNode>& node, WindowUpdateType type)137 void WindowLayoutPolicyCascade::LayoutDivider(const sptr<WindowNode>& node, WindowUpdateType type)
138 {
139     auto displayId = node->GetDisplayId();
140     switch (type) {
141         case WindowUpdateType::WINDOW_UPDATE_ADDED:
142             SetInitialDividerRect(node, displayId);
143             [[fallthrough]];
144         case WindowUpdateType::WINDOW_UPDATE_ACTIVE:
145             UpdateDividerPosition(node);
146             LayoutWindowNode(node);
147             SetSplitRectByDivider(node->GetWindowRect(), displayId); // set splitRect by divider
148             break;
149         case WindowUpdateType::WINDOW_UPDATE_REMOVED:
150             InitSplitRects(displayId); // reinit split rects when remove divider
151             break;
152         default:
153             WLOGFW("Unknown update type, type: %{public}u", type);
154     }
155     LayoutSplitNodes(displayId, type, true);
156 }
157 
LayoutPreProcess(const sptr<WindowNode>& node, WindowUpdateType updateType)158 void WindowLayoutPolicyCascade::LayoutPreProcess(const sptr<WindowNode>& node, WindowUpdateType updateType)
159 {
160     if (updateType == WindowUpdateType::WINDOW_UPDATE_ADDED) {
161         // Get aspect ratio from persistent storage when add window
162         GetStoragedAspectRatio(node);
163     }
164     SetDefaultCascadeRect(node);
165     FixWindowRectWithinDisplay(node);
166 }
167 
PerformWindowLayout(const sptr<WindowNode>& node, WindowUpdateType updateType)168 void WindowLayoutPolicyCascade::PerformWindowLayout(const sptr<WindowNode>& node, WindowUpdateType updateType)
169 {
170     HITRACE_METER(HITRACE_TAG_WINDOW_MANAGER);
171     const auto& windowType = node->GetWindowType();
172     const auto& requestRect = node->GetRequestRect();
173     WLOGFD("windowId: %{public}u, windowType: %{public}u, updateType: %{public}u, requestRect: "
174         "requestRect: [%{public}d, %{public}d, %{public}u, %{public}u]", node->GetWindowId(), windowType, updateType,
175         requestRect.posX_, requestRect.posY_, requestRect.width_, requestRect.height_);
176 
177     LayoutPreProcess(node, updateType);
178     switch (windowType) {
179         case WindowType::WINDOW_TYPE_DOCK_SLICE:
180             LayoutDivider(node, updateType);
181             break;
182         case WindowType::WINDOW_TYPE_STATUS_BAR:
183         case WindowType::WINDOW_TYPE_NAVIGATION_BAR:
184         case WindowType::WINDOW_TYPE_LAUNCHER_DOCK:
185             LayoutWindowTree(node->GetDisplayId());
186             // AvoidNodes will change limitRect, need to recalculate default cascade rect
187             InitCascadeRect(node->GetDisplayId());
188             break;
189         default:
190             if (node->IsSplitMode()) {
191                 LayoutSplitNodes(node->GetDisplayId(), updateType);
192             } else {
193                 LayoutWindowNode(node);
194             }
195     }
196     if (updateType == WindowUpdateType::WINDOW_UPDATE_REMOVED) {
197         NotifyClientAndAnimation(node, node->GetRequestRect(), WindowSizeChangeReason::HIDE);
198     }
199 }
200 
SetInitialDividerRect(const sptr<WindowNode>& node, DisplayId displayId)201 void WindowLayoutPolicyCascade::SetInitialDividerRect(const sptr<WindowNode>& node, DisplayId displayId)
202 {
203     const auto& restoredRect = restoringDividerWindowRects_[displayId];
204     const auto& presetRect = cascadeRectsMap_[node->GetDisplayId()].dividerRect_;
205     auto divRect = WindowHelper::IsEmptyRect(restoredRect) ? presetRect : restoredRect;
206     node->SetRequestRect(divRect);
207     restoringDividerWindowRects_.erase(displayId);
208 }
209 
SetSplitDividerWindowRects(std::map<DisplayId, Rect> dividerWindowRects)210 void WindowLayoutPolicyCascade::SetSplitDividerWindowRects(std::map<DisplayId, Rect> dividerWindowRects)
211 {
212     restoringDividerWindowRects_ = dividerWindowRects;
213 }
214 
LimitDividerInDisplayRegion(Rect& rect, DisplayId displayId) const215 void WindowLayoutPolicyCascade::LimitDividerInDisplayRegion(Rect& rect, DisplayId displayId) const
216 {
217     const Rect& limitRect = limitRectMap_[displayId];
218     if (rect.width_ < rect.height_) {
219         if (rect.posX_ < limitRect.posX_) {
220             rect.posX_ = limitRect.posX_;
221         } else if (rect.posX_ + static_cast<int32_t>(rect.width_) >
222             limitRect.posX_ + static_cast<int32_t>(limitRect.width_)) {
223             rect.posX_ = limitRect.posX_ + static_cast<int32_t>(limitRect.width_ - rect.width_);
224         }
225     } else {
226         if (rect.posY_ < limitRect.posY_) {
227             rect.posY_ = limitRect.posY_;
228         } else if (rect.posY_ + static_cast<int32_t>(rect.height_) >
229             limitRect.posY_ + static_cast<int32_t>(limitRect.height_)) {
230             rect.posY_ = limitRect.posY_ + static_cast<int32_t>(limitRect.height_ - rect.height_);
231         }
232     }
233     WLOGFD("limit divider move bounds: [%{public}d, %{public}d, %{public}u, %{public}u]",
234         rect.posX_, rect.posY_, rect.width_, rect.height_);
235 }
236 
UpdateDividerPosition(const sptr<WindowNode>& node) const237 void WindowLayoutPolicyCascade::UpdateDividerPosition(const sptr<WindowNode>& node) const
238 {
239     auto rect = node->GetRequestRect();
240     auto displayId = node->GetDisplayId();
241     LimitDividerInDisplayRegion(rect, displayId);
242     if (node->GetWindowSizeChangeReason() == WindowSizeChangeReason::DRAG_END) {
243         LimitDividerPositionBySplitRatio(displayId, rect);
244     }
245     node->SetRequestRect(rect);
246 }
247 
InitCascadeRect(DisplayId displayId)248 void WindowLayoutPolicyCascade::InitCascadeRect(DisplayId displayId)
249 {
250     constexpr uint32_t half = 2;
251     constexpr float ratio = DEFAULT_ASPECT_RATIO;
252 
253     /*
254      * Calculate default width and height, if width or height is
255      * smaller than minWidth or minHeight, use the minimum limits
256      */
257     const auto& displayRect = DisplayGroupInfo::GetInstance().GetDisplayRect(displayId);
258     auto vpr = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(displayId);
259     uint32_t defaultW = std::max(static_cast<uint32_t>(displayRect.width_ * ratio),
260                                  static_cast<uint32_t>(MIN_FLOATING_WIDTH * vpr));
261     uint32_t defaultH = std::max(static_cast<uint32_t>(displayRect.height_ * ratio),
262                                  static_cast<uint32_t>(MIN_FLOATING_HEIGHT * vpr));
263 
264     // calculate default x and y
265     Rect resRect = {0, 0, defaultW, defaultH};
266     const Rect& limitRect = limitRectMap_[displayId];
267     if (defaultW <= limitRect.width_ && defaultH <= limitRect.height_) {
268         resRect.posX_ = limitRect.posX_ + static_cast<int32_t>((limitRect.width_ - defaultW) / half);
269 
270         resRect.posY_ = limitRect.posY_ + static_cast<int32_t>((limitRect.height_ - defaultH) / half);
271     }
272     WLOGI("Init CascadeRect :[%{public}d, %{public}d, %{public}d, %{public}d]",
273         resRect.posX_, resRect.posY_, resRect.width_, resRect.height_);
274     cascadeRectsMap_[displayId].defaultCascadeRect_ = resRect;
275 }
276 
CheckAspectRatioBySizeLimits(const sptr<WindowNode>& node, WindowLimits& newLimits) const277 bool WindowLayoutPolicyCascade::CheckAspectRatioBySizeLimits(const sptr<WindowNode>& node,
278     WindowLimits& newLimits) const
279 {
280     // get new limit config with the settings of system and app
281     const auto& sizeLimits = node->GetWindowUpdatedSizeLimits();
282     if (node->GetWindowProperty() != nullptr && !node->GetWindowProperty()->GetDecorEnable()) {
283         newLimits = sizeLimits;
284     } else {
285         float vpr = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(node->GetDisplayId());
286         uint32_t winFrameW = static_cast<uint32_t>(WINDOW_FRAME_WIDTH * vpr) * 2; // 2 mean double decor width
287         uint32_t winFrameH = static_cast<uint32_t>(WINDOW_FRAME_WIDTH * vpr) +
288             static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * vpr); // decor height
289 
290         newLimits.maxWidth_ = sizeLimits.maxWidth_ - winFrameW;
291         newLimits.minWidth_ = sizeLimits.minWidth_ - winFrameW;
292         newLimits.maxHeight_ = sizeLimits.maxHeight_ - winFrameH;
293         newLimits.minHeight_ = sizeLimits.minHeight_ - winFrameH;
294     }
295 
296     float maxRatio = static_cast<float>(newLimits.maxWidth_) / static_cast<float>(newLimits.minHeight_);
297     float minRatio = static_cast<float>(newLimits.minWidth_) / static_cast<float>(newLimits.maxHeight_);
298     float aspectRatio = node->GetAspectRatio();
299     if (MathHelper::GreatNotEqual(aspectRatio, maxRatio) ||
300         MathHelper::LessNotEqual(aspectRatio, minRatio)) {
301         return false;
302     }
303     uint32_t newMaxWidth = static_cast<uint32_t>(static_cast<float>(newLimits.maxHeight_) * aspectRatio);
304     newLimits.maxWidth_ = std::min(newMaxWidth, newLimits.maxWidth_);
305     uint32_t newMinWidth = static_cast<uint32_t>(static_cast<float>(newLimits.minHeight_) * aspectRatio);
306     newLimits.minWidth_ = std::max(newMinWidth, newLimits.minWidth_);
307     uint32_t newMaxHeight = static_cast<uint32_t>(static_cast<float>(newLimits.maxWidth_) / aspectRatio);
308     newLimits.maxHeight_ = std::min(newMaxHeight, newLimits.maxHeight_);
309     uint32_t newMinHeight = static_cast<uint32_t>(static_cast<float>(newLimits.minWidth_) / aspectRatio);
310     newLimits.minHeight_ = std::max(newMinHeight, newLimits.minHeight_);
311     return true;
312 }
313 
ComputeRectByAspectRatio(const sptr<WindowNode>& node) const314 void WindowLayoutPolicyCascade::ComputeRectByAspectRatio(const sptr<WindowNode>& node) const
315 {
316     float aspectRatio = node->GetAspectRatio();
317     if (!WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode()) ||
318         node->GetWindowSizeChangeReason() == WindowSizeChangeReason::MOVE || MathHelper::NearZero(aspectRatio)) {
319         return;
320     }
321 
322     // 1. check ratio by size limits
323     WindowLimits newLimits;
324     if (!CheckAspectRatioBySizeLimits(node, newLimits)) {
325         return;
326     }
327 
328     float vpr = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(node->GetDisplayId());
329     uint32_t winFrameW = static_cast<uint32_t>(WINDOW_FRAME_WIDTH * vpr) * 2; // 2 mean double decor width
330     uint32_t winFrameH = static_cast<uint32_t>(WINDOW_FRAME_WIDTH * vpr) +
331         static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * vpr); // decor height
332 
333     // 2. get rect without decoration if enable decoration
334     auto newRect = node->GetRequestRect();
335     if (node->GetWindowProperty() != nullptr && node->GetWindowProperty()->GetDecorEnable()) {
336         newRect.width_ -= winFrameW;
337         newRect.height_ -= winFrameH;
338     }
339     auto oriRect = newRect;
340 
341     // 3. update window rect by new limits and aspect ratio
342     newRect.width_ = std::max(newLimits.minWidth_, newRect.width_);
343     newRect.height_ = std::max(newLimits.minHeight_, newRect.height_);
344     newRect.width_ = std::min(newLimits.maxWidth_, newRect.width_);
345     newRect.height_ = std::min(newLimits.maxHeight_, newRect.height_);
346     float curRatio = static_cast<float>(newRect.width_) / static_cast<float>(newRect.height_);
347     if (std::abs(curRatio - aspectRatio) > 0.0001f) {
348         if (node->GetDragType() == DragType::DRAG_BOTTOM_OR_TOP) {
349             // if drag height, use height to fix size.
350             newRect.width_ = static_cast<uint32_t>(static_cast<float>(newRect.height_) * aspectRatio);
351         } else {
352             // if drag width or corner, use width to fix size.
353             newRect.height_ = static_cast<uint32_t>(static_cast<float>(newRect.width_) / aspectRatio);
354         }
355     }
356 
357     // 4. fix window pos in case of moving window when dragging
358     FixWindowRectWhenDrag(node, oriRect, newRect);
359 
360     // 5. if posY is smaller than limit posY when drag, use the last window rect
361     if (newRect.posY_ < limitRectMap_[node->GetDisplayId()].posY_ &&
362         node->GetWindowSizeChangeReason() == WindowSizeChangeReason::DRAG) {
363         auto lastRect = node->GetWindowRect();
364         lastRect.width_ -= winFrameW;
365         lastRect.height_ -= winFrameH;
366         newRect = lastRect;
367     }
368     node->SetRequestRect(newRect);
369     node->SetDecoStatus(false); // newRect is not rect with decor, reset decor status
370     WLOGFD("WinId: %{public}u, newRect: %{public}d %{public}d %{public}u %{public}u",
371         node->GetWindowId(), newRect.posX_, newRect.posY_, newRect.width_, newRect.height_);
372 }
373 
ComputeDecoratedRequestRect(const sptr<WindowNode>& node) const374 void WindowLayoutPolicyCascade::ComputeDecoratedRequestRect(const sptr<WindowNode>& node) const
375 {
376     auto property = node->GetWindowProperty();
377     if (property == nullptr) {
378         WLOGE("window property is nullptr");
379         return;
380     }
381 
382     if (!property->GetDecorEnable() || property->GetDecoStatus() ||
383         node->GetWindowSizeChangeReason() == WindowSizeChangeReason::MOVE) {
384         return;
385     }
386 
387     float virtualPixelRatio = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(node->GetDisplayId());
388     uint32_t winFrameW = static_cast<uint32_t>(WINDOW_FRAME_WIDTH * virtualPixelRatio);
389     uint32_t winTitleBarH = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio);
390 
391     auto oriRect = property->GetRequestRect();
392     Rect dstRect;
393     dstRect.posX_ = oriRect.posX_;
394     dstRect.posY_ = oriRect.posY_;
395     dstRect.width_ = oriRect.width_ + winFrameW + winFrameW;
396     dstRect.height_ = oriRect.height_ + winTitleBarH + winFrameW;
397     property->SetRequestRect(dstRect);
398     property->SetDecoStatus(true);
399 }
400 
ApplyWindowRectConstraints(const sptr<WindowNode>& node, Rect& winRect) const401 void WindowLayoutPolicyCascade::ApplyWindowRectConstraints(const sptr<WindowNode>& node, Rect& winRect) const
402 {
403     WLOGFD("[Before constraints] windowId: %{public}u, winRect:[%{public}d, %{public}d, %{public}u, %{public}u]",
404         node->GetWindowId(), winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
405     ComputeRectByAspectRatio(node);
406     ComputeDecoratedRequestRect(node);
407     winRect = node->GetRequestRect();
408     LimitFloatingWindowSize(node, winRect);
409     LimitMainFloatingWindowPosition(node, winRect);
410 
411     /*
412      * Use the orientation of the window and display to determine
413      * whether the screen is rotating, then rotate the divider
414      */
415     if (node->GetWindowType() == WindowType::WINDOW_TYPE_DOCK_SLICE &&
416         ((!WindowHelper::IsLandscapeRect(winRect) && IsVerticalDisplay(node->GetDisplayId())) ||
417         (WindowHelper::IsLandscapeRect(winRect) && !IsVerticalDisplay(node->GetDisplayId())))) {
418         winRect = cascadeRectsMap_[node->GetDisplayId()].dividerRect_;
419         node->SetRequestRect(winRect);
420         WLOGFD("Reset divider when display rotation, divRect: [%{public}d, %{public}d, %{public}u, %{public}u]",
421             winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
422     }
423 
424     WLOGFD("[After constraints] windowId: %{public}u, winRect:[%{public}d, %{public}d, %{public}u, %{public}u]",
425         node->GetWindowId(), winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
426 }
427 
UpdateLayoutRect(const sptr<WindowNode>& node)428 void WindowLayoutPolicyCascade::UpdateLayoutRect(const sptr<WindowNode>& node)
429 {
430     auto property = node->GetWindowProperty();
431     if (property == nullptr) {
432         WLOGFE("window property is nullptr.");
433         return;
434     }
435     auto mode = node->GetWindowMode();
436     Rect winRect = property->GetRequestRect();
437     auto displayId = node->GetDisplayId();
438     WLOGFD("[Before CascadeLayout] windowId: %{public}u, mode: %{public}u, type: %{public}u requestRect: [%{public}d, "
439         "%{public}d, %{public}u, %{public}u]", node->GetWindowId(), mode, node->GetWindowType(), winRect.posX_,
440         winRect.posY_, winRect.width_, winRect.height_);
441     switch (mode) {
442         case WindowMode::WINDOW_MODE_SPLIT_PRIMARY:
443             winRect = cascadeRectsMap_[displayId].primaryRect_;
444             break;
445         case WindowMode::WINDOW_MODE_SPLIT_SECONDARY:
446             winRect = cascadeRectsMap_[displayId].secondaryRect_;
447             break;
448         case WindowMode::WINDOW_MODE_FULLSCREEN: {
449             UpdateWindowSizeLimits(node);
450             bool needAvoid = (node->GetWindowFlags() & static_cast<uint32_t>(WindowFlag::WINDOW_FLAG_NEED_AVOID));
451             winRect = needAvoid ? limitRectMap_[displayId] : DisplayGroupInfo::GetInstance().GetDisplayRect(displayId);
452             auto displayInfo = DisplayGroupInfo::GetInstance().GetDisplayInfo(displayId);
453             if (displayInfo && WmsUtils::IsExpectedRotatableWindow(node->GetRequestedOrientation(),
454                 displayInfo->GetDisplayOrientation(), node->GetWindowFlags())) {
455                 WLOGFD("[FixOrientation] the window is expected rotatable, pre-calculated");
456                 winRect = {winRect.posX_, winRect.posY_, winRect.height_, winRect.width_};
457             }
458             if (property->GetMaximizeMode() == MaximizeMode::MODE_AVOID_SYSTEM_BAR) {
459                 // restore the origin rect so when recover from fullscreen we can use
460                 node->SetRequestRect(node->GetOriginRect());
461                 property->SetMaximizeMode(MaximizeMode::MODE_FULL_FILL);
462             }
463             break;
464         }
465         case WindowMode::WINDOW_MODE_FLOATING: {
466             if (node->GetWindowType() == WindowType::WINDOW_TYPE_APP_COMPONENT) {
467                 break;
468             }
469             UpdateWindowSizeLimits(node);
470             winRect = property->GetRequestRect();
471             ApplyWindowRectConstraints(node, winRect);
472 
473             if (property->GetMaximizeMode() == MaximizeMode::MODE_AVOID_SYSTEM_BAR) {
474                 GetMaximizeRect(node, winRect);
475                 WLOGFI("[In CascadeLayout] winId: %{public}u, maxRect: %{public}d, %{public}d, %{public}u, %{public}u",
476                     node->GetWindowId(), winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
477             }
478             break;
479         }
480         default:
481             WLOGFW("Layout invalid mode, winId: %{public}u, mode: %{public}u", node->GetWindowId(), mode);
482     }
483     WLOGFD("[After CascadeLayout] windowId: %{public}u, isDecor: %{public}u, winRect: [%{public}d, %{public}d, "
484         "%{public}u, %{public}u], reason: %{public}u", node->GetWindowId(), node->GetDecoStatus(), winRect.posX_,
485         winRect.posY_, winRect.width_, winRect.height_, node->GetWindowSizeChangeReason());
486 
487     const Rect& lastWinRect = node->GetWindowRect();
488     node->SetWindowRect(winRect);
489 
490     // postProcess after update winRect
491     CalcAndSetNodeHotZone(winRect, node);
492     UpdateSurfaceBounds(node, winRect, lastWinRect);
493     NotifyClientAndAnimation(node, winRect, node->GetWindowSizeChangeReason());
494 }
495 
LimitDividerPositionBySplitRatio(DisplayId displayId, Rect& winRect) const496 void WindowLayoutPolicyCascade::LimitDividerPositionBySplitRatio(DisplayId displayId, Rect& winRect) const
497 {
498     int32_t oriPos = IsVerticalDisplay(displayId) ? winRect.posY_ : winRect.posX_;
499     int32_t& dstPos = IsVerticalDisplay(displayId) ? winRect.posY_ : winRect.posX_;
500     if (splitRatioPointsMap_[displayId].size() == 0) {
501         return;
502     }
503     uint32_t minDiff = std::max(limitRectMap_[displayId].width_, limitRectMap_[displayId].height_);
504     int32_t closestPoint = oriPos;
505     for (const auto& elem : splitRatioPointsMap_[displayId]) {
506         uint32_t diff = (oriPos > elem) ? static_cast<uint32_t>(oriPos - elem) : static_cast<uint32_t>(elem - oriPos);
507         if (diff < minDiff) {
508             closestPoint = elem;
509             minDiff = diff;
510         }
511     }
512     dstPos = closestPoint;
513 }
514 
InitSplitRects(DisplayId displayId)515 void WindowLayoutPolicyCascade::InitSplitRects(DisplayId displayId)
516 {
517     float virtualPixelRatio = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(displayId);
518     uint32_t dividerWidth = static_cast<uint32_t>(DIVIDER_WIDTH * virtualPixelRatio);
519     auto& dividerRect = cascadeRectsMap_[displayId].dividerRect_;
520     const auto& displayRect = DisplayGroupInfo::GetInstance().GetDisplayRect(displayId);
521     if (!IsVerticalDisplay(displayId)) {
522         dividerRect = { static_cast<uint32_t>((displayRect.width_ - dividerWidth) * DEFAULT_SPLIT_RATIO), 0,
523                 dividerWidth, displayRect.height_ };
524     } else {
525         dividerRect = { 0, static_cast<uint32_t>((displayRect.height_ - dividerWidth) * DEFAULT_SPLIT_RATIO),
526                displayRect.width_, dividerWidth };
527     }
528     SetSplitRectByDivider(dividerRect, displayId);
529 }
530 
SetSplitRectByDivider(const Rect& divRect, DisplayId displayId)531 void WindowLayoutPolicyCascade::SetSplitRectByDivider(const Rect& divRect, DisplayId displayId)
532 {
533     auto& dividerRect = cascadeRectsMap_[displayId].dividerRect_;
534     auto& primaryRect = cascadeRectsMap_[displayId].primaryRect_;
535     auto& secondaryRect = cascadeRectsMap_[displayId].secondaryRect_;
536     const auto& displayRect = DisplayGroupInfo::GetInstance().GetDisplayRect(displayId);
537 
538     dividerRect.width_ = divRect.width_;
539     dividerRect.height_ = divRect.height_;
540     if (!IsVerticalDisplay(displayId)) {
541         primaryRect.posX_ = displayRect.posX_;
542         primaryRect.posY_ = displayRect.posY_;
543         primaryRect.width_ = divRect.posX_;
544         primaryRect.height_ = displayRect.height_;
545 
546         secondaryRect.posX_ = divRect.posX_ + static_cast<int32_t>(dividerRect.width_);
547         secondaryRect.posY_ = displayRect.posY_;
548         secondaryRect.width_ = static_cast<uint32_t>(static_cast<int32_t>(displayRect.width_) - secondaryRect.posX_);
549         secondaryRect.height_ = displayRect.height_;
550     } else {
551         primaryRect.posX_ = displayRect.posX_;
552         primaryRect.posY_ = displayRect.posY_;
553         primaryRect.height_ = divRect.posY_;
554         primaryRect.width_ = displayRect.width_;
555 
556         secondaryRect.posX_ = displayRect.posX_;
557         secondaryRect.posY_ = divRect.posY_ + static_cast<int32_t>(dividerRect.height_);
558         secondaryRect.height_ = static_cast<uint32_t>(static_cast<int32_t>(displayRect.height_) - secondaryRect.posY_);
559         secondaryRect.width_ = displayRect.width_;
560     }
561     WLOGFD("DividerRect: [%{public}d %{public}d %{public}u %{public}u] "
562         "PrimaryRect: [%{public}d %{public}d %{public}u %{public}u] "
563         "SecondaryRect: [%{public}d %{public}d %{public}u %{public}u]",
564         dividerRect.posX_, dividerRect.posY_, dividerRect.width_, dividerRect.height_,
565         primaryRect.posX_, primaryRect.posY_, primaryRect.width_, primaryRect.height_,
566         secondaryRect.posX_, secondaryRect.posY_, secondaryRect.width_, secondaryRect.height_);
567 }
568 
GetCurCascadeRect(const sptr<WindowNode>& node) const569 Rect WindowLayoutPolicyCascade::GetCurCascadeRect(const sptr<WindowNode>& node) const
570 {
571     Rect cascadeRect = {0, 0, 0, 0};
572     const DisplayId& displayId = node->GetDisplayId();
573     const auto& appWindowNodeVec = *(const_cast<WindowLayoutPolicyCascade*>(this)->
574         displayGroupWindowTree_[displayId][WindowRootNodeType::APP_WINDOW_NODE]);
575     const auto& aboveAppWindowNodeVec = *(const_cast<WindowLayoutPolicyCascade*>(this)->
576         displayGroupWindowTree_[displayId][WindowRootNodeType::ABOVE_WINDOW_NODE]);
577 
578     std::vector<std::vector<sptr<WindowNode>>> roots = { aboveAppWindowNodeVec, appWindowNodeVec };
579     for (auto& root : roots) {
580         for (auto iter = root.rbegin(); iter != root.rend(); iter++) {
581             if ((*iter)->GetWindowType() == WindowType::WINDOW_TYPE_APP_MAIN_WINDOW &&
582                 (*iter)->GetWindowId() != node->GetWindowId()) {
583                 auto property = (*iter)->GetWindowProperty();
584                 if (property != nullptr && property->GetMaximizeMode() != MaximizeMode::MODE_AVOID_SYSTEM_BAR) {
585                     cascadeRect = ((*iter)->GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING ?
586                         property->GetWindowRect() : property->GetRequestRect());
587                 }
588                 WLOGFD("Get current cascadeRect: %{public}u [%{public}d, %{public}d, %{public}u, %{public}u]",
589                     (*iter)->GetWindowId(), cascadeRect.posX_, cascadeRect.posY_,
590                     cascadeRect.width_, cascadeRect.height_);
591                 break;
592             }
593         }
594     }
595 
596     if (WindowHelper::IsEmptyRect(cascadeRect)) {
597         WLOGFD("cascade rect is empty use first cascade rect");
598         return cascadeRectsMap_[displayId].defaultCascadeRect_;
599     }
600     return StepCascadeRect(cascadeRect, displayId);
601 }
602 
StepCascadeRect(Rect rect, DisplayId displayId) const603 Rect WindowLayoutPolicyCascade::StepCascadeRect(Rect rect, DisplayId displayId) const
604 {
605     float virtualPixelRatio = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(displayId);
606     uint32_t cascadeWidth = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio);
607     uint32_t cascadeHeight = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio);
608 
609     const Rect& limitRect = limitRectMap_[displayId];
610     Rect cascadeRect = {0, 0, 0, 0};
611     cascadeRect.width_ = rect.width_;
612     cascadeRect.height_ = rect.height_;
613     cascadeRect.posX_ = (rect.posX_ + static_cast<int32_t>(cascadeWidth) >= limitRect.posX_) &&
614                         (rect.posX_ + static_cast<int32_t>(rect.width_ + cascadeWidth) <=
615                         (limitRect.posX_ + static_cast<int32_t>(limitRect.width_))) ?
616                         (rect.posX_ + static_cast<int32_t>(cascadeWidth)) : limitRect.posX_;
617     cascadeRect.posY_ = (rect.posY_ + static_cast<int32_t>(cascadeHeight) >= limitRect.posY_) &&
618                         (rect.posY_ + static_cast<int32_t>(rect.height_ + cascadeHeight) <=
619                         (limitRect.posY_ + static_cast<int32_t>(limitRect.height_))) ?
620                         (rect.posY_ + static_cast<int32_t>(cascadeHeight)) : limitRect.posY_;
621     WLOGFD("Step cascadeRect :[%{public}d, %{public}d, %{public}u, %{public}u]",
622         cascadeRect.posX_, cascadeRect.posY_, cascadeRect.width_, cascadeRect.height_);
623     return cascadeRect;
624 }
625 
SetDefaultCascadeRect(const sptr<WindowNode>& node)626 void WindowLayoutPolicyCascade::SetDefaultCascadeRect(const sptr<WindowNode>& node)
627 {
628     auto property = node->GetWindowProperty();
629     if (property == nullptr) {
630         WLOGFE("window property is nullptr.");
631         return;
632     }
633     if (!WindowHelper::IsEmptyRect(property->GetRequestRect())) {
634         return;
635     }
636 
637     static bool isFirstAppWindow = true;
638     Rect rect;
639     if (WindowHelper::IsAppWindow(property->GetWindowType()) && isFirstAppWindow) {
640         WLOGFD("Set first app window cascade rect");
641         rect = cascadeRectsMap_[node->GetDisplayId()].defaultCascadeRect_;
642         isFirstAppWindow = false;
643     } else if (WindowHelper::IsAppWindow(property->GetWindowType()) && !isFirstAppWindow) {
644         WLOGFD("Set other app window cascade rect");
645         rect = GetCurCascadeRect(node);
646     } else {
647         // system window
648         WLOGFD("Set system window cascade rect");
649         rect = cascadeRectsMap_[node->GetDisplayId()].defaultCascadeRect_;
650     }
651     WLOGFD("Set cascadeRect :[%{public}d, %{public}d, %{public}u, %{public}u]",
652         rect.posX_, rect.posY_, rect.width_, rect.height_);
653     node->SetRequestRect(rect);
654     node->SetDecoStatus(true);
655 }
656 
GetDividerRect(DisplayId displayId) const657 Rect WindowLayoutPolicyCascade::GetDividerRect(DisplayId displayId) const
658 {
659     Rect dividerRect = {0, 0, 0, 0};
660     if (cascadeRectsMap_.find(displayId) != std::end(cascadeRectsMap_)) {
661         dividerRect = cascadeRectsMap_[displayId].dividerRect_;
662     }
663     return dividerRect;
664 }
665 
GetDockWindowShowState(DisplayId displayId, Rect& dockWinRect) const666 DockWindowShowState WindowLayoutPolicyCascade::GetDockWindowShowState(DisplayId displayId, Rect& dockWinRect) const
667 {
668     auto& displayWindowTree = displayGroupWindowTree_[displayId];
669     auto& nodeVec = *(displayWindowTree[WindowRootNodeType::ABOVE_WINDOW_NODE]);
670     for (auto& node : nodeVec) {
671         if (node->GetWindowType() != WindowType::WINDOW_TYPE_LAUNCHER_DOCK) {
672             continue;
673         }
674 
675         dockWinRect = node->GetWindowRect();
676         auto displayRect = DisplayGroupInfo::GetInstance().GetDisplayRect(displayId);
677         WLOGI("begin dockWinRect :[%{public}d, %{public}d, %{public}u, %{public}u]",
678             dockWinRect.posX_, dockWinRect.posY_, dockWinRect.width_, dockWinRect.height_);
679         if (dockWinRect.height_ < dockWinRect.width_) {
680             if (static_cast<uint32_t>(dockWinRect.posY_) + dockWinRect.height_ == displayRect.height_) {
681                 return DockWindowShowState::SHOWN_IN_BOTTOM;
682             } else {
683                 return DockWindowShowState::NOT_SHOWN;
684             }
685         } else {
686             if (dockWinRect.posX_ == 0) {
687                 return DockWindowShowState::SHOWN_IN_LEFT;
688             } else if (static_cast<uint32_t>(dockWinRect.posX_) + dockWinRect.width_ == displayRect.width_) {
689                 return DockWindowShowState::SHOWN_IN_RIGHT;
690             } else {
691                 return DockWindowShowState::NOT_SHOWN;
692             }
693         }
694     }
695     return DockWindowShowState::NOT_SHOWN;
696 }
697 
LimitFloatingWindowSize(const sptr<WindowNode>& node, Rect& winRect) const698 void WindowLayoutPolicyCascade::LimitFloatingWindowSize(const sptr<WindowNode>& node, Rect& winRect) const
699 {
700     if (node->GetWindowMode() != WindowMode::WINDOW_MODE_FLOATING) {
701         return;
702     }
703     Rect oriWinRect = winRect;
704     const Rect& displayRect = DisplayGroupInfo::GetInstance().GetDisplayRect(node->GetDisplayId());
705     UpdateFloatingWindowSizeBySizeLimits(node, displayRect, winRect);
706     UpdateFloatingWindowSizeForStretchableWindow(node, displayRect, winRect);
707 
708     // fix size in case of moving window when dragging
709     FixWindowRectWhenDrag(node, oriWinRect, winRect);
710 }
711 
LimitMainFloatingWindowPosition(const sptr<WindowNode>& node, Rect& winRect) const712 void WindowLayoutPolicyCascade::LimitMainFloatingWindowPosition(const sptr<WindowNode>& node, Rect& winRect) const
713 {
714     if (!WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode())) {
715         return;
716     }
717 
718     auto reason = node->GetWindowSizeChangeReason();
719     // if drag or move window, limit size and position
720     if (reason == WindowSizeChangeReason::DRAG) {
721         LimitWindowPositionWhenDrag(node, winRect);
722         FixWindowSizeByRatioIfDragBeyondLimitRegion(node, winRect);
723     } else {
724         // Limit window position, such as init window rect when show
725         LimitWindowPositionWhenInitRectOrMove(node, winRect);
726     }
727 }
728 
UpdateFloatingWindowSizeForStretchableWindow(const sptr<WindowNode>& node, const Rect& displayRect, Rect& winRect) const729 void WindowLayoutPolicyCascade::UpdateFloatingWindowSizeForStretchableWindow(const sptr<WindowNode>& node,
730     const Rect& displayRect, Rect& winRect) const
731 {
732     if (!node->GetStretchable() || !WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode())) {
733         return;
734     }
735     if (node->GetWindowSizeChangeReason() == WindowSizeChangeReason::DRAG) {
736         const Rect &originRect = node->GetOriginRect();
737         if (originRect.height_ == 0 || originRect.width_ == 0) {
738             WLOGE("invalid originRect. window id: %{public}u", node->GetWindowId());
739             return;
740         }
741         auto dragType = node->GetDragType();
742         if (dragType == DragType::DRAG_BOTTOM_OR_TOP) {
743             // if drag height, use height to fix size.
744             winRect.width_ = winRect.height_ * originRect.width_ / originRect.height_;
745         } else if (dragType == DragType::DRAG_LEFT_TOP_CORNER || dragType == DragType::DRAG_RIGHT_TOP_CORNER ||
746                    dragType == DragType::DRAG_LEFT_OR_RIGHT) {
747             // if drag width or corner, use width to fix size.
748             winRect.height_ = winRect.width_ * originRect.height_ / originRect.width_;
749         }
750     }
751     // limit minimum size of window
752 
753     const auto& sizeLimits = node->GetWindowUpdatedSizeLimits();
754     float scale = std::min(static_cast<float>(winRect.width_) / sizeLimits.minWidth_,
755         static_cast<float>(winRect.height_) / sizeLimits.minHeight_);
756     if (MathHelper::NearZero(scale)) {
757         WLOGE("invalid sizeLimits");
758         return;
759     }
760     if (scale < 1.0f) {
761         winRect.width_ = static_cast<uint32_t>(static_cast<float>(winRect.width_) / scale);
762         winRect.height_ = static_cast<uint32_t>(static_cast<float>(winRect.height_) / scale);
763     }
764 }
765 
FixWindowSizeByRatioIfDragBeyondLimitRegion(const sptr<WindowNode>& node, Rect& winRect) const766 void WindowLayoutPolicyCascade::FixWindowSizeByRatioIfDragBeyondLimitRegion(const sptr<WindowNode>& node,
767     Rect& winRect) const
768 {
769     if (!MathHelper::NearZero(node->GetAspectRatio())) {
770         return;
771     }
772     const auto& sizeLimits = node->GetWindowUpdatedSizeLimits();
773     if (sizeLimits.maxWidth_ == sizeLimits.minWidth_ && sizeLimits.maxHeight_ == sizeLimits.minHeight_) {
774         WLOGFD("window rect can not be changed");
775         return;
776     }
777     if (winRect.height_ == 0) {
778         return;
779     }
780     float curRatio = static_cast<float>(winRect.width_) / static_cast<float>(winRect.height_);
781     if (sizeLimits.minRatio_ <= curRatio && curRatio <= sizeLimits.maxRatio_) {
782         WLOGFD("window ratio is satisfied with limit ratio, curRatio: %{public}f", curRatio);
783         return;
784     }
785 
786     float virtualPixelRatio = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(node->GetDisplayId());
787     uint32_t windowTitleBarH = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio);
788     Rect limitRect = (node->isShowingOnMultiDisplays_) ? displayGroupLimitRect_ : limitRectMap_[node->GetDisplayId()];
789     int32_t limitMinPosX = limitRect.posX_ + static_cast<int32_t>(windowTitleBarH);
790     int32_t limitMaxPosX = limitRect.posX_ + static_cast<int32_t>(limitRect.width_ - windowTitleBarH);
791     int32_t limitMinPosY = limitRect.posY_;
792     int32_t limitMaxPosY = limitRect.posY_ + static_cast<int32_t>(limitRect.height_ - windowTitleBarH);
793 
794     Rect dockWinRect;
795     DockWindowShowState dockShownState = GetDockWindowShowState(node->GetDisplayId(), dockWinRect);
796     WLOGFD("dock window show type: %{public}u", dockShownState);
797     if (dockShownState == DockWindowShowState::SHOWN_IN_BOTTOM) {
798         limitMaxPosY = dockWinRect.posY_ - static_cast<int32_t>(windowTitleBarH);
799     } else if (dockShownState == DockWindowShowState::SHOWN_IN_LEFT) {
800         limitMinPosX = dockWinRect.posX_ + static_cast<int32_t>(dockWinRect.width_ + windowTitleBarH);
801     } else if (dockShownState == DockWindowShowState::SHOWN_IN_RIGHT) {
802         limitMaxPosX = dockWinRect.posX_ - static_cast<int32_t>(windowTitleBarH);
803     }
804 
805     float newRatio = curRatio < sizeLimits.minRatio_ ? sizeLimits.minRatio_ : sizeLimits.maxRatio_;
806     if ((winRect.posX_ + static_cast<int32_t>(winRect.width_) == limitMinPosX) || (winRect.posX_ == limitMaxPosX)) {
807         // height can not be changed
808         if (sizeLimits.maxHeight_ == sizeLimits.minHeight_) {
809             return;
810         }
811         winRect.height_ = static_cast<uint32_t>(static_cast<float>(winRect.width_) / newRatio);
812     }
813 
814     if ((winRect.posY_ == limitMinPosY) || (winRect.posX_ == limitMaxPosY)) {
815         // width can not be changed
816         if (sizeLimits.maxWidth_ == sizeLimits.minWidth_) {
817             return;
818         }
819         winRect.width_ = static_cast<uint32_t>(static_cast<float>(winRect.height_) * newRatio);
820     }
821     WLOGFD("After limit by ratio if beyond limit region, winRect: %{public}d %{public}d %{public}u %{public}u",
822         winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
823 }
824 
825 void WindowLayoutPolicyCascade::UpdateFloatingWindowSizeBySizeLimits(const sptr<WindowNode>& node,
826     const Rect& displayRect, Rect& winRect) const
827 {
828     // get new limit config with the settings of system and app
829     const auto& sizeLimits = node->GetWindowUpdatedSizeLimits();
830 
831     // limit minimum size of floating or subWindow (not system type) window
832     if ((!WindowHelper::IsSystemWindow(node->GetWindowType()) &&
833         (!WindowHelper::IsSubWindow(node->GetWindowType()))) ||
834         node->GetWindowType() == WindowType::WINDOW_TYPE_FLOAT_CAMERA ||
835         node->GetWindowType() == WindowType::WINDOW_TYPE_DIALOG) {
836         winRect.width_ = std::max(sizeLimits.minWidth_, winRect.width_);
837         winRect.height_ = std::max(sizeLimits.minHeight_, winRect.height_);
838     }
839     winRect.width_ = std::min(sizeLimits.maxWidth_, winRect.width_);
840     winRect.height_ = std::min(sizeLimits.maxHeight_, winRect.height_);
841     WLOGFD("After limit by size, winRect: %{public}d %{public}d %{public}u %{public}u",
842         winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
843 
844     // width and height can not be changed
845     if (sizeLimits.maxWidth_ == sizeLimits.minWidth_ &&
846         sizeLimits.maxHeight_ == sizeLimits.minHeight_) {
847         winRect.width_ = sizeLimits.maxWidth_;
848         winRect.height_ = sizeLimits.maxHeight_;
849         WLOGFD("window rect can not be changed");
850         return;
851     }
852 
853     if (!MathHelper::NearZero(node->GetAspectRatio())) {
854         return;
855     }
856     float curRatio = static_cast<float>(winRect.width_) / static_cast<float>(winRect.height_);
857     // there is no need to fix size by ratio if this is not main floating window
858     if (!WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode()) ||
859         (sizeLimits.minRatio_ <= curRatio && curRatio <= sizeLimits.maxRatio_)) {
860         WLOGFD("window is system window or ratio is satisfied with limits, curSize: [%{public}d, %{public}d], "
861             "curRatio: %{public}f", winRect.width_, winRect.height_, curRatio);
862         return;
863     }
864 
865     float newRatio = curRatio < sizeLimits.minRatio_ ? sizeLimits.minRatio_ : sizeLimits.maxRatio_;
866     if (sizeLimits.maxWidth_ == sizeLimits.minWidth_) {
867         winRect.height_ = static_cast<uint32_t>(static_cast<float>(winRect.width_) / newRatio);
868         return;
869     }
870     if (sizeLimits.maxHeight_ == sizeLimits.minHeight_) {
871         winRect.width_ = static_cast<uint32_t>(static_cast<float>(winRect.height_) * newRatio);
872         return;
873     }
874 
875     auto dragType = node->GetDragType();
876     if (dragType == DragType::DRAG_BOTTOM_OR_TOP) {
877         // if drag height, use height to fix size.
878         winRect.width_ = static_cast<uint32_t>(static_cast<float>(winRect.height_) * newRatio);
879     } else {
880         // if drag width or corner, use width to fix size.
881         winRect.height_ = static_cast<uint32_t>(static_cast<float>(winRect.width_) / newRatio);
882     }
883     WLOGI("After limit by customize config, winRect: %{public}d %{public}d %{public}u %{public}u",
884         winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
885 }
886 
FixWindowRectWhenDrag(const sptr<WindowNode>& node, const Rect& oriWinRect, Rect& winRect) const887 void WindowLayoutPolicyCascade::FixWindowRectWhenDrag(const sptr<WindowNode>& node,
888     const Rect& oriWinRect, Rect& winRect) const
889 {
890     // fix size in case of moving window when dragging
891     const auto& lastWinRect = node->GetWindowRect();
892     if (node->GetWindowSizeChangeReason() == WindowSizeChangeReason::DRAG) {
893         if (oriWinRect.posX_ != lastWinRect.posX_) {
894             winRect.posX_ = oriWinRect.posX_ + static_cast<int32_t>(oriWinRect.width_) -
895                 static_cast<int32_t>(winRect.width_);
896         }
897         if (oriWinRect.posY_ != lastWinRect.posY_) {
898             winRect.posY_ = oriWinRect.posY_ + static_cast<int32_t>(oriWinRect.height_) -
899                 static_cast<int32_t>(winRect.height_);
900         }
901     }
902 }
903 
LimitWindowPositionWhenDrag(const sptr<WindowNode>& node, Rect& winRect) const904 void WindowLayoutPolicyCascade::LimitWindowPositionWhenDrag(const sptr<WindowNode>& node, Rect& winRect) const
905 {
906     float virtualPixelRatio = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(node->GetDisplayId());
907     uint32_t windowTitleBarH = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio);
908     const Rect& lastRect = node->GetWindowRect();
909     Rect oriWinRect = winRect;
910 
911     Rect limitRect = (node->isShowingOnMultiDisplays_) ? displayGroupLimitRect_ : limitRectMap_[node->GetDisplayId()];
912     int32_t limitMinPosX = limitRect.posX_ + static_cast<int32_t>(windowTitleBarH);
913     int32_t limitMaxPosX = limitRect.posX_ + static_cast<int32_t>(limitRect.width_ - windowTitleBarH);
914     int32_t limitMinPosY = limitRect.posY_;
915     int32_t limitMaxPosY = limitRect.posY_ + static_cast<int32_t>(limitRect.height_ - windowTitleBarH);
916 
917     Rect dockWinRect;
918     DockWindowShowState dockShownState = GetDockWindowShowState(node->GetDisplayId(), dockWinRect);
919     if (dockShownState == DockWindowShowState::SHOWN_IN_BOTTOM) {
920         limitMaxPosY = dockWinRect.posY_ - static_cast<int32_t>(windowTitleBarH);
921     } else if (dockShownState == DockWindowShowState::SHOWN_IN_LEFT) {
922         limitMinPosX = dockWinRect.posX_ + static_cast<int32_t>(dockWinRect.width_ + windowTitleBarH);
923     } else if (dockShownState == DockWindowShowState::SHOWN_IN_RIGHT) {
924         limitMaxPosX = dockWinRect.posX_ - static_cast<int32_t>(windowTitleBarH);
925     }
926 
927     // limitMinPosX is minimum (x + width)
928     if (oriWinRect.posX_ + static_cast<int32_t>(oriWinRect.width_) < limitMinPosX) {
929         if (oriWinRect.width_ != lastRect.width_) {
930             winRect.width_ = static_cast<uint32_t>(limitMinPosX - oriWinRect.posX_);
931         }
932     }
933     // maximum position x
934     if (oriWinRect.posX_ > limitMaxPosX) {
935         winRect.posX_ = limitMaxPosX;
936         if (oriWinRect.width_ != lastRect.width_) {
937             winRect.width_ = static_cast<uint32_t>(
938                 oriWinRect.posX_ + static_cast<int32_t>(oriWinRect.width_) - winRect.posX_);
939         }
940     }
941     // minimum position y
942     if (oriWinRect.posY_ < limitMinPosY) {
943         winRect.posY_ = limitMinPosY;
944         if (oriWinRect.height_ != lastRect.height_) {
945             winRect.height_ = static_cast<uint32_t>(
946                 oriWinRect.posY_ + static_cast<int32_t>(oriWinRect.height_) - winRect.posY_);
947         }
948     }
949     // maximum position y
950     if (winRect.posY_ > limitMaxPosY) {
951         winRect.posY_ = limitMaxPosY;
952         if (oriWinRect.height_ != lastRect.height_) {
953             winRect.height_ = static_cast<uint32_t>(
954                 oriWinRect.posY_ + static_cast<int32_t>(oriWinRect.height_) - winRect.posY_);
955         }
956     }
957     WLOGI("After limit by position, winRect: %{public}d %{public}d %{public}u %{public}u",
958         winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
959 }
960 
LimitWindowPositionWhenInitRectOrMove(const sptr<WindowNode>& node, Rect& winRect) const961 void WindowLayoutPolicyCascade::LimitWindowPositionWhenInitRectOrMove(const sptr<WindowNode>& node, Rect& winRect) const
962 {
963     float virtualPixelRatio = DisplayGroupInfo::GetInstance().GetDisplayVirtualPixelRatio(node->GetDisplayId());
964     uint32_t windowTitleBarH = static_cast<uint32_t>(WINDOW_TITLE_BAR_HEIGHT * virtualPixelRatio);
965 
966     // if is cross-display window, the limit rect should be full limitRect
967     Rect limitRect = (node->isShowingOnMultiDisplays_) ? displayGroupLimitRect_ : limitRectMap_[node->GetDisplayId()];
968 
969     // limit position of the main floating window(window which support dragging)
970     if (WindowHelper::IsMainFloatingWindow(node->GetWindowType(), node->GetWindowMode())) {
971         Rect dockWinRect;
972         DockWindowShowState dockShownState = GetDockWindowShowState(node->GetDisplayId(), dockWinRect);
973         winRect.posY_ = std::max(limitRect.posY_, winRect.posY_);
974         winRect.posY_ = std::min(limitRect.posY_ + static_cast<int32_t>(limitRect.height_ - windowTitleBarH),
975                                  winRect.posY_);
976         if (dockShownState == DockWindowShowState::SHOWN_IN_BOTTOM) {
977             WLOGFD("dock window show in bottom");
978             winRect.posY_ = std::min(dockWinRect.posY_ - static_cast<int32_t>(windowTitleBarH),
979                                      winRect.posY_);
980         }
981         winRect.posX_ = std::max(limitRect.posX_ + static_cast<int32_t>(windowTitleBarH - winRect.width_),
982                                  winRect.posX_);
983         if (dockShownState == DockWindowShowState::SHOWN_IN_LEFT) {
984             WLOGFD("dock window show in left");
985             winRect.posX_ = std::max(static_cast<int32_t>(dockWinRect.width_ + windowTitleBarH - winRect.width_),
986                                      winRect.posX_);
987         }
988         winRect.posX_ = std::min(limitRect.posX_ + static_cast<int32_t>(limitRect.width_ - windowTitleBarH),
989                                  winRect.posX_);
990         if (dockShownState == DockWindowShowState::SHOWN_IN_RIGHT) {
991             WLOGFD("dock window show in right");
992             winRect.posX_ = std::min(dockWinRect.posX_ - static_cast<int32_t>(windowTitleBarH),
993                                      winRect.posX_);
994         }
995         auto reason = node->GetWindowSizeChangeReason();
996         // if init window on pc, limit position
997         if (floatingBottomPosY_ != 0 && reason == WindowSizeChangeReason::UNDEFINED) {
998             int32_t bottomPosY = static_cast<int32_t>(floatingBottomPosY_ * virtualPixelRatio);
999             if (winRect.posY_ + static_cast<int32_t>(winRect.height_) >= bottomPosY) {
1000                 winRect.posY_ = limitRect.posY_;
1001             }
1002         }
1003     }
1004     WLOGI("After limit by position if init or move, winRect: %{public}d %{public}d %{public}u %{public}u",
1005         winRect.posX_, winRect.posY_, winRect.width_, winRect.height_);
1006 }
1007 
GetMaximizeRect(const sptr<WindowNode>& node, Rect& maxRect)1008 void WindowLayoutPolicyCascade::GetMaximizeRect(const sptr<WindowNode>& node, Rect& maxRect)
1009 {
1010     auto property = node->GetWindowProperty();
1011     if (property == nullptr) {
1012         WLOGFE("window property is nullptr.");
1013         return;
1014     }
1015     const auto& displayRect = DisplayGroupInfo::GetInstance().GetDisplayRect(node->GetDisplayId());
1016     const Rect& limitRect = limitRectMap_[node->GetDisplayId()];
1017     Rect dockWinRect = { 0, 0, 0, 0 };
1018     DockWindowShowState dockState = GetDockWindowShowState(node->GetDisplayId(), dockWinRect);
1019     uint32_t dockHeight = dockState == DockWindowShowState::SHOWN_IN_BOTTOM ? dockWinRect.height_ : 0;
1020     maxRect.posX_ = limitRect.posX_;
1021     maxRect.posY_ = limitRect.posY_;
1022     maxRect.width_ = limitRect.width_;
1023     maxRect.height_ = displayRect.height_ - limitRect.posY_ - dockHeight;
1024     WLOGFI("GetMaximizeRect maxRect = %{public}d, %{public}d, %{public}u, %{public}u ",
1025         maxRect.posX_, maxRect.posY_, maxRect.width_, maxRect.height_);
1026 }
1027 } // Rosen
1028 } // OHOS
1029