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