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