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
28namespace OHOS {
29namespace Rosen {
30namespace {
31constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "Cascade"};
32}
33
34WindowLayoutPolicyCascade::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
48void WindowLayoutPolicyCascade::Launch()
49{
50    InitAllRects();
51    WLOGI("WindowLayoutPolicyCascade::Launch");
52}
53
54void 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
97void 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
108void 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
137void 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
158void 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
168void 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
201void 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
210void WindowLayoutPolicyCascade::SetSplitDividerWindowRects(std::map<DisplayId, Rect> dividerWindowRects)
211{
212    restoringDividerWindowRects_ = dividerWindowRects;
213}
214
215void 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
237void 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
248void 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
277bool 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
314void 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
374void 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
401void 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
428void 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
496void 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
515void 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
531void 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
569Rect 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
603Rect 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
626void 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
657Rect 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
666DockWindowShowState 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
698void 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
712void 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
729void 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
766void 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
825void 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
887void 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
904void 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
961void 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
1008void 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