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