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